Campaign journey pipeline
The campaign lifecycle page frames a campaign as one object with a status machine; the journey enrollment fan-out page details who gets in. This page covers what happens in between — the pipeline every enrolled contact moves through, from enrollment to measured funnel outcome, and the surfaces where you build and operate it: the journey builder at/campaigns/journey and the campaign execution view at /campaigns/:id.
The same pipeline shape holds for all three modes — a fixed-set audience (blast and drip) enters in batch, a streamed audience (journey) enters one contact at a time — and from that point on the stages are identical: personalize, pick the channel, pass the gate, measure.
Dashboard anatomy: builder vs execution
Two dashboard surfaces share one campaign id:/campaigns/journey— the builder. A visual canvas for the journey graph: a node palette (trigger, send, wait, branch, goal, exit), a graph validator that rejects cycles and unreachable nodes, a template picker, a dry-run simulator, and a goal-attachment panel. Everything you build here persists into the campaign’s journey definition; launching it is still the standard campaign launch./campaigns/:id— the execution view. Recipients and per-step analytics, the attribution funnel panel, holdout and lift panels, A/B results, link analytics, and the pause/resume controls. For a journey campaign, this is also where the per-node funnel overlay reads its numbers from.
cmp_ id, so clone, enroll, and analytics endpoints stay pointed at one campaign.
Pipeline stages
Every enrolled contact, however they entered, moves through the same five stages: 1. Enroll — entry into the audience. For a blast or drip, the whole audience resolves once at launch (a list, a segment, a filter, or all contacts). For a journey, enrollment is continuous and per-contact: inbound-reply keyword, segment entry/exit, CDP-track event, a rollout, or the single-contact enrollment endpoint behind the contact-360 enroll action. Every source funnels into the same guarded entry chain — offboard precheck, active-enrollment guard, re-entry policy, entry rate limit — detailed in journey enrollment fan-out. 2. Personalize — the template’s per-recipient variables resolve against the contact record ({{first_name}} and your custom fields), so one template renders a concrete message per contact. Channel branches in a journey graph — channelPreferenceBranch, smartChannel — pick the send channel from the contact’s preferences or engagement signal at this point, so the channel decision rides on the resolved profile.
3. Channel — the send dispatches over whatever channels the graph or campaign configuration picked: SMS, WhatsApp, email, voice, or the others your channels support. In a drip, each step carries its own channel; a journey graph has one send node per edge. Omnichannel fallback chains let one send attempt advance to a secondary channel when the primary fails to deliver.
4. Gate — the scheduling and safety gates all hold on the send path, tenant-owned and tenant-configured: the campaign’s throttle pace, quiet-hours windows in the recipient’s local timezone, frequency caps, send-time optimization (fixed or recipient-optimal), and the credit-cap governor. A gate defers or persists first — a contact in a quiet-hours window parks rather than failing — so gate outcomes show up in the funnel as a delay, not a drop.
5. Measure — outcomes persist per contact as they happen: sends, deliveries, link clicks, journey goal conversions, and terminal enrollment statuses. The funnel stage below is a read over those records, computed when you ask, not a batch job you wait on.
The stages are per-contact, so in a journey you see all five in flight at once — one contact is enrolling while another waits at a gate and a third converts against the goal.
Funnel metrics surface
Measurement in this pipeline is funnel-shaped: a counted base that progressively narrows through each next step.- Per-node contact funnel —
GET /campaigns/:id/journey/node-analyticsreturns, for every node in the journey graph, the distinct contacts that entered it, completed it end-to-end, dropped out of it, and are currently parked at it. The builder overlays this on the canvas, so a node shows its own enter/convert counts. Zero-fills nodes with no activity yet, so the graph always renders every node. - Attribution funnel —
GET /campaigns/:id/attribution-funnelanswers “how many contacts moved through, and what is that worth”: touched (contacts the campaign sent at least one message to), clicked (touched contacts who clicked a tracked short link), converted (touched contacts who fired the campaign’s journey goal), and ordered (the converted subset whose conversion links to a commerce order), with per-stage drop-off rates and the converted cohort’s gross purchase value, send spend, and ROAS. It is deliberately allocation-model-free — the ROAS counterpart across contributing campaigns lives atGET /campaigns/:id/roas. - Message-level delivery stats —
GET /campaigns/:id/journey-analyticsreports per-node total/delivered/failed message rows, complementing the contact-level funnel when you need to know why a node lost contacts.
API surface
Pipeline-interaction endpoints most integrations care about:
Guides walk these calls end to end: build a journey in the canvas and send a campaign end-to-end. The campaigns API reference is the payload contract.