> ## Documentation Index
> Fetch the complete documentation index at: https://docs.useboom.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Journeys

> The versioned workflow behind an initiative. Build it, validate it, and publish it, all over the API.

A journey is the step-by-step workflow a person moves through inside an initiative: a message, a wait, an AI-led conversation, a branch, all the way to an exit. It is fully authorable over the API and MCP, not read-only. You build a draft node by node, wire the connections, set how people enter, then validate and publish.

## Journey, initiative, run

Every journey belongs to exactly one initiative. Boom scaffolds a starting draft automatically when you create an initiative, sized from its `maxAttempts` setting, so you never start from an empty canvas. From there the initiative can carry several journey versions over its life:

```
Initiative "Renewal reminder"
  Journey v1  STOPPED     (retired)
  Journey v2  PUBLISHED   (live, one run per enrolled person)
  Journey v3  DRAFT       (being edited)
```

Each enrollment creates its own run against the version that was live at the moment the person entered. `journeys_list` and `journeys_get` return the read-only summary of a journey (its trigger and ordered steps, in plain language). `journeys_get_definition` returns the full editable graph, the shape you build with and save back.

## Node kinds

Discover these from `journeys_authoring_catalog` rather than hardcoding them: it returns every kind's inputs, its output handles (the signals it can emit), and the connection rules, scoped to what your organization actually has enabled.

| Node                  | What it does                                                                                      | Notable rule                                                                                                                       |
| --------------------- | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `ENTRY`               | Where people start: manual, segment, or CDP event, with an optional frequency cap                 | Exactly one per journey                                                                                                            |
| `SEND_MESSAGE`        | Sends an approved WhatsApp template from a chosen channel                                         | The template must belong to the same WhatsApp account as the channel, or publishing is blocked                                     |
| `WAIT_FOR_REPLY`      | Waits for the person to reply                                                                     | Emits `REPLIED` or `TIMEOUT`. Pair it with `MANAGE_CONVERSATION`                                                                   |
| `MANAGE_CONVERSATION` | Runs the AI-led conversation, or hands it to a human (`mode: ESCALATE`)                           | Emits `CLOSED` or `STALE`. An optional inactivity timeout closes the conversation after a window of silence                        |
| `CONVERSATION_BLOCK`  | Legacy combined wait-and-converse step                                                            | Kept so journeys published before the split keep running. Build new journeys with `WAIT_FOR_REPLY` + `MANAGE_CONVERSATION` instead |
| `DISPATCH_EVENT`      | Records a CDP event for the person                                                                | Lets one journey enroll people into another: the dispatched event can be a different journey's trigger                             |
| `DELAY`               | Pauses the run for a duration, until a date, or until a weekday window                            | A pure wait. It does not race an incoming reply                                                                                    |
| `DECISION`            | Two-way branch, combined by AND/OR, over workflow data, a reserved event, or a live CDP attribute | Both `YES` and `NO` must be wired before publishing                                                                                |
| `CASE`                | Switches on a single person attribute, up to 10 branches                                          | Every branch handle, plus the default handle, must be wired                                                                        |
| `HTTP_REQUEST`        | Calls an external endpoint, optionally with a stored credential                                   | Emits `SUCCESS` or `FAILED`. Behind a feature flag your organization may not have yet                                              |
| `EXIT`                | Ends the journey for the person                                                                   | At least one is required                                                                                                           |

<Note>
  The visual builder also has an email-send step, outbound only, with no reply of its own. It is not yet in the authoring catalog above, so `journeys_add_node` cannot add one today. A journey already built with one in the app still runs and can still be read back; the rule below under Troubleshooting still applies to it.

  It also needs a PUBLISHED email template, and templates are WhatsApp only on the API and MCP surface (`whatsapp_numbers_list`, `templates_list`, `templates_get`, `templates_create`). There is no email-template capability. An email template is created and published in the Boom app, after the organization has a verified sending domain and from address set up there too.
</Note>

## Build a journey

