Mint a short-lived WebRTC PBX token for the browser softphone
Requests a workspace-scoped WebRTC bearer token from the PBX. The token is returned as-is from the PBX; the caller passes it to the in-browser softphone SDK to register. Short-lived (typically 60–300 s); renew before expiry.
Optional body fields (client_name, role) are forwarded to
the PBX and reflected in token claims; both may be omitted.
Every body field is optional, but the request body itself must
be valid JSON — send at least {} (an empty body is rejected
400 validation.bad_request).
To bind the token to one of your DIDs (so the WebRTC session
routes through that number), pass either tenant_number_id
(the internal number id) or phone_number (the DID in
E.164). The backend resolves the number's PBX sip-profile and
embeds it as the token's sip.id claim. Omit both to mint a
non-DID-bound token, in which case the PBX assigns sip.id
"default". When both are supplied, tenant_number_id wins.
Authorization
bearerAuth Long-lived ES256 JWT minted from the dashboard (https://app.sautikit.com/developers/api-keys). Signed by the
platform keyring. Carries workspace_id and scopes claims;
revoked via the platform deny-list.
In: header
Request Body
application/json
All fields optional; send {} at minimum.
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/v1/webrtc/token" \ -H "Content-Type: application/json" \ -d '{ "phone_number": "+254712345678", "role": "agent" }'{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3ZTRhMWYxMi05ZDYyLTRmOWEtOWQyZi0xYjJlNmMxYzhhM2E6bWVtLTQyIiwicm9sZSI6ImRpYWxlciJ9.sig", "endpoint": "wss://webrtc.example.com", "protocol": "wss", "clientName": "agent-42", "sipProfile": { "id": "sp_9f2c1a" }, "turnServer": { "iceServers": [ { "urls": "turn:turn.cloudflare.com:3478?transport=udp", "username": "<short-lived>", "credential": "<short-lived>" } ] }, "expiresIn": 900}{ "error": { "code": "validation.bad_request", "message": "string", "request_id": "string", "details": [ "string" ], "resolution": "string", "reason": "invalid_characters", "suggested_e164": "+254727524723" }}{ "error": { "code": "validation.bad_request", "message": "string", "request_id": "string", "details": [ "string" ], "resolution": "string", "reason": "invalid_characters", "suggested_e164": "+254727524723" }}{ "error": { "code": "validation.bad_request", "message": "string", "request_id": "string", "details": [ "string" ], "resolution": "string", "reason": "invalid_characters", "suggested_e164": "+254727524723" }}{ "error": { "code": "validation.bad_request", "message": "string", "request_id": "string", "details": [ "string" ], "resolution": "string", "reason": "invalid_characters", "suggested_e164": "+254727524723" }}{ "error": { "code": "validation.bad_request", "message": "string", "request_id": "string", "details": [ "string" ], "resolution": "string", "reason": "invalid_characters", "suggested_e164": "+254727524723" }}{ "error": { "code": "validation.bad_request", "message": "string", "request_id": "string", "details": [ "string" ], "resolution": "string", "reason": "invalid_characters", "suggested_e164": "+254727524723" }}Fetch the recording resource for a call (redirect, JSON, or status) GET
Returns the recording asset for the given call in one of four ways depending on the recording's lifecycle state and the requested response mode: - **302** (default) — recording is ready; `Location` header carries a 15-minute presigned Sautikit CDN URL. The response body is empty. The client can pass `Location` directly to `<audio src=...>` — audio bytes do NOT flow through the API process. The Sautikit URL is the only URL ever surfaced; the raw PBX URL is never exposed. - **200** — JSON mode: send `Accept: application/json` or `?format=json` and a ready recording is returned as JSON metadata instead of the redirect. `url`/`recording_url` carry the same presigned Sautikit URL the 302 would have used (15-minute TTL), alongside `size_bytes`, `duration_seconds`, `mime`/`content_type`, and `expires_at`. Prefer this mode from browsers: a cross-origin `fetch` cannot follow the 302 (the redirect hop fails CORS) — fetch the JSON and hand `url` to `<audio src=...>` instead. - **202** — recording capture is still in progress (`status: pending`). The client should wait `retry_after_seconds` before re-polling (also reflected in the `Retry-After` response header). Error code: `recording_not_ready`. - **410** — the asset has been pruned per the workspace's storage-tier retention policy and is permanently unavailable. Error code: `recording_unavailable`. - **404** — the call does not exist, belongs to a different workspace, or was never configured for recording. Cross-tenant existence is not leaked. Error code: `recording_not_found`. Workspace isolation: `call_id` must belong to the active workspace; otherwise the endpoint returns 404. `call_id` may be the Sautikit call UUID or the PBX session id (`HD_…`) the same call carries on the wire — a caller that watched the call happen can fetch its recording without looking the UUID up first.
Send a control command to a conference room on the PBX POST
Dispatches one of the allowlisted PBX conference commands to the named room. The room must belong to the active workspace. Unknown commands are rejected with 400. | Command | Effect | |---------|--------| | `mute` / `unmute` | Stop or restore what the room hears from a participant. | | `tmute` | Toggle a participant's mute state. | | `deaf` / `undeaf` | Stop or restore what a participant hears from the room. | | `play` | Play an audio file into the room. | | `say` | Speak text into the room. | | `moh` | Start or stop hold music in the room. | | `dtmf` | Send DTMF digits into the room. | | `relate` | Set the audio relationship between two participants. | | `list` | List the participants currently in the room. | | `exit` | Remove a participant **without ending their call**. | | `kill` | End the conference and hang up every participant. | `exit` is how a caller leaves a room and carries on: the leg does not hang up, it requests a new set of voice actions from `callback_url`, which is required for this command. That is what allows a queued caller to be taken out of a waiting room, offered to an agent, and returned to the room if the agent does not answer. Ending the call instead is what `kill` is for.