# Custom Module

The Custom Module pauses a Workflow and hands control to your application, which runs custom logic and returns a result that determines how the Workflow continues. The SDK hands your app a `callbackName`, then resumes the Workflow at the next node once you report a result. It exists only inside Dashboard-defined Workflows, not in locally built flows.

For an overview of this module and how it works, see [Custom Module](https://developer.incode.com/docs/custom-module).

**Availability:** Workflows API only (Dashboard-defined Workflows); not available via a local `IncdOnboardingFlowConfiguration`.

## Add Custom Module

Because the Custom Module lives on a Workflow node, there is no `flowConfig.addXxx(...)` builder for it. You configure it in Dashboard and start the session against the Workflow.

1. In Dashboard, [add a Custom Module node to your Workflow](https://developer.incode.com/docs/custom-module-dashboard) and set its `callbackName`. This is just a string the SDK delivers to your app. On iOS, there is no automatic function invocation. Your app decides how to interpret the value: for example, by mapping it to a method or branching on it.
2. Activate the Workflow and note its ID.
3. In your app, start the session against that Workflow. Set the Workflow ID via `configurationId`, which is one of the optional named parameters of the single `IncdOnboardingSessionConfiguration` initializer. Then call `IncdOnboardingManager.shared.startFlow(sessionConfig:delegate:moduleId:)`. `moduleId` is optional and defaults to `nil`.
4. Handle the module by overriding `onCustomModuleStarted(callbackName:onCustomModuleCompleted:)` on your `IncdOnboardingDelegate`. If you don't override it, the default implementation reports `.unknown`, and your custom logic never runs. Always provide an implementation that calls the `onCustomModuleCompleted` completion handler.

### Example

The example below starts a session with a `configurationId`, overrides `onCustomModuleStarted` to run custom logic based on `callbackName`, and reports the result through the `onCustomModuleCompleted` completion handler.

```swift
let session = IncdOnboardingSessionConfiguration(
    configurationId: "<WORKFLOW_ID>",
    token: "<SESSION_TOKEN>"
)
IncdOnboardingManager.shared.startFlow(sessionConfig: session, delegate: self)
```

```swift
extension MyViewController: IncdOnboardingDelegate {
    func onCustomModuleStarted(
        callbackName: String,
        onCustomModuleCompleted: @escaping (CustomModuleStatus) -> Void
    ) {
        // Run your custom logic based on callbackName, then report a result.
        let status = runCustomLogic(for: callbackName)
        onCustomModuleCompleted(status)
    }
}
```

## Configuration Options

Custom Module has no client-side builder options. Its only setting, the `callbackName`, is configured on the Custom Module node in the Workflow in Dashboard. The SDK delivers that name to your app at runtime through the delegate callback.

For `startFlow(sessionConfig:delegate:moduleId:)`, see [API Reference](https://developer.incode.com/docs/ios-api-reference#starting-a-flow).

## Result

There is no result payload object. The module signals through the `onCustomModuleStarted(callbackName:onCustomModuleCompleted:)` callback on your `IncdOnboardingDelegate`. You then call the `onCustomModuleCompleted` completion handler with a `CustomModuleStatus` to report the outcome of your custom logic. Once you report a status, the SDK submits it and advances the Workflow to the next node.

`CustomModuleStatus` is an enum with the following values:

- `ok` (`"OK"`)
- `fail` (`"FAIL"`)
- `warn` (`"WARN"`)
- `unknown` (`"UNKNOWN"`)

When the module finishes, the SDK also invokes `onCustomModuleCompleted(_ result: IncdError?)` on the delegate: `result` is `nil` on success or carries an `IncdError`. There is no module-specific error type for Custom Module; generic failures surface through `onError(_ error: IncdFlowError)` on your `IncdOnboardingDelegate`.

<br />
