Campaigns
A Campaign (called a "Flow" internally) is either an outbound campaign that dials a contact list, or an inbound line tied to a phone number. Campaigns reference a Voice Agent and carry the script / persona prompt configuration.
The public API uses /v1/campaigns. The internal API uses /api/voice/flows — these are the same records.
List campaigns​
GET /v1/campaigns
Scope: voice:campaigns:read
Query parameters:
| Param | Type | Notes |
|---|---|---|
status | string | draft, active, paused, completed |
kind | string | inbound or outbound |
include_metrics | boolean | Attach live metrics; default false |
Response:
{
"campaigns": [
{
"uuid": "flw_f1g2h3",
"kind": "outbound",
"name": "Spring Reactivation Campaign",
"status": "active",
"voice_agent_id": "agt_a1b2c3d4",
"phone_number": "+15550010000",
"branches": ["Region:West", "Segment:Lapsed"],
"start_date": "2026-05-01",
"end_date": "2026-05-31",
"time_window": { "start": "09:00", "end": "18:00", "timezone": "America/New_York" },
"metrics": {
"calls_today": 142,
"total_calls": 891,
"connect_rate": 0.61,
"avg_handle_time": "01:32",
"peak_hour": 11
},
"created_at": "2026-05-01T00:00:00Z"
}
]
}
Get campaign​
GET /v1/campaigns/{campaign_id}
Scope: voice:campaigns:read
Create campaign​
POST /api/voice/flows — Rate limit: 20/minute
Request body:
{
"kind": "outbound",
"name": "Spring Reactivation Campaign",
"provider": "nextneural",
"voice_agent_id": "agt_a1b2c3d4",
"phone_number": "+15550010000",
"branches": ["Region:West", "Segment:Lapsed"],
"start_date": "2026-05-01",
"end_date": "2026-05-31",
"time_window": { "start": "09:00", "end": "18:00", "timezone": "America/New_York" },
"config": {
"persona_prompt": "You are Aria, a friendly advisor at Luminary Home...",
"recording_disclosure": "This call is being recorded for quality purposes.",
"guardrails": ["no_price_fabrication", "no_stock_fabrication"]
},
"status": "draft"
}
| Field | Type | Required | Notes |
|---|---|---|---|
kind | string | ✓ | inbound or outbound |
name | string | ✓ | |
provider | string | ✓ | TTS provider: nextneural, sarvam, elevenlabs |
voice_agent_id | string | — | UUID of existing agent; omit to auto-create from speaker |
speaker | string | — | Auto-create agent from this speaker name |
language_code | string | — | e.g. hi-IN, en-US |
phone_number | string | — | Inbound: number to receive calls on |
branches | string[] | — | Contact tag filters for outbound targeting |
start_date / end_date | date | — | Campaign date window |
time_window | object | — | {start, end, timezone} daily calling hours |
config | object | — | Carries persona prompt, guardrails, lead-trigger mappings |
status | string | — | Default draft |
Launch campaign​
POST /v1/campaigns/{campaign_id}/launch — Rate limit: 5/minute
Scope: voice:campaigns:write
Starts the outbound dialer. Filters contacts by branches tags, respects the time_window and date range, and deduplicates recently-dialled contacts.
Response:
{
"status": "launched",
"campaign_id": "flw_f1g2h3",
"contacts_queued": 284
}
Stop campaign​
POST /v1/campaigns/{campaign_id}/stop — Rate limit: 5/minute
Scope: voice:campaigns:write
Stops a running campaign. In-progress calls are not dropped.
{ "status": "stopped", "campaign_id": "flw_f1g2h3" }
Toggle campaign status​
POST /api/voice/flows/{flow_uuid}/toggle
Switches between active and paused. No body required.
Update campaign​
PATCH /api/voice/flows/{flow_uuid}
Partial update. All fields optional.
Delete campaign​
DELETE /api/voice/flows/{flow_uuid}
Stops any running campaign first, then deletes the record.