Dialer API
The Dialer API runs outbound calling campaigns: preview, progressive, and predictive modes for human agents, plus agentless voice broadcast and AI-voice-agent dispatch. You create a campaign, attach contact lists, then either let the pacing engine dial (progressive / predictive) or pull the next contact yourself (preview). Live statistics, local-presence caller-ID coverage, and per-attempt dispositions round out the surface. Base path:/api/v1/dialer
Authentication: API key (X-API-Key: dv_live_sk_…) or a Clerk session (Authorization: Bearer <token>).
Scopes: read endpoints require dialer:read; create / update / delete endpoints require dialer:write.
Response envelope: every endpoint returns { "data": …, "meta": { "request_id", "timestamp" } }. Errors return { "error": { "code", "message" } } (validation failures also carry error.issues).
Outbound calls placed by the dialer egress only through Orbit’s wholesale voice path. The caller ID you set on a campaign must be a number your account owns (or one you’ve verified) — a foreign number is rejected with
422 UNVERIFIED_CALLER_ID on both create and update.Campaign modes
dispatch_mode is a second axis. The default human fronts the call with a live operator. voice_agent connects each answered leg to the AI voice agent named by voice_agent_id; those campaigns are paced by POST /campaigns/:id/batch-dispatch instead of the human-agent scheduler.
Create a campaign
POST /api/v1/dialer/campaignsdialer:write. Created in draft status — activate it later with PATCH /campaigns/:id.
Human-readable campaign name. 1–200 characters.
One of
preview, progressive, predictive, agentless.Caller ID presented on each dial, in E.164 format. Must be a number your account owns.
Predictive over-dial ratio. 0.8–3.0.
Rolling abandon-rate ceiling. Greater than 0 and at most
0.03 (the FCC 3% cap). See FCC abandon-rate ceiling.Predictive pacing target — seconds to answer. 5–120.
human or voice_agent. voice_agent requires voice_agent_id.AI voice agent that answers each leg when
dispatch_mode='voice_agent'. Must reference an existing, non-archived voice agent in your workspace.Maximum simultaneous in-flight legs a single batch-dispatch invocation may originate. 1–200.
Skills an agent must hold to take this campaign’s calls. Accepts a string array (
["billing","french"]) or per-skill objects ([{ "skill": "billing", "min_level": 3, "weight": 2 }]).Rotation pool of E.164 numbers for local-presence dialing. Every entry must be a number your account owns. Required (non-empty) when
caller_id_strategy is not single.single (always caller_id_e164), npa_match (present the pool number matching the lead’s area code), or round_robin.HTTPS audio URL played on answer in
agentless mode. Required for agentless; rejected for every other mode.HTTPS audio URL dropped when answering-machine detection fires on an agent-driven dial. Not valid for
agentless mode.Per-campaign preview countdown the agent has to accept a contact. Only valid for
preview mode; omit to use the platform default.Record calls on this campaign. Requires
recording_consent_acknowledged: true in the same request.Affirms you have authority to record and the two-party-consent disclaimer will play. Required when
recording_enabled is true. Internal API-key callers cannot acknowledge on behalf of an operator (401).Request carrier answering-machine detection on each dial.
Voice application (UUID) bound to answered legs.
Per-outcome retry backoff keyed by outcome bucket (
no_answer, busy, machine, machine_silence, failed). Each entry sets retry delays (60–86400s) and max_attempts (0–10). Empty {} keeps the platform’s uniform retry schedule.Human-agent guided-dialog script (ordered sections plus per-disposition branches). Omit to store the canonical empty script
{ "version": 1, "sections": [], "branches": {} }.Arbitrary key-value pairs stored on the campaign.
cURL
List campaigns
GET /api/v1/dialer/campaignsdialer:read. Cursor-paginated, newest first. Soft-deleted campaigns are excluded.
Query parameters
Each row carries a bounded
contacts_total / contacts_connected rollup. When a campaign’s contact count exceeds the scan cap, contacts_count_capped is true and the totals are a floor; the envelope’s contacts_count_capped_at reports where the count stops being exact.
On a workspace that has never created a campaign — or one provisioned before the dialer shipped — this endpoint returns an empty list (
items: []) rather than an error, so an empty-state UI renders cleanly.Campaign stats summary
GET /api/v1/dialer/campaigns/statsdialer:read. Totals across every non-deleted campaign — the source of truth for a dashboard KPI strip, independent of pagination.
Query parameters
avg_abandon_rate is null when no active campaign carries a 30-day rate.
Get a campaign
GET /api/v1/dialer/campaigns/{id}dialer:read. Returns the full campaign row; campaign_script is always the canonical shape.
Errors
Update a campaign
PATCH /api/v1/dialer/campaigns/{id}dialer:write. Partial update — only the fields you send change. Accepts the same fields as create, plus status.
active, paused, completed, or aborted. aborted is the operator-initiated terminal state — once aborted, a campaign cannot be re-activated. Transitioning to active is blocked while your workspace’s compliance emergency-stop is engaged.voice_agent_id, voicemail_message_url, preview_decision_seconds, and call_script_id accept null to clear them. Sending caller_id_e164 or any caller_id_pool entry re-runs the ownership check. Sending retry_policy or campaign_script replaces the whole object.
cURL
Soft-delete a campaign
DELETE /api/v1/dialer/campaigns/{id}dialer:write. Soft-deletes the campaign and flips its pending contacts to archived. Terminal contacts (connected / failed / dnc / exhausted / wrong_number) are preserved untouched as a compliance audit trail. Campaign, lists, and contacts commit in one transaction.
Errors
List contact lists
GET /api/v1/dialer/campaigns/{id}/listsdialer:read. Cursor-paginated. Each list carries total_contacts and a live contacts_dialing badge.
Query parameters
Upload a contact list
POST /api/v1/dialer/campaigns/{id}/listsdialer:write. Attaches a new contact list to the campaign and enqueues its contacts.
List name. 1–200 characters.
Contacts to dial. At least one. Each entry:
phone_e164 (required, E.164), display_name (optional, ≤200 chars), contact_id (optional, links to a CRM contact). Duplicate phone_e164 values within the upload are de-duplicated (first occurrence wins) and reported back.Maximum dial attempts before a contact is exhausted. 1–20.
cURL
Soft-delete a contact list
DELETE /api/v1/dialer/campaigns/{id}/lists/{listId}dialer:write. Soft-deletes one list within the campaign. Pending contacts in the list flip to archived; terminal contacts are preserved as audit trail.
Errors
Campaign live stats
GET /api/v1/dialer/campaigns/{id}/statsdialer:read. Wallboard detail for one campaign: per-status contact breakdown, a 24-hour call-outcome rollup with average handle time, and a rolling 30-minute abandonment rate that mirrors what the pacing engine throttles against.
avg_handle_time_seconds is null until a connected call has terminated. contacts_count_capped is true when the contact set exceeds the scan cap (the totals are then a floor).
Errors
Caller-ID coverage
GET /api/v1/dialer/campaigns/{id}/caller-id-coveragedialer:read. Local-presence analytics for one campaign: which destination area codes (NPAs) your caller-ID pool can present locally, the rolling answer rate per destination NPA, and the highest-volume under-covered NPAs to add a local number for. Read-only; originates no calls. North American Numbering Plan (+1) numbers only.
Errors
Voice-agent campaign rollup
GET /api/v1/dialer/voice-agents/{agentId}/campaignsdialer:read. Lists the dispatch_mode='voice_agent' campaigns bound to one AI voice agent, with a per-campaign contact and call-outcome rollup over a rolling window. Cursor-paginated (limit / cursor, next_cursor / has_more). Human-mode campaigns never appear here. The envelope discloses contacts_count_capped_at and rollup_window_days. Returns a zeroed rollup (campaign_count: 0) for an unprovisioned workspace rather than an error.
Submit a disposition
POST /api/v1/dialer/campaigns/{id}/dispositionsdialer:write. An agent submits the outcome of a dial attempt; the platform routes the contact’s lifecycle status from the disposition (for example do_not_call adds the number to your do-not-call list, callback_later reschedules the contact).
The call-attempt id returned when the dial leg was placed.
Agent-selected disposition string (1–100 chars). Matched case-insensitively against the disposition matrix.
ISO-8601 timestamp with offset. Required when the disposition reschedules a callback (
callback_later / callback). Must be in the future and at most 90 days ahead.Free-form agent notes, up to 2000 characters.
Get the next contact (preview mode)
GET /api/v1/dialer/next-call?campaign_id=dcmp_abcdialer:read. For preview-mode campaigns: atomically claims the next eligible contact so two agents polling at once never receive the same row. Progressive / predictive campaigns return 204 No Content — those are server-paced. A preview contact stuck dialing for more than five minutes (agent abandoned the tab) becomes re-claimable.
progressive or predictive (the pacing engine handles dialing).
Errors
Place a preview dial
POST /api/v1/dialer/dialdialer:write. Originates the dial leg for a contact the agent claimed via GET /next-call. Only valid for active preview campaigns; progressive / predictive campaigns dial through the pacing engine. Requires an authenticated operator — an API-key caller cannot dial on behalf of an agent (401 AGENT_REQUIRED).
The preview campaign to dial within.
The contact (from
GET /next-call) to dial.Batch-dispatch voice-agent legs
POST /api/v1/dialer/campaigns/{id}/batch-dispatchdialer:write. Paces a dispatch_mode='voice_agent' campaign: originates up to the campaign’s concurrency_limit simultaneous AI-voice-agent legs. Each answered leg connects to the campaign’s voice_agent_id.
Optional per-invocation cap on legs to originate. 1–200. Clamped to the campaign’s
concurrency_limit (the effective cap is the smaller of the two).- 202 Accepted — every claimed leg was originated.
- 207 Multi-Status — some legs originated and some failed. Inspect each
legs[].okfor the per-leg result. - 204 No Content — no eligible contacts were pending, so nothing was dispatched on this tick.
FCC abandon-rate ceiling
max_abandon_rate is capped at 0.03 (3%) per the FCC Telemarketing Sales Rule. Any create or update that sends a higher value is rejected with 422 VALIDATION_ERROR. The pacing engine also auto-flips a campaign to status: 'aborted' if its rolling 30-day abandon rate trips the ceiling. aborted is terminal and cannot be re-activated — review the abort reason and create a new campaign.
See also
- Dialer Dispositions — the full disposition matrix and contact-status enum
- Voice API — calls, SIP trunks, IVR, conferences
- Numbers API — buy and manage the DIDs you present as caller ID