# Get user activity stats

Count one trader's messages, replies, reactions and social actions per day over the last 1 to 90 days.

- Endpoint: `POST https://api.returning.ai/v1/users/activity/stats`
- Section: Gamification / General
- Authentication: `Authorization: Bearer <API_KEY>` (Community API key)
- Permission: `getUserStats` (Shown in the dashboard as "Get User Stats")
- Retries: Read-only; exact retries are safe
- Guide: hand-written
- Verified: live, 2026-09-27
- Last updated: 26 Sep 2026
- Web page: https://docs.returning.ai/api-reference/gamification/get-user-activity-stats

## When to use this

- Show a trader how active they have been this month in your own app.
- Check whether a trader met an activity target, such as 10 messages in a week.
- Spot traders whose activity has dropped off, for a re-engagement campaign.

**Instead:** Use [Get daily user XP and coin changes](https://docs.returning.ai/api-reference/gamification/get-daily-user-xp-and-coin-changes.md) instead to see how much XP and how many coins traders earned on a day.

## Authentication

- Header: `Authorization: Bearer <API_KEY>`
- Permission: `getUserStats`

Use a Community API key with `getUserStats`, shown in the dashboard as Get User Stats, and keep it on your server. The key decides the community: the trader must be a member of it, and only activity in it is counted.

## Behaviour

This read changes nothing. Counts come from the trader's XP and coin history in your community. Each recorded message, reply, reaction or social action counts once. An entry that took XP or coins away, such as for a deleted message, counts as minus one, so a day's figure is net and can be `0` even after activity.

Days run from 00:00 to 23:59 UTC. The range always ends today, so `days: 7` covers today and the six days before it.

## Request

### Headers

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | `string` | Yes | Community API key with `getUserStats`. (`Bearer <API_KEY>`) |
| `Content-Type` | `string` | Yes | Request body format. (`application/json`) |

### Body

Send `identifier` and `identifier_type`. `days` is optional and must be a JSON number. An email with a space where a `+` should be is read as if it had the `+`.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `identifier` | `string` | Yes | The trader's email or platform user ID. Emails ignore case. (Email or platform user ID) |
| `identifier_type` | `string` | Yes | What `identifier` is: `email` or `userId` (platform user ID). `userID` is rejected. |
| `days` | `integer` | No | How many days to count, ending today (UTC). (JSON number, 1-90; default 30) |

### Example request

```bash
curl --request POST \
  --url https://api.returning.ai/v1/users/activity/stats \
  --header 'Authorization: Bearer <API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
    "identifier": "trader@example.com",
    "identifier_type": "email",
    "days": 7
  }'
```

## Response

A `200` returns totals for the range in `data.totals` and one entry per day in `data.daily_stats`, newest first. A trader with no activity gets `0` everywhere: that is a real result, not a missing trader. This endpoint has no top-level `code`; branch on the HTTP status.

### Response fields

| Field | Type | Presence | Description |
| --- | --- | --- | --- |
| `status` | `string` | always | Result of the request. (`success`) |
| `message` | `string` | always | Human-readable summary. Do not branch on it. |
| `data` | `object` | always | The trader's activity. |
| `data.user_id` | `string` | always | The trader's platform user ID, as a string. |
| `data.range` | `object` | always | The days counted. |
| `data.range.start_date` | `string` | always | First day counted, as `YYYY-MM-DD`. |
| `data.range.end_date` | `string` | always | Last day counted, today, as `YYYY-MM-DD`. |
| `data.totals` | `object` | always | Totals across the range. |
| `data.totals.messages` | `integer` | always | Messages posted. |
| `data.totals.replies` | `integer` | always | Replies posted, including replies to a mention. |
| `data.totals.reaction` | `integer` | always | Reactions added. The field name is singular. |
| `data.totals.socials` | `integer` | always | Social media actions the trader was rewarded for. |
| `data.daily_stats` | `object[]` | always | One entry per day in the range, newest first. Days with no activity show `0`. |
| `data.daily_stats.date` | `string` | always | The day, as `YYYY-MM-DD` in UTC. |
| `data.daily_stats.messages` | `integer` | always | Messages posted that day. |
| `data.daily_stats.replies` | `integer` | always | Replies posted that day. |
| `data.daily_stats.reaction` | `integer` | always | Reactions added that day. |
| `data.daily_stats.socials` | `integer` | always | Social actions that day. |

### Example response (200)

```json
{
  "status": "success",
  "message": "User gamification stats fetched successfully",
  "data": {
    "user_id": "3247779",
    "range": {
      "start_date": "2026-09-25",
      "end_date": "2026-09-27"
    },
    "totals": {
      "messages": 5,
      "replies": 2,
      "reaction": 3,
      "socials": 0
    },
    "daily_stats": [
      {
        "date": "2026-09-27",
        "messages": 1,
        "replies": 0,
        "reaction": 2,
        "socials": 0
      },
      {
        "date": "2026-09-26",
        "messages": 4,
        "replies": 2,
        "reaction": 1,
        "socials": 0
      },
      {
        "date": "2026-09-25",
        "messages": 0,
        "replies": 0,
        "reaction": 0,
        "socials": 0
      }
    ]
  }
}
```

## Errors

401 and 403 responses, and the authentication errors `404 COMMUNITY_NOT_FOUND` and `500 AUTHENTICATION_FAILED`, carry the code in `meta.code`. Other errors have no code. A trader who can't be found returns `500`, not `404`, with the reason in `detail`.

### Fix the request

| Status | Code | What to do |
| --- | --- | --- |
| 400 | - | A field is missing or invalid: no `identifier`, `identifier_type` isn't `email` or `userId`, or `days` is sent as a string. `detail` names each field. `days` below 1 or above 90 returns `400` with `message` `Days cannot be less than 1 or greater than 90` and no `detail`. |
| 401 | `AUTHENTICATION_REQUIRED` | The key is missing, invalid or expired. Send `Authorization: Bearer <API_KEY>` with a current Community API key. |
| 403 | `API_KEY_PERMISSION_DENIED` | The key lacks `getUserStats`, or it is a personal key. Use a Community API key and add Get User Stats in Settings > Integration > API Keys. |

### Fix the data

| Status | Code | What to do |
| --- | --- | --- |
| 500 | - | `detail` says why. `User not found`: no account matches the identifier. `User not found in community`: the trader isn't a member of your community. Check the identifier, or look the trader up with Get User Data. Any other `detail` means the counts could not be read; retry with exponential backoff. |
| 404 | `COMMUNITY_NOT_FOUND` | The community this key belongs to no longer exists. Contact Returning.AI support. |

### Retry with backoff

| Status | Code | What to do |
| --- | --- | --- |
| 500 | `AUTHENTICATION_FAILED` | The key could not be checked. Retry with backoff; nothing was read. |

**Retries:** This endpoint is read-only and doesn't accept an `Idempotency-Key`. Retrying the exact same request is safe after a network error or a `500` whose `detail` isn't about the trader; use bounded exponential backoff. Don't retry `User not found` or `User not found in community` without changing `identifier`. Over the [rate limit](https://docs.returning.ai/how-it-works.md#rate-limits), requests return `429`; wait for the window to reset, then retry.

## Next step

- [Get daily user XP and coin changes](https://docs.returning.ai/api-reference/gamification/get-daily-user-xp-and-coin-changes.md): `POST /v1/users/activity/daily`. See the XP and coins the same trader earned on a given day.
- [Check the trader's identifiers with Get User Data](https://docs.returning.ai/api-reference/users/get-user-data.md): `POST /v1/users/info`.
