# Session Tokens

Session tokens are **one-time-use tokens** that grant a single play of a game or stream. They
prevent abuse by ensuring each token can only be consumed once.

:::caution[Enable "Require API Session Token"]
For session tokens to take effect, you must enable
the **"Require API Session Token"** setting on each game or stream in the **Configuration** tab.
Without this setting enabled, games will be playable without any token restrictions.
:::

## Token Lifecycle

A session token goes through the following states:

```
active  →  consumed   (user played the game)
        →  expired    (token passed its expiration time)
        →  revoked    (manually invalidated)
```

## Step 1: Create a Session

Call the session creation endpoint from your server with your API key:

```bash
curl -X POST https://app.dailyplay.ai/api/org-api-keys?action=create-session \
  -H "Content-Type: application/json" \
  -H "x-api-key: dpk_YOUR_API_KEY" \
  -d '{
    "game_id": 42,
    "external_ref": "user-12345",
    "metadata": { "campaign": "summer-promo" },
    "expires_in_minutes": 60
  }'
```

### Request Parameters

| Parameter            | Type   | Required                        | Description                                              |
| -------------------- | ------ | ------------------------------- | -------------------------------------------------------- |
| `game_id`            | number | One of `game_id` or `stream_id` | The game to grant access to                              |
| `stream_id`          | number | One of `game_id` or `stream_id` | The stream to grant access to                            |
| `external_ref`       | string | No                              | Your reference ID for tracking (e.g., user ID, order ID) |
| `metadata`           | object | No                              | Arbitrary JSON data for your own tracking                |
| `expires_in_minutes` | number | No                              | Token expiry in minutes (default: 1440 = 24 hours)       |

### Response

```json
{
  "success": true,
  "data": {
    "token": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "stream_id": null,
    "game_id": 42,
    "expires_at": "2026-02-17T12:00:00.000Z",
    "external_ref": "user-12345"
  }
}
```

## Step 2: Redirect the User

Build a URL with the session token and redirect the end user to it:

```
https://app.dailyplay.ai/embed/42?session_token=a1b2c3d4-e5f6-7890-abcd-ef1234567890
```

For streams:

```
https://app.dailyplay.ai/stream/<org-slug>/<stream_id>?session_token=a1b2c3d4-e5f6-7890-abcd-ef1234567890
```

## Step 3: Validate the Token

Before allowing play, the token is validated to ensure it is still active and not expired:

```bash
curl https://app.dailyplay.ai/api/org-api-keys?action=validate-session&token=a1b2c3d4-e5f6-7890-abcd-ef1234567890
```

### Response

```json
{
  "success": true,
  "data": {
    "valid": true,
    "status": "active",
    "stream_id": null,
    "game_id": 42,
    "expires_at": "2026-02-17T12:00:00.000Z",
    "external_ref": "user-12345",
    "metadata": { "campaign": "summer-promo" }
  }
}
```

## Step 4: Consume the Token

When the user starts playing, the token is consumed so it cannot be reused:

```bash
curl -X POST https://app.dailyplay.ai/api/org-api-keys?action=consume-session \
  -H "Content-Type: application/json" \
  -d '{
    "token": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "player_uuid": "player-uuid-here"
  }'
```

### Success Response

```json
{
  "success": true,
  "data": {
    "session_id": 1,
    "org_id": 5,
    "stream_id": null,
    "game_id": 42,
    "external_ref": "user-12345",
    "metadata": { "campaign": "summer-promo" }
  }
}
```

### Already Consumed or Expired

If the token has already been used or has expired, the API returns a `410 Gone` status:

```json
{
  "success": false,
  "error": "Session is invalid, already consumed, or expired"
}
```

## Token Properties

| Property                | Description                                                  |
| ----------------------- | ------------------------------------------------------------ |
| `token`                 | UUID v4 identifier — passed in the game URL                  |
| `stream_id` / `game_id` | The target resource (at least one is required)               |
| `external_ref`          | Your reference ID for correlating with your system           |
| `metadata`              | Arbitrary JSON payload you attached at creation              |
| `status`                | Current state: `active`, `consumed`, `expired`, or `revoked` |
| `expires_at`            | When the token will automatically expire                     |

## Expiration

- Tokens default to a **24-hour expiry** if `expires_in_minutes` is not specified
- Expired tokens are automatically cleaned up by a background process
- You can set expiry as short as 1 minute for time-sensitive use cases

## Error Handling

| Status Code | Meaning                                                |
| ----------- | ------------------------------------------------------ |
| `200`       | Token is valid / operation succeeded                   |
| `400`       | Missing or invalid parameters                          |
| `401`       | Invalid or revoked API key                             |
| `403`       | API key does not have access to the requested resource |
| `410`       | Token is already consumed or expired                   |
| `429`       | Rate limit exceeded                                    |