Docs · API · Calls

Calls.

The Calls API is how you place outbound calls, list every call your agents handle — inbound and outbound alike — and fetch the full result of any one call: its recording, diarized transcript, the tools it called, and the outcome. Each call is a live conversation, not a recording you upload.

Call lifecycle#

A call moves through a small set of statuses. Outbound calls start at queued; inbound calls appear once the gateway answers. A terminal status is delivered to your webhook the moment the call ends.

FieldTypeDescription
queuedstatusAccepted and waiting for a line. This is what an outbound POST returns.
ringingstatusThe gateway is dialing the callee (outbound) or the call is being set up.
in_progressstatusConnected — the agent is on the call. Emitted as the call.started webhook.
completedstatusThe conversation ended normally. transcript, tool_calls, outcome, and recording_url are populated.
failedstatusThe call could not complete; error explains. No voice minutes are billed.
no_answerstatusThe callee never picked up before the ring timeout.
busystatusThe callee's line was busy.

Place an outbound call#

POST/v1/calls

Dials to with the given agent and returns the call at queued immediately — the conversation happens asynchronously. Poll GET /v1/calls/{id} or wait for the call.completed webhook for the result.

FieldTypeDescription
agent_idstringrequiredThe agent to run the call. It must be published — an outbound call to a draft agent returns 409 agent_not_published.
phone_number_idstringrequired for phoneThe phone number to place the call from. Required for PSTN calls; omit it for a web call. If the agent has no attachable number the request returns 409 number_unavailable.
tostringrequiredThe destination number in E.164 format, e.g. +966512345678.
varsobjectoptionalPer-call variables interpolated into the conversation — the first message, persona, and tool inputs. Reference them in agent copy as {{name}}. Echoed back on the call as vars.
recordbooleanoptionalOverride the agent's record_calls compliance setting for this one call. When recording is off, recording_url stays null.
metadataobjectoptionalArbitrary key/value pairs stored on the call and returned unchanged — useful for correlating with your CRM.
Request
curl -X POST https://voice.whizztech.ai/v1/calls \
  -H "Authorization: Bearer $WHIZZ_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "ag_7Q2c51b84a07",
    "phone_number_id": "pn_5b8f0d21",
    "to": "+966512345678",
    "vars": { "name": "سلطان", "order": "49207" },
    "record": true,
    "metadata": { "crm_ticket": "T-88213" }
  }'
Response · 201 Created
{
  "id": "call_1d84c0e795b2",
  "object": "call",
  "agent_id": "ag_7Q2c51b84a07",
  "direction": "outbound",
  "status": "queued",
  "from": "+966920000123",
  "to": "+966512345678",
  "phone_number_id": "pn_5b8f0d21",
  "channel": "phone",
  "duration_sec": 0,
  "billed_sec": 0,
  "language": "ar",
  "dialect": "saudi",
  "lang_tier": "arabic",
  "outcome": null,
  "sentiment": null,
  "recording_url": null,
  "vars": { "name": "سلطان", "order": "49207" },
  "campaign_id": null,
  "metadata": { "crm_ticket": "T-88213" },
  "cost": { "voice_credits": 0, "telephony_usd": 0 },
  "error": null,
  "created_at": "2026-07-13T09:33:02.000Z",
  "updated_at": "2026-07-13T09:33:02.000Z",
  "ended_at": null
}

Placing many calls at once? Don't loop this endpoint — create a campaign, which paces recipients at your plan concurrency and rolls up the results.

List calls#

GET/v1/calls

Returns both inbound and outbound calls, newest-first, with cursor pagination. All filters combine (logical AND).

QueryTypeDescription
agent_idstringoptionalOnly calls handled by this agent.
statusstringoptionalOne of queued, ringing, in_progress, completed, failed, no_answer, busy.
directionstringoptionalinbound or outbound.
phone_number_idstringoptionalOnly calls on this number.
campaign_idstringoptionalOnly calls placed by this campaign.
created_afterISO 8601optionalOnly calls created strictly after this timestamp.
created_beforeISO 8601optionalOnly calls created strictly before this timestamp.
limitintegerdefault: 25Page size, 1–100.
starting_afterstringoptionalCursor: a call ID from a previous page. Returns calls older than it.
Request
curl "https://voice.whizztech.ai/v1/calls?direction=outbound&status=completed&created_after=2026-07-01T00:00:00Z&limit=25" \
  -H "Authorization: Bearer $WHIZZ_KEY"
Response · 200 OK
{
  "object": "list",
  "data": [
    {
      "id": "call_1d84c0e795b2",
      "object": "call",
      "agent_id": "ag_7Q2c51b84a07",
      "direction": "outbound",
      "status": "completed",
      "from": "+966920000123",
      "to": "+966512345678",
      "channel": "phone",
      "duration_sec": 52.4,
      "billed_sec": 53,
      "language": "ar",
      "dialect": "saudi",
      "outcome": "resolved",
      "sentiment": "positive",
      "campaign_id": null,
      "created_at": "2026-07-13T09:33:02.000Z"
    }
  ],
  "has_more": true
}

