# Enrolment Flow

In order to use our SDK you need an authorization token. Please check our API "[Authorisation](https://docs.uqudo.com/docs/kyc/uqudo-api/authorisation)" in this regard.

The Uqudo SDK provides a builder class to initiate the "Enrollment Flow". The example below assumes that you have already [initialised the SDK](https://docs.uqudo.com/docs/kyc/uqudo-sdk/integration/usage#initialise-the-sdk):

{% code title="Objective-C" %}

```objectivec
UQBuilderController *builderController = [UQBuilderController defaultBuilder];
builderController.delegate = self;
builderController.appViewController = self;
//
UQEnrollmentBuilder *enrollmentBuilder = [[UQEnrollmentBuilder alloc] init];
enrollmentBuilder.authorizationToken = authorizationToken;
//
UQFacialRecognitionConfig *frConfig = [[UQFacialRecognitionConfig alloc] init];
frConfig.enableFacialRecognition = YES;
enrollmentBuilder.facialRecognitionConfig = frConfig;
//
UQDocumentConfig *documentConfig = [[UQDocumentConfig alloc] initWithDocumentType:PASSPORT];
//
UQReadingConfig *readingConfig = [[UQReadingConfig alloc] init];
readingConfig.enableReading = YES;
[readingConfig forceReadingIfSupported:YES];
documentConfig.reading = readingConfig;
//
[enrollmentBuilder add:documentConfig];
//
[builderController setEnrollment:enrollmentBuilder];
[builderController performEnrollment];
```

{% endcode %}

{% code title="Swift" %}

```swift
let uqudoBuilder = UQBuilderController.defaultBuilder()
uqudoBuilder.delegate = self
uqudoBuilder.appViewController = self
//
let enrollmentBuilder = UQEnrollmentBuilder()
enrollmentBuilder.authorizationToken = authorizationToken
//
let frConfig = UQFacialRecognitionConfig()
frConfig.enableFacialRecognition = true
enrollmentBuilder.facialRecognitionConfig = frConfig
//
let passport = UQDocumentConfig(documentType: PASSPORT.rawValue)
//
let readingConfig = UQReadingConfig()
readingConfig.enableReading = true
readingConfig.forceReadingIfSupported(true)
passport.reading = readingConfig
//
enrollmentBuilder.add(passport)
//
uqudoBuilder.setEnrollment(enrollmentBuilder)
uqudoBuilder.performEnrollment()
```

{% endcode %}

## **Uqudo Enrollment Builder Configuration**

In order to check if the document type supports the "Lookup Flow" you can use the following method:

{% code title="Objective-C" %}

```objectivec
UQDocumentConfig *documentConfig = [[UQDocumentConfig alloc] initWithDocumentType:PASSPORT];
[documentConfig isEnrollmentSupported]
```

{% endcode %}

{% code title="Swift" %}

```swift
let documentConfig = UQDocumentConfig(documentType: PASSPORT)
document.isEnrollmentSupported()
```

{% endcode %}

Please refer to the Scan API for [supported Document Types](https://docs.uqudo.com/docs/kyc/uqudo-api/scan).

Configuration options provided in the Uqudo Enrollment builder are:

<table><thead><tr><th width="150">Property</th><th width="99">Type</th><th width="99">Optional</th><th width="89">Default</th><th>Description</th></tr></thead><tbody><tr><td>authorizationToken</td><td>String</td><td>No</td><td>null</td><td>See <a href="../../../uqudo-api/authorisation">Authorisation</a></td></tr><tr><td>nonce</td><td><p>String</p><p>(max size 64 chars)</p></td><td>Yes</td><td>null</td><td>Nonce provided by the customer mobile application when the SDK is initiated. It is useful to make sure the process has been initiated by the customer mobile application. It should be generated server side.</td></tr><tr><td>setSessionID(sessionId)</td><td><p>String</p><p>(UUID v4)</p></td><td>Yes</td><td>Auto generated</td><td><p>Required during the enrolment process using a QR code, see <a href="broken-reference">QR code App</a>.</p><p><strong>Note</strong>: make sure to create always a new session id when you trigger the SDK flow</p></td></tr><tr><td>enableFacialRecognition</td><td>Boolean</td><td>Yes</td><td>false</td><td>Enable facial recognition. See <a href="#facial-recognition-configuration">Facial Recognition Configuration</a> for additional configurations</td></tr><tr><td><p>enableBackgroundCheck(isDisableConsent, backgroundCheckType,</p><p>monitoring,</p><p>skipView)</p></td><td><p>Boolean, Integer,</p><p>Boolean,</p><p>Boolean</p></td><td>Yes</td><td>None</td><td>Enable background check. See <a href="#background-check-configuration">Background Check Configuration</a> for details</td></tr><tr><td>add(documentConfig)</td><td>UQDocumentConfig</td><td>No</td><td>None</td><td>Add document config object. See <a href="#document-configuration">Document Configuration</a> for details.</td></tr><tr><td>returnDataForIncompleteSession</td><td>Boolean</td><td>Yes</td><td>false</td><td>When enabled, if the user or the SDK drops the session before completion, the SDK will return the partial data together with the SessionStatus object (see <a href="#session-status-handling">Session Status Handling</a>). Please note that you can expect some data only if the user passes at least the scanning step</td></tr><tr><td>setAppearanceMode</td><td>AppearanceMode</td><td>No</td><td>SYSTEM</td><td><p>Set the appearance mode for the SDK. The following options are available:</p><ul><li>SYSTEM: the SDK checks the OS setting for light or dark mode</li><li>LIGHT: force the light mode</li><li>DARK: force the dark mode</li></ul></td></tr><tr><td>enableLookup()</td><td>None</td><td>Yes</td><td>None</td><td><p>Enable third party lookup (Government database). See the supported documents and the data returned in <a href="../../sdk-result/data-structure/lookup-object">Lookup Object</a></p><p><strong>Note</strong>: this feature requires an additional permission and must be explicitly requested</p></td></tr><tr><td>enableLookup(documentTypes)</td><td>Array of document types</td><td>Yes</td><td>None</td><td><p>Enable third party lookup (Government database) filtered by document type. For instance, if your KYC process includes more than one document, you can decide to perform the lookup only for one single document. See the supported documents and the data returned in in <a href="../../sdk-result/data-structure/lookup-object">Lookup Object</a></p><p><strong>Note</strong>: this feature requires an additional permission and must be explicitly requested</p></td></tr><tr><td>allowNonPhysicalDocuments</td><td>Boolean</td><td>Yes</td><td>false</td><td>If enabled allows scanning of non-physical documents (where the SDK doesn't reject scans upon detecting a screen)<br><strong>Note</strong>: Available only on SDK version 3.x and above</td></tr><tr><td>disableTamperingRejection</td><td>Boolean</td><td>Yes</td><td>false</td><td>If enabled directs the SDK not to dismiss the scan upon detecting tampering, specifically for ID photo tampering detection.<br><strong>Note</strong>: Available only on SDK version 3.x and above</td></tr></tbody></table>

## **Document Configuration**

{% code title="Objective-C" %}

```objectivec
UQDocumentConfig *passport = [[UQDocumentConfig alloc] initWithDocumentType:PASSPORT];
passport.disableExpiryValidation = NO;
passport.enableAgeVerification = -1;
passport.scan = <Scan Config Object>;
passport.reading = <Reading Config Object>;
```

{% endcode %}

{% code title="Swift" %}

```swift
let passport = UQDocumentConfig(documentType: PASSPORT.rawValue)
passport.disableExpiryValidation = false
passport.enableAgeVerification = -1
passport.scan = <Scan Config Object>
passport.reading = <Reading Config Object>
```

{% endcode %}

See the options described below:

<table><thead><tr><th width="154">Property</th><th width="103">Type</th><th width="99">Optional</th><th width="110">Default</th><th>Description</th></tr></thead><tbody><tr><td>disableExpiryValidation</td><td>Boolean</td><td>Yes</td><td>false</td><td>Allows to scan expired documents</td></tr><tr><td>enableAgeVerification</td><td>Int</td><td>Yes</td><td>-1 (disabled)</td><td>Enable age verification. If the age calculated from the document is not above or equals the defined age, the scan fails showing a message to the user accordingly. Age must be above 0 otherwise is not taken into consideration</td></tr><tr><td>scan</td><td>UQScanConfig</td><td>Yes</td><td>None</td><td>Add scan configuration. See <a href="#scan-configuration">Scan Configuration</a> for details</td></tr><tr><td>reading</td><td>UQReadingConfig</td><td>Yes</td><td>None</td><td>Add reading configuration. See <a href="#read-configuration">Read Configuration</a> for details</td></tr></tbody></table>

## **Scan Configuration**

{% code title="Objective-C" %}

```objectivec
UQScanConfig *scanConfig = [[UQScanConfig alloc] init];
scanConfig.disableHelpPage = NO;
scanConfig.faceMinimumMatchLevel = 2;
[scanConfig enableScanReview:NO backSide:NO];
```

{% endcode %}

{% code title="Swift" %}

```swift
let scanConfig = UQScanConfig()
scanConfig.disableHelpPage = false
scanConfig.faceMinimumMatchLevel = 2
scanConfig.enableScanReview(false, false)
```

{% endcode %}

See the options described below:

<table><thead><tr><th width="153">Property</th><th width="104">Type</th><th width="100">Optional</th><th width="97">Default</th><th>Description</th></tr></thead><tbody><tr><td>disableHelpPage</td><td>Boolean</td><td>Yes</td><td>False</td><td>Disable scanning help page</td></tr><tr><td>faceMinimumMatchLevel</td><td>Integer</td><td>Yes</td><td>None</td><td>Defines the minimum match level that the facial recognition has to meet for scanned picture of this specific document</td></tr><tr><td>enableScanReview(frontSide, backSide)</td><td>Boolean,Boolean</td><td>Yes</td><td><p>Not</p><p>enabled</p></td><td>Enable scan review of the document for the front side, back side or both. After scanning the detected document side is presented to the user for review and confirmation</td></tr><tr><td>enableUpload</td><td>Boolean</td><td>Yes</td><td>False</td><td><p>Enable manual upload of the document instead of automatic scanning. The user can choose a single PDF that contains the image of the document. For a two-side document the first picture must be the front side and the second picture the back side.</p><p>If enabled, the reading step is automatically disabled<br><br><strong>Note</strong>: This feature has been deprecated since version 3.0.0 and will be removed in a future release of the SDK</p></td></tr></tbody></table>

## Read Configuration <a href="#id-62z1u5pjsn0r" id="id-62z1u5pjsn0r"></a>

In order to check if the document type supports the reading step you can use the following method:

{% code title="Objective-C" %}

```objectivec
UQDocumentConfig *documentConfig = [[UQDocumentConfig alloc] initWithDocumentType:PASSPORT];
[documentConfig isSupportReading]
```

{% endcode %}

{% code title="Swift" %}

```swift
let documentConfig = UQDocumentConfig(documentType: PASSPORT)
document.isSupportReading()
```

{% endcode %}

{% code title="Objective-C" %}

```objectivec
UQReadingConfig *readingConfig = [[UQReadingConfig alloc] init];
readingConfig.enableReading = YES;
readingConfig.faceMinimumMatchLevel = 3;
[readingConfig forceReading:NO];
readConfig.forceReadingTimeout = -1;
```

{% endcode %}

{% code title="Swift" %}

```swift
let readingConfig = UQReadingConfig()
readingConfig.enableReading = true
readingConfig.faceMinimumMatchLevel = 3
readingConfig.forceReading(false)
readingConfig.forceReadingTimeout(-1)
```

{% endcode %}

See the options described below:

<table><thead><tr><th width="162">Property</th><th width="98">Type</th><th width="105">Optional</th><th width="91">Default</th><th>Description</th></tr></thead><tbody><tr><td><strong>Property</strong></td><td><strong>Type</strong></td><td><strong>Optional</strong></td><td><strong>Default</strong></td><td><strong>Description</strong></td></tr><tr><td>enableReading</td><td>Boolean</td><td>Yes</td><td>false</td><td>Enable reading for the document, e.g. NFC reading of the chip</td></tr><tr><td>faceMinimumMatchLevel</td><td>Integer</td><td>Yes</td><td>None</td><td>Defines the minimum match level that the facial recognition has to meet for the picture in the chip for this specific document</td></tr><tr><td>forceReading(value)</td><td>Boolean</td><td>Yes</td><td>false</td><td>Force the reading part. Users will not be able to skip the reading part. If the device does not support NFC and forceReading is set to true, the enrollment builder will throw and exception when you trigger SDK</td></tr><tr><td>forceReadingIfSupported(value)</td><td>Boolean</td><td>Yes</td><td>false</td><td>Force the reading part only if NFC is supported. Users will not be able to skip the reading part if NFC is supported. Otherwise, after the Scan user will be moved to the next step.<br><br><strong>Note</strong>: This option has been deprecated in version 3.0.0 and is the default behaviour now</td></tr><tr><td>forceReadingTimeout</td><td>Int</td><td>Yes</td><td>-1 (disabled)</td><td>Defines the timeout in seconds. If the user isn't able to perform the NFC scanning of the document before the timeout expires, a message is shown accordingly, and the user is allowed to skip the NFC step.</td></tr></tbody></table>

## **Facial Recognition Configuration**

In order to check if the document type supports facial recognition you can use the following method:

{% code title="Objective-C" %}

```objectivec
UQDocumentConfig *documentConfig = [[UQDocumentConfig alloc] initWithDocumentType:PASSPORT];
[documentConfig isSupportFaceRecognition]
```

{% endcode %}

{% code title="Swift" %}

```swift
let documentConfig = UQDocumentConfig(documentType: PASSPORT)
document.isSupportFaceRecognition()
```

{% endcode %}

**Note**: By default the facial recognition is disabled. You will have to enable facial recognition explicitly as per the below example:

{% code title="Objective-C" %}

```objectivec
UQFacialRecognitionConfig *config = [[UQFacialRecognitionConfig alloc] init];
config.enableFacialRecognition = YES;
config.scanMinimumMatchLevel = 2;
config.readMinimumMatchLevel = 3;
config.maxAttempts = 3;
config.allowClosedEyes = NO;
```

{% endcode %}

{% code title="Swift" %}

```swift
let config = UQFacialRecognitionConfig()
config.enableFacialRecognition = true
config.scanMinimumMatchLevel = 2
config.readMinimumMatchLevel = 3
config.maxAttempts = 3
config.allowClosedEyes = false
```

{% endcode %}

Facial Recognition configuration options available:

<table><thead><tr><th width="156">Property</th><th width="97">Type</th><th width="104">Optional</th><th width="94">Default</th><th>Description</th></tr></thead><tbody><tr><td>scanMinimumMatchLevel</td><td>Integer</td><td>Yes</td><td>None</td><td>Defines the minimum match level that the facial recognition has to meet for scanned pictures</td></tr><tr><td>readMinimumMatchLevel</td><td>Integer</td><td>Yes</td><td>None</td><td>Defines the minimum match level that the facial recognition has to meet for pictures from the chip (e.g. NFC)</td></tr><tr><td>obfuscationType</td><td>ObfuscationType</td><td>Yes</td><td>None</td><td><p>Enables audit trail image background obfuscation leaving only the face visible. It can be used when there are privacy concerns related to the background of the selfie taken by the user and shared in the SDK result. There are two types of obfuscations:</p><ul><li><strong>FILLED</strong>: the background is entirely replaced</li><li><strong>FILLED_WHITE:</strong> the background is entirely replaced with a wihte background</li><li><strong>BLURRED</strong>: the background is heavily blurred, making sure the objects in the background are not clearly recognizable, but still giving a perception of the environment surrounding the user and therefore still being able to validate the reality of the image. If privacy is a concern, we recommend using this option</li></ul></td></tr><tr><td>maxAttempts</td><td>Int</td><td>Yes</td><td>3</td><td>Set the max failed facial recognition attempts before dropping the session.<br><strong>Note</strong>: only values between 1 and 3 are taken into consideration.</td></tr><tr><td>allowClosedEyes</td><td>bool</td><td>Yes</td><td>false</td><td>Allows to have closed eyes during facial recognition.</td></tr><tr><td>enableOneToNVerification</td><td>bool</td><td>Yes</td><td>False</td><td>Once activated, following a successful facial recognition (confirming liveness and matching the face), the system initiates a search for the user's selfie within your tenant. If the selfie is not found, it is added, and the indexed facial features are stored in the database. The SDK result includes a unique ID in the face object, along with an indication of whether there was a match with a previously onboarded selfie. It's essential to store this unique ID in your system alongside the user's record, facilitating future searches for users with the same ID. Please be aware that this option requires a specific permission, otherwise, it will be disregarded</td></tr><tr><td>enableActiveLiveness</td><td>bool</td><td>Yes</td><td>False</td><td><p>Enable active liveness when performing facial recognition. There are three gestures:</p><ul><li>LivenessGesture.FACE_MOVE</li><li>LivenessGesture.FACE_TILT</li><li>LivenessGesture.FACE_TURN</li></ul><p>Every gesture has two actions associated resulting in a total of six possible actions (move closer, move further, tilt right, tilt left, turn right, turn left). During verification, the SDK will randomly prompt the user to perform one of these actions to continue.<br>The configuration allows you to disable one gesture type (see below), reducing the pool to four actions.<br><strong>Warning</strong>: We recommend enabling this feature only if required for regulatory or compliance purposes, as it may significantly impact user conversion rates.</p></td></tr><tr><td>disableLivenessGesture</td><td>LivenessGesture</td><td>Yes</td><td>None</td><td></td></tr></tbody></table>

## **Background Check Configuration**

**Note:** This feature requires an additional permission and must be explicitly requested

**Note**: By default the Background Check is disabled. You need to enable Background Check explicitly. See the example below:

{% code title="Objective-C" %}

```objectivec
[enrollmentBuilder enableBackgroundCheck:YES type:RDC monitoring:NO skipView:YES];
```

{% endcode %}

{% code title="Swift" %}

```swift
enrollmentBuilder.enableBackgroundCheck(true, type: RDC, monitoring: false, skipView: true)
```

{% endcode %}

Background Check configuration options available:

<table><thead><tr><th width="181">Property</th><th width="98">Type</th><th width="99">Optional</th><th width="93">Default</th><th>Description</th></tr></thead><tbody><tr><td>isDisableConsent</td><td>Boolean</td><td>No</td><td>false</td><td>Disable consent option for the user</td></tr><tr><td>backgroundCheckType</td><td>Integer</td><td>No</td><td>RDC</td><td><p>Sets the background check type</p><p>RDC</p><p>DOW_JONES</p></td></tr><tr><td>enableMonitoring</td><td>Boolean</td><td>Yes</td><td>false</td><td>Enable continuous monitoring. See API documentation for details</td></tr><tr><td>skipView</td><td>Boolean</td><td>Yes</td><td>false</td><td>If enabled, the step will be skipped, and the SDK will trigger the background check without any user interaction.</td></tr></tbody></table>

## Handling Exceptions

The Uqudo SDK will throw certain exceptions which need to be handled by the application. The Exceptions are:

1. IllegalStateException - e.g. enabling the "Lookup Flow" for a document that doesn’t support it or because facial recognition is enabled and the documcent doesn't support it or because of some required configuration missing
2. UnsupportedDeviceException - e.g. forcing the reading / NFC step when the device doesn't support NFC

## Handling the Result

The enrollment result will be available to the builder delegate (the class that initiates the SDK has to extends **UQBuilderControllerDelegate**) if the operation succeeds and you get the result with the following method. See "[SDK result](https://docs.uqudo.com/docs/kyc/uqudo-sdk/sdk-result)" for the details about the JWS string:

{% code title="Objective-C" %}

```objectivec
- (void)didEnrollmentCompleteWithInfo:(NSString *)info {}
```

{% endcode %}

{% code title="Swift" %}

```swift
func didEnrollmentComplete(withInfo info: String) {}
```

{% endcode %}

A failure scenario can be handled with the following method:

{% code title="Objective-C" %}

```objectivec
- (void)didEnrollmentIncompleteWithStatus:(UQSessionStatus *)status {}
```

{% endcode %}

{% code title="Swift" %}

```swift
func didEnrollmentIncomplete(with status: UQSessionStatus) {}
```

{% endcode %}

See the details about the UQSessionStatus below.

## **Session Status Handling**

The **UQSessionStatus** is used to identify the status of the enrollment task. The object contains the following properties:

```
@property (nonatomic, assign) NSInteger statusCode;
@property (nonatomic, assign) NSInteger statusTask;
@property (nonatomic, strong) NSString *message;
@property (nonatomic, strong) NSString *data;
```

**statusCode** contains the following error codes:

* **USER\_CANCEL** = User canceled the enrollment process
* **SESSION\_EXPIRED** = Session expired or not found
* **UNEXPECTED\_ERROR** = Something went wrong. In the message the details of the error
* **SESSION\_INVALIDATED\_READING\_INVALID\_DOCUMENT** = Session gets invalidated because the digital signature validation fails after reading the data in the chip
* **SESSION\_INVALIDATED\_CHIP\_VALIDATION\_FAILED** = Session gets invalidated because chip authentication fails (e.g. chip authentication for passports)
* **SESSION\_INVALIDATED\_READING\_NOT\_SUPPORTED** = Session gets invalidated because the document doesn’t support reading (e.g. no chip available) and the reading step is forced by configuration
* **SESSION\_INVALIDATED\_FACE\_RECOGNITION\_TOO\_MANY\_ATTEMPTS** = Session gets invalidated because of too many failed facial recognition attempts
* **SESSION\_INVALIDATED\_CAMERA\_NOT\_AVAILABLE** = Session gets invalidated because the camera is not available
* **SESSION\_INVALIDATED\_CAMERA\_PERMISSION\_NOT\_GRANTED** = Session gets invalidated because the end user denied camera permission

**statusTask** contains the following codes:

* **SCAN** = The scanning task
* **READING** = The NFC reading task
* **FACE** = The facial recognition task
* **BACKGROUND\_CHECK** = The background check task (only if skipView() is not enabled)

**message** contains the details of the status code

**data** as String that contains the JWS object with the partial data of an incomplete KYC session. Returning the partial data for an incomplete KYC session is disabled by default, please see [Enrollment Builder Configuration](#uqudo-enrollment-builder-configuration) for details.
