Outbound Dialer & Campaigns
The outbound dialer runs calling campaigns: load a contact list, pick a pacing mode, and the dialer paces dials against your agents’ live availability, connects answered calls to the right agent, and recycles unanswered contacts by disposition. Power and predictive modes are kept safe by an abandon-rate governor, and local-presence caller-ID lifts answer rates.
The campaign
Section titled “The campaign”{ "id": "camp_01jay8r2k9m3n6p0xv4zb7dch5", "account_id": "acc_acme", "name": "Q3 renewals", "dial_mode": "power", "list_id": "pl_renewals", "queue_id": "q_support", "flow_id": "flow_renewals", "schedule_id": "sch_support", "cid_number": "15551230000", "cid_pool_id": "cidpool_us", "max_lines": 30, "power_ratio": 1.8, "abandon_cap_pct": 3, "dnc_check": 1, "max_attempts": 3, "retry_after_sec": 3600, "amd": 1, "status": "running"}| Field | Purpose |
|---|---|
dial_mode | Pacing strategy: preview · progressive · power · predictive. |
queue_id | The queue whose ready agents take the connected calls (and drive pacing). |
flow_id | The call flow / script run when an agent is connected (screen-pop the contact data). |
schedule_id | Calling-hours window, evaluated in the called number’s timezone (see Business Hours). |
cid_number / cid_pool_id | Caller-ID: a fixed number, or a local-presence pool. |
max_lines | Max concurrent dials for the campaign. |
power_ratio | Dials per ready agent in power/predictive (e.g. 1.8). |
abandon_cap_pct | The abandon-rate ceiling the governor holds to (default 3%). |
dnc_check | Run the do-not-call check before dialing. |
max_attempts / retry_after_sec | Frequency cap and retry delay per contact. |
amd | Enable answering-machine detection. |
Pacing modes
Section titled “Pacing modes”| Mode | How it paces |
|---|---|
preview | The agent is handed a contact and starts the dial themselves. |
progressive | One line per idle agent: never more dials than waiting agents, so there are no abandons. |
power | floor(ready × power_ratio) − dialing: dials ahead of availability by a ratio, governed by the abandon cap. |
predictive | Same formula, dialing further ahead; the governor continuously tunes the ratio to the cap. |
The pacing engine evaluates the target every few seconds against the queue’s live ready (idle, available) and dialing counts, and originates the difference.
The abandon-rate governor
Section titled “The abandon-rate governor”Power and predictive dialing risk abandoned calls, where a customer answers but no agent is free. Regulations (e.g. TCPA) cap that rate, so SIP.IO governs it automatically with an AIMD-style controller over a rolling window of connects vs. abandons:
abandonRate = abandoned / (connected + abandoned) over cap → ratio × 0.8 (back off hard, floor 1.0 = progressive-safe) under cap → ratio + 0.1 (recover gently, ceiling = power_ratio)The window decays each tick, so the governor tracks recent behavior. It only steers once it has a few samples, and the back-off floor of 1.0 means a misbehaving campaign degrades to progressive (zero-abandon) rather than running away.
Contacts, dispositions & retries
Section titled “Contacts, dispositions & retries”Contacts load into the campaign and move through a lifecycle driven by the disposition an agent (or the system) records:
pending → dialing → connected → [disposition] ▲ │ └──────── retry (next_retry_at) ◄──┤ done · failed · dnc ◄─┘Each disposition code maps to an outcome in your per-account catalog:
outcome | Effect on the contact |
|---|---|
closed | Terminal: done. |
retry / callback | Reschedule for retry_after_sec (or the disposition’s own delay) until max_attempts, then failed. |
dnc | Terminal: added to do-not-call. |
System outcomes work the same way: no_answer/busy/failed reschedule (capped), machine closes as done.
Answering-machine detection (AMD)
Section titled “Answering-machine detection (AMD)”With amd: 1, an answered call is classified human / machine before connecting. A human triggers the agent connect; a machine closes the contact (disposition machine) so an agent is never tied up on voicemail. Ambiguous results are treated as human (connect, don’t drop).
Local-presence caller-ID
Section titled “Local-presence caller-ID”Set cid_pool_id to present a caller-ID local to the number being dialed, since answer rates rise when the call appears local. The dialer picks the pool number whose prefix is the longest match for the called number, falling back to cid_number:
{ "pool_id": "cidpool_us", "e164": "14155550100", "prefix": "1415", "label": "SF Bay" }The connect path
Section titled “The connect path”When a dial is answered, the brain drives the connect using the same reserve→confirm fence as inbound ACD:
- Human → reserve a ready agent from the campaign’s queue and bridge (with the contact’s data for a screen-pop). If no agent is free, the call is counted as abandoned (feeding the governor) and the contact is rescheduled.
- Machine → close as
done. - No answer / busy / failed → reschedule (retry, capped to
max_attempts).
Campaign KPIs
Section titled “Campaign KPIs”GET /campaign/{id}/kpis returns live campaign metrics:
{ "campaign": { "id": "camp_…", "name": "Q3 renewals", "dial_mode": "power", "status": "running" }, "contacts": 5000, "attempts": 7200, "by_status": { "done": 1800, "retry": 900, "dialing": 12, "pending": 2200, "dnc": 40, "failed": 48 }, "by_disposition": { "sale": 320, "no_answer": 1400, "callback": 600, "dnc": 40 }, "rates": { "completion_pct": 37.8, "dnc_pct": 0.8, "avg_attempts": 1.44 }, "pacing": { "ratio": 1.6, "abandonRate": 0.027, "conn": 58, "aband": 2 }}pacing exposes the live governor: the current effective dial ratio and the rolling abandonRate, so you can watch predictive pacing self-tune to your cap.
Control API
Section titled “Control API”Campaigns are driven through the /v1/campaigns API (the campaign scope):
| Method · Path | Action |
|---|---|
POST /campaign | Create a campaign. |
POST /campaign/{id}/contacts | Bulk-load contacts ({ contacts: [{ e164, name?, data? }] }). |
POST /campaign/{id}/start · /pause | Start / pause pacing. |
POST /campaign/{id}/disposition | Record a disposition ({ contactId, code, at? }). |
GET /campaign/{id}/kpis · /status | Live KPIs / contact-status breakdown. |
Status & roadmap
Section titled “Status & roadmap”The campaign control plane is live: the campaign model, all four pacing modes, the abandon-rate governor, the disposition→retry lifecycle, local-presence caller-ID selection, the connect-path logic, and campaign KPIs.
Do-not-call (DNC). With dnc_check on, every number is checked against the dnc_entry list before dialing: the account’s own list plus a platform-global (*) list. A contact dispositioned dnc is added automatically (opt-out capture), and the list is managed via the /v1/dnc API (dnc scope).
Being wired (Phase 1 completion): the media-edge originate path: placing the outbound call and running AMD at the edge, then reporting the answer back to the brain. Until that lands end-to-end, the dialer paces and governs but the edge dial op is in progress.
Roadmap: the preview-mode agent assignment UI and time-series campaign history.