> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reflections.ai/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> The OpenAPI document at /api-reference/openapi.yaml defines the target contract. Its x-reflections-availability field and each operation's availability notice identify supported test and live forms. Do not infer implementation from a schema or code sample. Live keys support account details, reads of the licenses the calling account holds as licensee or issued as talent (GET /v1/licenses?role=issuer), and GET /v1/generations?license=… for the state of outputs under such a license (summaries only: no prompt, reference, bytes or metadata). Live image checks, submissions and receipts are built but not activated: until activation, a live POST /v1/checks or /v1/generations returns 403 live_not_activated, which must not be retried. Discovery and JWKS are at the origin root (https://app.reflections.ai/.well-known/...), not under /v1.
> Three rules hold everywhere: a decision is never an error (deny and escalate are 200 responses, and a live check still evaluating is a 202 with status checking); generate nothing for a named talent without an allow; deliver nothing until the generation is allow.
> The sandbox accepts personal rk_test_ keys. Persist a separate Idempotency-Key and body for each logical /v1 POST; retry an unknown outcome with the same key and body. OAuth and Talent API MCP remain planned.

# Session token

> The five-minute token a live session carries, its claims, how it is renewed, and how a provider verifies it.

<Note>
  Planned contract. The current sandbox does not create sessions or session tokens. Use the
  [quickstart](/quickstart) for supported check authorization and receipt verification.
</Note>

A live session runs under a session token instead of an authorization token.
[`POST /v1/sessions`](/api-reference/sessions/create-a-session) returns it as `token`, and
[renewing the session](/api-reference/sessions/renew-a-session) returns a new one. Each token lives
5 minutes, and the session is renewed every 60 seconds, so a revoked license stops a session at the
next renewal even when the session stream is lost.

The token is a JWS in compact serialization, signed with ES256.

## Header

```json theme={null}
{
  "alg": "ES256",
  "kid": "rfl-2026-10-docs3",
  "typ": "tlp-session+jwt"
}
```

`typ` is always `tlp-session+jwt`. `kid` names the signing key in the
[JWKS](/api-reference/formats/discovery#jwks).

## Claims

| Claim | Type | Value |
| - | - | - |
| `iss` | string | `https://app.reflections.ai` |
| `aud` | string | The `acct_` ID of the platform that runs the session. |
| `sub` | string | The `acct_` ID of the licensee whose license the session runs under. |
| `jti` | string | The session ID, `ses_…`. The same in every renewed token. |
| `iat` | number | Issue time, in Unix seconds. |
| `exp` | number | Expiry, 5 minutes after `iat`. Equal to the session's `expires_at`. |
| `tlp.ver` | string | The protocol version, `"1.0"`. |
| `tlp.session` | string | The session ID, `ses_…`. |
| `tlp.check` | string | The check that started the session, `chk_…`. |
| `tlp.talent` | string array | The `tal_` IDs the session covers. |
| `tlp.facets` | string array | The `fct_` IDs the session covers, such as one voice. |
| `tlp.licenses` | object array | The licenses the session runs under, as in the [authorization token](/api-reference/formats/authorization-token#claims): one entry per talent whose license applied, in the order of `tlp.talent`, each with `talent`, `license`, `revision` and `terms_digest`. The same in every renewed token. |
| `tlp.use` | object | The session's `use`. |
| `tlp.sampling` | object | The sampling the session must meet: `audio_window_max`, `transcript`, and for video `frame_interval`. |
| `tlp.eu` | string | An HMAC of the end user's ID, in hex. |

## Example payload

A fan voice chat in Maya Okafor's speaking voice, run by Northlight under its platform license:

```json theme={null}
{
  "iss": "https://app.reflections.ai",
  "aud": "acct_7p4r6s9t0wxyhk5zba2q8v1m3n",
  "sub": "acct_7p4r6s9t0wxyhk5zba2q8v1m3n",
  "jti": "ses_q8v1m3n7p4r6s9t0wxyhk5zba2",
  "iat": 1792260000,
  "exp": 1792260300,
  "tlp": {
    "ver": "1.0",
    "session": "ses_q8v1m3n7p4r6s9t0wxyhk5zba2",
    "check": "chk_n7p4r6s9t0wxyhk5zba2q8v1m3",
    "talent": ["tal_9t0wxyhk5zba2q8v1m3n7p4r6s"],
    "facets": ["fct_v1m3n7p4r6s9t0wxyhk5zba2q8"],
    "licenses": [
      {
        "talent": "tal_9t0wxyhk5zba2q8v1m3n7p4r6s",
        "license": "lic_ba2q8v1m3n7p4r6s9t0wxyhk5z",
        "revision": "lrv_7p4r6s9t0wxyhk5zba2q8v1m3n",
        "terms_digest": "sha256:8e0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a"
      }
    ],
    "use": {
      "modality": "speech",
      "kind": "impersonation",
      "purpose": "personal",
      "commercial": false,
      "channels": ["in_app"],
      "territories": ["US"]
    },
    "sampling": { "audio_window_max": "PT15S", "transcript": "every_turn" },
    "eu": "3f9c1a7e5b2d8f4061c3e9a7b5d2f8016e4c9a3b7d1f5e2c8a6b4d0f9e3c7a15"
  }
}
```

Northlight holds this license itself, so `aud` and `sub` are the same account.

## Renewal

| | Value |
| - | - |
| Token lifetime | 5 minutes |
| Renew every | `renew_every`, 60 seconds |
| Renewal returns | A new token and `expires_at`, with the same `jti`, `tlp.licenses` and `tlp.facets` |
| Renewal fails | `409 session_not_active` once the license is revoked, suspended or ends, or the session was terminated |

On `409 session_not_active`, stop output at once. On a network error, `429` or `5xx`, keep retrying, and stop when the current token expires if no renewal succeeded. Pass each new token to the provider that runs the
session; the provider stops when the token it holds expires and no newer one arrives.

## Verify a token

A provider that runs a live voice or video session verifies the token before it starts, and each
renewed token as it arrives. The steps are those for an
[authorization token](/api-reference/formats/authorization-token#verify-a-token), with these
differences:

1. `typ` is `tlp-session+jwt`.
2. `exp` is 5 minutes after `iat`. Allow at most 60 seconds of leeway on `exp` and on `iat`.
3. `tlp.session` is the session you are running.
4. There is no `tlp.max_generations` and no `tlp.execution`. A session token covers one session,
   identified by `jti`, until it expires.
5. A renewed token must have the same `jti`, `tlp.licenses` and `tlp.facets` as the one it replaces.

The session token also authenticates a client on the
[session stream](/api-reference/realtime/session-stream), as the subprotocol
`tlp.session.<token>`, offered with `tlp.session.v1`. The stream checks the token once, when the connection opens; renewing over
REST keeps the session and does not reconnect the stream.

## Related

<Columns cols={2}>
  <Card title="Real-time sessions" icon="microphone" href="/build/real-time-sessions">
    Renewal, sampling, termination and the one-second stop.
  </Card>

  <Card title="Voice platforms" icon="microphone" href="/guides/voice-platforms">
    Licensed voices, scripts and live sessions.
  </Card>
</Columns>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.