Core resources
Calls
Place outbound calls, then read everything about them: status, outcome, event timeline, transcript and recording.
Call lifecycle
A call moves through these statuses, and each change sends a webhook event:
Place a call
/v1/calls Returns straight away with "status": "queued". The worker then dials, and the call moves through the statuses above on its own.
Body parameters
| Field | Type | Description |
|---|---|---|
agent_idrequired | uuid | The agent that runs the call. It needs a telephony connection. |
to_numberrequired | string | The number to call, in E.164 format, e.g. +14155550123. |
from_numberoptional | string | The caller ID. Defaults to the telephony connection's number. |
contextoptional | object | Facts for this call. They are added to the agent's prompt. |
metadataoptional | object | Your own key/value data, stored on the call. The agent never sees it. |
tagsoptional | object | Up to 25 string labels for finding calls later, e.g. {"region": "North", "motive": "sales"}. Keys up to 64 characters, values up to 256. The agent never sees them. |
Headers
| Field | Type | Description |
|---|---|---|
Idempotency-Keyoptional | string | Retrying a request with the same key returns the original call instead of dialing again. |
curl -X POST http://localhost:8000/v1/calls \
-H "Authorization: Bearer $OFFHOOK_KEY" \
-H "Idempotency-Key: order-7741" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "<agent-id>",
"to_number": "+14155550123",
"context": { "patient_name": "Priya" },
"tags": { "region": "North", "motive": "sales" }
}'{
"id": "8f2c4d1e-6b7a-4c2e-9f1d-3a5b7c9e1f20",
"status": "queued",
"direction": "outbound",
"provider_call_id": null
} Retrieve a call
/v1/calls/{id} {
"id": "8f2c4d1e-6b7a-4c2e-9f1d-3a5b7c9e1f20",
"status": "completed",
"direction": "outbound",
"to_number": "+14155550123",
"from_number": "+14155550100",
"provider_call_id": "abc-123",
"outcome": { "summary": "Confirmed for Tuesday at 3 PM" },
"error": null,
"error_code": null,
"has_recording": true,
"tags": { "region": "North", "motive": "sales" },
"created_at": "2026-10-15T10:00:00Z",
"started_at": "2026-10-15T10:00:04Z",
"ended_at": "2026-10-15T10:00:42Z"
} List calls
/v1/calls Your calls, newest first. You can combine any of these query parameters:
Query parameters
| Field | Type | Description |
|---|---|---|
statusoptional | string | Only calls with this status, e.g. failed. |
directionoptional | string | outbound or inbound. |
to_number, from_numberoptional | string | Only calls to or from this exact number. |
error_codeoptional | string | Only calls that failed with this error code. |
tagoptional | string | Only calls with this tag, written key:value, e.g. region:North. Repeat it to require several tags at once. |
since, untiloptional | datetime | Only calls created in this range (ISO 8601). |
limit, offsetoptional | int | Paging. limit is 50 by default, at most 200. |
curl "http://localhost:8000/v1/calls?status=failed&limit=20" \
-H "Authorization: Bearer $OFFHOOK_KEY" Find calls by tag
Use the same tags you set when placing the call. One tag
parameter matches one label; add more to narrow the results to calls that have all
of them.
# all calls in the North region
curl "http://localhost:8000/v1/calls?tag=region:North" \
-H "Authorization: Bearer $OFFHOOK_KEY"# North region and sales motive
curl "http://localhost:8000/v1/calls?tag=region:North&tag=motive:sales" \
-H "Authorization: Bearer $OFFHOOK_KEY" Event timeline
/v1/calls/{id}/events Everything that happened on the call, in order. This is the call's audit trail.
[
{ "type": "call.queued", "ts": "…:00Z", "data": {}, "error_code": null },
{ "type": "call.dialing", "ts": "…:00Z", "data": { "provider_call_id": "abc-123" }, "error_code": null },
{ "type": "call.in_progress", "ts": "…:04Z", "data": {}, "error_code": null },
{ "type": "call.completed", "ts": "…:42Z", "data": { "duration_seconds": 38 }, "error_code": null }
] Transcript
/v1/calls/{id}/transcript What was said, turn by turn. t is seconds from the start of the conversation.
{
"call_id": "8f2c4d1e-6b7a-4c2e-9f1d-3a5b7c9e1f20",
"status": "completed",
"summary": "Confirmed for Tuesday at 3 PM",
"transcript": [
{ "role": "assistant", "text": "Hi, this is Alex from Acme Clinic.", "t": 0.4 },
{ "role": "user", "text": "Hi, yes, that's me.", "t": 2.1 },
{ "role": "assistant", "text": "Great. You're confirmed for Tuesday at 3.", "t": 4.0 }
]
} Recording
/v1/calls/{id}/recording
The whole call as one WAV file, with both sides mixed together. Phone calls are
recorded automatically; has_recording on the call tells you whether a
recording exists.
curl http://localhost:8000/v1/calls/8f2c4d1e-6b7a-4c2e-9f1d-3a5b7c9e1f20/recording \
-H "Authorization: Bearer $OFFHOOK_KEY" -o call.wav