Results come newest-first. When has_more is true, pass the last id of the page as starting_after to get the next one:

Pagination
# next page: pass the last id of the previous page as the cursor
curl "https://voice.whizztech.ai/v1/calls?limit=25&starting_after=call_1d84c0e795b2" \
  -H "Authorization: Bearer $WHIZZ_KEY"

Get a call#

GET/v1/calls/{id}

The full call object. On a completed call, transcript, tool_calls, outcome, and (if recording is on) recording_url are all populated. IDs from other organizations return 404 not_found.

Request
curl https://voice.whizztech.ai/v1/calls/call_1d84c0e795b2 \
  -H "Authorization: Bearer $WHIZZ_KEY"
Response · 200 OK
{
  "id": "call_1d84c0e795b2",
  "object": "call",
  "agent_id": "ag_7Q2c51b84a07",
  "direction": "outbound",
  "status": "completed",
  "from": "+966920000123",
  "to": "+966512345678",
  "phone_number_id": "pn_5b8f0d21",
  "channel": "phone",
  "duration_sec": 52.4,
  "billed_sec": 53,
  "language": "ar",
  "dialect": "saudi",
  "lang_tier": "arabic",
  "outcome": "resolved",
  "sentiment": "positive",
  "recording_url": "https://…signed…",
  "transcript": {
    "segments": [
      { "speaker": "agent", "start": 0.4, "end": 4.8, "text": "حياك الله في خدمة عملاء وِز، معك سلطان؟" },
      { "speaker": "caller", "start": 5.1, "end": 9.7, "text": "إي نعم، عندي استفسار عن الطلب." },
      { "speaker": "agent", "start": 10.0, "end": 15.2, "text": "أبشر، لحظة أتحقق من حالة الطلب." }
    ],
    "language_code": "ar",
    "word_count": 118
  },
  "tool_calls": [
    { "name": "lookup_order", "args": { "id": "49207" }, "result": { "status": "in_transit" } },
    { "name": "expedite_shipment", "args": { "id": "49207" }, "result": { "ok": true } }
  ],
  "vars": { "name": "سلطان", "order": "49207" },
  "campaign_id": null,
  "metadata": { "crm_ticket": "T-88213" },
  "cost": { "voice_credits": 44, "telephony_usd": 0.013 },
  "error": null,
  "created_at": "2026-07-13T09:33:02.000Z",
  "updated_at": "2026-07-13T09:34:01.000Z",
  "ended_at": "2026-07-13T09:33:58.000Z"
}

Call fields#

FieldTypeDescription
statusstringqueued · ringing · in_progress · completed · failed · no_answer · busy.
directionstringinbound (a caller reached the agent) or outbound (you placed the call).
from / tostringThe two ends in E.164. For outbound, from is your number; for inbound, from is the caller.
channelstringphone (PSTN), web (browser widget), or sip (your own trunk).
duration_secnumberWall-clock length of the connected conversation, in seconds (0 until the call ends).
billed_secintegerSeconds billed for voice — duration rounded up, subject to the 10-second minimum.
language / dialectstringThe language spoken (e.g. ar) and, for Arabic, the dialect (e.g. saudi).
outcomestring | nullresolved · unresolved · transferred · voicemail. null until the call completes.
sentimentstring | nullOverall caller sentiment: positive · neutral · negative. null until the call completes.
recording_urlstring | nullA short-lived signed URL to the audio. null when recording is off for the call.
errorstring | nullWhy the call failed, when status is failed / no_answer / busy.

transcript#

FieldTypeDescription
segmentsobject[]Diarized turns: { speaker, start, end, text } with speaker "agent" / "caller" and start/end in seconds.
language_codestringThe language the conversation was transcribed in, as an ISO code (e.g. ar).
word_countintegerTotal words across all segments.

tool_calls#

FieldTypeDescription
namestringThe tool the agent invoked mid-call, as declared on the agent.
argsobjectThe arguments the agent passed, resolved from the conversation and vars.
resultobjectWhat your tool returned. The agent speaks from this to continue the call.

cost#

FieldTypeDescription
voice_creditsintegerCredits charged for the conversation at the agent's language tier. 1 credit = 1 US cent.
telephony_usdnumberPass-through carrier cost for a phone call, at cost. 0 for web calls and bring-your-own SIP.

Web calls#

Calls placed from the embedded browser widget land in the same list and detail endpoints, with channel: "web", no phone_number_id, and no telephony cost — cost.telephony_usd is 0. Everything else — transcript, tool_calls, outcome, recording — works the same as a phone call.