# Ephemeral keys

> Short-lived tokens for one end user's device, with their own credit ceiling.

Short-lived tokens for one end user's device, with their own credit ceiling.

When and why to call these: the [ephemeral keys guide](https://docs.lumavox.ai/agents/end-users.md).

## What a token may be minted with

`GET /v1/ephemeral-keys/limits`

```bash title="curl"
curl "https://api.lumavox.ai/v1/ephemeral-keys/limits" \
  -H "Authorization: Bearer $API_KEY"
```

**Responses**

| Status | Description |
|---|---|
| `200` | `application/json` — The ceilings this platform will mint within |
| `401` | Missing or invalid credentials |
| `403` | The key is valid but its scopes do not cover this capability — a key limited to `tts` gets this from `/v1/images` rather than a 401 |
| `422` | The request failed validation |
| `429` | Rate limit exceeded |

**`200` response body**

| Field | Type | Description |
|---|---|---|
| `max_ttl_seconds` | integer | The platform's longest lifetime for a key. |
| `default_ttl_seconds` | integer |  |
| `max_credit_limit_micros` | integer | The platform's largest credit limit for a key. |
| `plan_max_ttl_seconds` | integer or null | Your plan's longest lifetime for one end user's key; `null` sets none. A key is held to the tighter of this and `max_ttl_seconds`. |
| `plan_max_credit_limit_micros` | integer or null | Your plan's largest credit limit for one end user's key, in micro-credits; `null` sets none. A key is held to the tighter of this and `max_credit_limit_micros`. |
| `plan_max_live_keys` | integer or null | How many live keys one end user may hold on your plan; `null` sets none. |
| `grantable_scopes` | array of string |  |

## This organisation's tokens

`GET /v1/ephemeral-keys`

```bash title="curl"
curl "https://api.lumavox.ai/v1/ephemeral-keys" \
  -H "Authorization: Bearer $API_KEY"
```

**Query parameters**

| Name | Type | Required | Description |
|---|---|---|---|
| `live_only` | boolean |  | Default `true`. |
| `limit` | integer |  | How many to answer, 1 to 200. 1–200. Default `50`. |
| `cursor` | string |  | The `next_cursor` of the page before. At least 1 characters. |

**Responses**

| Status | Description |
|---|---|
| `200` | `application/json` — Live tokens, unless you asked for the rest too |
| `400` | The request could not be read: malformed JSON |
| `401` | Missing or invalid credentials |
| `403` | The key is valid but its scopes do not cover this capability — a key limited to `tts` gets this from `/v1/images` rather than a 401 |
| `422` | The request failed validation |
| `429` | Rate limit exceeded |

**`200` response body**

| Field | Type | Description |
|---|---|---|
| `data` | array of EphemeralKeyInfo |  |
| `data[].id` | string |  |
| `data[].label` | string or null |  |
| `data[].prefix` | string |  |
| `data[].last4` | string |  |
| `data[].scopes` | array of string |  |
| `data[].credit_limit_micros` | integer | The most this key may spend, in micro-credits. |
| `data[].credits_spent_micros` | integer | What it has spent, as its end user DO last settled — at the end, or daily for a long-lived key. Final once `settled_at` is set. |
| `data[].credits_remaining_micros` | integer | Micro-credits: 1 credit is 1,000,000. |
| `data[].agent_ids` | array of string or null |  |
| `data[].created_by_api_key_id` | string or null |  |
| `data[].created_by_clerk_user_id` | string or null |  |
| `data[].end_user_id` | string or null |  |
| `data[].created_at` | string (date-time) |  |
| `data[].expires_at` | string (date-time) |  |
| `data[].last_used_at` | string (date-time) or null |  |
| `data[].revoked_at` | string (date-time) or null |  |
| `data[].revoked_reason` | string or null |  |
| `data[].settled_at` | string (date-time) or null | When its end user DO settled it for the last time — what it spent and what came back are final from then. `null` while it is live, and for a few seconds after it ends, longer while a memory job it paid for still runs. |
| `data[].active` | boolean |  |
| `next_cursor` | string or null | Pass as `cursor` for the next page; `null` when this is the last. |

## Mint a token for one end user

`POST /v1/ephemeral-keys`

**A token is prepaid**: its `credit_limit_micros` is set aside from your balance when it is minted — refused with 402 when the balance cannot cover it — and what it does not spend comes back when it expires, runs out or is revoked. Your plan caps a token's limit and lifetime for one end user, how many each end user may hold, how many you mint a minute (429) and how much credit live tokens may hold at once.

```bash title="curl"
curl -X POST "https://api.lumavox.ai/v1/ephemeral-keys" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"credit_limit_micros":0,"end_user_id":"..."}'
```

**Request body** (`application/json`)

| Field | Type | Required | Description |
|---|---|---|---|
| `scopes` | array of string |  | Default `["agent"]`. |
| `credit_limit_micros` | integer | yes | The most this key may spend, in micro-credits (1 credit is 1,000,000). Required — there is no unlimited key. |
| `expires_in_seconds` | integer |  | Default `900`. |
| `end_user_id` | string | yes |  |
| `agent_ids` | array of string or null |  |  |
| `label` | string or null |  | At most 120 characters. |

**Responses**

| Status | Description |
|---|---|
| `201` | `application/json` — The token, returned **once** — only a hash is stored |
| `400` | The request could not be read: malformed JSON |
| `401` | Missing or invalid credentials |
| `402` | The balance cannot set aside this credit limit, or the organisation is suspended or on no plan |
| `403` | Minted with an ephemeral key, or a revoked one |
| `422` | Scopes other than ["agent"], a minting key without `agent`, an unknown end user, or a limit out of range |
| `429` | The plan's ephemeral keys a minute, or a request window — `Retry-After` says when |

**`201` response body**

| Field | Type | Description |
|---|---|---|
| `id` | string |  |
| `label` | string or null |  |
| `prefix` | string |  |
| `last4` | string |  |
| `scopes` | array of string |  |
| `credit_limit_micros` | integer | The most this key may spend, in micro-credits. |
| `credits_spent_micros` | integer | What it has spent, as its end user DO last settled — at the end, or daily for a long-lived key. Final once `settled_at` is set. |
| `credits_remaining_micros` | integer | Micro-credits: 1 credit is 1,000,000. |
| `agent_ids` | array of string or null |  |
| `created_by_api_key_id` | string or null |  |
| `created_by_clerk_user_id` | string or null |  |
| `end_user_id` | string or null |  |
| `created_at` | string (date-time) |  |
| `expires_at` | string (date-time) |  |
| `last_used_at` | string (date-time) or null |  |
| `revoked_at` | string (date-time) or null |  |
| `revoked_reason` | string or null |  |
| `settled_at` | string (date-time) or null | When its end user DO settled it for the last time — what it spent and what came back are final from then. `null` while it is live, and for a few seconds after it ends, longer while a memory job it paid for still runs. |
| `active` | boolean |  |
| `key` | string | The token, in full. **Shown once**: it is signed rather than stored, so it cannot be shown again. |

## One token

`GET /v1/ephemeral-keys/{key_id}`

A token as the organisation's records hold it, live or not. After a revoke, read it until `settled_at` is set: its spend and refund are final from then.

```bash title="curl"
curl "https://api.lumavox.ai/v1/ephemeral-keys/$KEY_ID" \
  -H "Authorization: Bearer $API_KEY"
```

**Path parameters**

| Name | Type | Required | Description |
|---|---|---|---|
| `key_id` | string | yes |  |

**Responses**

| Status | Description |
|---|---|
| `200` | `application/json` — The token |
| `400` | The request could not be read: malformed JSON |
| `401` | Missing or invalid credentials |
| `403` | The key is valid but its scopes do not cover this capability — a key limited to `tts` gets this from `/v1/images` rather than a 401 |
| `404` | Unknown ephemeral key id |
| `422` | The request failed validation |
| `429` | Rate limit exceeded |

**`200` response body**

| Field | Type | Description |
|---|---|---|
| `id` | string |  |
| `label` | string or null |  |
| `prefix` | string |  |
| `last4` | string |  |
| `scopes` | array of string |  |
| `credit_limit_micros` | integer | The most this key may spend, in micro-credits. |
| `credits_spent_micros` | integer | What it has spent, as its end user DO last settled — at the end, or daily for a long-lived key. Final once `settled_at` is set. |
| `credits_remaining_micros` | integer | Micro-credits: 1 credit is 1,000,000. |
| `agent_ids` | array of string or null |  |
| `created_by_api_key_id` | string or null |  |
| `created_by_clerk_user_id` | string or null |  |
| `end_user_id` | string or null |  |
| `created_at` | string (date-time) |  |
| `expires_at` | string (date-time) |  |
| `last_used_at` | string (date-time) or null |  |
| `revoked_at` | string (date-time) or null |  |
| `revoked_reason` | string or null |  |
| `settled_at` | string (date-time) or null | When its end user DO settled it for the last time — what it spent and what came back are final from then. `null` while it is live, and for a few seconds after it ends, longer while a memory job it paid for still runs. |
| `active` | boolean |  |

## Revoke a token

`DELETE /v1/ephemeral-keys/{key_id}`

Answers at once, with the figures from before its end user's records settle it. `GET /v1/ephemeral-keys/{key_id}` reads the final ones once `settled_at` is set — seconds, longer while a memory job it paid for still runs.

```bash title="curl"
curl -X DELETE "https://api.lumavox.ai/v1/ephemeral-keys/$KEY_ID" \
  -H "Authorization: Bearer $API_KEY"
```

**Path parameters**

| Name | Type | Required | Description |
|---|---|---|---|
| `key_id` | string | yes |  |

**Responses**

| Status | Description |
|---|---|
| `200` | `application/json` — The token is dead; anything in flight still settles |
| `400` | The request could not be read: malformed JSON |
| `401` | Missing or invalid credentials |
| `403` | The key is valid but its scopes do not cover this capability — a key limited to `tts` gets this from `/v1/images` rather than a 401 |
| `404` | Unknown ephemeral key id |
| `422` | The request failed validation |
| `429` | Rate limit exceeded |

**`200` response body**

| Field | Type | Description |
|---|---|---|
| `id` | string |  |
| `label` | string or null |  |
| `prefix` | string |  |
| `last4` | string |  |
| `scopes` | array of string |  |
| `credit_limit_micros` | integer | The most this key may spend, in micro-credits. |
| `credits_spent_micros` | integer | What it has spent, as its end user DO last settled — at the end, or daily for a long-lived key. Final once `settled_at` is set. |
| `credits_remaining_micros` | integer | Micro-credits: 1 credit is 1,000,000. |
| `agent_ids` | array of string or null |  |
| `created_by_api_key_id` | string or null |  |
| `created_by_clerk_user_id` | string or null |  |
| `end_user_id` | string or null |  |
| `created_at` | string (date-time) |  |
| `expires_at` | string (date-time) |  |
| `last_used_at` | string (date-time) or null |  |
| `revoked_at` | string (date-time) or null |  |
| `revoked_reason` | string or null |  |
| `settled_at` | string (date-time) or null | When its end user DO settled it for the last time — what it spent and what came back are final from then. `null` while it is live, and for a few seconds after it ends, longer while a memory job it paid for still runs. |
| `active` | boolean |  |

## The credential you are calling with

`GET /v1/token`

Read it when a session starts and after a response — not on a timer.

```bash title="curl"
curl "https://api.lumavox.ai/v1/token" \
  -H "Authorization: Bearer $API_KEY"
```

**Responses**

| Status | Description |
|---|---|
| `200` | `application/json` — What this credential is, what it may do and what it has left |
| `401` | Missing or invalid credentials |
| `422` | The request failed validation |
| `429` | Rate limit exceeded |
