Skip to main content
There are two ways to get people called:

Contact-list campaign

The Quickstart shows the minimal flow. This section covers the options and the failure cases.
The contact-list endpoints below are part of the workspace API and need a scoped API key.

1. Create the campaign

POST /campaigns creates a campaign in DRAFT. Commonly used fields: The full schema is on the endpoint’s reference page.

2. Attach phone numbers

POST /campaigns/{id}/phone-numbers with {"phoneNumberIds": [...]} (1–50 IDs). Use GET /phone-numbers to list your numbers. Numbers already attached are skipped. A number that isn’t active in your workspace returns 400 phone_number_not_in_workspace.

3. Add contacts

POST /campaigns/{id}/contacts with up to 10,000 contacts per request:
  • phone must be E.164 (+ and 8–15 digits). It is not reformatted.
  • metadata holds the values for the agent’s variables.
  • Duplicate phone numbers in the request are dropped (the first one wins). Numbers already in the campaign are not added again.
  • If a phone number already exists elsewhere in your workspace, the existing contact’s name and metadata are kept, and the values you send are ignored.
  • Contacts can only be added while the campaign is in DRAFT (400 campaign_not_in_draft otherwise).
  • The response { "added": 2, "total": 2 } counts this request only: added is the number of new contacts and total the number of valid unique phones you sent.
You can also upload a CSV first with POST /campaigns/uploads and pass the returned uploadId to POST /campaigns.

4. Start

POST /campaigns/{id}/start returns 204 when the campaign is running. It checks, in order:

5. Monitor

stats counts contacts by status: PENDING, IN_FLIGHT, MESSAGED, COMPLETED, FAILED and SKIPPED. Calls are enriched after they end: the transcript, recording and extracted fields can appear a little later than the call’s final status. See Recordings & transcripts.

6. Pause, resume, stop, restart

All four are POST /campaigns/{id}/<action> with scope campaigns.edit and return 204.

Push leads with the public API

A standing API campaign stays running and calls each lead you push, then produces one final result per lead.
1

Create and start an API campaign

POST /v1/campaigns (source defaults to API), attach numbers with POST /v1/campaigns/{id}/phone-numbers, then POST /v1/campaigns/{id}/start. An API campaign can start with no contacts.
2

Push each lead

Response (202)
3

Collect the result

Receive it by webhook, or poll resultUrl (GET /v1/leads/{leadId}/result).

Lead rules

  • idempotencyKey is required (in the body, up to 200 characters). It identifies the lead within the campaign: pushing the same key again returns 200 with "deduplicated": true and the original leadId, and nobody is called twice. Use a stable ID from your system, such as your CRM’s lead ID. The same phone with a different key is a new lead.
  • phone is normalised. Include the country code; numbers without one are read as Indian numbers.
  • fields are string values for the agent’s variables. Keys the agent doesn’t use are returned in warnings.undeclaredVariables and dropped.
  • A number on your Do Not Call list is accepted but not called; its result (skipped) is produced immediately.
Every response includes a requestId, also sent as the X-Request-Id header. Quote it when contacting support.

Push up to 100 leads at once

POST /v1/campaigns/{campaignId}/leads/batch (scope campaigns.edit) takes {"leads": [ ... ]} with 1–100 items. Each item is shaped exactly like the single-lead body, including its own idempotencyKey in the body. The batch does not use the Idempotency-Key header.
It returns 200 with one result per item, in the order you sent them:
  • Each item is queued, duplicate or rejected, with the same rules as a single push. A rejected item carries the error code in error; the other items are not affected.
  • Every result echoes the item’s idempotencyKey and phone exactly as you sent them (when they were strings), for every outcome, including rejected and malformed items. Match results to your records with these rather than relying on order alone.
  • Items are processed in order, so a key that appears twice in the same batch is queued once and reported as duplicate the second time.
  • Items marked "retryable": true (a 429 live cap or an error on our side) were not accepted. Send them again later with the same idempotencyKey.
  • Problems with the campaign itself (403, 404, 409) or a malformed envelope (422 invalid_body) reject the whole batch.
  • A batch counts as one request towards your rate limit.