A bidirectional session with an Atoms agent. Mint an access token, open
the connection with it, and the server creates a session, bridges audio
and transcripts to the STT/LLM/TTS pipeline, and streams events back until
the client closes or the server ends the session.
Post-call, the full conversation (transcript + recording) is available
at `GET /atoms/v1/conversation/{callId}` using the `call_id` from
`session.created`.
## Connection
### Recommended: short-lived token flow
1. **Register the call.** Call `POST /conversation/register-call`
(see the **Register Call** reference in this section)
with your API key in the `Authorization: Bearer <key>` header and the
`agent_id` (plus optional `mode` and `variables`) in the body. It
returns a short-lived, single-use `access_token` (prefixed `wct_`,
valid for `expires_in` seconds).
2. **Open the WebSocket** with only the token:
```
wss://api.smallest.ai/atoms/v1/agent/connect?token=<access_token>
```
`agent_id`, `mode`, and `variables` are already baked into the token —
don't pass them on the URL.
This keeps your API key server-side; the browser only ever holds the
short-lived token.
### Alternative: connect with your API key directly
You can also connect with a raw API key — `?token=<sk_key>` or
`Authorization: Bearer <sk_key>` — plus the query params below. This is
convenient for server-side or trusted clients. For browser / client-side
apps, prefer the token flow above so your API key is never exposed.
| Parameter | Required | Type | Default | Description |
| --- | --- | --- | --- | --- |
| `token` | Yes\* | string | — | Raw API key (`sk_…`). Alternative to the `Authorization` header. |
| `agent_id` | Yes | string | — | The Atoms agent to connect to. |
| `variables` | No | string | — | URL-encoded JSON object of per-call prompt variables. Overrides the agent's `defaultVariables` for this session only. Values must be `string`, `number`, or `boolean`. Reserved system-variable keys are stripped server-side (they are populated by the server): `call_id`, `conversation_type`, `agent_number`, `user_number`, `current_date`, `current_time`, `current_day`, `agent_gender`, `default_language`, `supported_languages`, `timezone`. |
| `mode` | No | `webcall` \| `chat` | `webcall` | Session mode. `webcall` = full voice pipeline (audio in + audio out). `chat` = text-only pipeline. Invalid values are rejected with a connection error. |
| `sample_rate` | No | integer | `24000` | Requested audio sample rate in Hz for both input and output audio. Valid values: `8000`, `16000`, `24000`, `48000`. The negotiated rate is echoed in `session.created.sample_rate`. Set to `8000` for telephony-quality audio streams. (With a `wct_` token the rate is fixed at 24000.) |
\* `token` or `Authorization: Bearer <key>` — not both.
### Connection errors
- **401 Unauthorized** — invalid or missing token/API key, expired or
already-used `wct_` token, or `agent_id` not found.
- **503 Service Unavailable** — server is gracefully draining. The HTTP upgrade is rejected before the WebSocket handshake completes. Clients should retry with exponential backoff.
### Example: register a call, then connect (recommended)
```javascript
// 1. Mint a short-lived token (server-side — keeps your API key private)
const res = await fetch(
"https://api.smallest.ai/atoms/v1/conversation/register-call",
{
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
agent_id: agentId,
mode: "webcall",
variables: { customer_name: "Tanay", account_tier: "gold" },
}),
}
);
const { data } = await res.json(); // { access_token, expires_in, sample_rate }
// 2. Open the WebSocket with the token (e.g. in the browser)
const ws = new WebSocket(
`wss://api.smallest.ai/atoms/v1/agent/connect?token=${data.access_token}`
);
```
### Example: connect with your API key directly
```javascript
const variables = { customer_name: "Tanay", account_tier: "gold" };
const ws = new WebSocket(
"wss://api.smallest.ai/atoms/v1/agent/connect" +
`?token=${apiKey}` +
`&agent_id=${agentId}` +
`&mode=webcall` +
`&variables=${encodeURIComponent(JSON.stringify(variables))}`
);
```