Automations
List the canvas-authored flows in a project and see where one contact stands in them. Read-only, there is no manual enrollment.
Automations are the canvas-authored, event-triggered flows under Emails → Automations: a trigger, then wait/action/logic steps a contact walks through. This surface is read-only. There is no way to enroll a contact by API call, on purpose, every enrollment traces back to a real event on the events backbone (or, for a launch-day flow, the scheduled sweep).
Scopes#
| Operation | Scope |
|---|---|
| List, retrieve, a contact's enrollments | automations:read |
List automations#
GET /v1/automations
Every automation in a project, newest first, with its trigger and delivery counter-cache. Takes
project (required), plus the usual limit, starting_after, ending_before.
Retrieve an automation#
GET /v1/automations/{automation}
{automation} is an aut_… handle. Everything the list returns, plus steps: a readable
node-by-node summary of the canvas graph.
{
"object": "automation",
"id": "aut_4kq2mrpxv9nd",
"project": "prj_7Qk2mN4pR8",
"name": "Nudge unredeemed invites",
"status": "active",
"display_status": "active",
"trigger_label": "Stage changed",
"enrolled_count": 812,
"completed_count": 340,
"sent_count": 1104,
"delivered_count": 1061,
"bounced_count": 9,
"steps": [
{ "node_id": "trigger-1", "type": "trigger", "label": "Stage changed to Invited" },
{ "node_id": "wait-1", "type": "wait", "label": "Wait 3 days" },
{
"node_id": "branch-1",
"type": "branch",
"label": "If Is at an invite state: Waiting",
"refs": null
},
{
"node_id": "send-1",
"type": "send_email",
"label": "Send: Invite reminder",
"refs": { "template": "tpl_9phm4rtx2kqd" }
}
],
"created_at": "2026-08-19T14:02:11+00:00",
"url": "/v1/automations/aut_4kq2mrpxv9nd"
}
A contact's enrollments#
GET /v1/contacts/{contact}/automations
Every automation {contact} is, or has been, enrolled in: which flow, its current state, a human
label for the step it is on right now, and when a waiting step resumes. Unpaginated, a contact is
realistically enrolled in a handful of automations, not thousands.
{
"object": "list",
"url": "/v1/contacts/con_4mKp9Wq2Rx/automations",
"has_more": false,
"data": [
{
"object": "automation_enrollment",
"automation": { "id": "aut_4kq2mrpxv9nd", "name": "Nudge unredeemed invites" },
"state": "waiting",
"current_step": "Wait 3 days",
"resume_at": "2026-09-27T14:02:11+00:00",
"enrolled_at": "2026-09-24T14:02:11+00:00"
}
]
}
state is one of active, waiting, completed, exited, failed. resume_at is only
meaningful while state is waiting, it is when the flow's own wait step next checks in, not a
promise about exactly when the next email goes out.
Next#
Common questions
Can I enroll a contact in an automation through the API?
No. Manual enrollment is a deliberate omission, not a gap, every automation enrolls off the events backbone (a signup, a verification, a referral, a stage change, launch day) or not at all, so a contact's presence in a flow always traces back to something that actually happened to them.
What scope does this need?
automations:read for every endpoint here, including a contact's enrollments. It is not folded into contacts:read, since a key that can read the audience should not automatically see what marketing flows a person is inside.
Why is "steps" only on the detail endpoint, not the list?
Building the readable step list resolves every tag, segment, template and broadcast a flow references, which costs a handful of extra queries per automation. The list stays one query per page; ask for a specific automation when you need its steps.
What happens to a step whose tag, segment, template or broadcast was deleted?
Its label reads e.g. "Send: template deleted" instead of a broken reference, and refs omits that key. The same automation would also fail to publish from the dashboard until the step is repointed.