Journeys
This page is the API reference for developers who build or read journeys: the flows that follow a cart, an order, a sign-up or a date.
A journey is a versioned graph of steps. A trigger enrols a contact, and each enrollment waits, branches, sends or acts step by step until it finishes, reaches the goal or exits. Steps can send mail, SMS, WhatsApp and review requests, act in the CRM (a sales-rep task, a lifecycle stage, a lead score, a static audience, loyalty points) or start an Integration Studio workflow. A send always asks the marketing consents app first. A refused send is skipped with the reason; if that app cannot be reached, the step is tried again later, and the enrollment fails after six attempts. A journey is a draft until it is published. Once live, its version is frozen: a later edit becomes a new draft. The app ships seven templates that a shop can copy.
The app also keeps the figures of each journey: the per-step counts of a report, the enrollment timeline and the step counters.
Objects
| Object | What it holds |
|---|---|
| Journey | The name, status (draft, live, paused or archived), the trigger, the goal, the re-entry rule, the campaign, the live and draft version, the live period, the counters, and the six trash fields. |
| Version | One graph of a journey: draft, live or retired. |
| Step | One step of a version, with its next, yes and no edges. |
| Enrollment | One person in one version: the current step, due_at, the state, the exit reason and the trigger payload. |
| Enrollment event | One entry on the timeline of an enrollment. |
| Step counter | The counters of one step of one version, with the reasons behind the report. |
| Template | One of the seven shipped flows. |
| Stock watch | A "notify me when available" request for one product. |
Base path: https://api.revenexx.com/v1/journeys.
Scopes
A key calls these routes with the capability key of each route. The App's manifest names one per operation, in the form journeys.<group>.<operation>, and the API keys page explains that a key holds capability keys or a namespace such as journeys.*. The scope names are listed in the tables below. A call that needs a scope the key does not hold is refused with 403.
Journeys
| Operation | Scope | What it does |
|---|---|---|
GET /v1/journeys/journeys | journeys.journeys.list | Lists the journeys of the tenant. The trash is left out unless trashed asks for it. |
POST /v1/journeys/journeys | journeys.journeys.create | Creates a journey as a draft with version 1. |
GET /v1/journeys/journeys/{id} | journeys.journeys.get | Reads one journey. |
PUT /v1/journeys/journeys/{id} | journeys.journeys.update | Corrects a journey: name, description, currency, re-entry, campaign, trigger, goal and metadata. |
DELETE /v1/journeys/journeys/{id} | journeys.journeys.delete | Moves a journey into the trash, if it was never live and has no enrollment (see below). A second DELETE deletes it for good, unless something still needs it (409 with delete_blocked). |
POST /v1/journeys/journeys/{id}/restore | journeys.journeys.restore | Takes a journey back out of the trash. |
POST /v1/journeys/journeys/trash/empty | journeys.journeys.empty-trash | Deletes every journey in the trash for good. A journey something still blocks stays in the trash and is listed under blocked with its reason. |
POST /v1/journeys/journeys/trash/purge | journeys.journeys.purge | Deletes the journeys that have been in the trash longer than the tenant's trash retention (90 days unless the tenant set another). It is the nightly purge, callable by hand. When the retention cannot be read, nothing is deleted. |
GET /v1/journeys/journeysfilters:status,trigger_kind,campaign_ref,template_code,trashed(exclude,onlyorinclude) and further plain columns.limittakes 1 to 200 (default 50), withoffsetandorder.POST /v1/journeys/journeysbody: requiredname. Optional:description,trigger_kind,trigger_config,goal_config,reenrol,reenrol_gap_days,campaign_ref,currency,steps,entryandmetadata. Astatussent by the caller is never written: the journey stays a draft. The answer carriesproblems, which lists what stands between the draft and going live.trigger_kindvalues:event,audience_join,lifecycle_stageordate_field. The trigger and the goal are frozen while the journey is live: pause it first. Re-entry and campaign can change on a live journey, and so can the name.DELETEon a journey: only a journey that was never live and has no enrollment goes into the trash. Any other is refused with409andtrash_blocked, naming the blockerjourney_published. Archive it instead. A trashed journey takes no changes:409within_trash.restoreerror:409withnot_in_trashwhen the journey is not in the trash.- Errors on create and update:
400for a missingnameon create, an emptiednameon update, or a value of the wrong shape.409withjourney_livewhen a frozen trigger or goal is changed on a live journey, andjourney_archivedfor any change on an archived one exceptcampaign_refandmetadata. - Deleting for good: the second
DELETE,trash/emptyandtrash/purgeare refused for a storefront contact with403(not_permittedonDELETE,purge_not_allowedon the trash routes). A secondDELETEalso answers409withdelete_blockedwhile something still needs the journey.
Versions and canvas
| Operation | Scope | What it does |
|---|---|---|
GET /v1/journeys/journeys/{id}/graph | journeys.journeys.graph | Reads the steps and edges of one version, the trigger, the goal and the problems that would refuse publishing. |
PUT /v1/journeys/journeys/{id}/graph | journeys.journeys.save-graph | Writes the draft. |
GET /v1/journeys/versions | journeys.versions.list | Lists the versions. Filter ?journey_id=. |
GET /v1/journeys/versions/{id} | journeys.versions.get | Reads one version. |
- Canvas:
GET .../graph?version=takesdraft(default: the draft, else the live version),liveor a version number.400for any other value,404for a number the journey does not have. PUT .../graphbody: requiredsteps. Optional:entryandnotes. A graph with problems is saved; publishing refuses it.- Draft rule: when the journey has no draft,
PUT .../graphcreates the next version as the draft. A live version is never edited. PUT .../grapherrors:400for a value of the wrong shape or more than 200 steps,404when no journey has the id,409withjourney_archivedon an archived journey andin_trashon a trashed one.
Lifecycle
| Operation | Scope | What it does |
|---|---|---|
POST /v1/journeys/journeys/{id}/publish | journeys.journeys.publish | Checks the draft, the trigger and the goal, then makes the draft the live version. The version before is retired. |
POST /v1/journeys/journeys/{id}/pause | journeys.journeys.pause | Pauses a live journey. Nobody enters and nobody moves. |
POST /v1/journeys/journeys/{id}/resume | journeys.journeys.resume | Resumes a paused journey. |
POST /v1/journeys/journeys/{id}/archive | journeys.journeys.archive | Archives a journey. Nobody enters again. |
The status moves only through these four operations. The status draft lasts until the first publish. Each call names its errors below.
- Publish:
409withno_draftwhen there is no draft, and409withjourney_archivedon an archived journey (copy it instead).422withnot_readywhen the draft has problems: the body lists every problem by step. Running enrollments finish on the version they started on. A paused journey stays paused after publish. - Pause:
409withnot_liveunless the journey is live. Waits that pass during a pause run after the resume, in the job's budgeted chunks. - Resume:
409withnot_pausedunless the journey is paused. - Archive: everyone still inside leaves with the exit reason
journey_archived, up to 500 at once; the rest leave with the next runs. Archiving an archived journey does nothing and answers the journey as it is. - Errors on all four:
404when no journey has the id,401and403as for every route.
Running, reporting and timelines
| Operation | Scope | What it does |
|---|---|---|
POST /v1/journeys/journeys/{id}/enrol | journeys.journeys.enrol | Puts one person into the live version now, under the same re-enrolment rules as a trigger. For a test or for support. |
POST /v1/journeys/journeys/{id}/run | journeys.journeys.run | Processes the due steps of one live journey now. It also ends the active enrollments of archived journeys in the tenant (see below). |
GET /v1/journeys/journeys/{id}/report | journeys.journeys.report | Reads the per-step counts and the per-version totals: enrolled, completed, goal reached, exited, failed and conversion. |
GET /v1/journeys/journeys/{id}/timeline | journeys.journeys.timeline | Reads the entries and the goals reached per day, over all versions. |
enrolbody:contact_idoremailnames the person (400otherwise, and whencontact_idnames no contact). Optional:data(the payload the steps read),market, andkey, which makes a resent request enrol only once.enrolanswers:201with the enrollment on success. Otherwise409, with the reason ascode:already_enrolled,reenrol_off,reenrol_gap,cap_reached,duplicate(the samekeysent again) ornot_live(the journey is not live: draft, paused or archived, or it has no live version). The body carriesreasonandenrollment_id.run: on a journey that is not live it processes no steps. The call still ends the active enrollments of archived journeys across the tenant, in capped batches (exit reasonjourney_archived), because that sweep runs before the per-journey filter.timeline: reads the tenant time zone and covers at most the latest 60 days.
Enrollments and events
| Operation | Scope | What it does |
|---|---|---|
GET /v1/journeys/enrollments | journeys.enrollments.list | Lists enrollments. Filters: journey_id, state, contact_id and current_step. |
GET /v1/journeys/enrollments/{id} | journeys.enrollments.get | Reads one enrollment. |
POST /v1/journeys/enrollments/{id}/exit | journeys.enrollments.exit | Takes a person out of a journey. |
GET /v1/journeys/enrollment-events | journeys.timeline.list | Lists enrollment events. Filter enrollment_id for one person's timeline. |
GET /v1/journeys/enrollment-events/{id} | journeys.timeline.get | Reads one enrollment event. |
- Exit:
409withenrollment_endedwhen the enrollment has already ended, and409withenrollment_movedwhen it moved on while it was being removed. Try again. - Exit reasons on an ended enrollment:
exit_step,withdrawn,journey_archived,removed,failedorunresolvable.
Steps and step counters
| Operation | Scope | What it does |
|---|---|---|
GET /v1/journeys/steps | journeys.steps.list | Lists step rows. Filter journey_version_id, or journey_id with version. |
GET /v1/journeys/steps/{id} | journeys.steps.get | Reads one step row. |
GET /v1/journeys/step-stats | journeys.stats.list | Lists step counters. |
GET /v1/journeys/step-stats/{id} | journeys.stats.get | Reads one step counter. |
Templates
| Operation | Scope | What it does |
|---|---|---|
GET /v1/journeys/templates | journeys.templates.list | Lists the seven shipped flows. |
GET /v1/journeys/templates/{id} | journeys.templates.get | Reads one template. |
POST /v1/journeys/templates/{code}/copy | journeys.templates.copy | Copies a template into a new draft journey. Optional body field name. An unknown code answers 404 (not_found). |
Stock watches
A storefront posts a stock watch from a sold-out product page. The back-in-stock trigger enrols the people who wait for the product when it is back.
| Operation | Scope | What it does |
|---|---|---|
GET /v1/journeys/stock-watches | journeys.watches.list | Lists notification requests. Filter product_id and state=waiting. |
POST /v1/journeys/stock-watches | journeys.watches.create | Asks to be told when a product is back. |
GET /v1/journeys/stock-watches/{id} | journeys.watches.get | Reads one notification request. |
DELETE /v1/journeys/stock-watches/{id} | journeys.watches.delete | Withdraws a notification request. |
POSTbody: a person (contact_idoremail) and a product (product_idorsku) are required;400otherwise, and for an email without@or an id that is not a UUID. Optional:marketandsource. A new request answers201; a person already waiting for the product gets the existing request back with200.
Jobs
| Operation | Scope | What it does |
|---|---|---|
POST /v1/journeys/steps/run | journeys.jobs.steps | Runs the step job once: due steps of all live journeys, oldest first, within the budget. Optional body field budget_ms can only shorten the tenant's step budget. |
POST /v1/journeys/triggers/run | journeys.jobs.triggers | Runs the date triggers due today, then the three-hour sweep over carts, orders, subscriptions and audience joins. Optional body field force. |
The step job also runs on a five-minute schedule and the trigger job hourly. A caller can run either one by hand.
Vocabularies
| Operation | Scope | What it does |
|---|---|---|
GET /v1/journeys/vocabularies | journeys.vocabularies.list | Lists the closed vocabularies the app enforces. |
GET /v1/journeys/vocabularies/{name} | journeys.vocabularies.get | Reads one vocabulary with its values and labels. 404 when there is no such vocabulary. |
Related pages
- Audiences: the audience a journey's trigger names, and the members a journey can enter.
- Marketing consents: the consent a send checks before it goes out.
- Reviews: a review link is handed out through a journey step.