Documentation Index
Fetch the complete documentation index at: https://orbit-docs.devotel.io/llms.txt
Use this file to discover all available pages before exploring further.
Dialer Dispositions
When an agent submits a disposition on an outbound dial-attempt, the platform routes the contact’s lifecycle status based on a canonical mapping. The correct route is critical: ado_not_call disposition that’s mis-routed leaves the contact in the active pool, which creates a TCPA exposure (47 U.S.C. § 227(b)(3) carries a private right of action with 1,500 statutory damages per call).
This page documents the disposition matrix and the POST /campaigns/:id/dispositions endpoint that agents call to submit them.
Base path: /api/v1/dialer
Authentication: Clerk session (Authorization: Bearer <token>) or API key (X-API-Key).
Scope: dialer:write on every endpoint listed here.
Contact-status enum
dialer_list_contacts.status is the contact lifecycle. An agent disposition routes the contact to one of these statuses:
| Status | Meaning |
|---|---|
pending | Fresh contact, eligible for the next pacing claim once next_attempt_at <= now(). |
dialing | Currently being dialed (or claimed by an agent in preview mode). Atomic flip via FOR UPDATE SKIP LOCKED. |
connected | Talked, voicemail dropped, no answer, AMD-detected, busy, or general “outcome captured”. Terminal for the current attempt; the contact may be re-queued if attempts < max_attempts. |
callback_scheduled | Agent scheduled a callback. next_attempt_at is set to the requested ISO timestamp; pacing claim re-picks the contact at that moment. |
wrong_number | Number was reached but the called party is not the intended contact. Terminal — but not added to the DNC list (the rightful owner may still be contactable on reassignment). |
dnc | Do-not-call. Terminal. The phone is INSERTed into the tenant dnc_list so any future pacing tick across any campaign blocks at the compliance gate (checkDialerCompliance → checkDnc). |
exhausted | Max attempts consumed without a connected outcome. Terminal. |
archived | Soft-deleted via DELETE /campaigns/:id or DELETE /campaigns/:id/lists/:listId. Audit-trail only. |
failed | Carrier-level failure (invalid number, network error). Terminal for the attempt. |
Disposition → status matrix
Disposition matching is case-insensitive and trim-stripped at the request boundary. Any disposition not listed below falls through toconnected (preserving pre-fix semantics for campaign-script-specific freeform dispositions; the agent’s chosen string is still persisted on dialer_call_attempts.disposition).
| Disposition string | Routes to status | Side effects |
|---|---|---|
callback_later | callback_scheduled | Requires callback_scheduled_at in body. Stamps next_attempt_at on the contact. |
callback | callback_scheduled | Same as callback_later. |
wrong_number | wrong_number | Terminal — no DNC write. |
dnc | dnc | INSERT INTO tenant dnc_list (phone, source=dialer_disposition, reason=disposition). Idempotent on phone. |
do_not_call | dnc | Same as dnc. |
sale | connected | None beyond the status flip. |
no_sale | connected | None. |
voicemail | connected | None. The voicemail leg is already captured on dialer_call_attempts.outcome. |
interested | connected | None. |
not_interested | connected | None. |
| any other string | connected | None. The literal disposition string is still persisted for analytics. |
DNC writes are platform-wide per tenant. A
dnc disposition in Campaign A blocks future dials to the same phone in Campaign B, C, etc. on the same tenant — the DNC list is read by every pacing tick across every campaign in the tenant. Inserts are idempotent (UNIQUE on phone), so the first-write wins and existing entries’ source / reason are preserved.Submit disposition
POST /api/v1/dialer/campaigns/{id}/dispositionsdialer:write.
The
dialer_call_attempts.id returned when the dial leg was placed.Agent-selected disposition string. Matched case-insensitively against the matrix above. 1–100 chars.
Free-form agent notes. Persisted with the attempt. Max 2000 chars.
ISO-8601 timestamp with timezone offset. REQUIRED when disposition routes to
callback_scheduled (callback_later / callback). Must be strictly in the future and ≤90 days ahead.cURL
cURL
| Status | error.code | Cause |
|---|---|---|
404 | NOT_FOUND | attempt_id not found in this campaign (or cross-tenant). |
422 | VALIDATION_ERROR | callback_scheduled_at missing on callback disposition, in the past, or >90 days ahead. |
503 | TENANT_SCHEMA_INCOMPLETE | The tenant schema was provisioned before migration 280 ran. Contact support. |
List campaigns
GET /api/v1/dialer/campaignsdialer:read.
Cursor-paginated. Returns campaigns excluding soft-deleted (status = 'deleted') rows.
Query parameters
| Name | Type | Notes |
|---|---|---|
limit | integer (1–100) | Default 20. |
cursor | string | Opaque base64url cursor returned in the previous response’s next_cursor. |
Get next contact (preview mode)
GET /api/v1/dialer/next-call?campaign_id=dcmp_abcdialer:read.
Agent readiness endpoint for preview-mode campaigns. Atomically claims the next eligible contact (CTE + FOR UPDATE SKIP LOCKED) so two agents polling concurrently can never receive the same row. For progressive / predictive campaigns this endpoint returns 204 No Content — pacing is handled server-side by the scheduler.
Stale-claim recovery: A preview contact stuck in dialing for >5 minutes (agent abandoned the tab) is automatically re-claimable. Without this, abandoned previews would block the contact forever.
200 OK
progressive or predictive mode (pacing engine handles dial).
Errors
| Status | error.code | Cause |
|---|---|---|
400 | BAD_REQUEST | campaign_id query parameter missing. |
404 | NOT_FOUND | Campaign not found or not in active status. |
Soft-delete a campaign
DELETE /api/v1/dialer/campaigns/{id}dialer:write.
Soft-deletes the campaign. Pending contacts flip to archived; terminal contacts (connected / failed / dnc / exhausted / wrong_number) are left untouched as TCPA-dispute audit trail. All three updates (campaign, lists, contacts) commit in a single transaction.
Errors
| Status | error.code | Cause |
|---|---|---|
404 | NOT_FOUND | Campaign id not found or already soft-deleted. |
409 | DIALER_CAMPAIGN_IN_FLIGHT | At least one contact is currently in status dialing. Pause the campaign and wait for live legs to terminate, then retry. The details.in_flight_contacts count is returned. |
FCC abandon-rate ceiling
max_abandon_rate is hard-capped at 0.03 (3%) per the FCC Telemarketing Sales Rule. Any POST or PATCH request that sends a value above this is rejected with 422 VALIDATION_ERROR. The scheduler also auto-flips campaigns to status: 'aborted' if the rolling 30-day abandon rate trips the ceiling — aborted is terminal and cannot be re-activated; create a new campaign after reviewing the abort reason.