Create batch campaign
Calls
Create batch campaign
POST /v1/calls/batch
POST
Create batch campaign
Creates a batch campaign: queues many outbound calls under one campaign ID. Useful for appointment reminders, lead qualification, surveys.
All
With
Request
Body parameters
| Field | Type | Required | Notes |
|---|---|---|---|
agent_id | string | Yes | Agent used for all calls in this batch |
prompt | string | Yes | The call purpose for every call in the campaign - what the agent should say and why it is calling. Per-recipient prompt_override replaces it for that recipient. |
name | string | No | Display name for the campaign |
from_number | string | See note | Your Twilio number to dial from. Optional only when the agent has exactly one outbound-enabled number (it auto-resolves). If the agent has multiple numbers attached, this field is required - the launch fails otherwise. |
recipients | array | Yes | Recipient objects (see below) |
skip_invalid | bool | No | Default false: reject the whole request if any phone is invalid. true: dial valid numbers only; invalid ones are listed in the response. |
schedule_type | enum | No | now (launch immediately, default) or schedule |
scheduled_date | date | If schedule | YYYY-MM-DD - the day the campaign becomes due |
window_start_minutes | int | No | Calling window start, minutes since midnight (540 = 9:00am) |
window_end_minutes | int | No | Calling window end, minutes since midnight (1080 = 6:00pm) |
window_days | array | No | Allowed weekdays, e.g. ["mon","tue","wed","thu","fri"] |
timezone | string | No | IANA timezone the calling window runs in, e.g. Europe/London, Asia/Dubai, America/New_York. Invalid values are rejected with invalid_timezone. |
Recipient object
variables are automatically injected as context for the agent - you do not need {{placeholders}} in your prompt.
Calling window and timezone
Scheduled campaigns do not fire at midnight - they fire inside the calling window, in local time:- The scheduler checks every 60 seconds. A campaign that is due but outside its window stays
scheduledand is re-checked each minute - it fires within a minute of the window opening. - The window runs in this priority of timezones: campaign
timezone(if you sent one) -> the agent’s timezone ->Europe/London. - Resellers: your end-user picks their timezone in your app, you send it per campaign - their choice wins over the agent default.
- Overnight windows are supported (
window_start_minutesgreater thanwindow_end_minutes, e.g. 18:00-02:00). - No window set = the campaign fires when the date is due (legacy behaviour).
One campaign = one timezone. Calling recipients across multiple countries? Split them by region into separate campaigns, each with its own
timezone.Response
201 Created (schedule_type now launches immediately):
schedule_type: schedule the response returns status: scheduled and the campaign fires inside its window on the scheduled date.
Behaviour
- Calls are queued and processed respecting your per-key concurrent call limit
- Each recipient becomes one outbound call with its own
call_id - Failed calls are logged but do not stop the campaign
- Voicemail detection runs per call; detected voicemails end cleanly with
ended_reason: voicemail_detected
Errors
| Code | Cause |
|---|---|
missing_field | prompt missing - every campaign needs a call purpose |
invalid_phone_format | One or more recipient phones invalid (response lists them; resend with skip_invalid: true to dial valid only) |
campaign_creation_failed | Includes invalid_timezone (bad IANA value) and from_number ownership failures - the message states the exact reason |
Launching a scheduled campaign
Aschedule_type: schedule campaign fires automatically inside its window. You can also launch it manually with Launch batch.