welldun. offhook

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:

queued→ dialing→ in_progress→ completed or failed

Place a call

POST /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

FieldTypeDescription
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

FieldTypeDescription
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" }
  }'

Retrieve a call

GET /v1/calls/{id}
Response
{
  "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

GET /v1/calls

Your calls, newest first. You can combine any of these query parameters:

Query parameters

FieldTypeDescription
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
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"

Event timeline

GET /v1/calls/{id}/events

Everything that happened on the call, in order. This is the call's audit trail.

Response
[
  { "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

GET /v1/calls/{id}/transcript

What was said, turn by turn. t is seconds from the start of the conversation.

Response
{
  "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

GET /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
curl http://localhost:8000/v1/calls/8f2c4d1e-6b7a-4c2e-9f1d-3a5b7c9e1f20/recording \
  -H "Authorization: Bearer $OFFHOOK_KEY" -o call.wav