> 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-android/implement-nfc-wallet/make-payment/other-payment-methods/implement-qr-code-payment.md).

# Implement QR Code payment

## Overview

The 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 digitized card supports QR code payments using `DigitalizedCardDetails.paymentTypeSupported()`. This API returns a list of supported payment types. Verify that `PaymentType.QR` is present.

```java
public boolean isQRCodeSupported(DigitalizedCardDetails card) {
    final PaymentType[] supported = card.paymentTypeSupported();

    for (PaymentType p : supported) {
        if (p == PaymentType.QR) {
            return true;
        }
    }
    return false;
}
```

### Create the QR payment input data

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

Use `PaymentInputData.PaymentInputBuilder` with:

* `withQRCodePaymentParameters` to provide `amount`, `currencyCode` and `countryCode`
* `withPureQRCodePaymentParameters` to provide `idd` (iddData) and `aid` (aidData)

Use the following sample values as placeholders.

```java
String QR_NOMINAL_VALID_AID = “0000000000”;
String QR_NOMINAL_VALID_AMOUNT =  “000000000500”;
char currencyCode = 789;
String QR_NOMINAL_VALID_IDD = “000000000000000000000000000000”;

PaymentInputData paymentInputData = new PaymentInputData.PaymentInputBuilder(PaymentType.QR)
                .withQRCodePaymentParameters(QR_NOMINAL_VALID_AMOUNT, QR_NOMINAL_VALID_CURRENCY, (char)0)
                .withPureQRCodePaymentParameters(QR_NOMINAL_VALID_IDD.getBytes(), QR_NOMINAL_VALID_AID.getBytes())
                .build();
```

`PaymentInputData` for QR code has the following fields.

| Field          | Format                       | Length        | Requirement | Description                                                              |
| -------------- | ---------------------------- | ------------- | ----------- | ------------------------------------------------------------------------ |
| `aid`          | Hexadecimal (ISO/IEC 7816-5) | 5 to 16 bytes | Required    | Use `"0000000000"` to let the SDK use the primary AID.                   |
| `amount`       | BCD-encoded hexadecimal      | 6 bytes       | Required    | Transaction amount in BCD format. Example: 5.22 EUR is `"000000000522"`. |
| `currencyCode` | Numeric 3 (ISO-4217)         | 3 characters  | Required    | Transaction currency. Example: use `"978"` for EUR.                      |
| `countryCode`  | Numeric 3 (ISO 3166-1)       | 3 characters  | Required    | Transaction country code.                                                |
| `idd`          | Hexadecimal                  | 15 bytes      | Optional    | Issuer-specific data.                                                    |

### Generate QR payment data

In your digital wallet application, call `PaymentBusinessService.generateApplicationCryptogram()` using payment type `PaymentType.QR` to generate the payload to encode in a QR code.

You must implement a `QRCodePaymentServiceListener`.

```java
final PaymentBusinessService pbs = PaymentBusinessManager.getPaymentBusinessService();
pbs.generateApplicationCryptogram(
        PaymentType.QR, 
        paymentInputData, 
        qrCodePaymentServiceListener);
```

### Implement `QRCodePaymentServiceListener`

The QR code listener handles events during QR code generation.

The QR code listener has four callbacks:

* `onAuthenticationRequired`

  The SDK indicates CDCVM verification is required. See [Perform CDCVM verification](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/5.-perform-cdcvm-verification.md).
* `onDataReadyForPayment`

  QR code output data is ready.
* `onError`

  The SDK has encountered a failure during the QR code payment.
* `onNextTransactionReady`

  The SDK has finished payment service deactivation. This callback is only triggered after QR code generation completes. Use it to retrieve the deactivation status and check the digitized card state.

The following code snippet shows a basic implementation of the listener:

{% code expandable="true" %}

