# NFC / Reading Flow

The "NFC/Reading Flow" is essentially the same as the "Enrollment Flow," with the only difference being the initial step. Instead of automatically scanning a document using the phone's camera, the process begins with the NFC/Reading step. To proceed, you must provide the necessary data to unlock the chip. Only one document can be processed at a time. Additional features, such as facial recognition and background checks, can be enabled just as they are in the "Enrollment 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 "NFC / Reading 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;
//
UQReadingBuilder *readingBuilder = [[UQReadingBuilder alloc] init];
readingBuilder.authorizationToken = authorizationToken;
readingBuilder.sessionID = sessionID;
readingBuilder.userIdentifier = userIdentifier;
readingBuilder.nonce = nonce;
//
UQFacialRecognitionConfig *facialRecognitionConfig = [[UQFacialRecognitionConfig alloc] init];
facialRecognitionConfig.enableFacialRecognition = YES;
readingBuilder.facialRecognitionConfig = facialRecognitionConfig;
//
[readingBuilder enableBackgroundCheck:YES type:RDC monitoring:NO skipView:YES];
//
readingBuilder.documentType = UAE_ID;
readingBuilder.documentNumber = @"111111111";
readingBuilder.dateOfBirth = @"1980-08-25";
readingBuilder.dateOfExpiry = @"2022-03-06";
//
[builderController setReading:readingBuilder];
[builderController performReading];
```

{% endcode %}

{% code title="Swift" %}

```swift
let builderController = UQBuilderController.defaultBuilder()
builderController.delegate = self
builderController.appViewController = self
//
let readingBuilder = UQReadingBuilder()
readingBuilder.authorizationToken = authorizationToken
readingBuilder.sessionID = sessionID
readingBuilder.userIdentifier = userIdentifier
readingBuilder.nonce = nonce
//
let frConfig = UQFacialRecognitionConfig()
frConfig.enableFacialRecognition = true
readingBuilder.facialRecognitionConfig = frConfig
//
readingBuilder.enableBackgroundCheck(true, type: RDC, monitoring: false, skipView: true)
//
readingBuilder.documentType = UAE_ID;
readingBuilder.documentNumber = "111111111";
readingBuilder.dateOfBirth = "1980-08-25";
readingBuilder.dateOfExpiry = "2022-03-06";
//
builderController.setReading(readingBuilder)
builderController.performReading()
```

{% endcode %}

## **Reading Builder Configuration**

Configuration options provided in the Uqudo Reading 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><strong>Note</strong>: make sure to create always a new session id when you trigger the SDK flow</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>setDocumentType(documentType)</td><td>Integer</td><td>No</td><td>None</td><td>Set the document type</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 reading step</td></tr><tr><td>setAppearanceMode()</td><td>AppearanceMode</td><td>No</td><td>SYSTEM</td><td><p><strong>Note</strong>: this method is exposed by the UQBuilderController object.</p><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>documentNumber</td><td>String</td><td>No</td><td>None</td><td>Set the document number used to unlock the chip</td></tr><tr><td>dateOfBirth</td><td>String</td><td>No</td><td>None</td><td>Set the date of birth used to unlock the chip. The format must be "yyyy-MM-dd"</td></tr><tr><td>dateOfExpiry</td><td>String</td><td>No</td><td>None</td><td>Set the date of expiry used to unlock the chip. The format must be "yyyy-MM-dd"</td></tr><tr><td>mrz</td><td>String</td><td>Yes</td><td>None</td><td>Set the MRZ. TD1 and TD3 MRZ type are supported. Every MRZ line must be separated by a new line char. If the MRZ is set, it takes priority and the other information are ignored.</td></tr></tbody></table>

## **Facial Recognition Configuration**

By default the facial recognition is disabled. You need to enable Facial Recognition explicitly. See the example below:

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

```objectivec
UQFacialRecognitionConfig *config = [[UQFacialRecognitionConfig alloc] init];
config.enableFacialRecognition = YES;
```

{% endcode %}

{% code title="Swift" %}

```swift
let config = UQFacialRecognitionConfig()
config.enableFacialRecognition = true
```

{% 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>minimumMatchLevel</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 government database</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

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

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

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

{% endcode %}

{% code title="Swift" %}

```swift
readingBuilder.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>Sets the background check type</td></tr><tr><td>enableMonitoring</td><td>Boolean</td><td>Yes</td><td>false</td><td>Enable continuous monitoring</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 "NFC / Reading 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

## 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)didReadingCompleteWithInfo:(NSString *)info {}
```

{% endcode %}

{% code title="Swift" %}

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

{% endcode %}

A failure scenario can be handled with the following method:

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

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

{% endcode %}

{% code title="Swift" %}

```swift
func didReadingIncomplete(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\_AUTHENTICATION\_FAILED** = Session gets invalidated because the information provided to unlock the chip are incorrect
* **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:

* **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 Reading Builder Configuration for details.
