Campaigns

View as Markdown

Campaigns list in the Synthflow portal showing status and progress for each campaign

A campaign calls a whole list of people with one agent, without you having to place each call yourself. You hand Synthflow the list, and it dials through it over time, as fast as your account’s concurrency allows, inside the hours you allow it to call.

Every recipient that gets dialed becomes a regular call. It shows up in your call history with the same transcripts, recordings, billing, and webhooks as a call you place one at a time.

Campaigns are created through the Platform API. You start one with a single request, get back a batch_call_id, and use that id to follow the campaign, pause it, resume it, cancel it, or add more people to it later. In the Synthflow portal, each one appears under Campaigns, where you can watch progress without calling the API.

Campaigns are available on our Enterprise plans. Reach out to our support team to activate them on your account.

Create a campaign

Creating a campaign takes the agent that does the talking (model_id), the caller ID it dials from (from_phone_number), and the list of people to call (tasks, between 1 and 10,000 per request). Only tasks is marked required, because the same request also adds recipients to an existing campaign, where the other fields are ignored.

Expand the endpoint below to send a test request with your API key, then use the table for the fields that shape the campaign.

FieldRequiredDescription
tasksYesThe list of recipients, 1 to 10,000 per request
model_idNoThe agent that places the calls. Required when creating a new campaign, ignored when appending
from_phone_numberNoThe caller ID used for every call. Required when creating a new campaign, ignored when appending
nameNoA display name for the campaign, useful when you run several
trigger_timestampNoWhen dialing starts, as a Unix timestamp in milliseconds. Omit to start right away
call_time_windowNoThe hours the campaign is allowed to call. See calling windows
reserved_concurrencyNoCall slots held back for traffic outside the campaign. See dialing speed

Each entry in tasks describes one recipient:

FieldRequiredDescription
to_phone_numberYesThe number to call
idNoYour own recipient id, unique within the campaign. Re-sending an id that already exists skips that recipient instead of calling twice, which makes retries safe. Recipients sent without an id are never deduplicated
lead_nameNoThe recipient’s name
lead_emailNoThe recipient’s email address
custom_variablesNoPrompt variables passed into that recipient’s call, as key-value pairs
override_model_idNoA different agent for this one recipient

The response returns the batch_call_id you use everywhere else, along with the campaign’s status and total_task_count.

The agent and the phone number are not checked when the campaign 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.

Choose when calls go out

Two optional settings decide when your recipients hear from the agent.

Set trigger_timestamp to start the campaign later instead of immediately. It is a Unix timestamp in milliseconds, so a campaign created on Friday can start dialing Monday morning.

Set call_time_window to keep calls inside acceptable hours. Windows are evaluated in the agent’s timezone and are defined per weekday:

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}

Use lowercase day names (monday to sunday) and HH:MM in 24-hour format. A start must be earlier than its end, so a window cannot span midnight, and a day can hold several windows as long as they do not overlap. A day you leave out means no calls that day.

While a campaign’s window is shut, dialing stops and picks up again the next time it opens. Nothing in the queue is lost.

Campaign windows and agent business hours

The campaign window and the agent’s business hours are two separate gates, and a call has to clear both. The window decides whether a recipient waits. The agent’s hours are checked as the call goes out, and a recipient dialed while the agent is closed fails on the spot with Call cannot be initiated outside the configured working hours. It does not wait for the agent to reopen.

The simplest split is one gate per direction: business hours on the agents that take inbound calls, and a campaign’s calling window for anything outbound. Each direction then has a single schedule to reason about.

Use one or the other, not both. With the agent open 10:00 to 17:00 and a campaign window of 18:00 to 22:00, every recipient fails: the campaign waits until 18:00, and the agent gate then rejects each call. If you do set both, keep the campaign window inside the agent’s business hours.

Leave the campaign window out and the agent’s hours are the only gate, so recipients that come up while the agent is closed fail rather than wait. With neither configured, recipients are dialed at any time.

Add more recipients

A request carries at most 10,000 recipients, while a campaign holds up to 1,000,000 of them. To go past 10,000, or to keep feeding a campaign that is already running, send the same create request again with the batch_call_id of the existing campaign:

