# Configure Flows Locally and Run End to End

This is the standard integration pattern for the Incode iOS SDK. It involves:

- Defining the onboarding flow locally in code with `IncdOnboardingFlowConfiguration`
- Implementing an `IncdOnboardingDelegate` to receive results
- Running the session with one call to `startOnboarding(sessionConfig:flowConfig:delegate:)`

The SDK presents the Incode UI for each module in turn.

Use this integration pattern when you want full control over the flow in client code. If you prefer to define the flow in Dashboard instead, see [Run Flows Configured in Dashboard](https://developer.incode.com/docs/ios-run-flows-configured-in-dashboard). If you need to insert your own screens or logic between SDK modules, see [Configure Flows Locally and Run Step by Step](https://developer.incode.com/docs/ios-configure-flows-locally-and-run-step-by-step). For more information about these patterns, see [Integration Approaches](https://developer.incode.com/docs/ios-flow-configuration).

This page covers building the flow, receiving results, and starting the session. Ensure you have followed the steps to [install and initialize](https://developer.incode.com/docs/setup-ios) the Incode iOS SDK first.

***

## Imports and Package Paths

The snippets below use short type names. The iOS SDK ships as a single module, so one import brings in the entry point, configuration, delegate, and result types:

```swift
import IncdOnboarding
```

The key types used on this page are:

- `IncdOnboardingManager`: The entry point. Access the shared instance with `IncdOnboardingManager.shared`.
- `IncdOnboardingFlowConfiguration`: Builds the flow with `addXxx(...)` calls. Most `addXxx(...)` methods add a single module, but a few differ: `addIdScan(scanStep: .both)`, for example, also appends the Process ID module, and some methods add nothing in certain SDK modes. For example, ID processing and user score are skipped in the Capture Only and Submit Only modes.
- `IncdOnboardingSessionConfiguration`: The session settings passed to every start call.
- `IncdOnboardingDelegate`: The protocol your object conforms to in order to receive results. Your class adopts this protocol directly.
- Result types (`IdScanResult`, `SelfieScanResult`, `FaceMatchResult`, …) are delivered to the delegate. Each is documented on its own page in [Modules](https://developer.incode.com/docs/ios-individual-modules).

***

## Set Up This Integration Pattern

The pattern uses five actions: initialize the SDK, set the presenting view controller, build an `IncdOnboardingFlowConfiguration`, implement an `IncdOnboardingDelegate`, and call `startOnboarding(sessionConfig:flowConfig:delegate:)`.

`startOnboarding(sessionConfig:flowConfig:delegate:)` takes a `sessionConfig` argument. The argument is required, but every field of `IncdOnboardingSessionConfiguration` is optional. Pass `IncdOnboardingSessionConfiguration()` if you don't need to customize the session. Session customization is covered in [Optional Configuration](#optional-configuration) below.

### Build a Flow Configuration

Build an `IncdOnboardingFlowConfiguration` and add the modules you want in the flow. Modules appear in the order you add them; omitted modules are not shown.

```swift
let flow = IncdOnboardingFlowConfiguration()      // or .init(waitForTutorials:)
flow.addIntro(checks: [])
flow.addPhone(otpVerification: true, defaultRegionPrefix: 1)
flow.addEmail(otpVerification: true)
flow.addIdScan(scanStep: .both)
flow.addSelfieScan()
flow.addFaceMatch(matchType: .idSelfie, idCategory: .primary)
flow.addApproval()

IncdOnboardingManager.shared.startOnboarding(
    sessionConfig: IncdOnboardingSessionConfiguration(token: "<SESSION_TOKEN>"),
    flowConfig: flow,
    delegate: self
)
```

Each module exposes its own configuration through the parameters of its `addXxx(...)` method. For example, `addIdScan(...)` accepts an `idType`, a `scanStep`, tutorial toggles, and more. Several builders take defaulted parameters; for example, `addApproval(forceApproval: Bool? = nil)` may be called with no arguments (`forceApproval` defaults to `nil`), as shown above. See [Modules](https://developer.incode.com/docs/ios-individual-modules) for the options, result type, and callbacks of each module.

<Callout icon="❗" theme="error">
  ### Warning

  Some modules have order dependencies. Some modules are required by others. For example, `addIntro(checks:)` is intended to be the first module added. Modules that consume data, such as Face Match, should come after the modules that collect data.

  The SDK defines these ordering and dependency rules per module but does not currently enforce them at session start: the `addXxx(...)` methods do not throw, and an invalid order or a missing module is not validated or rejected when the session begins. Add the modules in a valid order yourself; an invalid configuration is not caught for you.
</Callout>

### Create a Delegate to Receive SDK Results

Conform to `IncdOnboardingDelegate` to receive results from each module and the overall flow. Only `onSuccess()` and `onError(_:)` are required. Every other method has a default empty implementation. Override only the events for the modules your flow includes.

```swift
final class VerificationCoordinator: IncdOnboardingDelegate {

    // MARK: Required

    func onSuccess() {
        // User successfully finished the whole onboarding flow.
    }

    func onError(_ error: IncdFlowError) {
        // Onboarding flow was aborted due to an error.
        print("Flow error: \(error.description)")
    }

    // MARK: Optional (each has a default empty implementation)

    func userCancelledSession() {
        // User backed out of the flow.
    }

    func onOnboardingSessionCreated(_ result: OnboardingSessionResult) {
        // Session created successfully.
    }

    func onAddPhoneNumberCompleted(_ result: PhoneNumberResult) {
        // Phone number step completed.
    }

    func onIdFrontCompleted(_ result: IdScanResult) {
        // Front of the ID captured.
    }

    func onIdBackCompleted(_ result: IdScanResult) {
        // Back of the ID captured.
    }

    func onIdProcessed(_ result: IdProcessResult) {
        // ID processing/validation completed.
    }

    func onSelfieScanCompleted(_ result: SelfieScanResult) {
        // Selfie scan completed.
    }

    func onFaceMatchCompleted(_ result: FaceMatchResult) {
        // Face match completed.
    }

    func onApproveCompleted(_ result: ApprovalResult) {
        // Onboarding approval completed.
    }
}
```

The video-conference queue also reports progress through `onQueuePositionChanged(_:)` and `onEstimatedWaitingTime(_:)`. For the shape and fields of each result object, see the corresponding page in [Modules](https://developer.incode.com/docs/ios-individual-modules).

### Start the Onboarding Process

After building the flow configuration and your delegate, set the presenting view controller and call `startOnboarding(sessionConfig:flowConfig:delegate:)`. The `sessionConfig` argument is required; its contents are optional.

```swift
IncdOnboardingManager.shared.presentingViewController = self   // required for UI flows

let session = IncdOnboardingSessionConfiguration() // or a customized session (see below)

IncdOnboardingManager.shared.startOnboarding(
    sessionConfig: session,
    flowConfig: flow,
    delegate: self
)
```

***

## Optional Configuration

These configuration points are optional. Use the session configuration to bind a Dashboard flow, resume a session, or set custom fields. Use the manager's UX properties to adjust presentation behavior.

### Session Configuration

Customize the onboarding session by constructing an `IncdOnboardingSessionConfiguration`, which configures the session for `startOnboardingSection`, `startFlow(sessionConfig:delegate:)`, and `startWorkflow(sessionConfig:delegate:)`, but not the URL-based `startFlow(url:delegate:isShortened:)`.

iOS uses a single initializer whose parameters are all optional. The table below highlights the most commonly used ones; see the full initializer signature at the end of this section.

| Parameter            | Description                                                                                                                                                        |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `configurationId`    | The flow ID from Dashboard, to apply the configuration set on that flow. You still add onboarding steps via `IncdOnboardingFlowConfiguration` to display the flow. |
| `validationModules`  | The list of `OnboardingValidationModule` values used for user scoring and approval. Defaults to `.id`, `.liveness`, `.faceRecognition`.                            |
| `customFields`       | A `[String: String]` of custom fields stored for this session.                                                                                                     |
| `interviewId`        | The ID of the onboarding session. Use it to resume an existing session.                                                                                            |
| `token`              | The JSON Web Token (JWT) of the onboarding session. Use it to resume an existing session.                                                                          |
| `externalId`         | An ID used outside of the Incode Platform. If the first session is interrupted and a session with the same `externalId` already exists, that session is resumed.   |
| `externalCustomerId` | Similar to `externalId`, but always creates a new session if interrupted, even if a session with the same `externalCustomerId` already exists.                     |
| `queue`              | The `ConferenceQueue` the user enters after the flow completes when using the Conference module. If none is specified, the user goes to the default queue.         |

Bind a Dashboard flow by its configuration ID:

```swift
let session = IncdOnboardingSessionConfiguration(configurationId: "xxxxxxxxxxxxxxxx")
```

Resume an existing session—for example, one started API to API—by its `interviewId`:

```swift
let session = IncdOnboardingSessionConfiguration(interviewId: "<INTERVIEW_ID>")
```

For reference, here is the complete `IncdOnboardingSessionConfiguration` initializer:

```swift
let session = IncdOnboardingSessionConfiguration(
    configurationId: nil,
	  validationModules: nil,
    customFields: ["partnerId": "abc123"],
    interviewId: nil,
    token: "<SESSION_TOKEN>",
    externalId: nil,
    externalCustomerId: nil,
  	queue: nil,
    downloadImagesEnabled: nil,
    e2eEncryptionEnabled: false,
    mergeSessionRecordings: nil,
    language: "en"
)
```

### Presentation and UX Configuration

On iOS, presentation and UX behaviors are set as properties on the shared `IncdOnboardingManager` rather than through a separate configuration object. Set them before starting the flow.

| Property                    | Default          | Description                                                                                                   |
| --------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------- |
| `presentingViewController`  | `nil`            | The view controller the SDK presents its UI from. Required for UI flows.                                      |
| `dismissOnCompletion`       | `true`           | Whether the SDK dismisses its UI automatically when the flow finishes. Set to `false` to dismiss it yourself. |
| `modalTransitionStyle`      | `.coverVertical` | The `UIModalTransitionStyle` used when presenting the SDK UI.                                                 |
| `ageAssurance`              | `false`          | Enables the Age Assurance UX (privacy tutorials and customized capture screens).                              |
| `sendDiagnosticsData`       | `true`           | Whether the SDK sends diagnostics data.                                                                       |
| `externalAnalyticsEnabled`  | `true`           | Whether external analytics events are emitted.                                                                |
| `enableExternalScreenshots` | `false`          | Whether screenshots are allowed while the SDK UI is on screen.                                                |

```swift
let manager = IncdOnboardingManager.shared
manager.presentingViewController = self
manager.dismissOnCompletion = true
manager.modalTransitionStyle = .coverVertical
manager.ageAssurance = false
```

### Interrupt or Dismiss the Session

Use these to end a session before it reaches a terminal delegate callback, or to control the SDK's presented UI directly.

```swift
// Interrupt an in-progress flow (optionally try to finish it first)
IncdOnboardingManager.shared.forceInterrupt(tryFinishingFlow: true) { success, error in /* … */ }

// Dismiss the SDK UI
IncdOnboardingManager.shared.dismiss(forceInterrupt: false)
```

`allowUserToCancel` controls whether the SDK shows its own cancel button; `dismissOnCompletion` (see [Presentation and UX Configuration](#presentation-and-ux-configuration)) controls whether the SDK dismisses itself automatically when the flow ends.
