Skip to main content
A journey has two layers of public state:
  • journeyStage: the top-level state of the journey.
  • sequence.phase: the common state inside a routed experience.
  • sequence.mechanism: the consumer path for that phase, such as queue, draw, auction, appointment, or timed_release.
Waitlisting is no longer a mechanism — it appears as an optional waitlist attachment on a scheduled sequence, with join()/leave(). Public journey model showing the ready, routing, gated, and routed stages, with the routed sequence phases from scheduled through ended.

Use view$ first

JourneyView is the primary public UI surface. It exposes only the actions valid for the current state.
const view = journey.view$.get();

if (view.journeyStage === "routed" && view.sequence.phase === "enterable" && "enter" in view.sequence) {
  await view.sequence.enter();
}
Use snapshot$ when you need raw diagnostic fields, event history, or exhaustive state inspection. Do not drive normal UI from private assumptions about how the snapshot was produced. Both view$ and snapshot$ are reactive readable stores. Calling .get() reads the current value once; calling .listen(...) subscribes to future changes and returns an unsubscribe function. For framework integrations, prefer the adapter’s state helper where one exists, such as useExperienceJourney in React.

Top-level stages

StageMeaningTypical UI
readyThe journey exists but has not started.Start button or auto-start setup
routingFanfare is resolving the consumer’s current public path.Loading state
gatedThe consumer must complete a public requirement before continuing.Auth, access-code, or verification UI
routedThe consumer has a public sequence state.Scheduled, enterable, participating, granted, ended, or unavailable UI

Routed sequence phases

PhaseMeaningTypical action
unavailableNo public sequence is currently available.Explain that access is not available
scheduledA sequence exists but its primary action is not open yet.Show timing. May expose a waitlist attachment (waitlist.join() / waitlist.leave()).
enterableA sequence is open for entry.Let the consumer enter (queue/draw/timed release), bid (auction), or book (appointment).
participatingThe consumer is participating.Show status and valid participation actions
settlingA draw or auction is closed to action but final results are pending.Show pending-result copy
grantedThe consumer has an active handoff grant. Appointments never reach granted.Send them to checkout or the next app step. Call claim() promptly: an unclaimed grant lapses to ended with an expired outcome.
endedThe sequence has a terminal outcome.Show outcome copy

State-gated actions

Actions are intentionally state-gated. For example:
  • ready exposes start().
  • gated exposes reroute(opts?: { accessCode? }) and retry(). Omitting accessCode re-sends the journey’s stored code; passing accessCode: undefined explicitly clears the stored code first.
  • routed exposes reroute() (no arguments — reuses the stored access code), retry(), submitAccessCode(accessCode), and the routed sequence view. submitAccessCode returns an AccessCodeSubmitResult; only the "advanced" outcome commits the submitted code as the stored code (see Upgrade offers and access codes).
  • routed.scheduled may expose a waitlist attachment with waitlist.join() and waitlist.leave() while the primary distribution is not yet open.
  • routed.enterable exposes enter() for queue, draw, or timed release; bid(amount) for auction; or book(slotId, locationId?) for appointment.
  • routed.participating exposes mechanism-specific actions such as leave(), bid(amount), complete(), cancel(reason?), or reschedule(newSlotId, newLocationId?).
  • routed.granted exposes claim() and the active grant. claim() returns the AdmissionGrant synchronously, marks checkout as started, and stops the client-side grant-expiry and capability-refresh timers so the server reservation owns the deadline. An unclaimed grant lapses to ended with an expired outcome.
  • routed.ended does not expose sequence actions.
This prevents your integration from presenting actions that are not valid for the current consumer state.

Waitlist attachment

A waitlist is not a mechanism or a phase. It is an optional attachment that appears on a scheduled sequence while the primary distribution has not yet opened. When present, sequence.waitlist exposes:
  • status: one of "not_waitlisted", "waitlisted", or "notified".
  • join(): join the scheduled distribution’s waitlist.
  • leave(): leave the scheduled distribution’s waitlist.
The attachment never grants access on its own. It is cleared when the primary distribution opens, and a "notified" status is restored only from /consumers/me.

Upgrade offers and access codes

A routed view can carry gated upgrade offers and accept an access code to attempt an upgrade:
  • offers: the gated sequences the consumer could route to. They are informational until a reroute or access code selects one.
  • submitAccessCode(accessCode): a single-shot, stateless upgrade attempt. It returns an AccessCodeSubmitResult:
    • { outcome: "advanced"; sequenceId }: the code unlocked a higher-priority offered sequence; the journey moved into it and the code became the stored code.
    • { outcome: "unchanged" }: the code unlocked nothing; the journey stays in its current sequence and the stored code is untouched.
    • { outcome: "gated" }: routing no longer yields an admissible sequence; the journey is now gated and the gate UI should take over.
Only the "advanced" outcome commits the submitted code. A rejected code never displaces the stored code or the current participation. This routed upgrade flow is distinct from the gated-stage reroute({ accessCode }) flow.

Sequence-change events

When the routed sequence changes, the SDK emits a reroute journey event. Its detail.direction is one of "upgrade", "downgrade", "lateral", or "unknown". A downgrade surfaces as a reroute event with severity "warning" and the message "Sequence downgraded"; other changes use severity "info" and "Sequence changed". The direction is event-level diagnostic context, not a field on the view.

Public-state mindset

The state model tells you what the consumer can do next. It does not tell you private reasons for routing, verification, admission, or denial. Keep your UI tied to the public state and avoid messaging that implies knowledge of private enforcement logic.