Campaigns ship behind a per-environment flag. Until they are enabled on your
environment, every endpoint returns
503 CAMPAIGNS_DISABLED. A campaign runs a
stored callflow, so create also needs stored callflows on your
environment. Without them, create returns 409 CAMPAIGN_NEEDS_IVR.Create a campaign
POST /v1/campaigns creates a campaign. Needs the campaigns:write scope. Send
an Idempotency-Key header: a retry with the same key returns the first campaign
and does not create a second one. Wave keeps the key for 24 hours. A refused
request is not kept.
201 with the campaign, and two counts: recipients_accepted
and duplicates_removed.
Fields
The request body can be at most 2 MB. Wave removes duplicate phone numbers: the
first row of a number stays.
Sandbox and production
- Sandbox key: at most 5 recipients. The campaign always presents the shared
sandbox number, and Wave ignores
caller_id. - Production key:
caller_idis required. A number that your account does not own returns403 CLI_NOT_OWNED.
Activate the callflow first
How Wave calls
- Pacing. Wave starts new calls only while the campaign is below
max_concurrent, your account is below its concurrency cap, and your call limits allow a new call. When your call limits stop a call, or when outbound calling is suspended on your account, the recipient waits for a later try. Wave does not count an attempt. - When. Wave calls from
start_at, and only inside the calling window (KSA time). During quiet hours, a call waits until the quiet hours end. - Opted-out numbers. A recipient who opted out is not called. Its outcome is
skipped. - On each answer. Machine detection runs first:
- A person (or Wave is not sure): the person hears your callflow.
- An answering machine, with a voicemail message: Wave waits for the beep, plays or speaks the message, then hangs up. If no beep comes, Wave also plays the message and hangs up.
- An answering machine, with no voicemail message: Wave hangs up.
Outcomes and retries
Each recipient ends with one outcome:
Retries: after
no_answer, busy or failed, Wave tries again after
retry_after_minutes, until the recipient has max_attempts attempts. Then that
outcome is final. Two cases are failed at once, with no retry:
- The voice engine sent no signal for the call 5 minutes after Wave sent it.
- Wave or the voice engine refused the call, or the voice engine cancelled it.
Pause, resume and stop
A campaign has one of these statuses:
Use
POST /v1/campaigns/{id}/pause, /resume and /stop. Each needs the
campaigns:write scope and returns the campaign.
Any other move returns
409 CAMPAIGN_INVALID_STATE. On pause or stop, calls that
are in progress go on to their end. Stop gives cancelled to every recipient that is not
done yet.
Read a campaign and its recipients
All reads need thecampaigns:read scope. A sandbox key sees only sandbox
campaigns, and a production key only production campaigns.
GET /v1/campaignslists the project’s campaigns, newest first, as a cursor page (limitdefault 20, at most 100).GET /v1/campaigns/{id}returns the campaign withcounts(total,by_state,by_outcome) andestimated_cost_sar. The cost is an estimate only: billing can be different.GET /v1/campaigns/{id}/recipientslists the recipients, newest first, as a cursor page (limitdefault 50, at most 100). Filter with?outcome=.
next_cursor back as ?cursor= to get the next page. A recipient’s state
is pending, waiting, dialling or done. machine_detection_result is
human, machine, notsure, or null when detection did not run.
Webhooks
Subscribe to two webhook events instead of polling. They carry no phone number: match onreference or recipient_id.
campaign.recipient_completed — a recipient got its final outcome:
campaign.completed — every recipient has an outcome (status: "completed"), or
you stopped the campaign (status: "stopped"). by_outcome lists every
outcome, with 0 when there is none:
Errors
Next steps
IVR menus
Build the callflow that a person hears.
Webhooks
Get each outcome pushed to you instead of polling.

