Skip to main content
Every journey settles with a JourneyResult. This page is the outcome contract — what each outcome means, what each reason under it means, and what your app should do in response.

Three guarantees

  • start() settles exactly once. Every ending — including failure — arrives as a single resolved JourneyResult. There is nothing further to await after that.
  • start() never rejects. The only two errors are thrown by journey() itself, synchronously, before a handle exists — because the journey never ran. See Errors for both.
  • checkResult rides on decision outcomes only. It’s present on success, pending, and declined; absent on abandoned and error.
These are what make a switch on outcome safe: it will always run exactly once, it will always run, and it never needs a catch for the happy path. Safe to switch on is not the same as safe to stop at, though — success still needs its reason checked before you grant access, see captured is not verified below. With withResult: false, start() still settles exactly once with this same JourneyResult, but nothing is shown first — no terminal screen mounts, so rendering the outcome to the applicant is yours to do; see Configuring a journey: Screens for what the option changes.

The five outcomes

JourneyResult is a discriminated union keyed on result.outcome, with result.reason as the second discriminant. Branch on both.

success

The applicant was verified — except for captured, which is not a verification decision at all. Check reason, not just outcome, before granting access.

pending

No decision has been made yet. Wait for a webhook or poll; do not grant access.

declined

A decision was made against the applicant.

abandoned

Nothing was decided and the applicant stopped.

error

The flow could not complete. Check recoverable and error.code before deciding how to respond.

Common fields

Every JourneyResult carries these fields, regardless of outcome: ref.entityId is resolved at settlement, not at construction — so even a first-time applicant, with no prior profile, has an entityId by the time the journey settles.

Reading extracted data

JourneyResult carries the decision, not the applicant’s data — there is no field on it for a captured document’s name, date of birth, or similar. The journey calls individual().search() internally as it runs, so that data is already loaded into the individual module by the time the journey settles. Read it from there:
See Individual Module for the full set of accessible fields.

Error detail

error results carry an error field shaped { code, message, vendor?, httpStatus?, requestId? }. requestId is what support asks for when you raise an issue about a failed run.

pending is not success

pending is not success. A pending journey has no decision yet. Granting access on pending grants access to an unverified applicant. Branch on outcome exhaustively rather than testing for failure.

captured is not verified

success / captured is not a verification decision. It means the journey was configured with triggerVerificationOnSubmit: false: capture completed and the data is saved on the entity, but no check ever ran. Branching on outcome === 'success' alone will treat it as a pass — check reason and verify server-side before granting access.

Reference

See JourneyResult for the exact types, including JourneyRef and the full reason-code table.