Journeys API
CRUD + lifecycle endpoints for Adaptive Journeys. All endpoints require workspace authentication. Routes under /api/journeys/internal/ are reserved for the runtime (Step Functions dispatcher, GDPR sweep) and authenticate via shared-secret bearer.
List journeys
/api/journeysList all journeys (drafts + published) for the current workspace
Returns the list of journeys in the workspace. Each entry includes the latest version + draft pointer.
Create a journey (draft)
/api/journeysCreate a new draft journey. Returns the new journey with version=draft.
| Parameter | Type | Description |
|---|---|---|
namerequired | string | Display name in the dashboard. Required. |
description | string | Free-form description shown in the canvas info sidebar. |
audienceId | string | ID of the audience this journey is scoped to. If omitted, all matching subjects are eligible. |
triggerContractId | string | ID of the trigger contract the journey listens to. If omitted, the journey is manually-triggered only. |
goalEventName | string | Event name that counts as goal completion for calibrated impact. |
goalEventWindowDays | number | Attribution window in days. Defaults to workspace default (7). |
steps | JourneyStep[] | Initial step graph. Defaults to a single 'exit' step. |
Update a journey draft
/api/journeys/[id]Mutate the draft. Cannot modify a published version — bump to a new draft first.
Same body shape as POST. Setting goalEventName or goalEventWindowDays here updates the journey-level optimization goal.
Concurrent edits are detected via a conditional write on the updatedAt timestamp. If two clients edit the same draft, the second client gets a 409.
Publish a journey
/api/journeys/[id]/publishPromote the draft to a new immutable version + advance the latest pointer.
Validates:
- Every send step references a
marketingcommunication. Transactional comms are refused (400 send_step_uses_transactional_comm). - Workspace tier
maxJourneyscount is not exceeded. (Lifted as of 2026-05-15 while pricing is reworked toward usage-based billing — every workspace gets unlimited published journeys regardless of tier. The 402 path will return once gates are re-enabled.) - The draft is internally consistent (every
nextreference resolves, no cycles).
On success returns the new version pointer:
{ "id": "act-onb-2026", "version": 4 }
In-flight executions on prior versions stay on their pinned version. New executions pick up the latest at trigger time.
Pause / resume / archive
/api/journeys/[id]/pausePause the journey. Stops new executions; in-flight executions continue.
/api/journeys/[id]/resumeResume a paused journey.
/api/journeys/[id]/archiveArchive permanently. Cannot be reversed via the dashboard (DDB record is preserved).
Audit log
/api/journeys/[id]/auditAppend-only audit timeline (authoring + runtime events).
Returns up to 200 most recent audit entries. Each entry has timestamp, actor, action, and optional metadata. See Debugging journeys for the full action catalog.
Live executions
/api/journeys/[id]/executionsLast 50 executions with their current state.
Powers the live executions panel on the journey detail page. Reads from the JEXEC# index (DynamoDB) for execution pointers, then enriches with sfn.DescribeExecution for live status.
[
{
"executionArn": "arn:aws:states:us-east-1:0:execution:disp:act-onb-2026__v3__usr_a__evt_b",
"endUserId": "usr_a",
"status": "RUNNING",
"startedAt": "2026-04-30T13:00:00.000Z",
"currentStepId": "wait-3d"
}
]
Branch performance
/api/journeys/[id]/branch-performancePer-arm reach + goal-event rate for every adaptive branch in the journey.
Returns:
[
{
"stepId": "branch-2",
"arms": [
{
"armId": "discount",
"subjectsReached": 1240,
"goalEvents": 89,
"rate": 0.0718,
"credibleInterval95": [0.0568, 0.0892]
},
{
"armId": "education",
"subjectsReached": 1187,
"goalEvents": 54,
"rate": 0.0455,
"credibleInterval95": [0.0331, 0.0598]
}
]
}
]
Cold-start arms (below the min-sample floor of 200) emit coldStart: true and don't yet have a credible interval.
Calibrated impact
/api/journeys/[id]/calibrated-impactTriggered + converted counts split by exposed/holdout cohort.
{
"triggered": { "exposed": 4500, "holdout": 240 },
"converted": { "exposed": 312, "holdout": 9 },
"exposureRate": 0.0693,
"holdoutRate": 0.0375,
"lift": 0.848,
"underpowered": false,
"dailyTrend": [ /* 30 daily buckets */ ]
}
underpowered: true is set when either cohort has n < 100. See Calibrated Impact for the methodology.
Step stats
/api/journeys/[id]/step-statsPer-step executed / skipped / failed counts. Powers the canvas transparency badges.
Simulation
/api/journeys/[id]/simulateDry-run trace for a chosen subject without sending.
| Parameter | Type | Description |
|---|---|---|
subjectId | string | Real end-user ID. Mutually exclusive with subjectAttributes. |
subjectAttributes | object | Synthetic profile attributes (used when subjectId is omitted). |
overrides | string[] | Workspace-owner-only. Bypass gates: 'opt_out' | 'suppression' | 'frequency_cap' | 'holdout'. |
Returns the full trace with eligibility decisions, rendered template output (PII-masked), and branch / wait simulations. See Dry-run guide for usage patterns.
Internal endpoints (runtime + admin)
These endpoints authenticate via Authorization: Bearer ${SYNC_API_KEY} and are not intended for customer use. They exist for completeness:
POST /api/journeys/internal/dispatch— called by the Step Functions dispatcher Lambda.POST /api/journeys/internal/start-execution— called by the trigger evaluator on inbound events.POST /api/journeys/internal/forget-end-user— GDPR erasure sweep.POST /api/journeys/internal/translate-pinpoint— Pinpoint export → Apex bundle translator.POST /api/journeys/internal/import-bundle— applies a translated import bundle.