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

# Journey

> Complete reference for oneSdk.journey() — options, handle, and result contract

## Overview

`journey()` mounts a complete, pre-assembled verification flow into an element you own and resolves with a single decision. See the [quick start guide](/docs/embedded-flows/journey/quick-start) to get one running.

## Method

### oneSdk.journey(name, options?)

```typescript theme={null}
oneSdk.journey(name: JourneyName, options?: JourneyOptions): JourneyHandle
```

### JourneyName

`name` is a member of the `JourneyName` enum. A string that isn't one of its values is rejected at runtime.

```typescript theme={null}
import { JourneyName } from '@frankieone/one-sdk';

JourneyName.IDV   // 'idv'
JourneyName.OCR   // 'ocr'
JourneyName.EKYC  // 'ekyc'
```

## Options

| Option | Type | Default | Notes |
| - | - | - | - |
| `container` | `HTMLElement` | see [Container ownership](#container-ownership) | The journey empties this element on teardown — give it one of its own. Explicit `null` throws `E_CONTAINER_NOT_FOUND` |
| `withStart`, `withWelcome`, `withConsent` | `boolean` | off | All flows |
| `withReview` | `boolean` | off | idv/ocr only; ekyc always mounts review |
| `withResult` | `boolean` | **on** | All flows. Opt-out, unlike the other `with*` toggles — the result screen renders today, so defaulting it off would be a silent breaking change. `false` means the host owns the ending: `start()` resolves as soon as the outcome is known, nothing is mounted, and the container is emptied on settlement. Governs the terminal screen only — the `PARTIAL` retry card is controlled by `withReview` |
| `triggerVerificationOnSubmit` | `boolean` | on | idv/ocr only; rejected on ekyc, which verifies through its review screen. `false` settles `success / captured` |
| `maxAttempts` | `number` | `3` | One attempt plus two data corrections |
| `logo` | `string` | — | `style.logo` wins over this |
| `style` | `{ logo, fontFamily, primaryColor, secondaryColor }` | — | Scoped to mount element, reverted on teardown |
| `simulate` | `string` | — | **Development only.** `'<outcome>/<reason>'` |
| `startAt` | `'CAPTURE' \| 'REVIEW'` | — | **Development only.** First attempt only |
| `start`, `welcome`, `consent`, `review` | `object` | — | Form module config, verbatim. See [Form module](/docs/sdk-reference/form-module/configuration) |
| `result` | `object` keyed by result state | — | Form module RESULT config per state. Keys: `SUCCESS`, `PENDING`, `FAIL`, `PROVIDER_ERROR`, `TIMEOUT`, `PARTIAL`. A `cta` here makes the journey settle on the click |
| `personal`, `document`, `retry` | `object` | — | ekyc only, form module config, verbatim. See [Form module](/docs/sdk-reference/form-module/configuration) |
| `captureLoader`, `verifying` | `object` | — | idv/ocr only, form module config, verbatim. See [Form module](/docs/sdk-reference/form-module/configuration) |

## Container ownership

The journey owns the element you hand it. On `stop()` or `destroy()` it empties that element, so anything else you render inside it is removed too — including your own loading state or placeholder. Give the journey an element of its own rather than sharing one with your app's UI:

```html theme={null}
<div id="verify"></div>
```

If you omit `container`, the journey creates a `<div data-onesdk-journey>` inside `document.body` and removes only that node on teardown. Your page is left untouched. This default exists so a journey can be started with no markup at all — useful in a console or a spike — but a dedicated element is the intended integration, and the only form in which the journey's styling and layout are under your control.

Passing `container: null` is rejected outright with `E_CONTAINER_NOT_FOUND`, because it almost always means a `document.querySelector(...)` that found nothing.

## Handle

`journey()` returns a `JourneyHandle` synchronously, exposing `start()`, `stop()`, and `destroy()`
across the two bullets below:

* **`start()`** — begins the flow. Idempotent: calling it a second time returns the same settled promise rather than starting a second run.
* **`stop()`** and **`destroy()`** — the same operation under two names. Both settle the in-flight `start()` promise with `abandoned / user_exited` and leave no screens, vendor iframe, or journey-owned instances behind: a `container` you passed is emptied, and if you passed none, the journey's own node is removed (see [Container ownership](#container-ownership)). `destroy()` is a conventional name, not a stronger teardown — there is no behavioural difference between the two, and neither leaves the journey resumable.

A journey torn down mid-step still settles — `await start()` never hangs.

## JourneyResult

`JourneyResult` is a discriminated union keyed on `outcome`, with `reason` as the second discriminant. These are the two fields a host actually branches on:

| Field | Type | Description |
| - | - | - |
| `outcome` | `'success' \| 'pending' \| 'declined' \| 'abandoned' \| 'error'` | The decision the journey settled with |
| `reason` | one of the 25 reason codes below | Why it settled with that outcome |

Common fields, present on every result regardless of outcome:

| Field | Type | Description |
| - | - | - |
| `flow` | `JourneyName` | The flow the journey ran |
| `attempts` | `{ used: number; max: number }` | Attempts consumed against `maxAttempts` |
| `finishedAt` | `string` | ISO 8601 timestamp of when the journey settled |
| `ref` | `JourneyRef` | Identifiers gathered during the run, resolved at settlement |

```typescript theme={null}
type JourneyRef = {
  entityId: string | null;
  serviceProfileId?: string;
  workflowExecutionId?: string;
  checkId?: string;
  requestId?: string;
};
```

`entityId` is resolved at settlement, not at construction. `checkResult` is a `CheckSummary` — see
[Individual module: CheckSummary Structure](/docs/sdk-reference/individual-module#checksummary-structure)
for its shape — and rides on decision outcomes only: it is present on `success`, `pending`, and
`declined`, and absent otherwise.

The 25 reason codes:

| Outcome | Reasons |
| - | - |
| `success` | `verified`, `verified_manually`, `captured` |
| `pending` | `manual_review`, `awaiting_checks`, `processing_timeout` |
| `declined` | `checks_failed`, `declined_manually`, `duplicate`, `blocklisted`, `fraud`, `attempts_exhausted`, `profile_archived`, `profile_inactive`, `profile_deleted` |
| `abandoned` | `session_interrupted`, `user_exited` |
| `error` | `vendor_load_failed`, `vendor_offline`, `network`, `session_expired`, `submit_failed`, `workflow_error`, `workflow_timeout`, `internal` |

`error` results carry an additional shape:

```typescript theme={null}
{
  outcome: 'error';
  reason: /* one of the error reasons above */;
  recoverable: boolean;
  error: {
    code: string;
    message: string;
    vendor?: string;
    httpStatus?: number;
    requestId?: string;
  };
}
```

## Errors

Two pre-flight errors, both `OneSDKError`:

| Code | Thrown when |
| - | - |
| `E_FLOW_NOT_SUPPORTED` | `name` is not a member of `JourneyName` |
| `E_CONTAINER_NOT_FOUND` | `container` is explicitly `null` |

Both are thrown rather than resolved on the `JourneyResult`, because the journey never ran.

## Telemetry

`journey()` emits `JOURNEY:READY`, carrying `elapsedMs` — the time from the `journey()` call to first paint. This fires for real runs only; a simulated journey (see `simulate`) mounts no screen and emits no `JOURNEY:READY`. See the [event system reference](/docs/sdk-reference/events) for how telemetry events are consumed.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.