Skip to main content
POST
Launch a run
Fans a draft run out into one conversation per contact, now or at a time you choose.

Starting it later

Send scheduledAt and the run is booked instead of dispatched. It moves to SCHEDULED, queues nothing, and starts on its own when the time arrives.
affectedCalls is 0 because nothing was queued. That is the honest count, not an omission. Up to 30 days ahead — the same ceiling scheduleTime has always had on a single conversation, enforced by the same rule so one call and a batch of them cannot disagree about how far ahead you may plan. Further out, or not a valid ISO 8601 date-time, is a 400 and the run stays a DRAFT. A scheduled run behaves like any other draft until it fires: attach more contacts, or cancel it to call the whole thing off. Cancelling clears the appointment, so a cancelled run never starts. Contacts attached before the run fires are held, not dialledAttach Contacts returns queued: 0 and they go out with everyone else at scheduledAt. A booked run has not started, so dispatching them on arrival would call those contacts days early.

What happens at the appointed time

The run is launched by exactly the code path an immediate launch takes — the same admission, the same fan-out — so a run that starts on Monday morning is indistinguishable from one somebody launched by hand on Monday morning. It may begin up to a minute late; a scheduled start is an appointment, not a deadline.
Scheduling is not a reservation. The batch is admitted against your billing when you schedule it and again when it fires, and it is the second one that decides. Nothing is held in between, so a balance that has moved can leave a booked run unable to start.A run refused at its time stays SCHEDULED and is retried, with the reason in scheduleError on Get Run. Topping up is enough to make it go; there is nothing to re-book. Poll scheduleError, or a run you booked for a Monday can sit there unstarted with nobody watching.

Queued, not dialled

A 2xx from this endpoint means the conversations exist and are on the dispatch queue. It does not mean anybody has been called. The provider is called later by the dispatch worker, outside your request. So:
  • per-contact outcomes do not come back in this response. They arrive as conversation.* webhooks, and each payload carries runId so you can attribute it to this run without a lookup
  • a 2xx is not a promise that every call connects. Contacts who never answer end up UNREACHABLE, which Get Run counts in its own bucket
affectedCalls is how many conversations were queued, not how many calls were placed.

All of it, or none of it

The whole contact list is admitted against your billing before any of it is dispatched. A run you cannot afford in full is refused whole with a 402, nothing is queued, and the run stays a DRAFT you can launch once you have topped up. Partial admission — dialling as far as the balance goes — was deliberately rejected. It turns one request into an outcome nobody can predict or undo: you cannot un-call the contacts that already went out. The 402 carries a billing object with what the batch needed and what was available, so you can size a smaller batch or work out the top-up.
Admission is a preflight, not a reservation. Nothing is held, so two different runs launched at the same moment can both pass, and your balance can move between admission and the dial. What protects the money is the per-call reservation made before each individual call, which fails closed. What admission buys you is being refused up front instead of discovering the problem one failed call at a time.

Launching twice

DRAFT is the only status a run can be launched from, so a second launch is a 422 rather than a second fan-out — including when two launches arrive at the same instant. The run is locked for the duration, so concurrent launches cannot both pass the check.

A run with no contacts

422. There is nothing to dial, and a RUNNING run with no conversations would report a meaningless aggregate.

Error Scenarios

  • 400 Bad Request: scheduledAt is not a valid ISO 8601 date-time, or is more than 30 days ahead
  • 402 Payment Required: the company cannot afford the batch. Nothing dispatched, run stays a draft. A scheduled run is admitted at schedule time too, so an unaffordable run is refused before it is booked rather than at its start time
  • 404 Not Found: the run does not exist, or belongs to another company
  • 422 Unprocessable Entity: the run is not a draft, has no contacts, or its agent can no longer back a dispatch
  • 403 Forbidden: the API key does not hold write:runs

Get Run

Watch the aggregate as it dials

Pause Run

Stop it without losing the work

Webhooks

Per-contact outcomes as they happen

Billing Errors

Reading the 402 body

Authorizations

Authorization
string
header
required

API key for authentication using Bearer scheme

Path Parameters

id
string<uuid>
required

Query Parameters

companyId
string

Required for ATS API keys to specify which company to access. Ignored for standard company API keys.

Body

application/json
scheduledAt
string<date-time>

When the run should start dialling, ISO 8601, at most 30 days ahead. Omit it to start immediately. With it, the run becomes SCHEDULED and dispatches nothing until the time arrives.

Example:

"2026-09-15T09:00:00Z"

Response

Run launched, or scheduled to launch

status
enum<string>
required

The run's status after the transition

Available options:
DRAFT,
SCHEDULED,
RUNNING,
PAUSED,
COMPLETED,
CANCELLED
Example:

"RUNNING"

affectedCalls
number
required

How many of the run's calls this request moved: queued by a launch, withdrawn by a pause, restored by a resume, closed out by a cancel. Not calls placed - a 2xx means queued, not dialled.

Example:

42