Calls
Place outbound calls with bidirectional audio streaming, and retrieve call records. Calls are scoped to your agent identity and span dedicated phone numbers plus shared and dedicated iMessage lines.
When you place a call, Inkbox dials the to_number and opens a WebSocket media stream to the client_websocket_url you provide. Your agent connects to that URL to send and receive audio (or text, depending on the pipeline mode). See Media Stream for details on pipeline modes. Alternatively, place the call with mode="hosted_agent" and Inkbox runs Inkbox Voice AI on the call — no WebSocket required.
Place call POST
POST /place-callInitiate an outbound call. Inkbox dials the to_number and opens a bidirectional media stream to your client_websocket_url.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
origination | string | No | "dedicated_number" (default), "shared_imessage_number", or "dedicated_imessage_number". Selects the phone or iMessage line used for the call |
from_number | string | null | Conditional | Caller ID in E.164 — REQUIRED for dedicated_number origination and must be an active number in your org. Omit for either iMessage origination; Inkbox resolves the line from the identity |
to_number | string | Yes | Destination number in E.164 format |
agent_identity_id | UUID | null | Conditional | The agent identity placing the call. Required for either iMessage origination when using an admin API key or the Inkbox Console; identity-scoped API keys resolve their own identity automatically (naming a different one returns 403) |
client_websocket_url | string | null | No | WebSocket URL (wss://) your agent listens on. Can carry text or audio, depending on how the connection is configured. Falls back to the identity's configured client_websocket_url (see Incoming calls) if omitted (400 if none is set). Must be absent when mode is "hosted_agent" (422) |
mode | string | No | Who drives the call: "client_websocket" (default — your agent, over the media stream) or "hosted_agent" (Inkbox Voice AI) |
hosted_agent_authority_mode | string | null | No | Optional data-scope override for a Voice AI call: "contact_scoped" or "yolo". Omit or send null to inherit the identity's saved mode. Explicit "contact_scoped" can always narrow one call; explicit "yolo" requires an admin API key or the Inkbox Console only when the saved mode is "contact_scoped" |
reason | string | null | Conditional | The voice agent's task brief — what this call is for, in plain language. REQUIRED with mode="hosted_agent" (non-empty, max 2,000 characters); invalid with mode="client_websocket" (422) |
voicemail_detection | string | No | "enabled" (default) ends the call when voicemail is detected. "disabled" keeps the call connected so the caller can leave a message |
Request example
To place the call from your agent identity's shared iMessage line, omit from_number — the outbound line is resolved automatically:
To have Inkbox Voice AI run the call, pass mode and a reason instead of a WebSocket URL:
Voicemail detection is enabled by default. Set voicemail_detection to "disabled" when your agent should stay connected and leave a message:
Voice AI inherits the identity's saved authority when
hosted_agent_authority_mode is omitted or null. Set contact_scoped to
narrow one call. Set yolo when the call needs identity-wide access to
contacts, email, SMS, iMessage, or historical calls:
Response (200)
The place call response includes a rate_limit object with your organization's rolling 24-hour usage snapshot (calls_used, calls_remaining, calls_limit, minutes_used, minutes_remaining, minutes_limit).
For shared_imessage_number origination, local_phone_number is null because the shared line is never surfaced. A dedicated_imessage_number call surfaces its dedicated iMessage line as local_phone_number.
Error responses
| Status | Description |
|---|---|
| 400 | from_number is not active, or no WebSocket URL is available |
| 403 | Recipient rejected for policy reasons, an identity-scoped key names a different identity, or yolo would widen a saved contact_scoped mode without an admin API key or the Inkbox Console |
| 404 | from_number not found |
| 409 | For iMessage-line originations: no active shared connection, no dedicated iMessage line, an inactive agent identity, or an identity that is not iMessage-enabled |
| 422 | Cannot call the number itself; for iMessage-line originations, also returned when the line is not voice-enabled or not verified. Also returned for Voice AI shape violations: mode="hosted_agent" without a reason (or with a client_websocket_url), a reason with mode="client_websocket", or hosted_agent_authority_mode="yolo" without mode="hosted_agent" |
| 429 | Organization has exceeded 100 calls or 100 minutes in the last 24 hours. Response includes Retry-After (seconds), X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers |
| 502 | Upstream dial failed |
| 503 | hosted_agent_at_capacity — Voice AI capacity is momentarily saturated; retry shortly. hosted_agent mode only |
For iMessage-line originations, actionable placement rejections use these structured 422 details:
detail.error | detail.code | detail.message |
|---|---|---|
destination_country_not_enabled | D13 | Dialed number is not enabled for this voice line. Contact Inkbox support to enable this destination country. |
invalid_destination_number | D11 | Dialed number is invalid. |
Code examples
List calls GET
GET /callsList calls for an agent identity, newest first — spans dedicated phone numbers plus shared and dedicated iMessage lines.
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
agent_identity_id | UUID | — | The agent identity whose calls to list. Required for admin API keys and Console sessions (omitting it returns 422); identity-scoped keys resolve their own automatically and cannot name another (403) |
limit | integer | 50 | Number of results to return (1–200) |
offset | integer | 0 | Pagination offset |
is_blocked | boolean | — | Filter by blocked state. true returns only blocked rows, false returns only non-blocked rows, and omitting it applies the caller's default visibility |
start_datetime | string | — | Only calls created on or after this date/time |
end_datetime | string | — | Only calls created on or before this date/time; a bare date includes the whole day |
tz | string | UTC | IANA zone for interpreting zone-less start_datetime/end_datetime values. Defaults to UTC |
Identity-scoped API keys never see contact-rule-blocked calls, regardless of is_blocked. Admin API keys and human sessions see blocked and non-blocked calls by default; use is_blocked=true for an admin-side blocked listing.
start_datetime, end_datetime, and tz filter on created_at. Both bounds are optional and non-breaking — omit them for unchanged behavior. See Filtering by date.
Response (200)
Code examples
The number-scoped listing is deprecated.
GET /numbers/{phone_number_id}/callsonly returns calls on that dedicated phone number and omits iMessage-line calls. It accepts the samestart_datetime/end_datetime/tzdate filters for parity. UseGET /callsinstead.
Get call GET
GET /calls/{call_id}Get a single call by ID across all three call origins.
Path parameters
| Parameter | Type | Description |
|---|---|---|
call_id | UUID | Unique identifier of the call |
Response (200)
Returns a call object.
Error responses
| Status | Description |
|---|---|
| 404 | Call not found (for identity-scoped keys, cross-identity reads are masked as 404) |
Code examples
The number-scoped route is deprecated.
GET /numbers/{phone_number_id}/calls/{call_id}cannot address iMessage-line calls. UseGET /calls/{call_id}.
List Voice AI tool activity GET
GET /calls/{call_id}/tool-invocationsList a call's Voice AI tool activity in execution order. Activity is recorded for Voice AI calls using yolo authority; other calls return an empty page.
The response is intentionally safe to display or log. It includes the tool name, execution status, timestamps, and a small result summary. Tool arguments and delivery-system details are not returned.
Path parameters
| Parameter | Type | Description |
|---|---|---|
call_id | UUID | Unique identifier of the call |
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 50 | Number of results to return (1–200) |
offset | integer | 0 | Pagination offset (0–10,000) |
Response (200)
status is "started", "succeeded", or "failed". An accepted write can remain "started" after the call ends while Inkbox finishes it; poll this endpoint until it reaches a terminal status when completion matters.
Error responses
| Status | Description |
|---|---|
| 404 | Call not found (for identity-scoped keys, cross-identity reads are masked as 404) |
| 422 | Invalid pagination value |
Code example
Hang up call POST
POST /calls/{call_id}/hangupEnd a live call from outside it. The agent on the call can always end it in-band over the media WebSocket; this endpoint is the lever for everything else — tests, operator tooling, or any process that only holds the call ID. It works identically on Inkbox Voice AI calls, where it's the operator kill switch.
The carrier confirms the teardown asynchronously, so the returned call may still show its live status for a moment; the final status, ended_at, and transcript land through the normal call lifecycle (including the call.ended webhook).
Path parameters
| Parameter | Type | Description |
|---|---|---|
call_id | UUID | Unique identifier of the call |
Response (200)
Returns the call object as of the hangup request, normally with hangup_reason set to "local". If the call ended on its own at the same moment — the carrier reports it already over before the hangup lands — the request still returns 200, but the call closes with hangup_reason "remote". Don't branch on hangup_reason to confirm the hangup took effect.
Error responses
| Status | Description |
|---|---|
| 404 | Call not found (for identity-scoped keys, cross-identity calls are masked as 404) |
| 409 | call_already_ended — the call already finished; or call_not_active — the call has no active carrier leg yet |
Code examples
Call object
| Field | Type | Description |
|---|---|---|
id | UUID | Unique call identifier |
origin | string | "dedicated_number", "shared_imessage_number", or "dedicated_imessage_number" |
local_phone_number | string | null | Your number (E.164) for dedicated phone and dedicated iMessage calls. null for shared_imessage_number calls — the shared line is never surfaced. |
remote_phone_number | string | The other party's number (E.164) |
direction | string | "outbound" or "inbound" |
status | string | Call status (see below) |
client_websocket_url | string | null | WebSocket URL the call was streamed to |
mode | string | Who drove the call: "client_websocket" or "hosted_agent" |
hosted_agent_authority_mode | string | Authority snapshot for the call: "contact_scoped" or "yolo". Always present |
voicemail_detection | string | Whether voicemail detection was "enabled" or "disabled" for this call. Always present; legacy calls default to "enabled" |
reason | string | null | The voice agent's task brief on outbound hosted_agent calls; null otherwise |
post_call_action_items | array | Open action items Inkbox Voice AI recorded, ordered by seq — each { id, seq, action, details, status }, the same shape the call.ended webhook delivers. Always present; empty for client_websocket calls and Voice AI calls with none |
use_inkbox_tts | boolean | null | Whether Inkbox handles text-to-speech (null until negotiated via WebSocket) |
use_inkbox_stt | boolean | null | Whether Inkbox handles speech-to-text (null until negotiated via WebSocket) |
hangup_reason | string | null | Why the call ended: "local", "remote", "max_duration", "voicemail", "rejected", or "failed" |
started_at | string | null | When the call was answered (ISO 8601) |
ended_at | string | null | When the call ended (ISO 8601) |
is_blocked | boolean | Whether the call was rejected by a contact rule or by default-block in whitelist mode. Identity-scoped API keys never receive rows where this is true |
created_at | string | Creation timestamp (ISO 8601) |
updated_at | string | Last updated timestamp (ISO 8601) |
Call statuses
| Status | Description |
|---|---|
initiated | Call created, dialing in progress |
ringing | Remote party is ringing |
answered | Call connected and active |
completed | Call ended normally |
canceled | Call ended before being answered |
failed | Call could not be connected |