Automations
Manage event-triggered email workflows, their steps, and per-contact runs.
Automations are event-triggered workflows that run a sequence of steps per contact. This page covers the REST endpoints for building, activating, and inspecting them. For trigger types, step config shapes, and re-entry behavior, see the Automations guide.
All endpoints require Authorization: Bearer <api_key>. Mutation endpoints require full_access scope; reads accept read_only and above.
Create automation
POST /v1/automations
Requires full_access scope. The automation is created in draft status.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Automation name. 1-200 characters. |
trigger_type | string | Yes | One of event, contact_added_to_segment, schedule, manual. |
description | string | No | Free-form description. Max 1000 characters. |
trigger_config | object | No | Trigger parameters. { "event_name": "..." } is required when trigger_type is event. |
entry_segment_id | string | No | Segment a contact must be in before entering the automation. |
reentry_policy | string | No | once_per_contact, cooldown, or always. Default once_per_contact. |
reentry_cooldown_seconds | integer | No | Cooldown window when reentry_policy is cooldown. Minimum 1. |
Example request
{
"name": "Welcome series",
"trigger_type": "event",
"trigger_config": { "event_name": "user.signed_up" },
"reentry_policy": "once_per_contact"
}
Response
{
"id": "auto_abc123",
"name": "Welcome series",
"description": null,
"status": "draft",
"trigger_type": "event",
"trigger_config": { "event_name": "user.signed_up" },
"entry_segment_id": null,
"reentry_policy": "once_per_contact",
"reentry_cooldown_seconds": null,
"total_runs": 0,
"active_runs": 0,
"completed_runs": 0,
"failed_runs": 0,
"created_at": "2026-05-10T09:00:00Z",
"updated_at": "2026-05-10T09:00:00Z"
}
List automations
GET /v1/automations
Requires read_only scope.
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | number | 50 | Results per page (1-100). |
cursor | string | Pagination cursor from the previous response's next_cursor. | |
status | string | Filter by status: draft, active, paused, archived. |
Response
{
"data": [
{
"id": "auto_abc123",
"name": "Welcome series",
"description": null,
"status": "active",
"trigger_type": "event",
"trigger_config": { "event_name": "user.signed_up" },
"entry_segment_id": null,
"reentry_policy": "once_per_contact",
"reentry_cooldown_seconds": null,
"total_runs": 128,
"active_runs": 4,
"completed_runs": 120,
"failed_runs": 4,
"created_at": "2026-05-10T09:00:00Z",
"updated_at": "2026-05-12T11:30:00Z"
}
],
"has_more": false,
"next_cursor": null
}
Pagination is cursor-based. Pass next_cursor as the cursor parameter to get the next page.
Get automation
GET /v1/automations/:id
Requires read_only scope. Returns the same automation object as Create.
Update automation
PATCH /v1/automations/:id
Requires full_access scope. Only draft or paused automations can be edited; other statuses return 409 invalid_status. trigger_type is immutable.
Request body
All fields are optional. Send only the fields you want to change.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | No | Automation name. 1-200 characters. |
description | string | null | No | Set to null to clear. Max 1000 characters. |
trigger_config | object | No | Replaces the trigger parameters. |
entry_segment_id | string | null | No | Set to null to clear. |
reentry_policy | string | No | once_per_contact, cooldown, or always. |
reentry_cooldown_seconds | integer | null | No | Cooldown window. Set to null to clear. Minimum 1. |
Example request
{
"name": "Welcome series v2",
"trigger_config": { "event_name": "user.completed_onboarding" }
}
Response
Returns the updated automation object (same shape as Create).
Delete automation
DELETE /v1/automations/:id
Requires full_access scope. Only draft or archived automations may be deleted; other statuses return 409 invalid_status.
{
"deleted": true
}
Activate automation
POST /v1/automations/:id/activate
Requires full_access scope. The automation must have at least one step, otherwise the request returns 409 no_steps. Activating an already-active automation is a no-op; archived automations cannot be activated (409).
Returns the automation object with status set to active.
Pause automation
POST /v1/automations/:id/pause
Requires full_access scope. Existing runs continue; new triggers are ignored. Only active automations can be paused (409 otherwise).
Returns the automation object with status set to paused.
Archive automation
POST /v1/automations/:id/archive
Requires full_access scope. New triggers are ignored and run history is retained. Archiving an already-archived automation is a no-op.
Returns the automation object with status set to archived.
Trigger a manual automation
POST /v1/automations/:id/trigger
Requires full_access scope. Enqueues a run for an automation whose trigger_type is manual, bypassing the configured trigger. The automation must be active, and the run is quota-checked against your plan. Using this endpoint on a non-manual automation returns 409 invalid_trigger_type.
Request body
At least one of contact_id or contact_email is required.
| Field | Type | Required | Description |
|---|---|---|---|
contact_id | string | No* | ID of the contact to run the automation for. |
contact_email | string | No* | Email of the contact. Created automatically if it does not exist. |
context | object | No | Arbitrary key/value payload available to step variables and conditions. |
Example request
{
"contact_email": "jane@acme.com",
"context": { "plan": "pro" }
}
Response
{
"run_id": "run_abc123"
}
List automation steps
GET /v1/automations/:id/steps
Requires read_only scope. Steps are returned in execution order.
Response
{
"data": [
{
"id": "step_def456",
"automation_id": "auto_abc123",
"parent_step_id": null,
"branch_label": null,
"position": 0,
"type": "send_email",
"config": {
"type": "send_email",
"from": "Acme <hello@acme.com>",
"subject": "Welcome to Acme",
"html": "<h1>Welcome!</h1>"
},
"created_at": "2026-05-10T09:05:00Z",
"updated_at": "2026-05-10T09:05:00Z"
}
]
}
Add step
POST /v1/automations/:id/steps
Requires full_access scope. The automation must be draft or paused. If position is omitted the step is appended after the highest existing position.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
config | object | Yes | Step configuration. Must include a type: send_email, wait, branch, or ab_split. |
parent_step_id | string | null | No | Parent step for branching paths. |
branch_label | string | null | No | Which branch this step belongs to (e.g. a, b). |
position | integer | No | Execution order. Minimum 0. Defaults to append. |
The shape of config depends on its type. See the step type reference. ab_split weights must sum to 100. Branch steps require condition.op.
Example request
{
"config": {
"type": "wait",
"duration_seconds": 86400
}
}
Response
Returns the created step object (same shape as List automation steps). type is copied from config.type.
Update step
PATCH /v1/automations/:id/steps/:stepId
Requires full_access scope. The automation must be draft or paused. All fields are optional.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
config | object | No | Replacement step configuration. |
parent_step_id | string | null | No | Parent step for branching paths. |
branch_label | string | null | No | Which branch this step belongs to. |
position | integer | No | New execution order. Siblings at or after this position are shifted up. |
Returns the updated step object.
Delete step
DELETE /v1/automations/:id/steps/:stepId
Requires full_access scope. The automation must be draft or paused.
{
"deleted": true
}
List automation runs
GET /v1/automations/:id/runs
Requires read_only scope.
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | number | 50 | Results per page (1-100). |
cursor | string | Pagination cursor from the previous response's next_cursor. | |
status | string | Filter by run status: pending, in_progress, completed, failed, cancelled. |
Response
{
"data": [
{
"id": "run_abc123",
"automation_id": "auto_abc123",
"contact_id": "con_abc123",
"contact_email": "jane@acme.com",
"trigger_event_id": "evt_abc123",
"status": "in_progress",
"current_step_id": "step_def456",
"context": { "plan": "pro" },
"started_at": "2026-05-10T09:00:00Z",
"completed_at": null,
"failed_at": null,
"failure_reason": null,
"created_at": "2026-05-10T09:00:00Z",
"updated_at": "2026-05-10T09:00:01Z"
}
],
"has_more": false,
"next_cursor": null
}
A run starts as pending, moves to in_progress while steps execute, and ends as completed, failed, or cancelled.
Enqueue a run manually
POST /v1/automations/:id/runs
Requires full_access scope. Creates and enqueues a run for an active automation, bypassing the configured trigger (any trigger type). The automation must have at least one step. At least one of contact_id or contact_email is required.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
contact_id | string | No* | ID of the contact to run for. |
contact_email | string | No* | Email of the contact. |
context | object | No | Arbitrary key/value payload for the run. |
Example request
{
"contact_id": "con_abc123",
"context": { "source": "dashboard" }
}
Response
Returns the created run object (same shape as List automation runs), typically with status: "pending".
Get automation run
GET /v1/automations/:id/runs/:runId
Requires read_only scope.
Response
{
"id": "run_abc123",
"automation_id": "auto_abc123",
"contact_id": "con_abc123",
"contact_email": "jane@acme.com",
"trigger_event_id": "evt_abc123",
"status": "completed",
"current_step_id": null,
"context": { "plan": "pro" },
"started_at": "2026-05-10T09:00:00Z",
"completed_at": "2026-05-11T09:00:00Z",
"failed_at": null,
"failure_reason": null,
"created_at": "2026-05-10T09:00:00Z",
"updated_at": "2026-05-11T09:00:00Z"
}
Cancel automation run
POST /v1/automations/:id/runs/:runId/cancel
Requires full_access scope. Cancelling a run that is already completed, failed, or cancelled is a no-op.
Returns the run object with status set to cancelled.
List run steps
GET /v1/automations/:id/runs/:runId/steps
Requires read_only scope. Returns one record per step the run has reached, in creation order.
Response
{
"data": [
{
"id": "runstep_ghi789",
"run_id": "run_abc123",
"step_id": "step_def456",
"status": "completed",
"email_id": "email_abc123",
"branch_taken": null,
"scheduled_for": null,
"started_at": "2026-05-10T09:00:00Z",
"completed_at": "2026-05-10T09:00:01Z",
"error": null,
"created_at": "2026-05-10T09:00:00Z"
}
]
}
Run step status values: pending, in_progress, completed, skipped, failed.
Plan limits
| Plan | Automations | Runs / month |
|---|---|---|
| Free | Not available | 0 |
| Pro | Unlimited | 10,000 |
| Business | Unlimited | 100,000 |
| Enterprise | Unlimited | Unlimited |
Runs are counted per calendar month. On the Free plan, creating an automation returns 403 automation_not_available. Exhausting the monthly run quota returns 429 plan_limit_reached.