Journeys API
A journey is an automated, per-subscriber flow: a trigger starts a run for a subscriber, and the run walks a directed graph of steps (sends, delays, branches, event waits) until it completes or exits.
These endpoints are authenticated with a bearer token:
Authorization: Bearer YOUR_ACCESS_TOKEN
The journey object
| Field | Type | Description |
|---|---|---|
id | string | Journey UUID. |
name | string | Display name. |
trigger | object | What starts a run (see Trigger). |
entry_rules | object | Who may enter and whether they may re-enter (see Entry rules). null when unset. |
steps | object | The step graph (see Step graph). |
status | string | One of draft, active, paused, archived. |
version | integer | Definition version, incremented on update. |
entered | integer | Runs entered. Populated on the list endpoint; 0 elsewhere. |
completed | integer | Runs that reached the end. Populated on the list endpoint; 0 elsewhere. |
created_at | string | Creation timestamp. |
updated_at | string | Last-update timestamp. |
Trigger
| Field | Type | Description |
|---|---|---|
type | string | segment_entered, segment_exited, or event. |
segment_id | string | Segment UUID, for the segment trigger types. |
event_name | string | Event name, for the event trigger type. |
Entry rules
| Field | Type | Description |
|---|---|---|
eligibility | object | Optional attribute/rule predicate evaluated at entry; subscribers who do not match never enter. |
allow_reentry | boolean | Allow a subscriber to re-enter after completing a run. Default false (one run per subscriber). |
reentry_window | string | Minimum wait before re-entry, e.g. "24h". |
Step graph
The steps object names a start step and maps step IDs to step nodes:
{
"start": "s1",
"steps": {
"s1": {
"id": "s1",
"type": "send",
"send": {
"channel_ids": ["ch_11111111-2222-3333-4444-555555555555"],
"template_id": "tpl_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"next": "s2"
}
},
"s2": { "id": "s2", "type": "delay", "delay": { "duration": "2d", "next": "s3" } },
"s3": {
"id": "s3",
"type": "wait_for_event",
"wait_for_event": {
"event_name": "app_opened",
"within": "3d",
"on_event": "done",
"on_timeout": "s4"
}
},
"s4": { "id": "s4", "type": "send", "send": { "channel_ids": ["ch_11111111-2222-3333-4444-555555555555"] } },
"done": { "id": "done", "type": "exit" }
}
}
Step types and their config objects:
| Type | Config key | Fields |
|---|---|---|
send | send | channel_ids, template_id or content, next (empty next completes the run). |
delay | delay | duration (e.g. "30m", "2h", "3d"), next (required). |
branch | branch | condition (predicate), then (required), else. |
wait_for_event | wait_for_event | event_name (required), within (timeout window), where (property filter), on_event (required), on_timeout. |
exit | — | Terminal step; no config. |
Durations accept whole-unit m, h, or d suffixes. The graph may also
carry a top-level exit_conditions array of global early-exit predicates
(each sets exactly one of attribute, event, or rule), evaluated on every
tick — e.g. "exit the moment the subscriber purchases."
GET /api/v1/journeys
Returns the tenant's journeys, cursor-paginated (up to 100 per page). Each
journey includes its entered / completed run rollup.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
cursor | string | Optional. The next_cursor from the previous page. |
Response — 200 OK
{
"journeys": [
{
"id": "jrn_1a2b3c4d-5e6f-7890-abcd-ef1234567890",
"name": "Win-back",
"trigger": { "type": "segment_entered", "segment_id": "seg_00000000-0000-0000-0000-000000000001" },
"entry_rules": null,
"steps": { "start": "s1", "steps": {} },
"status": "active",
"version": 3,
"entered": 1240,
"completed": 987,
"created_at": "2026-04-20T10:00:00Z",
"updated_at": "2026-05-01T08:30:00Z"
}
],
"next_cursor": ""
}
next_cursor is empty when there are no more pages.
POST /api/v1/journeys
Creates a journey as a draft. Draft saves are tolerant of an incomplete step graph, so you can persist work-in-progress; full validation runs on activation.
Request Body
{
"name": "Win-back",
"trigger": { "type": "event", "event_name": "subscription_canceled" },
"entry_rules": { "allow_reentry": true, "reentry_window": "24h" },
"steps": {
"start": "s1",
"steps": {
"s1": { "id": "s1", "type": "send", "send": { "channel_ids": ["ch_11111111-2222-3333-4444-555555555555"] } }
}
}
}
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Journey name. |
trigger | object | Yes | What starts a run. |
entry_rules | object | No | Entry eligibility and re-entry policy. |
steps | object | Yes | The step graph. |
Response — 201 Created
Returns the full journey object with status: "draft" and version: 1.
Error Codes
| Status | Reason |
|---|---|
| 401 | Missing or invalid credentials. |
| 422 | Empty name, malformed JSON in trigger / entry_rules / steps, or an invalid trigger type. |
GET /api/v1/journeys/:id
Retrieves a single journey.
Response — 200 OK
Returns the full journey object.
Error Codes
| Status | Reason |
|---|---|
| 401 | Missing or invalid credentials. |
| 404 | No journey found with that ID, or it belongs to a different tenant. |
PUT /api/v1/journeys/:id
Replaces the definition (name, trigger, entry rules, steps) of a draft or
paused journey and increments its version. Active journeys must be
paused before editing.
Request Body
Same shape as POST /api/v1/journeys.
Response — 200 OK
Returns the full updated journey object.
Error Codes
| Status | Reason |
|---|---|
| 401 | Missing or invalid credentials. |
| 404 | Journey not found. |
| 409 | The journey is active — pause it first. |
| 422 | Invalid definition. |
POST /api/v1/journeys/:id/activate
Transitions a draft or paused journey to active. Activation runs full
validation on the step graph: every step needs the config for its type, all
next targets must exist, and an exit must be reachable from the start step.
Response — 200 OK
Returns the full journey object with status: "active".
Error Codes
| Status | Reason |
|---|---|
| 401 | Missing or invalid credentials. |
| 404 | Journey not found. |
| 409 | The journey cannot be activated from its current status. |
| 422 | The definition fails validation (e.g. dangling step target, no reachable exit, invalid duration). |
POST /api/v1/journeys/:id/pause
Transitions an active journey to paused. In-flight runs stop advancing
until the journey is activated again.
Response — 200 OK
Returns the full journey object with status: "paused".
Error Codes
| Status | Reason |
|---|---|
| 401 | Missing or invalid credentials. |
| 404 | Journey not found. |
| 409 | The journey is not active. |
DELETE /api/v1/journeys/:id
Permanently deletes a journey and all of its runs.
Deletion is irreversible and removes run history. If you only want to stop the
journey, use POST /api/v1/journeys/:id/pause instead.
Response — 204 No Content
An empty body is returned on success.
Error Codes
| Status | Reason |
|---|---|
| 401 | Missing or invalid credentials. |
| 404 | Journey not found. |
GET /api/v1/journeys/:id/stats
Returns the journey's run overview: run counts by status and per-step traffic.
Response — 200 OK
{
"runs": { "active": 120, "completed": 987, "exited": 45, "canceled": 3 },
"steps": {
"s1": { "active": 20, "outcomes": { "sent": 1100 } },
"s2": { "active": 100, "outcomes": { "branch:then": 640, "branch:else": 360 } }
}
}
| Field | Type | Description |
|---|---|---|
runs | object | Run counts keyed by status (active, completed, exited, canceled). |
steps | object | Keyed by step ID. active is how many runs currently sit on the step; outcomes counts recorded step outcomes (e.g. sent, branch:then, wait:event) — their sum is how many runs passed through. |
GET /api/v1/journeys/counts
Returns the tenant's active/total journey counts.
Response — 200 OK
{ "active": 4, "total": 11 }