# 3️⃣ Read NFC

To scan the NFC you need to provide the Basic Access Control - BAC - key. The BAC key is computed from the Machine Readable Zone - MRZ and acts as "[proof of authorization](https://www.icao.int/Security/FAL/PKD/BVRT/Pages/Document-readers.aspx)" to access the chip content.

### Api Signature

{% tabs %}
{% tab title="Android" %}

```kotlin
fun readNfcDocumentData(
    bacKey: BacKey,
    onCompletion: (DocumentResult<EDocument>) -> Unit,
)
```

{% endtab %}

{% tab title="iOS" %}

```swift
public static func readDocumentNfcChip(
    bacKey: BacKey,
    completion: @escaping (Result<EDocument, DocumentError>) -> Void
)
```

{% endtab %}

{% tab title="Flutter" %}

```dart
Future<DocumentResult<EDocument>> readNfcDocumentData(BacKey bacKey) 
```

{% endtab %}
{% endtabs %}

### Returned result

If the Keyless Document SDK can read the NFC tag it will return an instance of `EDocument` containing the data read.

{% tabs %}
{% tab title="Android" %}

```kotlin
public data class EDocument(
	// The path to the image extracted from the document
    var facePath: String = UNKNOWN,
    // Personal information of the document holder
    var personalInformation: PersonalInformation = PersonalInformation(),
    // Information about the document itself    
    var documentInformation: DocumentInformation = DocumentInformation(),
    // Security-related information and verification status
    var security: DocumentSecurity = DocumentSecurity(),
)
```

{% endtab %}

{% tab title="iOS" %}

```swift
public struct EDocument {
    /// The image extracted from the document
    public let passportImage: UIImage?
    /// Personal information of the document holder
    public let personalInformation: PersonalInformation
    /// Information about the document itself
    public let documentInformation: DocumentInformation
    /// Security-related information and verification status
    public let security: DocumentSecurity
```

{% endtab %}

{% tab title="Flutter" %}

```dart
class EDocument {
    // Person image extracted from the document
    Uint8List? documentImage;
    // Personal information of the document holder
  	PersonalInformation personalInformation;
    // Information about the document itself      	
  	DocumentInformation documentInformation;
    // Security-related information and verification status  	
  	DocumentSecurity security;
}
```

{% endtab %}
{% endtabs %}

### Errors

In case of errors the Keyless Document SDK will return the following errors:

{% tabs %}
{% tab title="Android" %}

```kotlin
public sealed class DocumentError(
    public open val code: Int,
    public open val message: String,
) 

// errors launching the MrzCameraActivity
public data class InternalError(override val code: Int) : DocumentError(code, "Internal error")

public data object UserCancelled : DocumentError(
	code = 5000,
    message = "User cancelled the operation."
)

public data object LauncherNotInitialized : DocumentError(
    code = 5002,
    message = "Launcher is null or not initialized"
)

public data class ChipAuthError(val  errorMessage: String?  = null) : DocumentError(
    code = 7002,
    message =  errorMessage ?: "BAC Authentication failed"
)

public data class ChipException(val e: Throwable?) : DocumentError(
    code = 7003,
    message =  e?.message ?: "Chip exception"
)

public data class ChipLost(val permissionDenial: Boolean = false) : DocumentError(
    code = 7004,
    message = "Chip lost"
)

public data class UnknownError( override val message: String) : DocumentError(
    code = 9999,
    message = message
)
```

{% endtab %}

{% tab title="iOS" %}

```swift
public enum DocumentError: Error {

        case userCancelled
        case chipAuthError(message: String)
        case chipException(underlyingError: Error?)
        case invalidDocument
        case unknownError(message: String)

       public var code: Int {
            switch self {
                case .userCancelled: return 5000
                case .invalidDocument: return 6003
                case .chipAuthError: return 7002
                case .chipException: return 7003
                case .unknownError: return 9999
            }
        }

        public var message: String {
            switch self {
                case .userCancelled: return "User cancelled the operation"
                case .chipAuthError(let message): return message
                case .chipException(let underlyingError): 
                	guard let ke = underlyingError as? DocumentError else {
                        return underlyingError?.localizedDescription ?? "Chip exception"
                    }
                    return ke.message
                case .invalidDocument: return "Invalid document format"
                case .unknownError(let message): return message
            }
        }
}
```

{% endtab %}

{% tab title="Flutter" %}

```dart
enum DocumentError {
  internalError,
  userCancelled,
  launcherNotInitialized,
  chipAuthError,
  chipException,
  chipLost,
  invalidDocument,
  unknownError;
```

{% endtab %}
{% endtabs %}

### Example usage

{% tabs %}
{% tab title="Android" %}

```kotlin
KeylessDocument.readNfcDocumentData(bacKey =  mrz.toBac()) {
    when (it) {
        is DocumentResult.Success -> {
            Log.d(TAG, "EDocument ${it.value}")
 		}
    	is DocumentResult.Failure -> {
            Log.d(TAG, "Error ${it.error}")
        }
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
KeylessDocument.readDocumentNfcChip(bacKey: mrz.toBac()) { result in
    switch result {
    case .success(let document):
        print("EDocument: \(document)")
    case .failure(let error):
        print("Error: \(error)")
    }
}
```

{% endtab %}

{% tab title="Flutter" %}

```dart
DocumentResult<EDocument> documentResult = await KeylessDocument.instance.readNfcDocumentData(bacKey);

switch (documentResult) {
    case DocumentSuccess<EDocument>(data: final document):
        String docRead = 'Document: ${document.facePath}, ...';
        break;
    case DocumentFailure(message: final error, code: final code, errorType: final type):
        String error = 'Document Error: $error $code ($type)';
        break;
```

{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.keyless.io/mobile-document-sdk/mobile-document-sdk-guide/3-read-nfc.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
