Batch calling

View as Markdown

This feature is available only on our Enterprise plan. Please reach out your account rep to gain access

Batch calling lets you send one API request with a list of recipients and have Synthflow dial them over time, as fast as your account’s concurrency allows. Batches appear as campaigns in the Synthflow portal, and every dialed recipient becomes a regular call with the same billing, call records, and webhooks as a single outbound call.

A batch is created with one request, then managed through its batch_call_id: you can check its status, list its recipients, pause, resume, or cancel it at any time.

Create a batch call

Use POST /v2/calls/batch. A new batch needs the model_id of the agent that places the calls, the from_phone_number used as caller ID, and between 1 and 10,000 tasks (recipients).

$curl --request POST \
> --url https://api.synthflow.ai/v2/calls/batch \
> --header 'Authorization: Bearer YOUR_API_KEY' \
> --header 'Content-Type: application/json' \
> --data '{
> "name": "August re-engagement",
> "model_id": "1631a495-e29b-4933-a0b7-3ea0f4a45e64",
> "from_phone_number": "+16286666348",
> "tasks": [
> {
> "id": "lead-0001",
> "to_phone_number": "+12025551234",
> "lead_name": "John Doe",
> "custom_variables": { "plan": "pro" }
> }
> ]
> }'

Successful response:

1{
2 "status": "ok",
3 "response": {
4 "batch_call_id": "3f6f2f5e-4f4b-4f0e-9a4e-2b6d1a5c7e90",
5 "name": "August re-engagement",
6 "from_phone_number": "+16286666348",
7 "scheduled_timestamp": null,
8 "total_task_count": 1,
9 "call_time_window": null,
10 "status": "scheduled"
11 }
12}

Each recipient accepts an optional id of your own choosing, unique within the batch. If you retry a request or append a recipient whose id already exists in the batch, that recipient is skipped instead of being called twice. Recipients sent without an id are never deduplicated. A recipient can also set override_model_id to be called by a different agent than the rest of the batch, and custom_variables to inject prompt variables into its call.

The agent and phone number are not validated when the batch is created. If the from_phone_number is not attached to your workspace, every recipient fails at dialing time with the reason in its error_message.

Schedule dialing and calling windows

Two optional fields control when recipients are dialed:

  • trigger_timestamp is a Unix timestamp in milliseconds. Dialing starts at that time; omit it to start immediately.
  • call_time_window restricts dialing to weekly time windows, evaluated in the agent’s timezone. When set, it overrides the agent’s working hours for this batch. When it is omitted, the agent’s own working hours apply, and if neither is configured, recipients are dialed at any time.
1{
2 "call_time_window": {
3 "weekly_hours": {
4 "monday": [{ "start": "09:00", "end": "17:00" }],
5 "tuesday": [{ "start": "09:00", "end": "12:00" }, { "start": "13:00", "end": "17:00" }]
6 }
7 }
8}

Days use lowercase names (monday to sunday), times use HH:MM in 24-hour format, start must be earlier than end (windows cannot span midnight), and a day can hold several windows as long as they do not overlap. A missing or empty day means no calls on that day. When the window closes, dialing stops and picks up again the next time it opens; nothing is lost.

Add more recipients to a batch

A single request accepts at most 10,000 recipients. To go beyond that, or to feed a long-running batch, send POST /v2/calls/batch again with the batch_call_id of the existing batch:

$curl --request POST \
> --url https://api.synthflow.ai/v2/calls/batch \
> --header 'Authorization: Bearer YOUR_API_KEY' \
> --header 'Content-Type: application/json' \
> --data '{
> "batch_call_id": "3f6f2f5e-4f4b-4f0e-9a4e-2b6d1a5c7e90",
> "tasks": [
> { "id": "lead-0002", "to_phone_number": "+12025556789" }
> ]
> }'

In append mode model_id, from_phone_number, trigger_timestamp, reserved_concurrency, and call_time_window are ignored; the batch keeps its original configuration. Appending to a completed or canceled batch returns a 400 error. The response’s total_task_count is the batch’s new total after deduplication.

Control dialing speed

Dialing speed is bounded by your account’s maximum concurrent calls. Every dialing cycle, the dispatcher counts your workspace’s currently active calls (batch and non-batch alike) and only places as many new calls as fit under the limit, up to roughly 20 new calls per second.

Set reserved_concurrency to hold back capacity for calls outside the batch, such as inbound traffic or one-off outbound calls. With a limit of 10 concurrent calls and reserved_concurrency: 4, the batch never uses more than 6 slots. The value must be lower than your account’s maximum concurrent calls, otherwise the request fails with a 400 error.

Monitor a batch

GET /v2/calls/batch/{batch_call_id} returns the batch’s status and counters, and GET /v2/calls/batch lists all batches in the workspace, most recent first. A batch has one of five statuses:

StatusMeaning
scheduledThe batch is accepted and dials recipients when its start time, calling window, and capacity allow.
in_progressRecipients are being dialed.
pausedDialing is suspended; queued recipients are kept and dialing resumes on request.
completedEvery recipient was dialed or failed; nothing is left to do.
canceledThe batch was canceled; queued recipients will never be dialed.

Track individual recipients

GET /v2/calls/batch/{batch_call_id}/tasks lists every recipient with its outcome, and accepts a status filter:

StatusMeaning
pendingWaiting to be dialed.
claimedPicked up by the dispatcher, about to be dialed.
dispatchedThe call was placed; call_id links to the call record.
failedThe call could not be placed; error_message explains why.
canceledThe batch was canceled before this recipient was dialed.

Common error_message values include Insufficient minutes remaining. Please top up or switch to a higher plan., Please attach a phone number to the agent, and Call cannot be initiated outside the configured working hours.

To work with the calls themselves (transcripts, recordings, outcomes), filter the list calls endpoint with ?batch_call_id=. That list only contains recipients whose call was actually placed, while the recipients endpoint also covers queued recipients and failures that never produced a call.

Pause, resume, and cancel

POST /v2/calls/batch/{batch_call_id}/pause suspends dialing. Queued recipients stay queued, and calls already in progress continue normally. POST /v2/calls/batch/{batch_call_id}/resume restarts dialing within a few seconds, continuing with the recipients that were still queued.

POST /v2/calls/batch/{batch_call_id}/cancel permanently stops the batch: queued recipients are marked canceled and will never be dialed, while calls already in progress are not hung up. A canceled batch cannot be resumed and cannot take new recipients. All three endpoints return the batch’s updated status.

FAQ

A single request accepts up to 10,000 recipients. The batch itself has no size limit; append more recipients with additional requests carrying the batch_call_id.

No. Every dispatched recipient becomes a regular outbound call with the same billing, call records, and webhook events as a call created through the calls endpoint.

No. Webhooks fire per call, not per batch. Poll the batch status endpoint to detect completion: the batch turns completed when no recipients are left to dial.

The recipient is marked failed with the reason in error_message, and the batch moves on. Failed recipients are not retried automatically; re-send them in an append request (with a new id, or no id) to try again.

No. Cancel only removes recipients that have not been dialed yet. Connected calls run to their natural end.

The batch’s own call_time_window cannot be changed after creation. If the batch relies on the agent’s working hours instead, editing those hours takes effect on the next dialing cycle.