Skip to main content
A campaign calls a list of recipients for you. You give Wave the numbers, a stored callflow and a caller ID. Wave calls each recipient, retries the ones that did not answer, and runs machine detection on each answered call. A person hears your callflow. An answering machine gets your voicemail message, if you set one.
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.
The response is 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_id is required. A number that your account does not own returns 403 CLI_NOT_OWNED.

Activate the callflow first

A person hears the active version of the callflow. Create accepts a callflow that has no active version. Then every answered call ends and the person hears nothing, but the outcome is still answered. Activate a version of the callflow before the campaign starts.

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 the campaigns:read scope. A sandbox key sees only sandbox campaigns, and a production key only production campaigns.
  • GET /v1/campaigns lists the project’s campaigns, newest first, as a cursor page (limit default 20, at most 100).
  • GET /v1/campaigns/{id} returns the campaign with counts (total, by_state, by_outcome) and estimated_cost_sar. The cost is an estimate only: billing can be different.
  • GET /v1/campaigns/{id}/recipients lists the recipients, newest first, as a cursor page (limit default 50, at most 100). Filter with ?outcome=.
Pass 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 on reference 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.