# List mini-game logs by user email

List one trader's spin-the-wheel history in your community, newest first, one page at a time.

- Endpoint: `POST https://api.returning.ai/v1/mini-game-logs/by-email`
- Section: Gamification / Streaks and mini games
- Authentication: `Authorization: Bearer <API_KEY>` (Community API key)
- Permission: `customerSuccess` (Shown in the dashboard as "Customer Success")
- 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-streaks-and-mini-games/list-mini-game-logs-by-user-email

## When to use this

- A trader says a spin disappeared, and support needs to see when it was earned, used or expired.
- Check how a trader's wheel streak grew or broke, and which prize each spin paid.
- Confirm that a spin or streak correction was recorded.

**Instead:** Use [Get mini-game and streak state](https://docs.returning.ai/api-reference/gamification-streaks-and-mini-games/get-mini-game-and-streak-state.md) instead to see the spins and streaks a trader has right now.

## Authentication

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

Use a Community API key with `customerSuccess`, shown in the dashboard as Customer Success, and keep it on your server. The key decides the community: you only see entries from your own community. Entries can include a trader's email and prize claim details, so never call this endpoint from a browser or app.

## Behaviour

This read changes nothing. Each event writes one entry, so a trader's history reads as a timeline: a `spin-earned` entry is later followed by `spin-used` or `spin-expired` with the same `spinInventoryId`. Fields depend on `action`, so don't expect every field on every entry.

New events push older entries down while you page. To copy history, start at page 1 and use `_id` to skip entries you already have.

## Request

### Headers

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

### Body

Send the trader's email. The email lookup isn't limited to your community: an email that belongs to someone outside your community returns `200` with an empty list, not `404`. `limit` and `page` also accept numbers sent as strings.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `email` | `string` | Yes | The trader's email. Matched without regard to case. (Email format) |
| `limit` | `integer` | No | Entries per page. (Default 10; max 100) |
| `page` | `integer` | No | Page number, starting at 1. (Whole number, 1 or more; default 1) |

### Example request

```bash
curl --request POST \
  --url https://api.returning.ai/v1/mini-game-logs/by-email \
  --header 'Authorization: Bearer <API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
    "email": "trader@example.com",
    "limit": 20,
    "page": 1
  }'
```

## Response

A `200` returns the page in `data.logs` and the totals in `data.pagination`. An empty `data.logs` means the trader has no mini-game history in your community. It says nothing about whether they can spin now; read Get mini-game and streak state for that. 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. (`Mini game logs fetched successfully`) |
| `data` | `object` | always | The page of entries and the paging totals. |
| `data.logs` | `object[]` | always | Entries on this page, newest first. Empty when the trader has no history in your community. |
| `data.logs._id` | `string` | always | The entry's ID. (`^[a-fA-F0-9]{24}$`) |
| `data.logs.createdAt` | `string` | always | When the event happened, ISO 8601 UTC. Use it for the timeline. (Date-time) |
| `data.logs.action` | `string` | always | What happened: `spin-earned`, `spin-used`, `spin-expired`, `spin-claimed`, `mission-progress`, `streak-earned`, `streak-broken`, `admin-updated`, or a `quiz-...` value. Communities with raffles also see `raffle-...` values. Ignore values you don't recognise. |
| `data.logs.actionDetails` | `string` | - | A readable summary, such as `Complete 3 trades Completed`, `Prize earned: 50 XP 10 Coins`, `streak: 4 days` or `Streak broken`. Wording can change; don't parse it. |
| `data.logs.miniGameType` | `string` | always | The kind of game: `spin_the_wheel` or `quiz`, or `raffle` in communities with raffles. |
| `data.logs.gameName` | `string` | always | The game's name when the entry was written. Names can change. |
| `data.logs.miniGameId` | `string` | always | The game's ID. (`^[a-fA-F0-9]{24}$`) |
| `data.logs.userId` | `string` | always | The trader's platform user ID, as a string. (Decimal digits) |
| `data.logs.user` | `object` | - | A copy of the trader's `id`, `username`, `displayName`, `avatar` and `email` when the entry was written. Personal data: match on `userId` instead, and don't store it. |
| `data.logs.communityId` | `string` | always | Your community ID. (`^[a-fA-F0-9]{24}$`) |
| `data.logs.missionId` | `string` | - | The mission that earned the spin, on `spin-earned` and `mission-progress` entries. |
| `data.logs.missionName` | `string` | - | The mission's name, on the same entries. |
| `data.logs.missionTimeframe` | `string` | - | How often the mission resets. (`daily`, `weekly` or `monthly`) |
| `data.logs.spinCount` | `number` | - | Spins the trader had available after the event. |
| `data.logs.expiresAt` | `string` | - | When the earned spin expires, ISO 8601 UTC. (Date-time) |
| `data.logs.expiredAt` | `string` | - | When the spin was marked expired, on `spin-expired` entries. (Date-time) |
| `data.logs.prizeReward` | `object` | - | The prize before any streak multiplier, as `xp` and `currency` (coins). On `spin-used` and `spin-claimed` entries. |
| `data.logs.prizeReward.currency` | `number` | - | Coins. |
| `data.logs.prizeReward.xp` | `number` | - | XP. |
| `data.logs.finalReward` | `object` | - | What the trader received after the multiplier, as `xp` and `currency` (coins). |
| `data.logs.finalReward.currency` | `number` | - | Coins. |
| `data.logs.finalReward.xp` | `number` | - | XP. |
| `data.logs.multiplier` | `number` | - | The streak multiplier applied to the prize. |
| `data.logs.streakBefore` | `number` | - | The trader's wheel streak before the event. |
| `data.logs.streakAfter` | `number` | - | The trader's wheel streak after the event. `0` on `streak-broken`. |
| `data.logs.streakTimeframe` | `string` | - | The streak period, on streak and correction entries: `daily`, `weekly` or `monthly`. |
| `data.logs.highestStreak` | `number` | - | The trader's best streak on this wheel, on `streak-earned` entries. |
| `data.logs.spinsBefore` | `number` | - | Available spins before a correction, on `admin-updated` entries that changed spins. |
| `data.logs.spinsAfter` | `number` | - | Available spins after the correction. |
| `data.logs.spinsAdded` | `number` | - | Spins the correction added. |
| `data.logs.spinsRemoved` | `number` | - | Spins the correction removed. |
| `data.logs.adminUser` | `object` | - | Who made an `admin-updated` correction. Corrections made through the API show `username` `API Admin`. |
| `data.logs.spinInventoryId` | `string` | - | ID of the spin the entry is about. Use it to pair a `spin-earned` entry with the later `spin-used` or `spin-expired` entry. (`^[a-fA-F0-9]{24}$`) |
| `data.logs.updatedAt` | `string` | always | When the entry last changed, ISO 8601 UTC. (Date-time) |
| `data.logs.actionArray` | `string[]` | - | Extra detail about the actions behind a mission. Its shape can change; don't rely on it. |
| `data.logs.actionId` | `string` | - | An identifier for the event behind the entry. Treat it as opaque text. |
| `data.logs.actionLogs` | `object` | - | Extra detail about the actions behind a mission. Its shape can change; don't rely on it. |
| `data.logs.customFieldResponses` | `object[]` | - | Details the trader entered to claim a prize, on `spin-claimed` entries. Personal data. |
| `data.logs.spinResultId` | `string` | - | ID of the spin's result, on `spin-used` and `spin-claimed` entries. (`^[a-fA-F0-9]{24}$`) |
| `data.pagination` | `object` | always | Paging totals for all of the trader's entries in your community. |
| `data.pagination.total` | `integer` | always | Entries across all pages. (Min 0) |
| `data.pagination.page` | `integer` | always | The page you asked for. (Min 1) |
| `data.pagination.limit` | `integer` | always | The page size used. (1-100) |
| `data.pagination.totalPages` | `integer` | always | Pages at this `limit`. `0` when there are no entries. (Min 0) |

### Example response (200)

```json
{
  "status": "success",
  "message": "Mini game logs fetched successfully",
  "data": {
    "logs": [
      {
        "_id": "66f000000000000000000701",
        "communityId": "66f000000000000000000010",
        "miniGameId": "66f000000000000000000702",
        "userId": "3247779",
        "user": {
          "id": "3247779",
          "username": "sample_trader",
          "displayName": "Sample Trader",
          "avatar": "",
          "email": "trader@example.com"
        },
        "gameName": "Daily Spin the Wheel",
        "miniGameType": "spin_the_wheel",
        "action": "spin-earned",
        "actionDetails": "Complete 3 trades Completed",
        "missionId": "66f000000000000000000704",
        "missionName": "Complete 3 trades",
        "missionTimeframe": "daily",
        "spinInventoryId": "66f000000000000000000703",
        "spinCount": 1,
        "expiresAt": "2026-09-26T23:59:59.999Z",
        "createdAt": "2026-09-26T08:30:00.000Z",
        "updatedAt": "2026-09-26T08:30:00.000Z"
      }
    ],
    "pagination": {
      "total": 1,
      "page": 1,
      "limit": 20,
      "totalPages": 1
    }
  }
}
```

## Errors

Errors on this endpoint have no machine-readable code; branch on the HTTP status. A key without `customerSuccess` gets `401`, not `403`, with only a `message`. A validation `400` names the field in `detail`.

### Fix the request

| Status | Code | What to do |
| --- | --- | --- |
| 400 | - | `email` is missing or isn't an email, `limit` is outside 1-100, or `page` is below 1. `detail` names each field. Correct it and send again. |
| 401 | - | The key is missing, invalid or expired, it's a personal key, or it lacks `customerSuccess` (`message` is then `Your api key does not have permission to access this action`). Send `Authorization: Bearer <API_KEY>` with a current Community API key, and add Customer Success in Settings > Integration > API Keys. |

### Fix the data

| Status | Code | What to do |
| --- | --- | --- |
| 404 | - | No account uses this email. Check the email, or look the trader up with Get User Data. A trader with no history returns `200` with an empty list, not `404`. |

### Retry with backoff

| Status | Code | What to do |
| --- | --- | --- |
| 500 | - | The entries could not be read, or the key could not be checked (`Authentication failed`). Retry the same request with exponential backoff. |

**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`; use bounded exponential backoff. Don't retry a `404` without changing `email`. 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 mini-game and streak state](https://docs.returning.ai/api-reference/gamification-streaks-and-mini-games/get-mini-game-and-streak-state.md): `POST /v1/users/mini-game-streak-stats`. Read the same trader's spins and streaks as they are right now.
- [Confirm the trader is in your community with Get User Data](https://docs.returning.ai/api-reference/users/get-user-data.md): `POST /v1/users/info`.