<Steps>
  <Step title="Discover what you can build">
    Call `journeys_authoring_catalog` for the node kinds, and the reference catalogs for the ids and paths a node needs: `journeys_message_channels` and `journeys_message_templates` for a `SEND_MESSAGE` node, `journeys_event_catalog` for event names, `journeys_condition_catalog` for `DECISION`/`CASE` attribute paths, and `journeys_message_variables` for what a template placeholder can bind to.
  </Step>

  <Step title="Start a draft">
    `journeys_create_draft` with an `initiativeId` and a definition (name, nodes, edges). Omit node positions and the server lays the graph out for you. To keep editing an initiative's existing draft instead, load it with `journeys_get_definition`.
  </Step>

  <Step title="Add and wire nodes">
    Shape the graph with `journeys_add_node`, `journeys_update_node`, and `journeys_delete_node`, then connect them with `journeys_connect_nodes`, naming the source node's output handle (`SENT`, `REPLIED`, `YES`, `case:<id>`, and so on). A handle wires to at most one node. `journeys_disconnect_nodes` removes an edge.
  </Step>

  <Step title="Set the trigger">
    `journeys_set_trigger` configures the ENTRY node: `manual`, `segment` (needs a `segmentId`), or `cdp_event` (needs an `eventName`), with an optional frequency cap.

    <Warning>
      A segment trigger needs the segment's internal id, and the public API
      identifies segments by `slug` instead, so you cannot wire one from the API
      or MCP today. Passing a slug fails with a not-found error. Set a segment
      trigger in the Boom app. Manual and event triggers work fully from here.
    </Warning>
  </Step>

  <Step title="Validate">
    `journeys_validate` dry-runs the publish checks against a stored draft or an arbitrary definition, without saving anything. It returns whether the graph is valid and the full list of issues, errors block publishing, warnings are advisory.
  </Step>

  <Step title="Publish">
    `journeys_publish` with `confirm: true`. This is the one action here that starts real outreach.
  </Step>
</Steps>

## Publishing and versioning

Publishing is deliberately guarded:

* It validates first. Any error-severity issue blocks the publish, the same checks `journeys_validate` runs.
* It requires an explicit `confirm: true`. There is no accidental publish, because publishing enrolls real people and sends them real messages.
* It is atomic. The previous PUBLISHED version is retired in the same operation that promotes the new one, never a moment where two versions are both live.
* People already mid-journey are unaffected. Each run is pinned to the version it enrolled under, so publishing a new version never changes someone's path partway through.

Published journeys are frozen: there is no in-place edit. To change anything, even a small fix, fork it first with `journeys_create_draft_from_published`, which copies the live version into a new editable draft while the original keeps running untouched. Edit the fork, validate it, and publish it, which then supersedes the version you forked from.

## Triggers

A journey enters people one of three ways, set on its ENTRY node:

* **Manual**: an operator or an API call adds people directly.
* **Segment**: anyone who enters the segment enrolls. Pass `includeExisting: true` on publish to also backfill current members once. Backfill takes whoever is a member at that moment, so a segment that has never been evaluated has no members and backfills nobody, with no error to tell you.
* **CDP event**: a person enrolls the moment a matching event arrives and resolves to a known person.

An optional frequency cap (`maxEnrollments` plus `enrollmentWindow`, set together or not at all) limits how often the same person can re-enter within a rolling window, useful for a journey that can otherwise re-trigger on repeat events or segment membership.

## Troubleshooting

**A template placeholder sends blank instead of erroring.** It is usually bound to a path that does not resolve for this journey's trigger. Call `journeys_message_variables` for the exact set of paths this journey can use. A custom person attribute binds as `person.<key>`, not `attributes.<key>`, that second form is the syntax for `DECISION`/`CASE` conditions, not message bindings.

**Publish fails because a conversational node follows an email send.** An email-send step has no reply lifecycle: only a delay, an exit, or another non-conversational node may come after it. Route any reply-driven path around it instead of through it.

**Publish fails with validation errors you did not expect.** `journeys_publish` always validates before publishing and refuses on any error-severity issue, it does not publish "mostly working" journeys. Run `journeys_validate` while you iterate so you see the same issues before you attempt to go live.

## Related

<CardGroup cols={2}>
  <Card title="Use MCP" icon="plug" href="/use-mcp">
    Connect an AI tool to author and run journeys conversationally.
  </Card>

  <Card title="Template variables" icon="message-square" href="/template-variables">
    The full variable catalog a SEND\_MESSAGE binding can reference, and what resolves per trigger.
  </Card>

  <Card title="Events" icon="bolt" href="/events">
    Record the CDP events that trigger a journey or feed a DECISION condition.
  </Card>

  <Card title="One uniform surface" icon="layers" href="/one-surface">
    Why every journey tool here has a matching REST endpoint.
  </Card>
</CardGroup>
