Skip to main content

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/campaigns
Scope: dialer:write. Created in draft status — activate it later with PATCH /campaigns/:id.
name
string
required
Human-readable campaign name. 1–200 characters.
mode
string
required
One of preview, progressive, predictive, agentless.
caller_id_e164
string
required
Caller ID presented on each dial, in E.164 format. Must be a number your account owns.
pacing_ratio
number
default:"1.2"
Predictive over-dial ratio. 0.8–3.0.
max_abandon_rate
number
default:"0.03"
Rolling abandon-rate ceiling. Greater than 0 and at most 0.03 (the FCC 3% cap). See FCC abandon-rate ceiling.
target_service_level_seconds
number
default:"20"
Predictive pacing target — seconds to answer. 5–120.
dispatch_mode
string
default:"human"
human or voice_agent. voice_agent requires voice_agent_id.
voice_agent_id
string
AI voice agent that answers each leg when dispatch_mode='voice_agent'. Must reference an existing, non-archived voice agent in your workspace.
concurrency_limit
number
default:"10"
Maximum simultaneous in-flight legs a single batch-dispatch invocation may originate. 1–200.
agent_skills_required
array
default:"[]"
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 }]).
caller_id_pool
array
default:"[]"
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.
caller_id_strategy
string
default:"single"
single (always caller_id_e164), npa_match (present the pool number matching the lead’s area code), or round_robin.
broadcast_message_url
string
HTTPS audio URL played on answer in agentless mode. Required for agentless; rejected for every other mode.
voicemail_message_url
string
HTTPS audio URL dropped when answering-machine detection fires on an agent-driven dial. Not valid for agentless mode.
preview_decision_seconds
number
Per-campaign preview countdown the agent has to accept a contact. Only valid for preview mode; omit to use the platform default.
recording_enabled
boolean
default:"false"
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).
amd_enabled
boolean
default:"false"
Request carrier answering-machine detection on each dial.
application_sid
string
Voice application (UUID) bound to answered legs.
retry_policy
object
default:"{}"
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.
campaign_script
object
Human-agent guided-dialog script (ordered sections plus per-disposition branches). Omit to store the canonical empty script { "version": 1, "sections": [], "branches": {} }.
metadata
object
default:"{}"
Arbitrary key-value pairs stored on the campaign.
cURL
201 Created
Errors

List campaigns

GET /api/v1/dialer/campaigns
Scope: dialer: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/stats
Scope: dialer: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}
Scope: dialer:read. Returns the full campaign row; campaign_script is always the canonical shape. Errors

Update a campaign

PATCH /api/v1/dialer/campaigns/{id}
Scope: dialer:write. Partial update — only the fields you send change. Accepts the same fields as create, plus status.
status
string
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.
Nullable PATCH fields: 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
Errors

Soft-delete a campaign

DELETE /api/v1/dialer/campaigns/{id}
Scope: 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}/lists
Scope: dialer: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}/lists
Scope: dialer:write. Attaches a new contact list to the campaign and enqueues its contacts.
name
string
required
List name. 1–200 characters.
contacts
array
required
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.
max_attempts_per_contact
number
default:"5"
Maximum dial attempts before a contact is exhausted. 1–20.
cURL
Errors

Soft-delete a contact list

DELETE /api/v1/dialer/campaigns/{id}/lists/{listId}
Scope: 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}/stats
Scope: dialer: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-coverage
Scope: dialer: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}/campaigns
Scope: dialer: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}/dispositions
Scope: dialer: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).
attempt_id
string
required
The call-attempt id returned when the dial leg was placed.
disposition
string
required
Agent-selected disposition string (1–100 chars). Matched case-insensitively against the disposition matrix.
callback_scheduled_at
string
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.
notes
string
Free-form agent notes, up to 2000 characters.
The full disposition-to-status matrix and side effects (do-not-call writes, callback scheduling, connect-rate accounting) are documented on the Dialer Dispositions page. Errors

Get the next contact (preview mode)

GET /api/v1/dialer/next-call?campaign_id=dcmp_abc
Scope: dialer: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.
204 No Content — the campaign is progressive or predictive (the pacing engine handles dialing). Errors

Place a preview dial

POST /api/v1/dialer/dial
Scope: dialer: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).
campaign_id
string
required
The preview campaign to dial within.
contact_id
string
required
The contact (from GET /next-call) to dial.
Errors

Batch-dispatch voice-agent legs

POST /api/v1/dialer/campaigns/{id}/batch-dispatch
Scope: dialer: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.
max_legs
number
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).
A successful call returns one of three statuses:
  • 202 Accepted — every claimed leg was originated.
  • 207 Multi-Status — some legs originated and some failed. Inspect each legs[].ok for the per-leg result.
  • 204 No Content — no eligible contacts were pending, so nothing was dispatched on this tick.
202 Accepted / 207 Multi-Status
204 No Content — no pending contacts to dispatch on this tick. Errors

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