# NFC

The NFC module reads the secure [NFC](https://developer.incode.com/docs/glossary#nfc-scan) chip embedded in ICAO 9303-compliant travel documents, such as e-passports. It then returns the document holder's data, including the chip's portrait image. When a flow captures multiple IDs, NFC Scan applies only to the first ID. Chip reading uses secure messaging; see [Security](https://developer.incode.com/docs/ios-security).

For an overview of this module and how it works, see [NFC Scan](https://developer.incode.com/docs/nfc).

This page covers the code-configured flow: building an `IncdOnboardingFlowConfiguration` in your app and calling `startOnboarding`. When the flow is defined in Dashboard instead and started with `startFlow` or `startWorkflow`, the NFC step is configured server-side. See [Integration Approaches](https://developer.incode.com/docs/ios-flow-configuration).

This module requires the `NFCReaderUsageDescription` key and the ISO 7816 application identifiers. See [Add Required Permissions](https://developer.incode.com/docs/setup-ios#add-required-permissions).

**Availability:** The `-nfc` build variant, on NFC-capable devices running iOS 13 or later. Calling it from a non-NFC variant triggers a runtime variant assertion (`IncdOnboardingVariant.assertIncludes(.nfc)`).

**UI:** standalone (Apple's system NFC sheet).

Use this module when:

- You need a high-assurance read of the document chip, not just an OCR of the printed page.
- Your flow performs `.nfcSelfie` or `.nfc3Way` [Face Match](https://developer.incode.com/docs/module-face-match) against the chip photo. These match types become available when `processNFCData` is enabled.

## Add NFC

1. Build the SDK with the `-nfc` variant so the NFC module is linked in.
2. Add [ID Capture](https://developer.incode.com/docs/module-id-scan) (`addIdScan(scanStep: .both)`) then [Process ID](https://developer.incode.com/docs/module-process-id) (`addIdProcess()`), before NFC. NFC reads the chip after the document has been captured and processed.
3. Add the module with `addNfcScan()`. All parameters are optional; omitting one falls back to its default.
   ```swift
   flowConfig.addNfcScan(
       idType: nil,                              // .id or .passport; nil uses the captured/selected type
       showNFCSymbolConfirmationScreen: nil,     // ask the user to confirm the chip symbol (default true)
       showInitialDataConfirmationScreen: nil,   // confirm the key data before reading (default true)
       showTutorials: nil,                       // show scanning tutorials (default true)
       nfcMaxRetries: nil,                        // retry budget (default 5)
       processNFCData: nil,                       // process the read data on the backend (default true)
       returnResultImmediately: nil               // return as soon as the chip is read (default false)
   )
   ```

### Example

The example below adds NFC after ID Capture and ID OCR/Process, shows the NFC symbol confirmation screen, processes the chip data, and listens for the result through the `onNFCScanCompleted(_:)` delegate callback.

```swift
let flow = IncdOnboardingFlowConfiguration()
flow.addIdScan(scanStep: .both)
// ID OCR runs automatically after a .both ID Capture
flow.addNfcScan(
    showNFCSymbolConfirmationScreen: true,
    processNFCData: true
)

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

```swift
extension MyViewController: IncdOnboardingDelegate {
    func onNFCScanCompleted(_ result: NFCScanResult) {
        // NFC scan completed. Process the result.
    }
}
```

## Configuration Options

Configure the module with `addNfcScan()`.

| Option                              | Type      | Description                                                                                                                                                                                                    |
| ----------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `idType`                            | `IdType?` | `.id` or `.passport`; `nil` uses the document already captured or selected.                                                                                                                                    |
| `showNFCSymbolConfirmationScreen`   | `Bool?`   | Shows a screen asking whether the document contains an NFC chip. Default: `true`.                                                                                                                              |
| `showInitialDataConfirmationScreen` | `Bool?`   | Confirms the key data before reading the chip. Default: `true`.                                                                                                                                                |
| `showTutorials`                     | `Bool?`   | Shows tutorials on how to scan the document. Default: `true`.                                                                                                                                                  |
| `nfcMaxRetries`                     | `Int?`    | Sets the maximum number of NFC scan attempts. Default: `5`.                                                                                                                                                    |
| `processNFCData`                    | `Bool?`   | Submits the chip data to the back end for identity validation. Enables the `.nfcSelfie` and `.nfc3Way` [Face Match](https://developer.incode.com/docs/module-face-match) types. Default: `true`. |
| `returnResultImmediately`           | `Bool?`   | Returns as soon as the chip is read. Default: `false`.                                                                                                                                                         |

For each NFC read, the SDK tries the PACE protocol first and falls back to BAC when PACE is unavailable or fails. PACE and BAC are alternatives, not both required. An NFC chip whose access protocol the device cannot complete fails the scan and routes through the retries configured using `nfcMaxRetries`.

## Result

```swift
func onNFCScanCompleted(_ result: NFCScanResult)
```

`NFCScanResult` fields:

- `facePhoto: UIImage?`: The document holder's face image decoded from the chip.
- `dg1: NFCDataModel.DG1?`: The machine-readable zone (MRZ) data (DG1). Its fields include:
  - `documentNumber`: The nine most-significant digits of the document number.
  - `documentCode`: The MRZ document code. One of the following: `TD1`, `TD2`, `TD3`, `MRVA`, or `MRVB`. The default is `TD3`.
  - `nationality`: The document holder's nationality as a three-letter code.
  - `issuingStateOrOrganization`: The issuing state or organization as a three-letter code.
  - `birthDate`: The date of birth in `yyMMdd` format (DG1).
  - `expireAt`: The document expiry date in `yyMMdd` format (DG1).
  - `gender`: The document holder's gender. One of the following: `MALE`, `FEMALE`, `UNKNOWN`, or `UNSPECIFIED`.
  - `primaryIdentifier`: The document holder's last name.
  - `secondaryIdentifier`: The document holder's first name.
  - `optionalData1`: First optional data field (ID-1 and ID-3 style MRZs).
  - `optionalData2`: Second optional data field (ID-1 style MRZs only); may be `null`.
  - `personalNumber`: Personal number, if encoded in `optionalData1`.
  - The corresponding MRZ check-digit fields:
    - `compositeCheckDigit`: The MRZ composite check digit (DG1); `<` when unset.
    - `dateOfBirthCheckDigit`: The check digit for the date of birth; `<` when unset.
    - `documentNumberCheckDigit`: The check digit for the document number; `<` when unset.
    - `expirationDateCheckDigit`: The check digit for the expiration date; `<` when unset.
    - `personalNumberCheckDigit`: The check digit for the personal number (TD3 only); may be `null`.
- `error: NFCScanError?`: Set when the scan did not complete successfully.

## Errors

Errors surface on the completion callback as `result.error`. Wrong-variant calls fail immediately via `IncdOnboardingVariant.assertIncludes(.nfc)` instead of through this callback.

`NFCScanError` cases:

- `error`: A wrapped `IncdError`.
- `notAvailable`: NFC not available on this OS/device.
- `userDocumentHasNoChip`
- `noScanAttemptsRemaining`

<br />