```java
QRCodePaymentServiceListener l = new QRCodePaymentServiceListener() {

    @Override
    public void onDataReadyForPayment(PaymentService paymentService,TransactionContext transactionContext) {
        //The Payment has been processed and is succesful.


        //Retrieve the QR Code output data generated by the SDK
        //in order for the MPA to build the payload and generate the QR code symbol
        QRCodeData qrCodeData = paymentService.getQRCodeData();

        // Logic to display the QR Code on the screen
    }

    @Override
    public void onAuthenticationRequired(PaymentService activatedPaymentService, CHVerificationMethod cvm, long cvmResetTimeout)
        //The SDK requests a CVM Verification to be done.

        if (chVerificationMethod == CHVerificationMethod.DEVICE_KEYGUARD) {
            // Logic to use the Device Keyguard for CVM Verification
        } else if (chVerificationMethod == CHVerificationMethod.BIOMETRICS) {
            // Logic to use the Biometrics for CVM Verification
        }

    }

    @Override
    public void onError(TransactionContext transactionContext, PaymentServiceErrorCode paymentServiceErrorCode, String s) {
        // Logic to handle an error during the payment.
    }

		@Override
    public void onNextTransactionReady(DeactivationStatus deactivationStatus, DigitalizedCardStatus digitalizedCardStatus, DigitalizedCard        		digitalizedCard) {
        // Payment service deactivation process is finish.
      	//Retrieve Deactivation Status
      if (deactivationStatus.getSdkStatusCode() == DEACTIVATION_SUCCESS) {
           // Deativation process is finish successfully. Ready to do next payment.
      else{
          // Deativation process is failed.
         	// Check Replishment is needed.
          if (digitalizedCardStatus.needsReplenishment())
          {
               // logic trigger replenishment process.
          }else{
              // logic trigger reset default card.
          }
      }
    }
```

{% endcode %}

### Get QR payment data

Get `QRCodeData` when `QRCodePaymentServiceListener.onDataReadyForPayment()` is triggered.

`QRCodeData` contains the following fields.

| Field                  | Description                                                                                       |
| ---------------------- | ------------------------------------------------------------------------------------------------- |
| `statusWord`           | Transaction status word. `9000` indicates success. See [Handle status word](#handle-status-word). |
| `cid`                  | Cryptogram Information Data. Determines if CDCVM is required for this transaction.                |
| `chipDataField`        | Chip data field computed by NFC, including the cryptogram.                                        |
| `condensedPaymentData` | Not applicable.                                                                                   |
| `cardMainAid`          | Main AID used for the payment.                                                                    |
| `cardMainAppTemplate`  | Main application template used for the payment.                                                   |
| `cardAliasAid`         | Alternate AID used for the payment.                                                               |
| `cardAliasAppTemplate` | Alternate application template used for the payment.                                              |
| `commonDataTemplate`   | Common data template calculated during the payment.                                               |

### Handle status word

Always check `statusWord` before using any other field.

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

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>QRCodeData</code> object are available 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 CVM information such as No CVM Required, Local CDCVM entered, 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 is 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 issuer-defined limit.</td></tr><tr><td>6986</td><td>Transaction amount exceeds the end user-defined limit.</td></tr><tr><td>6985</td><td>ATC limit is reached, or the selected AID does not refer to a payment application that is compliant with this specification.</td></tr></tbody></table>

### Handle errors

When the `QRCodePaymentServiceListener#onError(…)` function is called, an error code and a message will be provided.

If the input data is null, empty, or the listener is not an instance of `QRCodePaymentServiceListener`, an `IllegalArgumentException` will be thrown with a message.

The following table shows the QR code error codes:

| Error code                      | Description                                                                | Recommended action                                                                                                                               |
| ------------------------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `NO_DEFAULT_CARD`               | No default card is set.                                                    | Set a default card before you initiate a QR code payment.                                                                                        |
| `QR_CODE_PAYMENT_NOT_SUPPORTED` | The default card does not support QR code payments.                        | Call `DigitalizedCardDetails#paymentTypeSupported()` and verify `PaymentType.QR` is present.                                                     |
| `QR_CODE_WRONG_STATE`           | The payment service is already activated when you start a QR code payment. | If the end user cancels CDCVM, call `PaymentBusinessService#deactivate()`.                                                                       |
| `QR_CODE_INPUT_INVALID`         | Input data is present, but one or more fields are invalid.                 | Provide valid input data and include all required fields. The SDK validates JSON structure, hexadecimal values, value ranges, and field lengths. |
| `QR_CODE_OUTPUT_INVALID`        | Output data cannot be parsed and is not available.                         | Treat the QR code payment as failed and do not display the QR code.                                                                              |
| `CARD_OUT_OF_PAYMENT_KEYS`      | No payment credentials are available.                                      | Replenish credentials before attempting another payment.                                                                                         |

### Generate and display QR code image

Your digital wallet application generates the QR code payload using the data provided by the NFC Wallet SDK.

After you generate the QR code payment data, your digital wallet application must:

* Build a payload symbol using one of the cryptograms generated by the SDK.
* Encode in Base64.
* Display the QR code symbol.

Several libraries are available, such as the ZXing library, to render the QR code.

Your digital wallet application can choose the correction level (L, M, Q, H) to fine-tune error correction.


---

# 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, and the optional `goal` query parameter:

```
GET https://docs.payments.thalescloud.io/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/other-payment-methods/implement-qr-code-payment.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
