Skip to main content

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.
The builder answers “what does the graph do”; the execution view answers “what did it do”. Both bind to the same 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-analytics returns, 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-funnel answers “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 at GET /campaigns/:id/roas.
  • Message-level delivery stats — GET /campaigns/:id/journey-analytics reports per-node total/delivered/failed message rows, complementing the contact-level funnel when you need to know why a node lost contacts.
For the message statuses dripping under these counts, see delivery lifecycle.

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.