Campaigns¶
Batch, paced outbound calling: upload a contact list once, and AiFlow
dials through it at a configured pace, instead of the strictly
one-call-per-matched-event flow that
Triggers drive. Each contact becomes exactly one
Call once dialed, and from there that Call's own status
tracks the actual call.
Endpoint family¶
GET /api/v1/agents/{agent_id}/campaigns
POST /api/v1/agents/{agent_id}/campaigns
GET /api/v1/agents/{agent_id}/campaigns/{campaign_id}
POST /api/v1/agents/{agent_id}/campaigns/{campaign_id}/contacts
GET /api/v1/agents/{agent_id}/campaigns/{campaign_id}/progress
POST /api/v1/agents/{agent_id}/campaigns/{campaign_id}/start
POST /api/v1/agents/{agent_id}/campaigns/{campaign_id}/pause
POST /api/v1/agents/{agent_id}/campaigns/{campaign_id}/cancel
Authentication and roles¶
Every endpoint takes an admin session token (see
Authentication). Reading (GET)
is available to every role, including Viewer. Every mutating action
requires Owner, Admin, or Editor.
Lifecycle¶
stateDiagram-v2
[*] --> draft
draft --> running: start
running --> paused: pause
paused --> running: start
running --> completed: every contact dispatched
draft --> cancelled: cancel
running --> cancelled: cancel
paused --> cancelled: cancel
completed --> [*]
cancelled --> [*]
A campaign starts as draft: create it, then upload one or more contact
CSVs (uploading again just appends more pending contacts, even onto a
running campaign). start begins dispatching.
One shared background tick paces every running campaign, rather than a worker
per campaign. It creates one call at a time, spaced by pacing_per_minute,
and hands each to the same durable queue used by
manual calls and
Trigger-placed calls. Per-agent concurrency limits and retry
behaviour are therefore unchanged.
If Twilio Lookup screening is on, each number is checked just before dialling. A number that comes back invalid, or on a blocked line type, is marked failed and never dialled.
pause stops new dispatches and leaves calls already placed alone. cancel
stops dispatching and marks every still-pending contact cancelled. A
campaign that runs out of pending contacts becomes completed on its own.
Create a campaign¶
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | 1-120 characters. |
pacing_per_minute |
integer | No | Contacts dispatched per minute, 1-60. Defaults to 10. |
{
"id": 7,
"agent_id": 1,
"name": "Q1 lapsed customers",
"status": "draft",
"pacing_per_minute": 5,
"created_at": "2026-01-15T10:00:00Z"
}
Upload contacts¶
A multipart file upload, multipart/form-data with a file field: a CSV
with a required phone_number column and an optional context column,
the per-contact equivalent of a
manual call's context, used
verbatim in the agent's dynamic context with no template rendering. Blank
phone_number rows are skipped. Rejected with 422 if the campaign is
already completed or cancelled, or the file has no phone_number
column.
Check progress¶
{
"total": 200,
"pending": 140,
"dispatched": 55,
"cancelled": 5,
"calls_completed": 40,
"calls_failed": 10,
"calls_in_flight": 5
}
dispatched counts every contact a Call row has been created for,
regardless of how that call turned out. calls_completed,
calls_failed, and calls_in_flight break that number down further by
the linked Call's own current status.
Start, pause, cancel¶
POST /api/v1/agents/{agent_id}/campaigns/{campaign_id}/start
POST /api/v1/agents/{agent_id}/campaigns/{campaign_id}/pause
POST /api/v1/agents/{agent_id}/campaigns/{campaign_id}/cancel
Each returns the updated Campaign. start returns 422 if the agent
has no twilio_phone_number configured, there are no pending contacts,
or the campaign isn't currently draft or paused. pause returns
422 unless the campaign is running. cancel returns 422 if the
campaign is already completed or cancelled.