Marketing Journeys
Behavioral journeys (a.k.a. flows) are multi-step automations that enroll
contacts on a trigger and advance them through steps over time. They live in the
journeys tRPC router on the company-manager API, called at
/api/trpc/journeys.<procedure> with the standard
tRPC conventions.
v1 limitation — only EMAIL steps actually do anything outbound. The SMS
step is a non-functional stub, and several action steps are advance-only no-ops
today. Read Step types before designing a journey — a WEBHOOK
step does not emit a webhook yet.
Procedures
| Procedure | Purpose | Permission |
|---|---|---|
list |
List journeys. | automation:read |
get |
Fetch one journey. | automation:read |
create |
Create a journey. | automation:write |
update |
Update journey metadata. | automation:write |
updateSteps |
Replace the journey's steps. | automation:write |
activate |
Activate a journey (starts firing). | automation:write |
pause |
Pause a journey. | automation:write |
setActive |
Set active state explicitly. | automation:write |
listTemplates |
List prebuilt templates. | automation:read |
createFromTemplate |
Create a journey from a template. | automation:write |
listEnrollments |
List enrollments. | automation:read |
enroll |
Manually enroll a contact. | automation:write |
getStats |
Journey statistics. | automation:read |
tick |
Advance due enrollments (see Firing). | automation:write |
Triggers
A journey starts when its trigger fires for a contact:
| Trigger | Fires on |
|---|---|
NEWSLETTER_SIGNUP |
A public newsletter / signup submit. |
CART_ABANDONED |
An abandoned-cart sweep. |
ORDER_MINTED |
An order being minted. |
DATE_WINBACK |
A date-based win-back sweep. |
MANUAL |
An explicit journeys.enroll call. |
Step types
Steps are declared on the journey (via create + updateSteps, or a template).
The status column reflects the v1 reality:
| Step type | Status |
|---|---|
EMAIL |
Functional — this is the only step that sends. |
WAIT |
Flow control — the delay between steps (e.g. J+3). |
CONDITION |
Flow control — branching marker. |
GOAL |
Flow control — goal marker. |
SMS |
Non-functional stub — does not send. |
WEBHOOK |
Advance-only no-op (v1) — emits no outbound webhook. |
UPDATE_FIELD |
Advance-only no-op (v1). |
ADD_TO_SEGMENT |
Advance-only no-op (v1). |
REMOVE_FROM_SEGMENT |
Advance-only no-op (v1). |
CREATE_TASK |
Advance-only no-op (v1). |
SEND_NOTIFICATION |
Advance-only no-op (v1). |
An "advance-only no-op" step is traversed — the enrollment moves past it — but it
performs no side effect. Do not rely on WEBHOOK, UPDATE_FIELD,
ADD_TO_SEGMENT / REMOVE_FROM_SEGMENT, CREATE_TASK, or SEND_NOTIFICATION
to do anything today, and treat SMS as inert.
Prebuilt templates
listTemplates exposes ready-made journeys; createFromTemplate instantiates
one:
| Template | Trigger | Shape |
|---|---|---|
welcome |
NEWSLETTER_SIGNUP |
J+0 / J+3 / J+7 emails + a GOAL. |
abandoned-cart |
CART_ABANDONED |
1h + 24h. |
post-purchase |
ORDER_MINTED |
J+0 thanks + J+7 review. |
win-back |
DATE_WINBACK |
J+0 + J+3. |
createFromTemplate creates an inactive journey. Nothing fires until an admin
activates it.
How firing works
Enrollment happens differently per trigger:
| Trigger | How it fires | Default |
|---|---|---|
NEWSLETTER_SIGNUP |
From the public newsletter / signup submit. | Live. |
CART_ABANDONED |
A cron sweep emitter (JOURNEYS_CART_EMITTER). Bounded, capped 500/tick. |
On. |
DATE_WINBACK |
A cron sweep emitter (JOURNEYS_WINBACK_EMITTER). Bounded, capped 500/tick. |
On. |
ORDER_MINTED |
Event-driven from the order lifecycle + the Stripe magazine webhook (JOURNEYS_PURCHASE_EMITTER). |
Off. |
MANUAL |
Call journeys.enroll with a journeyId. |
n/a |
Once a contact is enrolled, the recurring "advance due enrollments" work is
driven by journeys.tick. tick is invoked on a schedule by the bext SDK
scheduler over loopback — not BullMQ. See Scheduled Jobs.
Defining and activating a journey
The developer path is short:
journeys.createFromTemplate (or: journeys.create + journeys.updateSteps)
│
▼
journeys.activate
After activate:
- Enrollment is automatic for the trigger types (subject to the emitter defaults above).
- Or enroll contacts manually with
journeys.enroll(theMANUALpath).
Related
- Scheduled Jobs — the scheduler that calls
journeys.tick - Email & MJML — what the functional
EMAILstep sends - tRPC Procedures — how to call
journeys.*