API Reference
Calls

Get one call by id

GET
/v1/calls/{id}

Authorization

bearerAuth
AuthorizationBearer <token>

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

Path Parameters

id*string

The call's Sautikit UUID, or the PBX session id the same call carries on the wire (HD_…, returned as session_id on POST /v1/calls and on every webhook). Either form addresses the same call.

Query Parameters

transcript?"1"

Set to 1 to embed the call's transcript on the response as call.transcript. There is no separate transcript endpoint — this is how you read a finished AI-agent conversation.

Turns are final and ordered: partials (transcript.delta on the live stream) are never persisted, so a turn appears here only once it has been flushed. Fetch after the call ends — typically from your call.completed handler, which already carries the id.

Omitted (or any other value) returns the plain call detail with no transcript field at all. A call with no AI leg has no transcript to embed.

Value in

  • "1"

Response Body

application/json

application/json

application/json

curl -X GET "https://example.com/v1/calls/string"
{  "call": {    "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",    "workspace_id": "0967198e-ec7b-4c6b-b4d3-f71244cadbe9",    "session_id": "string",    "direction": "inbound",    "local_e164": "string",    "remote_e164": "string",    "country": "string",    "started_at": "2019-08-24T14:15:22Z",    "answered_at": "2019-08-24T14:15:22Z",    "ended_at": "2019-08-24T14:15:22Z",    "duration_seconds": 0,    "status": "ringing",    "cost_minor": 0,    "cost_currency": "string",    "rate_per_minute_minor": 0,    "ledger_entry_id": "34c94b99-ae7e-4ed1-928e-78f0df05c275",    "pbx_call_id": "string",    "failure_code": "string",    "metadata": {},    "created_at": "2019-08-24T14:15:22Z",    "updated_at": "2019-08-24T14:15:22Z",    "events": [      {        "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",        "call_id": "0d0a16ab-a508-4d58-bf24-5dc3cb248f3e",        "kind": "string",        "payload": {},        "occurred_at": "2019-08-24T14:15:22Z",        "created_at": "2019-08-24T14:15:22Z"      }    ],    "transcript": {      "turns": [        {          "role": "string",          "text": "string",          "started_at": "2019-08-24T14:15:22Z",          "ended_at": "2019-08-24T14:15:22Z",          "interrupted": true,          "tool_calls": [            {}          ]        }      ],      "session_end_reason": "string"    },    "streaming": {      "seconds": 90,      "cost_minor": 75,      "currency": "KES"    }  }}
{  "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"  }}

Workspace stats (calls today / failed / minutes / spend) GET

Aggregates over the window selected by `since`. Supported values: `today` (default), `7d`, `month`. Currency follows the workspace wallet currency. **Eventual consistency.** `spend_minor` and (to a lesser extent) `minutes_total` are finalized asynchronously, after the call's `call.completed` event has been processed. The lag between hang-up and stats reflecting final cost is typically under 5 seconds, and can be longer at times of high load. Customers building real-time dashboards SHOULD poll this endpoint no more frequently than every 30 seconds. For per-call cost in near-real-time, subscribe to the `call.completed` webhook event instead — its payload carries the final `cost_minor` after rating.

Live Server-Sent Events stream of a call's lifecycle GET

Opens a `text/event-stream` (SSE) connection that pushes call lifecycle transitions (ringing, answered, completed, failed, …) as they happen. Intended for the in-app dialer's live call view. Past lifecycle events are also embedded inline on the Call resource (`Call.events`) — this endpoint is only for the live tail; there is no separate read endpoint for historical events. For a call handled by an AI agent the same stream also carries the live transcript, as two additional event kinds: - `transcript.turn` — a complete, flushed turn (`{kind, call_id, seq, role, text, final, occurred_at}`). The durable copy of the same turns is on `GET /v1/calls/{id}?transcript=1`. - `transcript.delta` — an incremental chunk of the turn being spoken right now (`delta` instead of `text`). Stream-only: partials are never persisted. The stream opens with a `: ready` SSE comment the moment it attaches — useful as a connection check, and ignorable by any conforming SSE client. A subscriber that joins mid-call is replayed the last 20 transcript events so it does not sit silent until the next turn. Neither transcript kind is available as a workspace webhook — they are per-call and far too chatty for HTTP fan-out. Read them here, with an API key (`calls.read`) like any other call read. Note that a browser `EventSource` cannot send an `Authorization` header, so an API-key subscriber must be server-side (curl, `fetch` with a reader, or any SSE client that sets headers). The connection stays open until the call reaches a terminal state or the client disconnects. The two id forms behave slightly differently by design. A session id (`HD_…`) attaches immediately — the browser dialer knows it before the call row exists, and subscribing early is the point, so no existence check is made; the channel is always scoped to the calling workspace, so an unknown session id simply yields a stream that never emits. A call UUID is looked up, and 404s when this workspace owns no such call. A call whose PBX session has not landed yet holds the request open for a few seconds rather than failing, since origination returns the UUID before the box calls back.