# 4️⃣ Scan Document

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.\
The `scanDocument` API will compute the bac key from the MRZ and return an `EDocument` if the entire flow is successful.

### Api Signature

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

```kotlin
fun scanDocument(onCompletion: (DocumentResult<EDocument>) -> Unit)
```

{% endtab %}

{% tab title="iOS" %}

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

{% endtab %}

{% tab title="Flutter" %}

```dart
Future<DocumentResult<EDocument>> scanDocument();
```

{% 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.scanDocument() {
    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.scanDocument() { 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.scanDocument();

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 %}
