Automations

A short sequence that runs itself — a reminder the day before, a follow-up the day after, and a stop as soon as somebody replies.

MethodPathDoes
GET/v1/automationsList them with their steps
POST/v1/automationsCreate, with every step, paused
PATCH/v1/automations/{id}Activate, pause or archive
POST/v1/automations/{id}/enterPut one contact into it

Creating one

POST /v1/automations

{
  "name": "Appointment reminders",
  "trigger_type": "contact_created",
  "steps": [
    { "type": "send",    "config": { "body": "Booked. See you soon." } },
    { "type": "wait",    "config": { "minutes": 1440 } },
    { "type": "stop_if", "config": { "condition": "replied" } },
    { "type": "send",    "config": { "body": "See you tomorrow." } }
  ]
}

The whole sequence goes in one request. Not step by step over several: a half-built sequence that was somehow active would message people through an incomplete flow, and there is no undo for a sent SMS.

Every automation is created paused, whatever you send in status.One that started the moment it was saved would have messaged people before anybody had read it back.

Triggers

TriggerFires when
contact_createdA contact is added, however it was added
list_joinedA contact joins a list
inbound_keywordSomebody texts a keyword you chose
apiOnly when you call /enter

Steps

TypeConfigNotes
sendbodySent as marketing, so consent and quiet hours both apply.
waitminutes1 to 43,200 — thirty days. Anchored the first time the step is reached.
stop_ifconditionreplied or opted_out. Ends the run for that contact.

Up to twenty steps. The list of types is short on purpose: a step engine that can branch arbitrarily is a programming language with no debugger, built by somebody who did not think they were writing one.

stop_if is the one that matters

It checks before every remaining message, not only when the step is reached. Somebody who replies on day two of a five-day sequence hears nothing more from it — which is the difference between a reminder and a nuisance.

A stop_if without a condition is refused. It would be accepted, stored, and then silently continue, on the one step whose entire job is to stop messaging someone.

Activating

PATCH /v1/automations/{id}   { "status": "active" }

An automation with no steps cannot be activated — an empty active automation is almost always a half-finished one.

Pausing does less than you think

New contacts will not enter. Contacts already part-way through will continue.The API says this in the response, because the natural assumption is the opposite. To stop somebody mid-sequence, suppress them or let a stop_if catch them.

Entering a contact

POST /v1/automations/{id}/enter   { "phone_number": "+447400123456" }
{ "entered": true, "run_id": "01j8xk…" }

A contact who does not enter is told why, rather than simply refused:

reasonMeans
automation_not_activeIt is paused or archived.
contact_opted_outThey have opted out. They will not be entered.
already_enteredThey have been through it, and re-entry is off.

Every one of those is deliberate, so answering "not entered" without saying which would send you hunting for a bug that is not there.

Opt-outs are re-checked, not assumed

Consent is checked before every send in a run, not once at entry. A five-day sequence that checked only at the start would keep messaging somebody for four days after they asked it to stop.

Timing

Runs advance on a sweep every minute. A reminder an hour late is a reminder nobody needed, so that interval is the resolution of the feature rather than a tuning choice.