1{
2 "batch_call_id": "3f6f2f5e-4f4b-4f0e-9a4e-2b6d1a5c7e90",
3 "tasks": [
4 { "id": "lead-0002", "to_phone_number": "+12025556789" }
5 ]
6}

The campaign keeps its original setup, so model_id, from_phone_number, trigger_timestamp, reserved_concurrency, and call_time_window are ignored in this mode. The returned total_task_count is the campaign’s new total once duplicates have been skipped. Adding recipients to a completed or canceled campaign returns a 400 error.

Control dialing speed

How fast a campaign dials is bounded by your account’s concurrency limit. On every dialing cycle, Synthflow counts the calls your workspace currently has running, campaign and non-campaign alike, and only starts as many new ones as fit under that limit.

Set reserved_concurrency to keep room for everything else, such as inbound traffic or one-off outbound calls. With a limit of 10 concurrent calls and reserved_concurrency: 4, the campaign never uses more than 6 slots. The value has to be lower than your account’s maximum concurrent calls, otherwise the request fails with a 400 error.

Follow a campaign

Fetch a campaign by its id to see where it stands. The response carries its status alongside total_task_count, dispatched_count, failed_count, and pending_count, which is enough to build a progress bar or decide when to stop polling.

To see every campaign in the workspace, most recent first, list them instead:

A campaign is always in one of five states:

StatusMeaning
scheduledAccepted and waiting to dial, as soon as its start time, calling window, and capacity allow. New campaigns start here, and resuming returns here.
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, and the campaign is final.
canceledThe campaign was canceled, by you or by the seven-day limit. Queued recipients will never be dialed, and the campaign is final.

Track individual recipients

For a per-person view, list the campaign’s recipients. Each one comes back with its outcome, and the list accepts a status filter when you only care about, say, the failures.

StatusMeaning
pendingWaiting to be dialed.
claimedPicked up for dialing, about to be called.
dispatchedThe call was placed. call_id links to the call record.
failedThe call could not be placed. error_message explains why.
canceledThe campaign was canceled before this recipient was dialed.

Three failures cover most cases, each spelled out verbatim in error_message: Insufficient minutes remaining. Please top up or switch to a higher plan. when the workspace is out of minutes, Please attach a phone number to the agent when the agent has no number attached, and Call cannot be initiated outside the configured working hours when the recipient came up while the agent was closed.

To work with the conversations themselves (transcripts, recordings, outcomes), filter the list calls endpoint with ?batch_call_id=. That list only holds recipients whose call was actually placed, while the recipient list above also covers everyone still queued and everyone who failed before a call happened.

Pause, resume, and cancel

Pausing suspends dialing, whether the campaign is waiting to start or already working through its list. Queued recipients stay queued, and calls already in progress carry on as normal.

Resuming restarts dialing within a few seconds, picking up with the recipients that were still queued. The campaign goes back to scheduled rather than in_progress, and dials again as soon as capacity and its calling window allow. Only a paused campaign can be resumed.

Canceling stops the campaign for good. Queued recipients are marked canceled and will never be dialed, while calls already connected are not hung up. A canceled campaign cannot be resumed and cannot take new recipients, so pause instead if you might continue later.

All three return the campaign’s updated status.

How long a campaign runs

A campaign has seven days to work through its list. It can sit in scheduled, in_progress, or paused across that time, but once the seven days are up an unfinished campaign is canceled, and everything still queued is canceled with it, exactly as if you had canceled it yourself.

Two things make that deadline easier to hit than it sounds. A narrow calling window leaves only a few hours a day to dial, and a pause nobody lifts keeps burning days while nothing goes out. Size a list against the hours you have actually opened, and split anything that will not fit into more than one campaign.

FAQ

Up to 1,000,000. Each request carries at most 10,000, so you build a larger campaign by adding more recipients with additional requests that carry the batch_call_id.

Campaigns run for seven days. An unfinished campaign is canceled at that point and its queued recipients are canceled with it, so plan long lists against the hours your calling window actually leaves open.

No. Every dialed 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 campaign. Poll the campaign status to detect completion: it turns completed when no recipients are left to dial.

That recipient is marked failed with the reason in error_message, and the campaign moves on. Failed recipients are not retried automatically. Send them again in an append request (with a new id, or no id) to try once more.

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

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