API docs

Concepts

The call-request lifecycle

POST /v1/calls creates a call request — a queued instruction to dial. A background dispatcher claims it, re-checks every compliance and capacity gate at dial time, and originates the call. Statuses:

StatusMeaning
queuedWaiting to be dialed (or rescheduled to the next calling window / capacity slot).
dialingClaimed by the dispatcher; originating now.
completedDispatched — the call was successfully placed; call_id is set. Track the call itself via GET /v1/calls/{call_id} and webhooks.
blockedA compliance/capacity gate refused it; error_code says why (recipient_dnd, consent_withdrawn, outside_calling_hours, insufficient_credits, no_from_number).
failedA technical/provider error; error_code is provider_error, error_detail has the reason.
canceledYou canceled it while still queued.

completed means dispatched, not finished. The conversation’s result arrives on the call: GET /v1/calls/{call_id} and the call.completed webhook.

There are no automatic dial retries — a blocked/failed request stays terminal; create a new request when appropriate (your idempotency_key controls dedupe).

external_ref

Pass your own identifier ("external_ref": "crm-lead-4821") when creating a call. It’s stored on the call, echoed in every webhook payload, and filterable: GET /v1/calls?external_ref=…. This is how you join results to your CRM without keeping a mapping table.

Idempotency

Send idempotency_key in the POST /v1/calls body (or an Idempotency-Key header — the body wins if both). Replaying the same key returns the original request with 200 (not 202) and never dials twice. Keys are unique per workspace.

Calling hours

Outbound calls are only placed inside the permitted calling window (Indian telecom regulations — typically 09:00–21:00 IST). Outside it, POST /v1/calls returns 422 outside_calling_hours — unless you pass "schedule_if_outside_hours": true, in which case the request queues and dials when the window opens. You can also schedule explicitly with "scheduled_for": "<ISO8601>".

Variables

variables (a JSON object) personalizes the conversation: they’re merged into the contact’s stored variables (yours win on conflict) and available to the agent’s prompt — e.g. {"name": "Harsh", "due_amount": "₹4,500"}.

Recordings & transcripts

GET /v1/calls/{id}/recording and /transcript are coming soon — they currently return 404 recording_not_available / 404 transcript_not_available. The call.completed payload’s summary and outcome are available today.