> For the complete documentation index, see [llms.txt](https://docs.payments.thalescloud.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.payments.thalescloud.io/nfc-wallet-sdk-ios/implement-nfc-wallet/make-payments/other-payment-methods/implement-qr-code-payment.md).

# Implement QR code payment

## Overview

NFC Wallet SDK supports QR code payments for Thales white-label EMV PURE cards only.

Before you implement QR code payments, complete **Tokenization**. See [Tokenize a card](/nfc-wallet-sdk-ios/implement-nfc-wallet/tokenize-a-card.md).

## SDK Integration

### Check prerequisites

Confirm the digital card supports QR code payments using `DigitalCard.Details.isPaymentTypeSupported()` with `PaymentType.qr`.

```swift
func checkCardSupportForQR(card: DigitalCard) async throws -> Bool {
    return try await card.details.isPaymentTypeSupported(.qr)
}
```

### Create the QR payment input data

Create `QRPaymentSession.QRPaymentInputData`. It contains the transaction parameters used to build the QR code payment payload.

```swift
let amount   = "000000500030"  // 5000.30 EUR
let currency = "0978" // EUR
let aid      = "00000000000000000000000000000000"    // 16 bytes long
let idd      = "000000000000000000000000000000"      // 15 bytes long
let inputData = QRPaymentSession.QRPaymentInputData(amount: amount, currencyCode: currency, aid: aid, idd: idd)
```

`QRPaymentSession.QRPaymentInputData` has the following fields:

<table><thead><tr><th width="138">Input data</th><th width="160">Format</th><th width="169">Length</th><th>Description</th></tr></thead><tbody><tr><td><code>aid</code></td><td><p>Hexadecimal</p><p>ISO/IEC 7816-5</p></td><td>10 to 32 characters</td><td><p><strong>Mandatory</strong></p><p>Use "0000000000" to let the SDK use the primary AID.</p></td></tr><tr><td><code>amount</code></td><td>BCD-encoded hexadecimal</td><td>12 characters</td><td><p><strong>Mandatory</strong></p><p>Transaction amount in BCD format.</p><p>An amount of 5.22 EUR has the value “000000000522”.</p></td></tr><tr><td><code>currencyCode</code></td><td><p>ISO-4217</p><p>numeric string</p></td><td>4 characters</td><td><p><strong>Mandatory</strong><br>Transaction currency.</p><p>Use "0978" for EUR.</p></td></tr><tr><td><code>idd</code></td><td>Hexadecimal</td><td>30 characters</td><td><p><strong>Optional</strong></p><p>Issuer-specific data</p></td></tr></tbody></table>

### Generate QR payment data

In your digital wallet application, call `generateQRPaymentData` to generate the payload to encode in a QR code.

This API can throw an error. See [Handle errors](#handle-errors).

On success, the API returns `QRPaymentOutputData` with the following fields:

<table><thead><tr><th width="220">Parameter</th><th>Description</th><th data-hidden>Example</th></tr></thead><tbody><tr><td><code>statusWord</code></td><td>Transaction status word. <strong>9000</strong> indicates success.<br>See <a href="#handle-status-word">Handle status word</a></td><td><code>"000000500030"</code></td></tr><tr><td><code>cid</code></td><td>Cryptogram Information Data. Determines if a CDCVM is required for this transaction.</td><td><code>"0978"</code></td></tr><tr><td><code>chipDataField</code></td><td>Chip data field computed by NFC including the cryptogram.</td><td><code>"00000000000000000000000000000000"</code></td></tr><tr><td><code>condensedPaymentData</code></td><td>Not applicable</td><td></td></tr><tr><td><code>cardMainAid</code></td><td>The main AID for the card that is used for the payment.</td><td></td></tr><tr><td><code>cardMainAppTemplate</code></td><td>The main Application Template of the card that is used for payment.</td><td></td></tr><tr><td><code>cardAliasAid</code></td><td>The alternate AID of the card that is used for payment.</td><td></td></tr><tr><td><code>cardAliasAppTemplate</code></td><td>The alternate Application Template of the card that is used for payment.</td><td></td></tr><tr><td><code>commonDataTemplate</code></td><td>The Common Data Template calculated during the payment.</td><td></td></tr></tbody></table>

{% hint style="info" %}
You can use a non-default digital card for the QR code payment by passing `digitalCardID` to `generateQRPaymentData`.
{% endhint %}

### Handle status word

Always check `statusWord` before using any other field.

* `9000` indicates a successful payload generation. You can read the other fields in `QRPaymentOutputData`.
* Other values indicate a failure. Do not use the other fields in `QRPaymentOutputData`.

See table below for more details:

<table><thead><tr><th width="225">Status word value</th><th>Description</th></tr></thead><tbody><tr><td>9000</td><td><p>A successful transaction. All fields in the <code>QRPaymentOutputData</code> object are available to fetch if the <code>cid</code> value is <code>0x8x</code>.<br>Where:</p><ul><li>The first digit indicates "Request to process the transaction online".</li><li>The second digit indicates the CVM information such as No CVM Required, Local CDCVM entered, Local CDCVM required and so on. If the CID is not in the 0x8x format, the fields are empty.</li></ul></td></tr><tr><td>6989</td><td>Customer verification required due to CIAC values and no method is defined in Application Control.</td></tr><tr><td>6988</td><td>Zero transaction amount is not allowed.</td></tr><tr><td>6987</td><td>Transaction amount exceeds the card issuer defined limit.</td></tr><tr><td>6986</td><td>Transaction amount exceeds the consumer defined limit.</td></tr><tr><td>6985</td><td>ATC limit reached or the selected AID is not referring to a payment application that is compliant to this specification.</td></tr></tbody></table>

### Handle errors

If `generateQRPaymentData` throws an error, treat the payment as failed. Reset your UI state. Guide the end user to the next best action.

<table><thead><tr><th width="274">Error</th><th>Description</th></tr></thead><tbody><tr><td><code>deviceEnvironmentUnsafe</code></td><td>The device does not meet the security requirements.</td></tr><tr><td><code>sessionInProgress</code></td><td>Another payment session is still running.</td></tr><tr><td><code>unsupportedPaymentType</code></td><td>The digital card does not support QR code payment.</td></tr><tr><td><code>invalidQRInputData</code></td><td>One or more fields in <code>QRPaymentInputData</code> are missing or malformed.</td></tr><tr><td><code>qrPaymentFailed</code></td><td>The payload cannot be generated due to an internal failure.</td></tr><tr><td><code>authenticationKeyInvalidated</code></td><td>The device passcode was disabled and secure storage was wiped.</td></tr><tr><td><code>biometricNotEnrolled</code></td><td>Biometrics are unavailable or not enrolled.</td></tr></tbody></table>

{% hint style="info" %}
Each error can include a message that explains the failure. Use it for troubleshooting and support diagnostics.
{% endhint %}

{% hint style="warning" %}
NFC Wallet SDK automatically wipes stored credentials when `authenticationKeyInvalidated` occurs (for example, after a passcode reset or security change).

Your application should guide the end user through re-enrollment.
{% endhint %}

### Full implementation example

Use this code sample to understand how the previous steps fit together.

{% code expandable="true" %}

```swift
func generateOutputData(digitalCard: DigitalCard?) async -> QRPaymentSession.QRPaymentOutputData? {
    do {
        let paymentSession = QRPaymentSession()
        // Use your maximum amount for QR code payments, if applicable.
        let amount   = "000000000000"
        let currency = "0000"
        let aid      = "00000000000000000000000000000000"
        let idd      = "000000000000000000000000000000"
        let inputData = QRPaymentSession.QRPaymentInputData(amount: amount, currencyCode: currency, aid: aid, idd: idd)
        
        if let digitalCard = digitalCard, try await digitalCard.isDefaultCard {
            // QR code payment with default card
            return try await paymentSession.generateQRPaymentData(withQRPaymentInputData: inputData, userPrompt: "Authenticate")
        } else {
            // QR code payment with provided digital card
            return try await paymentSession.generateQRPaymentData(withQRPaymentInputData: inputData, digitalCardID: digitalCard?.digitalCardID, userPrompt: "Authenticate")
        }
        
    } catch {
        // Handle error
        if let error = error as? QRPaymentSession.Error {
            switch error {
            case.deviceEnvironmentUnsafe(_): break
            case .sessionInProgress: break
            case .unsupportedPaymentType(_): break
            case .invalidQRInputData(_): break
            case .qrPaymentFailed(_): break
            case .authenticationKeyInvalidated(_): break
            case .biometricNotEnrolled(_): break
            @unknown default:
                break
            }
        } else {
            //
        }
        return nil
    }
}
```

{% endcode %}

### Generate and display QR code image

Your digital wallet application is responsible for generating and displaying the QR code image using the output returned by the NFC Wallet SDK.

After you receive `QRPaymentOutputData` for a QR code payment, your digital wallet application must:

1. Build the QR code payload.
2. Generate the QR code image.
3. Display the QR code image for the end user to present at the POS.

{% hint style="info" %}
iOS supports QR code generation natively (Core Image).
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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.payments.thalescloud.io/nfc-wallet-sdk-ios/implement-nfc-wallet/make-payments/other-payment-methods/implement-qr-code-payment.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.
