https://app.cntillion.com/api/v2. Reads accept either
key permission. Every write requires a Full access key, a plan with
campaigns and an Idempotency-Key header.
A batch belongs to one agent. Its settings and recipients can change while
it is a draft. Launch freezes them; duplicate a launched batch to make changes.
The dashboard and API share the same calling checks and results.
Endpoints
Paths below are relative to/api/v2.
Create a draft
201, with the batch in data. Keep data.id and
data.updatedAt for subsequent requests. data.config.import.kind is ready
after a complete recipient list is saved. Without recipients, it is empty.
Each recipient requires
phone, name, variables and overrides. Use an
E.164 phone with its country code for both transports. The dashboard’s
WhatsApp file column whatsapp_user_id is normalized to this API format.
Use an empty name or empty objects when those fields are not needed.
Variables are strings with simple names, up to 60 values per recipient.
Each value can contain up to 2,048 characters, and each recipient must fit
within 16 KB. Protected names such as system, call, contact, campaign,
constructor and __proto__ are unavailable. Overrides must be enabled in
allowedOverrides. language accepts en, es or it; a voice_id must use
the agent’s voice provider and be saved in the workspace. The request body
must fit within 4 MB.
The API rejects duplicate numbers. Creating a batch and importing inline
recipients is atomic: a failed import leaves no partial batch or new contacts.
Update or launch
SendPUT /batch-calls/{batchId} with the complete draft settings from the
table above and updatedAt from the latest response. Omit recipients and
launch from the update body. Updating settings keeps the imported recipients.
If another request changed the draft, the API returns 409; fetch the latest
draft before applying your changes.
Launch with:
POST /batch-calls/{batchId}/launch with a new
Idempotency-Key. A future startsAt produces SCHEDULED; otherwise the
batch becomes RUNNING. Available capacity, the agent’s call limits and the
calling number’s daily limit can postpone individual recipients. A batch has
no calling hours or quiet hours: it calls at any hour until its list is done.
Calls don’t check consent records, calling hours or how often a number is
called. Those are your responsibility, and consentConfirmed is your
confirmation. Numbers on the workspace’s do-not-call list, and numbers that
reached someone other than the contact on an earlier call, are skipped. The
agent needs voice enabled and a calling number that can place calls. WhatsApp
also requires cloud voice calling, a calling-enabled account and an active
WhatsApp calling permission for the recipient.
Import larger lists
Up to 50,000 recipients can be imported into a draft. The total serialized import must remain within 25 MB.-
Begin with
POST /batch-calls/{batchId}/import: -
Send consecutive chunks to
POST /batch-calls/{batchId}/recipients:
whatsapp_user_id in headers
for a WhatsApp batch. Headers describe the original file; the API receives
parsed JSON rows. Each chunk holds 1 to 200 rows. Increase offset by the
number of rows committed in the previous chunk. Each chunk needs its own
idempotency key; retry a lost response with the same key and body.
A repeated offset with identical rows is also safe after the response replay
expires. Different rows at a previously committed offset are refused. Starting
a new import replaces the previous recipient list. The batch cannot launch
until import.kind becomes ready and all expected rows are present.
Read results and manage a batch
List endpoints acceptlimit and cursor. Use the returned
pagination.cursor for the next page with the same filters. Batch lists
also accept status and search; the workspace list accepts agent_id.
Statuses are DRAFT, SCHEDULED, RUNNING, PAUSED, COMPLETED and
CANCELLED.
The recipient list accepts a status filter of QUEUED, WAITING_FOR_VOICE,
SENDING, SENT, FAILED, SKIPPED or NEEDS_REVIEW. A SENT row can still
have an active call. Inspect voiceCall.endedAt, dialOutcome, outcome and
lastError for its result. voiceCall.conversationLogId identifies the
conversation when available. Uploaded variables and overrides are returned
with the recipient.
Send {} for pause, resume, cancel, duplicate and retry actions. Duplication
and retry return 201 with a new draft, with consent confirmation cleared.
Retry excludes recipients marked for review because their prior dial could
not be confirmed. Review them before making another attempt. Deleting a batch
keeps contacts and conversation history.
A reused idempotency key with a different body returns
409 IDEMPOTENCY_KEY_REUSED. Missing batches return 404 BATCH_NOT_FOUND.
A stale revision, incomplete import, unavailable calling setup or unsupported
state transition returns 409 BATCH_STATE_CONFLICT, with the reason in
error.message.
Recipient variables accept text, finite numbers and booleans. Names beginning
with secret__ or system__, internal names beginning with __, and built-in
namespaces are reserved. Batch calls use the supplied recipient data and skip
the initiation webhook. The same agent can answer incoming calls. See
one agent for inbound and outbound calls.