Automations
Build workflows from triggers and steps, run them, and inspect their runs.
- POST/automations
- GET/automations/{id}
- POST/automations/{id}
- GET/automations
- DEL/automations/{id}
- POST/automations/{id}/start
- POST/automations/{id}/pause
- POST/automations/{id}/stop
- POST/automations/{id}/trigger
- GET/automations/{id}/runs
- GET/automations/{id}/runs/{run_id}
- GET/automations/{id}/stats
- GET/automations/{id}/steps/{step_key}/stats
Create an automation
Creates an automation in draft status from a graph of steps and connections. Requires an API key with the full scope. Automations are in beta.
The automation does nothing until you start it. Each run costs 3 credits when it starts, and every email sent by send_email or forward_email costs 1 more credit. In an unverified workspace, those actions can only send to workspace members’ account emails.
/automationsBody parameters
contextstringrequiredcontact, email or event. The context decides which triggers and actions you can use and can’t be changed later. See Contexts.namestringrequireddescriptionstring | nullsettingsobjectstepsobject[]requiredconnectionsobject[]required[] for a graph with only a trigger. See Connections.Settings
on_step_failurestringdefault: stopstop marks the run failed when a step fails. skip records the failed step and lets the rest of the run finish.allow_reentrybooleandefault: truefalse skips a trigger when the same contact (or email) already has a running run in this automation.max_concurrent_runsintegerdefault: 0running status at once. 0 means no limit.cooldown_secondsintegerdefault: 0Steps
keystringrequiredwelcome_email. Connections, step statistics and updates refer to steps by key.typestringrequiredtrigger or action.triggerstringactionstringconfigobjectConnections
fromstringrequiredtostringrequiredbranchstringdefault: defaultfrom step follows this edge. condition steps use yes and no; experiment steps use variant keys. Every other step uses default.Contexts
| Context | A run is about | Triggers | Rules |
|---|---|---|---|
contact |
One contact. send_email goes to that contact. |
contact.*, system.* |
One or more triggers. They must all connect to the same first action. |
email |
One email (sent or received). | email.*, system.* |
One or more triggers. They must all connect to the same first action. |
event |
The trigger payload only. | event.*, system.* |
Exactly one trigger. |
Every action must be reachable from a trigger. A run starts at the action connected to the trigger that fired and follows connections:
conditionfollows only the edge whosebranchisyesorno, depending on the result.experimentfollows the edges of the chosen variant. When that path ends, the run continues on the experiment step’sdefaultedges.waitdelays the next step.- Every other action follows its
defaultedges. A step with several outgoing edges runs all of them.
A run is completed when no steps are left, failed when a step fails (with on_step_failure: "stop"), and canceled when you stop the automation.
Triggers
| Trigger | Context | Fires when |
|---|---|---|
contact.added_to_audience |
contact | A contact subscribes to an audience, including resubscribes. |
contact.removed_from_audience |
contact | A subscriber is deleted from an audience. |
contact.updated |
contact | A contact is updated. |
contact.loaded_email |
contact | A recipient who is a contact in the workspace opens an email. |
contact.clicked_in_email |
contact | A recipient who is a contact in the workspace clicks a tracked link. |
contact.date_anniversary |
contact | Daily at 00:00 UTC, for contacts whose date custom field (YYYY-MM-DD) has today’s month and day. |
contact.on_date |
contact | Daily at 00:00 UTC, for contacts whose date custom field equals today’s date. |
contact.visits_url, contact.on_purchase, contact.on_event |
contact | Accepted, but Emailit doesn’t fire these yet. |
email.received |
An inbound email arrives. | |
email.delivered, email.bounced, email.complained, email.loaded, email.clicked, email.failed, email.suppressed, email.canceled |
The email event of the same name occurs. | |
event.<name> |
event | Any name that starts with event.. Emailit doesn’t emit event.* events yet; start event automations with system.manual. |
system.manual |
all | You call Trigger a run. |
system.schedule |
all | Accepted, but Emailit doesn’t fire scheduled triggers yet. |
Trigger config fields:
audience_idstringcontact.added_to_audience and contact.removed_from_audience: only fire for this audience (aud_…).date_fieldstringcontact.date_anniversary and contact.on_date: the custom field key that holds the date, for example birthday.filterobjectOnly fire when the event matches: { "match": "all", "rules": [{ "field": "subject", "operator": "contains", "value": "Invoice" }] }. match is all (default) or any. field is a dotted path into the event’s object, for example to or email.subject; a leading payload. is ignored.
Operators: equals, not_equals, contains, not_contains, starts_with, ends_with, greater_than, less_than, in, not_in, is_set, is_not_set. Every operator except is_set and is_not_set needs a value; in and not_in take an array.
Actions
| Action | Context | Config |
|---|---|---|
send_email |
all | type (required, template), template_id (required: a tem_ ID or the alias of a published template), from, subject, reply_to, to |
forward_email |
email, event | to (required), from, subject, email_id |
wait |
all | seconds (required, 0 to 2,592,000, which is 30 days) |
condition |
all | filter (required, see below) |
experiment |
all | variants (required), control |
call_webhook |
all | url (required), method, headers, body |
run_automation |
all | automation_id (required) |
end |
all | None |
add_to_audience |
contact | audience_id (required) |
remove_from_audience |
contact | audience_id (required) |
edit_contact |
contact | fields (required) |
add_to_suppressions |
email, event | type, reason, email |
remove_from_suppressions |
email, event | email |
create_contact |
email, event | email, first_name, audience_id |
send_emailsends the template.fromdefaults to the template’s sender and must be on a verified sending domain.subjectoverrides the template subject.reply_tois an address or an array of addresses. In thecontactcontext the email goes to the run’s contact; in theemailandeventcontexts setto.forward_emailforwards the run’s email (or the email inemail_id) toto.fromdefaults to the original sender andsubjecttoFwd: <original subject>.conditiontakes{ "match": "all" | "any", "rules": [...] }with the same operators as trigger filters. Bare fields resolve against the run’s contact (first_name,custom_fields.plan) or email (rcpt_to,subject); prefix a field withcontact.,email.,payload.ormeta.to be explicit. The step continues onyesorno.experimentpicks one ofvariants(andcontrol), each{ "key": "a", "weight": 50 }, at random by weight, and continues on the branch named after the chosen key.call_webhooksends an HTTP request (default methodPOST, JSONContent-Type) and records the status class (2xx,4xx,5xx) ortimeoutornetwork_error. A non-2xx response doesn’t fail the step.run_automationstarts a run of another running automation with this run’s payload. The current run continues.edit_contacttakesfields: [{ "key": "first_name", "value": "Ada" }]. The keysemail,first_name,last_nameandunsubscribedupdate the contact; any other key sets a custom field.add_to_suppressionssuppresses the run’s address (defaulttyperecipient, defaultreasonautomation).remove_from_suppressionsremoves it. In theeventcontext, passemail.create_contactcreates the contact (or finds the existing one) and optionally subscribes it toaudience_id. In theemailcontext,emaildefaults to the email’s recipient.
String values in any action config can use placeholders that Emailit fills in when the step runs: {{contact.email}}, {{email.mail_from}}, {{payload.object.subject}} or {{meta.source_event_id}}, for example "to": "{{email.mail_from}}". Templates sent by send_email also render the contact’s fields directly, such as {{ first_name }}.
Returns
Returns 201 Created with the automation in data, including each step’s ID (aus_…) and the connections. status is draft.
Create checks the graph structure: trigger and action names for the context, unique keys, valid connections, reachability, and that any send_email from address uses a verified sending domain. It doesn’t check that every action config is complete; Update an automation does. Errors return 400 with errors keyed by field path.
{
"data": {
"id": "aut_3xqC9YD79FZZA36uTekWTBO1ghe",
"context": "contact",
"name": "Welcome series",
"description": "Welcome new subscribers, then nudge free users a day later.",
"status": "draft",
"settings": { "allow_reentry": false },
"last_triggered_at": null,
"published_at": null,
"created_at": "2026-10-01T09:41:05.318274+00:00",
"updated_at": "2026-10-01T09:41:05.318274+00:00",
"steps": [
{
"id": "aus_3ZqpuxjmL1szZ8og6uGL1mT6QEJ",
"key": "joined",
"type": "trigger",
"trigger": "contact.added_to_audience",
"action": null,
"config": { "audience_id": "aud_3Cz7WJ9GpvD7P0PQez50xOmkZSV" }
},
{
"id": "aus_3V5TZIXXak1SSmGcOmzPOeFaguQ",
"key": "welcome_email",
"type": "action",
"trigger": null,
"action": "send_email",
"config": { "type": "template", "template_id": "welcome", "from": "Acme <hello@acme.com>" }
},
{
"id": "aus_3vM0ORwEXCQcyS7rylfQBQEXjVk",
"key": "wait_1_day",
"type": "action",
"trigger": null,
"action": "wait",
"config": { "seconds": 86400 }
},
{
"id": "aus_3HOgOzxaXBgVRpLFtpvJNo4vd5c",
"key": "is_free_user",
"type": "action",
"trigger": null,
"action": "condition",
"config": {
"filter": {
"match": "all",
"rules": [{ "field": "custom_fields.plan", "operator": "is_not_set" }]
}
}
},
{
"id": "aus_3gCI5SWMPFVhOSawR6nz8sF55wp",
"key": "upgrade_tips",
"type": "action",
"trigger": null,
"action": "send_email",
"config": { "type": "template", "template_id": "getting-started-tips" }
},
{
"id": "aus_3Pq7Wd2LxN8cVt5RmK0sHy4BfJe",
"key": "done",
"type": "action",
"trigger": null,
"action": "end",
"config": {}
}
],
"connections": [
{ "from": "joined", "to": "welcome_email", "branch": "default" },
{ "from": "welcome_email", "to": "wait_1_day", "branch": "default" },
{ "from": "wait_1_day", "to": "is_free_user", "branch": "default" },
{ "from": "is_free_user", "to": "upgrade_tips", "branch": "yes" },
{ "from": "is_free_user", "to": "done", "branch": "no" }
]
},
"message": "Automation was successfully created.",
"notify": true
}{
"message": "Validation failed.",
"errors": {
"steps.1.action": ["Action \"forward_email\" is not allowed for context \"contact\"."],
"steps": ["Action step \"upgrade_tips\" is not reachable from any trigger."]
}
}Retrieve an automation
Retrieves an automation with its full graph. Requires an API key with the full scope.
/automations/{id}Path parameters
idstringrequiredaut_…).Returns
Returns the automation in data.
idstringaut_.contextstringcontact, email or event.namestringdescriptionstring | nullstatusstringdraft, running, paused, stopped or archived.settingsobjecton_step_failure, allow_reentry, max_concurrent_runs, cooldown_seconds. Empty when you haven’t set any.last_triggered_atstring | nullpublished_atstring | nullstepsobject[]id (aus_…), key, type, trigger, action and config. Run details refer to steps by id; statistics refer to them by key.connectionsobject[]from and to step keys and its branch.See Create an automation for the meaning of every trigger, action and setting. Returns 404 if the automation doesn’t exist or was deleted.
{
"data": {
"id": "aut_3xqC9YD79FZZA36uTekWTBO1ghe",
"context": "contact",
"name": "Welcome series",
"description": "Welcome new subscribers, then nudge free users a day later.",
"status": "running",
"settings": { "allow_reentry": false },
"last_triggered_at": "2026-10-03T14:12:40.551870+00:00",
"published_at": "2026-10-01T10:00:02.204118+00:00",
"created_at": "2026-10-01T09:41:05.318274+00:00",
"updated_at": "2026-10-03T14:12:40.551870+00:00",
"steps": [
{
"id": "aus_3ZqpuxjmL1szZ8og6uGL1mT6QEJ",
"key": "joined",
"type": "trigger",
"trigger": "contact.added_to_audience",
"action": null,
"config": { "audience_id": "aud_3Cz7WJ9GpvD7P0PQez50xOmkZSV" }
},
{
"id": "aus_3V5TZIXXak1SSmGcOmzPOeFaguQ",
"key": "welcome_email",
"type": "action",
"trigger": null,
"action": "send_email",
"config": { "type": "template", "template_id": "welcome", "from": "Acme <hello@acme.com>" }
},
{
"id": "aus_3vM0ORwEXCQcyS7rylfQBQEXjVk",
"key": "wait_1_day",
"type": "action",
"trigger": null,
"action": "wait",
"config": { "seconds": 86400 }
}
],
"connections": [
{ "from": "joined", "to": "welcome_email", "branch": "default" },
{ "from": "welcome_email", "to": "wait_1_day", "branch": "default" }
]
}
}{
"message": "Automation not found."
}Update an automation
Updates an automation’s name, description, settings or graph. Requires an API key with the full scope. The context can’t be changed.
To change the graph, send steps and connections together; they replace the current graph. Steps whose key already exists keep their ID and run history, steps you leave out are deleted, and new keys are added. Unlike create, update also validates every action’s config (for example, send_email needs type and template_id, wait needs seconds).
Pause the automation before you change the graph of a running automation, then start it again so the new triggers take effect.
/automations/{id}Path parameters
idstringrequiredaut_…).Body parameters
namestringdescriptionstringsettingsobjecton_step_failure, allow_reentry, max_concurrent_runs, cooldown_seconds. See Settings.stepsobject[]connections. See Steps.connectionsobject[]steps. See Connections.Returns
Returns the updated automation in data, with message and notify. Returns 400 with errors keyed by field path when validation fails, and 404 if the automation doesn’t exist.
{
"data": {
"id": "aut_3xqC9YD79FZZA36uTekWTBO1ghe",
"context": "contact",
"name": "Welcome series (v2)",
"description": "Welcome new subscribers, then nudge free users a day later.",
"status": "paused",
"settings": { "allow_reentry": false, "on_step_failure": "skip" },
"last_triggered_at": "2026-10-03T14:12:40.551870+00:00",
"published_at": "2026-10-01T10:00:02.204118+00:00",
"created_at": "2026-10-01T09:41:05.318274+00:00",
"updated_at": "2026-10-04T08:15:22.730115+00:00",
"steps": [
{
"id": "aus_3ZqpuxjmL1szZ8og6uGL1mT6QEJ",
"key": "joined",
"type": "trigger",
"trigger": "contact.added_to_audience",
"action": null,
"config": { "audience_id": "aud_3Cz7WJ9GpvD7P0PQez50xOmkZSV" }
},
{
"id": "aus_3V5TZIXXak1SSmGcOmzPOeFaguQ",
"key": "welcome_email",
"type": "action",
"trigger": null,
"action": "send_email",
"config": { "type": "template", "template_id": "welcome", "from": "Acme <hello@acme.com>" }
}
],
"connections": [
{ "from": "joined", "to": "welcome_email", "branch": "default" }
]
},
"message": "Automation was successfully updated.",
"notify": true
}{
"message": "Validation failed.",
"errors": {
"steps.2.config.seconds": ["Wait seconds cannot exceed 2592000 (30 days)."],
"steps.1.config.template_id": ["Template ID is required when type is \"template\"."]
}
}{
"message": "Automation not found."
}List automations
Returns the workspace’s automations, newest first, without their steps and connections. Requires an API key with the full scope. Deleted automations aren’t listed.
/automationsQuery parameters
pageintegerdefault: 1per_pageintegerdefault: 25filter[context]stringcontact, email or event.filter[status]stringdraft, running, paused, stopped or archived.filter[name]stringsortstringdefault: created_atname, created_at, updated_at or last_triggered_at.orderstringdefault: descasc or desc.You can also use the generic key.condition=value filters on name, status, context and created_at, with match. See Filtering.
Returns
dataobject[]id, context, name, description, status, settings, last_triggered_at, published_at, created_at, updated_at. settings is always an empty object in this list; retrieve the automation to read it.total_recordsintegerper_pageintegercurrent_pageintegertotal_pagesinteger{
"data": [
{
"id": "aut_3xqC9YD79FZZA36uTekWTBO1ghe",
"context": "contact",
"name": "Welcome series",
"description": "Welcome new subscribers, then nudge free users a day later.",
"status": "running",
"settings": {},
"last_triggered_at": "2026-10-03T14:12:40.551870+00:00",
"published_at": "2026-10-01T10:00:02.204118+00:00",
"created_at": "2026-10-01T09:41:05.318274+00:00",
"updated_at": "2026-10-03T14:12:40.551870+00:00"
}
],
"total_records": 1,
"per_page": 50,
"current_page": 1,
"total_pages": 1
}Delete an automation
Deletes an automation. It disappears from lists and stops reacting to triggers. Requires an API key with the full scope.
Runs that are already in progress aren’t canceled. To cancel them, stop the automation before you delete it.
/automations/{id}Path parameters
idstringrequiredaut_…).Returns
Returns a message confirming the deletion. Returns 404 if the automation doesn’t exist or was already deleted.
{
"message": "Automation was deleted successfully.",
"notify": true
}{
"message": "Automation not found."
}Start an automation
Sets the automation’s status to running. From then on, matching triggers start runs; events that happened before you started it don’t. Requires an API key with the full scope.
You can start a draft, paused or stopped automation. The first start sets published_at.
Starting doesn’t validate the graph again. If you built the automation with Create an automation, which only checks structure, make sure every action config is complete, or send the graph once through Update an automation, which validates it fully. A step with an incomplete config fails when a run reaches it.
/automations/{id}/startPath parameters
idstringrequiredaut_…).Returns
Returns the automation in data with status set to running. Returns 404 if the automation doesn’t exist.
{
"data": {
"id": "aut_3xqC9YD79FZZA36uTekWTBO1ghe",
"context": "contact",
"name": "Welcome series",
"description": "Welcome new subscribers, then nudge free users a day later.",
"status": "running",
"settings": { "allow_reentry": false },
"last_triggered_at": null,
"published_at": "2026-10-01T10:00:02.204118+00:00",
"created_at": "2026-10-01T09:41:05.318274+00:00",
"updated_at": "2026-10-01T10:00:02.204118+00:00",
"steps": [
{
"id": "aus_3ZqpuxjmL1szZ8og6uGL1mT6QEJ",
"key": "joined",
"type": "trigger",
"trigger": "contact.added_to_audience",
"action": null,
"config": { "audience_id": "aud_3Cz7WJ9GpvD7P0PQez50xOmkZSV" }
},
{
"id": "aus_3V5TZIXXak1SSmGcOmzPOeFaguQ",
"key": "welcome_email",
"type": "action",
"trigger": null,
"action": "send_email",
"config": { "type": "template", "template_id": "welcome", "from": "Acme <hello@acme.com>" }
}
],
"connections": [
{ "from": "joined", "to": "welcome_email", "branch": "default" }
]
},
"message": "Automation was successfully started.",
"notify": true
}{
"message": "Automation not found."
}Pause an automation
Sets the automation’s status to paused. Its triggers stop starting new runs, but runs already in progress continue, including those waiting on a wait step. Requires an API key with the full scope.
To also cancel runs in progress, stop the automation instead. Start it again to resume triggering.
/automations/{id}/pausePath parameters
idstringrequiredaut_…).Returns
Returns the automation in data with status set to paused. Returns 404 if the automation doesn’t exist.
{
"data": {
"id": "aut_3xqC9YD79FZZA36uTekWTBO1ghe",
"context": "contact",
"name": "Welcome series",
"description": "Welcome new subscribers, then nudge free users a day later.",
"status": "paused",
"settings": { "allow_reentry": false },
"last_triggered_at": "2026-10-03T14:12:40.551870+00:00",
"published_at": "2026-10-01T10:00:02.204118+00:00",
"created_at": "2026-10-01T09:41:05.318274+00:00",
"updated_at": "2026-10-04T08:10:51.004732+00:00",
"steps": [
{
"id": "aus_3ZqpuxjmL1szZ8og6uGL1mT6QEJ",
"key": "joined",
"type": "trigger",
"trigger": "contact.added_to_audience",
"action": null,
"config": { "audience_id": "aud_3Cz7WJ9GpvD7P0PQez50xOmkZSV" }
},
{
"id": "aus_3V5TZIXXak1SSmGcOmzPOeFaguQ",
"key": "welcome_email",
"type": "action",
"trigger": null,
"action": "send_email",
"config": { "type": "template", "template_id": "welcome", "from": "Acme <hello@acme.com>" }
}
],
"connections": [
{ "from": "joined", "to": "welcome_email", "branch": "default" }
]
},
"message": "Automation was successfully paused.",
"notify": true
}{
"message": "Automation not found."
}Stop an automation
Sets the automation’s status to stopped and cancels every run that is still running; those runs get the status canceled and their remaining steps don’t execute. Requires an API key with the full scope.
Stopping is only available through the API. To keep runs in progress going, pause the automation instead. You can start a stopped automation again; new runs start from scratch.
/automations/{id}/stopPath parameters
idstringrequiredaut_…).Returns
Returns the automation in data with status set to stopped. Returns 404 if the automation doesn’t exist.
{
"data": {
"id": "aut_3xqC9YD79FZZA36uTekWTBO1ghe",
"context": "contact",
"name": "Welcome series",
"description": "Welcome new subscribers, then nudge free users a day later.",
"status": "stopped",
"settings": { "allow_reentry": false },
"last_triggered_at": "2026-10-03T14:12:40.551870+00:00",
"published_at": "2026-10-01T10:00:02.204118+00:00",
"created_at": "2026-10-01T09:41:05.318274+00:00",
"updated_at": "2026-10-05T16:45:09.882301+00:00",
"steps": [
{
"id": "aus_3ZqpuxjmL1szZ8og6uGL1mT6QEJ",
"key": "joined",
"type": "trigger",
"trigger": "contact.added_to_audience",
"action": null,
"config": { "audience_id": "aud_3Cz7WJ9GpvD7P0PQez50xOmkZSV" }
},
{
"id": "aus_3V5TZIXXak1SSmGcOmzPOeFaguQ",
"key": "welcome_email",
"type": "action",
"trigger": null,
"action": "send_email",
"config": { "type": "template", "template_id": "welcome", "from": "Acme <hello@acme.com>" }
}
],
"connections": [
{ "from": "joined", "to": "welcome_email", "branch": "default" }
]
},
"message": "Automation was successfully stopped.",
"notify": true
}{
"message": "Automation not found."
}Trigger a run
Fires the system.manual trigger with a payload you choose. The automation must be running and have a system.manual trigger step; otherwise no run starts. Requires an API key with the full scope. Manual triggers are only available through the API.
The run starts asynchronously and costs 3 credits like any other run. Find it with List runs.
/automations/{id}/triggerPath parameters
idstringrequiredaut_…).Body parameters
payloadobjectData for the run. Emailit adds automation_id and stores the result as the run’s payload. Steps can read it with placeholders such as {{payload.order_id}} and conditions such as payload.plan.
What the run is about depends on the automation’s context:
contact: passcontact_id(con_…). Contact actions andsend_emailuse that contact.email: passemail_id(em_…). Email actions use that email.event: any data. Settooremailin the action configs, for example"to": "{{payload.customer_email}}".
Returns
Returns 200 with a message once the trigger is queued. Returns 422 if the automation isn’t running and 404 if it doesn’t exist.
{
"message": "Automation trigger dispatched."
}{
"message": "Automation must be running to trigger."
}{
"message": "Automation not found."
}List runs
Returns an automation’s runs, newest first. Each run is one pass through the graph, started by a trigger. Requires an API key with the full scope.
/automations/{id}/runsPath parameters
idstringrequiredaut_…).Query parameters
pageintegerdefault: 1per_pageintegerdefault: 25filter[status]stringrunning, completed, failed or canceled.You can also filter with key.condition=value on status, event and created_at (for example created_at.after=2026-10-01), and sort with order and direction on the same keys. See Filtering.
Returns
dataobject[]total_records, per_page, current_page, total_pagesintegerEach run has:
idstringaur_.automation_idstringaut_…).contact_idstring | nullcon_…) in the contact context.email_idstring | nullem_…) in the email context.event_idstring | nulleventstringcontact.added_to_audience or system.manual.payloadobjectmetaobjectfailure_reason.statusstringrunning, completed, failed or canceled (the automation was stopped).started_at, completed_at, created_at, updated_atstring | null{
"data": [
{
"id": "aur_3q6GdFk2eRSG093grI0v9e6REu8",
"automation_id": "aut_3xqC9YD79FZZA36uTekWTBO1ghe",
"contact_id": "con_3munwNLaXKUARc6ff9wPtxKVq4A",
"email_id": null,
"event_id": null,
"event": "contact.added_to_audience",
"payload": {},
"meta": {},
"status": "failed",
"started_at": "2026-10-03T14:12:40.551870+00:00",
"completed_at": "2026-10-03T14:12:41.093355+00:00",
"created_at": "2026-10-03T14:12:40.551870+00:00",
"updated_at": "2026-10-03T14:12:41.093355+00:00"
}
],
"total_records": 1,
"per_page": 25,
"current_page": 1,
"total_pages": 1
}{
"message": "Automation not found."
}Retrieve a run
Retrieves one run of an automation, including the steps it executed. Requires an API key with the full scope.
/automations/{id}/runs/{run_id}Path parameters
idstringrequiredaut_…).run_idstringrequiredaur_…).Returns
Returns the run in data with the fields described in List runs, plus the full payload and meta and a run_steps array.
payloadobject | null{ "object": { … } }) or the payload you passed to Trigger a run, with automation_id added.metaobject | nullsource_event_id links the run to the event that started it. Failed runs can have failure_reason: insufficient_credits (the 3 run credits couldn’t be charged) or run_timeout (the run was still running after 72 hours without a step waiting).run_stepsobject[]One entry per step the run reached:
step_id: the step’s ID (aus_…). Match it tosteps[].idfrom Retrieve an automation.status:running,waiting(awaitstep that hasn’t elapsed),completedorfailed.data: the step’s result. For examplesend_emailreturns{ "result": "email_queued", "email_oid": "em_…", "to": "…" },conditionreturns{ "result": true, "branch": "yes" }, and failed steps return{ "error": "…" }.started_at,completed_at,created_at.
Returns 404 if the automation or the run doesn’t exist.
{
"data": {
"id": "aur_3q6GdFk2eRSG093grI0v9e6REu8",
"automation_id": "aut_3xqC9YD79FZZA36uTekWTBO1ghe",
"contact_id": "con_3munwNLaXKUARc6ff9wPtxKVq4A",
"email_id": null,
"event_id": null,
"event": "contact.added_to_audience",
"payload": {
"object": {
"id": "sub_3Fh2pQx9LmZr4Wt7Nc0bVd8KsYe",
"object": "subscriber",
"subscribed": true,
"audience": { "id": "aud_3Cz7WJ9GpvD7P0PQez50xOmkZSV", "name": "Newsletter" },
"contact": { "id": "con_3munwNLaXKUARc6ff9wPtxKVq4A", "email": "ada@example.com" }
}
},
"meta": { "source_event_id": "evt_3Kd8sWq1NzXc5Vb7Mt2LpRy0HgA" },
"status": "running",
"started_at": "2026-10-03T14:12:40.551870+00:00",
"completed_at": null,
"created_at": "2026-10-03T14:12:40.551870+00:00",
"updated_at": "2026-10-03T14:12:40.551870+00:00",
"run_steps": [
{
"step_id": "aus_3V5TZIXXak1SSmGcOmzPOeFaguQ",
"status": "completed",
"data": {
"result": "email_queued",
"outcome": "accepted",
"email_oid": "em_3Cp8cMgPskzB8tIlgUyNJkpDp9O",
"to": "ada@example.com"
},
"started_at": "2026-10-03T14:12:40.702113+00:00",
"completed_at": "2026-10-03T14:12:40.918540+00:00",
"created_at": "2026-10-03T14:12:40.702113+00:00"
},
{
"step_id": "aus_3vM0ORwEXCQcyS7rylfQBQEXjVk",
"status": "waiting",
"data": { "status": "waiting", "delayMs": 86400000, "seconds": 86400 },
"started_at": "2026-10-03T14:12:41.004221+00:00",
"completed_at": null,
"created_at": "2026-10-03T14:12:41.004221+00:00"
}
]
}
}{
"message": "Run not found."
}Retrieve statistics
Returns counts for every step of an automation, keyed by step key. Requires an API key with the full scope.
/automations/{id}/statsPath parameters
idstringrequiredaut_…).Query parameters
sincestring2026-10-01T00:00:00Z.untilstringrun_ids[]stringaur_…). Repeat the parameter for several runs.Returns
Returns data, an object with one entry per step key. Steps no run has reached have a total of 0.
totalintegerby_statusobjectrunning, waiting, completed, failed.by_outcomeobjectsend_email and forward_email: accepted, then the email’s latest state (delivered, loaded, clicked, bounced, failed, complained, unsubscribed, canceled). condition: matched, not_matched. experiment: the chosen variant key. call_webhook: 2xx, 4xx, 5xx, timeout, network_error. Failed steps: error.funnelobjectsend_email steps. Cumulative counts: accepted includes every email that got further, delivered includes loaded and clicked emails, and loaded includes clicked ones. bounced, failed, complained and unsubscribed are plain counts.{
"data": {
"joined": { "total": 0, "by_status": {}, "by_outcome": {} },
"welcome_email": {
"total": 412,
"by_status": { "completed": 409, "failed": 3 },
"by_outcome": { "delivered": 251, "loaded": 98, "clicked": 41, "bounced": 19, "error": 3 },
"funnel": {
"accepted": 390,
"delivered": 390,
"loaded": 139,
"clicked": 41,
"bounced": 19,
"failed": 0,
"complained": 0,
"unsubscribed": 0
}
},
"wait_1_day": {
"total": 409,
"by_status": { "completed": 352, "waiting": 57 },
"by_outcome": {}
},
"is_free_user": {
"total": 352,
"by_status": { "completed": 352 },
"by_outcome": { "matched": 270, "not_matched": 82 }
},
"upgrade_tips": {
"total": 270,
"by_status": { "completed": 270 },
"by_outcome": { "accepted": 12, "delivered": 180, "loaded": 61, "clicked": 17 },
"funnel": {
"accepted": 270,
"delivered": 258,
"loaded": 78,
"clicked": 17,
"bounced": 0,
"failed": 0,
"complained": 0,
"unsubscribed": 0
}
},
"done": {
"total": 82,
"by_status": { "completed": 82 },
"by_outcome": {}
}
}
}{
"message": "Automation not found."
}Retrieve step statistics
Returns the counts for one step of an automation. Requires an API key with the full scope. The fields are the same as in Retrieve statistics.
/automations/{id}/steps/{step_key}/statsPath parameters
idstringrequiredaut_…).step_keystringrequiredkey, for example welcome_email.Query parameters
sincestringuntilstringReturns
Returns data with total, by_status, by_outcome and, for send_email steps, funnel. Returns 404 if the automation or the step key doesn’t exist.
{
"data": {
"total": 412,
"by_status": { "completed": 409, "failed": 3 },
"by_outcome": { "delivered": 251, "loaded": 98, "clicked": 41, "bounced": 19, "error": 3 },
"funnel": {
"accepted": 390,
"delivered": 390,
"loaded": 139,
"clicked": 41,
"bounced": 19,
"failed": 0,
"complained": 0,
"unsubscribed": 0
}
}
}{
"message": "Step not found."
}