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

# Create realtime session

> Mint a short-lived url and token so a browser can start a realtime voice session with an assistant

Use this endpoint from **your backend**. It returns `{ url, token }` for the browser SDK. Never put your API key in frontend code.

<Info>
  **Rate limited** to 10 requests per minute per authenticated user.

  **Concurrent cap** of 10 sessions per account. Unused tokens count toward this cap until they expire (15 minutes). In-progress website-widget voice sessions on the same account also count.
</Info>

The token expires after 15 minutes. Start the browser session before it expires.

Minting a token does **not** create a Call History row. A row appears only after the browser connects and the session actually starts. Unused tokens leave no call record.

## Request body

<ParamField body="assistant_id" type="string" required>
  The assistant UUID. Use the `uuid` field from [Get Assistants](/api-reference/assistants/get-assistants), not the numeric id.
</ParamField>

<ParamField body="variables" type="object">
  Optional context variables passed into the assistant (prompt variables). Keys and scalar values only. Maximum 50 keys.
</ParamField>

<ParamField body="external_identifier" type="string">
  Optional CRM or customer id. Passed through as a variable when not already set.

  Maximum length: 255 characters.
</ParamField>

## Response

<ResponseField name="id" type="string">
  Session id (UUID). Useful for your own logging.
</ResponseField>

<ResponseField name="url" type="string">
  Media server URL. Pass this to the browser SDK. Do not expose it in a public repo or log it in client analytics.
</ResponseField>

<ResponseField name="token" type="string">
  Short-lived session token. Treat it like a password. Pass it to the browser SDK only.
</ResponseField>

<ResponseField name="expires_in" type="number">
  Token lifetime in seconds. Currently 900 (15 minutes).
</ResponseField>

## Browser SDK

Install `@voice-session/web` and pass `url` and `token` from this response. Do not send the API key to the browser.

```ts theme={null}
import { RealtimeSession } from "@voice-session/web";

const session = new RealtimeSession({ url, token });

session.on("transcript", ({ role, text, final }) => {
  if (final) {
    console.log(role, text);
  }
});

session.on("agent_state", (state) => {
  console.log(state);
});

await session.start({ microphone: true });
```

See [Realtime voice SDK](/ai-assistants/realtime-sdk) for events and a full example.

## Example

```bash theme={null}
curl -X POST "https://app.autocalls.ai/api/user/realtime/session" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "assistant_id": "a7b3c942-5f1e-4d28-8c59-2e4f7a8b9c3d",
    "variables": {
      "name": "Jane"
    },
    "external_identifier": "crm-99"
  }'
```

```json theme={null}
{
  "id": "2c4f1a8e-3b7d-4e9a-9c1f-8d6b2a0e5f33",
  "url": "wss://example.invalid",
  "token": "short-lived-token",
  "expires_in": 900
}
```

## Error responses

<ResponseField name="success" type="boolean">
  `false` when the request fails
</ResponseField>

<ResponseField name="error" type="string">
  Human-readable error message
</ResponseField>

<ResponseField name="error_code" type="string">
  One of `ASSISTANT_NOT_FOUND`, `ASSISTANT_BLOCKED`, `INSUFFICIENT_BALANCE`, `CONCURRENT_LIMIT`, `CONNECTION_FAILED`
</ResponseField>

| Status | `error_code`           | When                                                                     |
| ------ | ---------------------- | ------------------------------------------------------------------------ |
| 401    |                        | Missing or invalid API key                                               |
| 402    | `INSUFFICIENT_BALANCE` | The account does not have enough minutes to start a voice session        |
| 403    | `ASSISTANT_BLOCKED`    | The assistant or account is unavailable for compliance review            |
| 404    | `ASSISTANT_NOT_FOUND`  | Unknown UUID, or the assistant does not belong to the authenticated user |
| 422    |                        | Validation failed (`assistant_id` must be a UUID)                        |
| 429    | `CONCURRENT_LIMIT`     | 10 unused or live realtime sessions already exist for this account       |
| 429    |                        | Rate limit exceeded (10 session creations per minute)                    |
| 503    | `CONNECTION_FAILED`    | The session could not be created. Retry shortly                          |
