# Thales D1 Platform

## Thales <mark style="color:$primary;">D1 Platform</mark>

Thales D1 is a cloud-native platform empowering you with modern and instant card issuance. Whether you're a bank, fintech, digital wallet provider, or transit operator, Thales D1 makes it easy to deliver real-time and digital-first experiences to your customers. Built on token-centric principles and modular managed services, Thales D1 ensures fast deployment through seamless API integration: keeping you agile in a rapidly evolving digital world

<a href="https://www.thalesgroup.com/en/enterprise/financial-services" class="button primary">Learn more</a>&#x20;

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

<p align="center"></p>

{% columns %}
{% column width="33.33333333333333%" valign="middle" %}

<figure><img src="/files/Nwn6iKx7c3v7WxWPzvZT" alt="" width="188"><figcaption></figcaption></figure>
{% endcolumn %}

{% column width="66.66666666666667%" valign="middle" %}

### <mark style="color:$primary;">Connect once</mark>, and enable new services easily

Adapt your roadmap with 10+ modular, ready-to-deploy use cases
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column width="66.66666666666666%" valign="middle" %}

<h3 align="right"><mark style="color:$primary;">Faster</mark> Time to Market</h3>

<p align="right">Launch new payment services faster with a simple API framework</p>
{% endcolumn %}

{% column width="33.33333333333334%" valign="middle" %}

<figure><img src="/files/7fDA2dGAYghSM2t0Ib7W" alt="" width="188"><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column width="33.33333333333333%" valign="middle" %}

<div align="center"><figure><img src="/files/3851X3CU55qCIRoBgxnb" alt="" width="188"><figcaption></figcaption></figure></div>
{% endcolumn %}

{% column width="66.66666666666667%" valign="middle" %}

### Scale <mark style="color:$primary;">Real-Time</mark> services

Confidently expand your use-cases across your consumer base
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column width="66.66666666666666%" valign="middle" %}

<h3 align="right">Predictive, Cost-Efficient <mark style="color:$primary;">Card Programs</mark></h3>

<p align="right">Automate compliance and manage costs with built-in updates and regulatory support</p>
{% endcolumn %}

{% column width="33.33333333333334%" valign="middle" %}

<figure><img src="/files/O5s6doLN976PNNMtrhd2" alt="" width="188"><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

<h3 align="center">Explore solutions <mark style="color:$primary;">by industry</mark></h3>

<table data-view="cards"><thead><tr><th></th><th data-hidden data-card-target data-type="content-ref"></th><th data-hidden data-card-cover data-type="image">Cover image</th></tr></thead><tbody><tr><td><strong>Card Issuers &#x26; Banks</strong></td><td><a href="/spaces/GoiaS1zZF7HYf9TBNRtL">/spaces/GoiaS1zZF7HYf9TBNRtL</a></td><td><a href="/files/khKGpxO2S2fxruYcTcCq">/files/khKGpxO2S2fxruYcTcCq</a></td></tr><tr><td><strong>Digital Wallets</strong></td><td><a href="/spaces/gQfTdnj47zqjVBY0ph2U">/spaces/gQfTdnj47zqjVBY0ph2U</a></td><td><a href="/files/GjbCaJ7rJh5L3FJ3PD9w">/files/GjbCaJ7rJh5L3FJ3PD9w</a></td></tr><tr><td><strong>Domestic Payment Schemes</strong></td><td><a href="/spaces/mtLmICADYP00L1L2sKVt">/spaces/mtLmICADYP00L1L2sKVt</a></td><td><a href="/files/nxgHrS0aIPZzwO8FTTMe">/files/nxgHrS0aIPZzwO8FTTMe</a></td></tr><tr><td><strong>Private Label Issuers</strong></td><td><a href="/spaces/eLCnxsXBbVi6tvy1hAul/pages/FNNiUlubIAIjab1bXvRq">/spaces/eLCnxsXBbVi6tvy1hAul/pages/FNNiUlubIAIjab1bXvRq</a></td><td><a href="/files/J1HcIi7AGcGfP9DIGOPR">/files/J1HcIi7AGcGfP9DIGOPR</a></td></tr><tr><td><strong>Transit</strong></td><td><a href="/spaces/4yfTlsdDUsx1RJMjgnAh">/spaces/4yfTlsdDUsx1RJMjgnAh</a></td><td><a href="/files/ZcSQutrDSjW8LfF4deMS">/files/ZcSQutrDSjW8LfF4deMS</a></td></tr><tr><td><strong>Digital Commerce</strong></td><td><a href="/spaces/rqQkVoXPulPc47POlP6U">/spaces/rqQkVoXPulPc47POlP6U</a></td><td><a href="/files/drcfnxBqylXZ8A4dnrgF">/files/drcfnxBqylXZ8A4dnrgF</a></td></tr></tbody></table>


# Welcome to Thales Documentation for Developer

Welcome to the Thales D1 Platform documentation. Explore everything you need to design, launch, and manage modern digital and physical banking experiences, from instant card issuance to tokenization and transaction control.

{% embed url="<https://www.youtube.com/watch?v=QXa5tpcH6Jg>" %}

## Building The Future of Banking, Together

<table data-view="cards"><thead><tr><th></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Issuers &#x26; Processors</strong><br>Magister librum discipulis dat.</td><td><a href="/files/h4Z006is4wafrBuE7z0A">/files/h4Z006is4wafrBuE7z0A</a></td><td><a href="https://www.thalesgroup.com/en">https://www.thalesgroup.com/en</a></td></tr><tr><td><strong>Digital Retail &#x26; Wallet Solutions</strong><br>Caelum hodie serenum est.</td><td><a href="/files/y2t8QAnZ2xWTyChXqHn3">/files/y2t8QAnZ2xWTyChXqHn3</a></td><td><a href="https://www.thalesgroup.com/en">https://www.thalesgroup.com/en</a></td></tr></tbody></table>

<figure><img src="/files/31UFlsRNxD3x4OZkMKGm" alt=""><figcaption></figcaption></figure>

## Partners in Innovation&#x20;

<figure><img src="/files/ziblRT76IBuqlv4dSLRM" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/Uhq1C203jqXEWDH1FuMg" alt=""><figcaption></figcaption></figure>

## Latest News

<table data-view="cards"><thead><tr><th><select><option value="t7vLxlslAFrk" label="02/05/2025" color="blue"></option><option value="e7ZU8Bd2q4JG" label="02/27/2025" color="blue"></option></select></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><span data-option="t7vLxlslAFrk">02/05/2025</span></td><td><strong>Multi-Card Issuance Support</strong><br>Now supporting the issuance of multiple card types from a single interface, including debit, credit, and prepaid.</td><td><a href="https://www.thalesgroup.com/en">https://www.thalesgroup.com/en</a></td></tr><tr><td><span data-option="e7ZU8Bd2q4JG">02/27/2025</span></td><td><strong>API Enhancements for Developers</strong><br>New developer tools and sandbox environments are available to speed up testing and integration with DayOne APIs.</td><td><a href="https://www.thalesgroup.com/en">https://www.thalesgroup.com/en</a></td></tr><tr><td><span data-option="t7vLxlslAFrk">02/05/2025</span></td><td><strong>Localized UX for Global Markets</strong><br>The platform now supports 15+ languages and region-specific user experiences to enhance customer engagement worldwide.</td><td><a href="https://www.thalesgroup.com/en">https://www.thalesgroup.com/en</a></td></tr></tbody></table>


# Overview

D1 offer API and Web UI to manage the end user's virtual and physical card based on its data model.

### End User management

As described in D1 Data Model it is mandatory to register the End User (Consumer) before creating any new card.

During this registration it is mandatory to provides useful end user personal information so D1 can provides all the digital Tokenization services.&#x20;

The [Manage end users](/home/card-creation-and-management/manage-end-users) section explain in details how to register but also how to update personal information with D1.

### Card Management

The Manage Card section explain how to create a physical or virtual card , but also how to manage the life cycle of the card.

The physical card creation trigger the personalization and shippment of the card.

### Orchestration

The card creation is not limited to PAN and expiry date allocation but also the orchestration of the enalbment of all digital services (Tokenization, registration to Click2PAy, 3DS enablment, ...) this without any additional implementation.

&#x20;


# Manage end users


# Register end users via API

Register end users in D1 to link cards to an end user.

This is a backend-to-backend flow between your **issuer backend** and the **D1 backend**.

### When end user registration is required

End user registration depends on how you use D1:

* **Card creation model**: Register the end user before you create any card in D1.
* **Card registration model**: End user registration can be:
  * **Explicit**, via the D1 API, or
  * **Implicit**, during card creation or card registration (based on `consumerId`).

### Define `consumerId`

Your issuer backend provides a `consumerId` for each end user. D1 uses it to identify the end user. It is used in the D1 API, D1 SDK, and D1 portal.

`consumerId` must not contain personal information. Do not include name, email address, phone number, PAN, or similar data.

### Choose a registration model

Choose whether the D1 backend stores end user personal information. This choice changes your registration flow.

#### Store personal information in the D1 backend

Use this model when you want D1 to store personal information. D1 can then cache the data. This reduces calls to your issuer backend.

You must provide the mandatory fields in `personalInformation`.

You must keep D1 up to date when personal information changes.

<figure><img src="/spaces/62lLFDcmLCeqqwmy4Fee/files/i5w22YlP0DfCZyKP7F4y" alt=""><figcaption><p>Consumer registration flow between the issuer backend and the D1 backend</p></figcaption></figure>

#### Do not store personal information in the D1 backend

Use this model when D1 must not store personal information.

You can still register the end user explicitly without `personalInformation`.

You can also skip explicit registration. Rely on implicit registration during card creation or card registration.

When D1 needs personal information, it calls your issuer backend. For example, it can do this for Tokenization.

{% hint style="info" %}
If you already use **Register Consumer 1.0**, you can keep using it. Use **Register Consumer 2.0** for new integrations.
{% endhint %}

<figure><img src="/spaces/62lLFDcmLCeqqwmy4Fee/files/WExE2X1EC8srhZAcoLqX" alt=""><figcaption></figcaption></figure>


# Manage end users life cycle

This page explains how your issuer backend can update personal information for an end user and how to perform a logical deletion of an end user in D1.

## Update end user information

D1 lets the issuer backend update the personal information stored for an end user (called a "consumer" in the D1 API).

### Sequence diagram

<figure><img src="/spaces/62lLFDcmLCeqqwmy4Fee/files/rzprb6v0WWEe6S9VKKdH" alt=""><figcaption><p>Update end user information flow between the issuer backend and the D1 backend</p></figcaption></figure>

## Delete an end user

D1 lets the issuer backend logically delete an end user.

When you delete an end user:

* The end user transitions to the `DELETED` state.
* You can no longer create new cards for this end user.
* All cards linked to this end user, including digital cards, are deleted.

### Sequence diagram

<figure><img src="/spaces/62lLFDcmLCeqqwmy4Fee/files/1Ip4KmG7JiqLkjk2Ep6P" alt=""><figcaption><p>Logical end user deletion flow between the issuer backend and the D1 backend</p></figcaption></figure>


# Manage Card

##


# Virtual Card Creation

## **Flow**

<mark style="color:$danger;">NB: Drawing to be ported back in the reusable content</mark>

<figure><img src="/files/aNzRs7ztmrsbuObaAMD9" alt=""><figcaption></figcaption></figure>

Virtual cards are used exclusively for e-commerce payments and tokenization use cases.

## Domain controls for virtual cards

The domain controls that you can configure for a virtual card are limited to:

* International payment control
* Denied currency list
* Forbidden merchant category list (MCC list)

## Use dynamic CVV (dCVV2)

You can configure the virtual card product to enable dynamic CVV (also referred to as DCVV or dCVV2).

When DCVV is enabled:

* A new dynamic CVV is generated each time the virtual card is displayed with the D1 SDK.
* The dynamic CVV is valid only for a limited period, which you configure in the card product.

This reduces the risk of card-on-file (COF) data being misused, as the CSC / CVV2 value frequently changes.

## Virtual card renewal

The virtual card renewal process is transparent for the end user.

When renewal is enabled for the virtual card product:

* D1 automatically renews the virtual card before its expiration date.
* D1 automatically activates the renewed card.
* D1 generates a new expiry date but keeps the same PAN.
* D1 keeps the same `cardId` for the renewed card.
* The renewed card is automatically displayed the next time it is shown through the D1 SDK.
* D1 updates existing digital cards with the new expiry date.

As a result, the end user can continue to use the virtual card for e-commerce payments and Tokenization without any manual action.

## Sequence diagram

<figure><img src="/spaces/62lLFDcmLCeqqwmy4Fee/files/Fylj27cqPUUHWLZuSqNq" alt="Virtual card creation flow diagram"><figcaption><p>Virtual card creation and activation flow</p></figcaption></figure>

If the virtual card is created with state `active`, it is immediately ready for a first payment.

When the card is created:

* D1 returns a `cardId`.
* The `cardId` is not the PAN; it is a technical unique identifier for the card.
* The `cardId` is used with the D1 API and the D1 SDK to reference the card for any subsequent operation.
* If the consumer referenced in Create Card is not yet register in D1 then D1 register it from the `consumerId`

Once created, you can use the same virtual card across different D1 Digital services, for example:

* [Transaction control](https://docs.payments.thalescloud.io/transaction-control/)
* [Secure card display](https://docs.payments.thalescloud.io/secure-card-display/)
* [Tokenization](https://docs.payments.thalescloud.io/tokenization/)
* [Push provisioning](https://docs.payments.thalescloud.io/push-provisioning/)


# Physical Card Creation and Personalization


# Create and Order

D1 create and produces a physical card by running a set of issuance and personalization steps on a single API request of the issuer.

Each step uses your D1 API request , the consumer information register to D1 as well as configuration defined during D1 onboarding of the Card Product.

## **Flow**

<figure><img src="/files/GI1kD7E0nrB562bzcKOt" alt=""><figcaption></figcaption></figure>

### steps

Use these pages in the order below. You can skip steps that are not enabled for your card product.

1. [<mark style="color:$danger;">Magnetic stripe tracks</mark>](broken://spaces/ol7FqojHqm5it3effNc4/pages/wV74gpmJaCZquZvwyApF)
2. [<mark style="color:$danger;">Chip personalization</mark>](broken://spaces/ol7FqojHqm5it3effNc4/pages/4iNzJeAwH0QoqbwXMHMG)
3. [<mark style="color:$danger;">Graphical personalization</mark>](broken://spaces/ol7FqojHqm5it3effNc4/pages/fnPOF3pC9KHJlREsegPb)
4. [<mark style="color:$danger;">Card carrier personalization</mark>](broken://spaces/ol7FqojHqm5it3effNc4/pages/LoOpab0mtoFLbhXvqKmz)
5. [<mark style="color:$danger;">Packaging</mark>](broken://spaces/ol7FqojHqm5it3effNc4/pages/FoDbdxNa8Ne2AQNUZ9Pn)
6. [<mark style="color:$danger;">Shipment</mark>](broken://spaces/ol7FqojHqm5it3effNc4/pages/xzuOcVnVQ02lAE8ae1np)
7. [<mark style="color:$danger;">SLA management</mark>](broken://spaces/ol7FqojHqm5it3effNc4/pages/mzDSBpRRUoJX4NShWcgG)


# Magnetic stripe tracks

```
TO BE CONFIRMED WITH FABRICE
SEEMS THE ISSUER AS NOTHING TO PROVIDES TO ENABLE
MAGSTRIPE
NEED TO know DURING card product definition a parameter magstripe  : yes or no
```


# Graphical personalization

<figure><img src="/files/ZpX3lkG5kYUfAvR6beyW" alt=""><figcaption></figcaption></figure>

D1 prints text, images, and barcodes on the front and back of a physical card during personalization. D1 uses your D1 API request and the graphical configuration defined during D1 onboarding.

### What D1 can print

Typical printed fields include:

* End user name&#x20;
* Primary Account Number (PAN)
* Expiry date
* Card security code (CSC, also known as CVV2)
* Optional elements such as logos, product mentions (for example, `"Credit"`), support phone numbers, and member IDs

Whether a field is required depends on your card product and graphical configuration. Placement (front/back), fonts, and render types are set during D1 onboarding.

{% hint style="warning" %}
Treat PAN and CSC as sensitive card data.

* Do not log these values.
* Do not expose them outside controlled channels.
* Do not expose them digitally (for example, in logs, analytics, monitoring, or support tooling).
* Never store CSC after personalization.
  {% endhint %}

### Inputs used for personalization

Required D1 API inputs:

* `cardProductId`: Card product identifier configured during D1 onboarding.
* `name`: End user name to print on the card.

Optional D1 API inputs:

* `secondName`: Secondary printed name line (if supported by the artwork).
* `cardDesign`: Object controlling artwork and dynamic graphical content.
  * `cardImage` (Optional): Identifier of an end user image for picture card programs (for example, AllAboutMe, SketchMyCard, and BrandMyCard).
  * `images` (Optional): Additional image identifiers to print on the card (for example, program logos).
  * `customLines` (Optional): Extra text lines to print (for example, `"Credit"`).
  * `memberId` (Optional): Program, affinity, or membership identifier to print as text or a barcode. Barcode formats depend on your configuration (for example, Code 39 and Code 128).

### How D1 selects printed values

<mark style="color:$danger;">D1 prints a field only if it is mapped in your graphical configuration.</mark>

### Example payload

This example shows the typical input shape. Field names depend on the specific endpoint you call.

```json
{
  "cardProductId": "my-card-product",
  "name": "Alice Doe",
  "secondName": "Company Name",
  "cardDesign": {
    "artworkId": "standard-01",
    "images": ["logoName.jpg"],
    "customLines": ["Credit"],
    "memberId": "1234567890"
  }
}
```

### Configuration in D1

For each `cardProductId` (and optionally `artworkId`), D1 onboarding defines the graphical configuration.

Configuration typically defines:

* Printing technology (for example, embossing, indent, inkjet, laser, or thermal color)
* Color
* Optional overlays (for example, overlay or cardguard)
* Per input field:
  * Side (front/back)
  * Render type (text, image, or barcode)
  * Font and font size (for text)
  * Position on the card

Barcode rendering supports common formats such as Code 39 and Code 128 (depending on your configuration).

### Example mapping

<figure><img src="/files/1nJr7lC44Oazsg93WPBb" alt=""><figcaption></figcaption></figure>

<p align="center">Example graphical configuration for printed fields.</p>


# Chip personalization

<figure><img src="/files/Ej7mKmBxpJS9icscT3wy" alt=""><figcaption></figcaption></figure>

D1 supports EMV chip personalization for physical card personalization.

Choose one of two integration models:

* **Model 1 (recommended):** The **Issuer backend** sends minimal inputs. D1 computes the EMV dataset.
* **Model 2:** The **Issuer backend** sends a prepared EMV dataset. D1 validates and loads it.

### Standard profiles

D1 supports the following standard chip profiles:

* **Visa product (global):** Dual-interface Visa debit/credit cards — VIS 1.6.3 and VCPS 2.2.4.
* **Visa product (US only):** VIS 1.5.4 and VCPS 2.1.3.
* **Mastercard product:** M/Chip Advance 1.2.3 (no data storage).

{% hint style="info" %}
If you need a profile not listed here, contact the Thales delivery team
{% endhint %}


# Card carrier personalization

<figure><img src="/spaces/ol7FqojHqm5it3effNc4/files/REw2SsRwlf8vCnz2AJtf" alt="Example card carrier layout"><figcaption><p>Example card carrier layout</p></figcaption></figure>

D1 prints text, images, and barcodes on the card carrier. It uses your D1 API request fields and the card carrier configuration set during D1 onboarding.

### Select a card carrier

D1 selects the card carrier template from your request fields. It applies the rules defined during D1 onboarding.

Common selection fields:

* `services.cardCarrier`: Card carrier identifier configured during D1 onboarding.
* `services.issuance`: Issuance type. D1 can use different card carriers per issuance type (for example, `CREATION` vs. `RENEWAL`).
* `cardCarrierConfig.language` (Optional): Card carrier language (ISO 639-1 alpha-2, example: `en`).

### Inputs used for personalization

Required D1 API inputs:

Provide an End user name and delivery address. Exact fields can vary by endpoint and configuration.

End user name (one of the following, depending on your API payload):

* `name`
* `shipment.deliveryAddress.title`, `shipment.deliveryAddress.firstName`, `shipment.deliveryAddress.lastName`

Delivery address (`shipment.deliveryAddress`):

* `line1`: Address line 1.
* `zipCode`: Postal code.
* `city`: City.
* `countryCode`: Country code (ISO 3166-1 alpha-2, example: `US`).

Optional D1 API inputs:

* `cardCarrierConfig.images`: Image references to print on the card carrier.
* `cardCarrierConfig.customLines`: Custom text lines to print on the card carrier.
* `shipment.deliveryAddress.companyName`: Company name.
* `shipment.deliveryAddress.line2`: Address line 2.
* `shipment.deliveryAddress.line3`: Address line 3.

#### Example

{% code title="Example (request excerpt)" %}

```json
{
  "services": {
    "cardCarrier": "standard-carrier",
    "issuance": "CREATION"
  },
  "shipment": {
    "deliveryAddress": {
      "title": "Mr",
      "firstName": "Alex",
      "lastName": "Chen",
      "companyName": "Example Co",
      "line1": "10 Main St",
      "line2": "Apt 3B",
      "zipCode": "10001",
      "city": "New York",
      "countryCode": "US"
    }
  },
  "cardCarrierConfig": {
    "language": "en",
    "images": ["img_welcome_01"],
    "customLines": ["Welcome to Example Bank"]
  }
}
```

{% endcode %}

### Configuration in D1

During D1 onboarding, Thales configures:

* Card carrier templates and print mappings (text, images, barcodes).
* Supported languages and the default language behavior.
* Allowed `images` references and the rendering rules for each image slot.
* Placement and maximum length rules for `customLines`.

### Multiple cards on one card carrier

You can group up to six cards on the same card carrier.

Set these fields:

* `cardCarrierConfig.multiCardId`: Group identifier. Cards with the same value share one card carrier.
* `cardCarrierConfig.multiCardOrder`: Card position on the card carrier.

D1 prints the delivery address from the first card in the group.


# Packaging

<figure><img src="/spaces/ol7FqojHqm5it3effNc4/files/NKySPGecYvOYF0rgez9M" alt="" width="563"><figcaption><p>Packaging options for physical cards.</p></figcaption></figure>

After personalization, D1 inserts the physical card into the configured packaging. Packaging can be an envelope, sleeve, or box (depending on your setup).

### Select a packaging

D1 selects the packaging from your request fields. It applies the rules defined during D1 onboarding.

### Inputs used for personalization

Required D1 API inputs:

* `services.packaging`: Packaging identifier configured during D1 onboarding.

Optional D1 API inputs:

* `packagingConfig.inserts`: Insert identifiers to add to the package (for example, flyers or legal notices).

Each insert identifier must be configured and allowed for your program.

#### Example (request excerpt)

```json
{
  "services": {
    "packaging": "standard-envelope"
  },
  "packagingConfig": {
    "inserts": ["welcome-letter", "terms-and-conditions-v3"]
  }
}
```

### Configuration in D1

During D1 onboarding, Thales configures:

* Supported packaging identifiers.
* Rules to select packaging (when multiple options exist).
* Allowed insert identifiers and their handling rules.


# Shipment

<figure><img src="/spaces/ol7FqojHqm5it3effNc4/files/sEREnFJEWDoigZBsXc5i" alt=""><figcaption><p>Shipment options for physical cards.</p></figcaption></figure>

D1 supports selecting a shipment provider for physical card orders. D1 uses your D1 API request fields and shipment configuration set during D1 onboarding.

### Shipment types

Two shipment types are available through `shipment.type`:

* `INDIVIDUAL` (default): Ship each card to the end user.
* `BULK`: Group multiple cards and ship them together (for example, to a branch).

### Inputs used for personalization

Required D1 API inputs:

* `services.delivery`: Shipment method identifier configured during D1 onboarding.
* `shipment.type`: `INDIVIDUAL` or `BULK`.
* `shipment.deliveryAddress`: Delivery address used for the shipment.

Conditional D1 API inputs:

* `shipment.individualAddress`: Address of the card holder, usually printed onto the card carrier.
  * Required for `INDIVIDUAL`.

Optional D1 API inputs (BULK grouping):

* `shipment.groupId`: Groups cards into a first-level container.
* `shipment.orderId`: Groups multiple first-level containers into a second-level container.

#### Example (INDIVIDUAL)

```json
{
  "services": {
    "delivery": "usps-imb"
  },
  "shipment": {
    "type": "INDIVIDUAL",
    "deliveryAddress": {
      "line1": "10 Main St",
      "zipCode": "10001",
      "city": "New York",
      "countryCode": "US"
    }
  }
}
```

#### Example (BULK)

```json
{
  "services": {
    "delivery": "laposte-cip"
  },
  "shipment": {
    "type": "BULK",
    "groupId": "container-001",
    "orderId": "dispatch-2026-02-19",
    "deliveryAddress": {
      "line1": "Branch 12",
      "zipCode": "75001",
      "city": "Paris",
      "countryCode": "FR"
    }
  }
}
```

### Shipment flows

#### Ship to the end user (INDIVIDUAL)

Typical flow:

1. The end user address is printed onto a card carrier.
2. The card is affixed to the card carrier.
3. The card carrier is folded.
4. The card carrier is placed in an envelope.
5. The envelope is shipped to the end user.

#### Ship to a branch (BULK)

You can group multiple cards and send them to a branch or a designated delivery location.

Enable this mode with `shipment.type = "BULK"`.

Typical flow:

* The end user address is printed onto a card carrier.
* The card is affixed to the card carrier.
* The card carrier is folded.
* The card carrier is placed in an envelope.
* Several envelopes are grouped and packed in a box.
* The box is shipped to the branch.

In this mode, cards can be grouped into one to three levels.

**One level of grouping**

<figure><img src="/spaces/ol7FqojHqm5it3effNc4/files/idHw6kaHMV1Ayy0LeIa0" alt=""><figcaption><p>One‑level grouping: group by `deliveryAddress`.</p></figcaption></figure>

**Level 1:** All cards with the same `shipment.deliveryAddress` are grouped and shipped together to that address.

**Two levels of grouping**

<figure><img src="/spaces/ol7FqojHqm5it3effNc4/files/b89zidmkmrqnPODcNfcI" alt=""><figcaption><p>Two‑level grouping: `groupId` containers grouped by `deliveryAddress`.</p></figcaption></figure>

**Level 1:** All cards with the same `shipment.groupId` are grouped together and placed in a container.

**Level 2:** All containers with the same `shipment.deliveryAddress` are grouped and shipped together to that address.

**Three levels of grouping**

<figure><img src="/spaces/ol7FqojHqm5it3effNc4/files/crLlXFxzNtUcSLXjjeDP" alt=""><figcaption><p>Three‑level grouping: `groupId` → small containers, aggregated by `orderId`, then by `deliveryAddress`.</p></figcaption></figure>

**Level 1:** All cards with the same `shipment.groupId` are grouped together and placed in a small container.

**Level 2:** All small containers with the same `shipment.orderId` are grouped together in a larger container.

**Level 3:** All large containers with the same `shipment.deliveryAddress` are grouped and shipped together to that address.

### Shipment grouping reference

* `deliveryAddress`: Cards shipped together share the same delivery address (outermost grouping in one‑level mode).
* `groupId`: Groups cards into a first‑level container.
* `orderId`: Groups multiple first‑level containers into a second‑level container (used for three‑level grouping).

Typical patterns:

* One level: `deliveryAddress` only.
* Two levels: `groupId` + `deliveryAddress`.
* Three levels: `groupId` + `orderId` + `deliveryAddress`.

### Carrier-specific services

| Country     | Carrier        | Details                                                                                                                                                                                                                      |
| ----------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| France      | La Poste - CIP | <p>Courrier Industriel Premium (CIP)<br>Generates a unique smart data barcode to identify and track each envelope.</p><p><img src="/spaces/ol7FqojHqm5it3effNc4/files/wiQVtrc5ywMaeZZZ5KsO" alt="" data-size="original"></p> |
| Netherlands | PostNL - KIX   | <p>KlantIndeX (KIX)<br>Generates a unique barcode to identify and track each envelope.</p><p><img src="/spaces/ol7FqojHqm5it3effNc4/files/cdZAfq4zSl9jkiWdyHMM" alt="" data-size="original"></p>                             |
| US          | USPS - IMB     | <p>Intelligent Mail Barcode (IMB)<br>Generates a unique barcode to identify and track each envelope with IV-MTR.</p><p><img src="/spaces/ol7FqojHqm5it3effNc4/files/FG8MAVH0mFVmNfg6FAHZ" alt="" data-size="original"></p>   |

### Configuration in D1

During D1 onboarding, Thales configures:

* Allowed values for `services.delivery`.
* The mapping between shipment attributes and carrier options.
* Input validation rules (for example, phone number presence checks).


# SLA management

### SLA definition

The SLA

* starts when Thales receives your D1 API request
* ends when the physical card is shipped
* does not include carrier transit time

### Business days and cut-off

SLA working days follow the personalization center’s local calendar. By default, working days are Monday to Friday.

The daily cut-off time is local to the personalization center. Requests received after cut-off start on the next calendar day.

{% hint style="info" %}
In "D+N", **D** is the production request date after time zone conversion and cut-off handling.
{% endhint %}

### Standard SLAs

Standard SLAs depend on your contract and configuration.

Common examples:

* CREATION or REPLACEMENT: `D+1` (ready for carrier pickup at 17:00 local time).
* RENEWAL: `D+10`.
* URGENT: 4 hours if the urgent request is received before 12:00 local time.

D1 calculates the production due date for each physical card order based on the personalization center’s time zone, daily cut‑off, and the applicable SLA in working days.

### Sequence

<figure><img src="/files/jPB6ahl7QH5x1vNHsgbR" alt=""><figcaption></figcaption></figure>

### Inputs for due date calculation

D1 API inputs:

* `services.issuance`: Issuance type.
* `services.priority`: Priority level agreed for card production.
* `shipment.type`: BULK or INDIVIDUAL. May impact the SLA
* Request timestamp (from the API call).

D1 configuration:

* Cut-off time: local time after which the base date moves to the next day.
* SLA: number of working days to produce the physical card.

Derived by D1:

* Personalization center and its time zone.

{% hint style="info" %}
If your program maps `services.priority` to different SLAs, that mapping is configured in D1.
{% endhint %}

### Calculation

The due date is calculated as follows:

1. Capture the production request timestamp in UTC.
2. Convert the timestamp to the personalization center’s local time zone to get the local request time.
3. Determine the production request date:
   * If the local request time is strictly after the daily cut‑off, set the production request date to the next calendar day.
   * Otherwise, use the local calendar day of the request.
4. Add the SLA (in working days) to the production request date to obtain the due date.
5. If configured, skip non‑working days (weekends and local holidays) in step 4.

{% hint style="info" %}
Working days and holiday calendars are based on the personalization center’s local configuration. If your program uses multiple personalization centers, the applicable calendar may vary per order.
{% endhint %}

{% hint style="warning" %}
Decide and document whether “exactly at cut‑off” is considered before or after cut‑off. The examples below assume “strictly after” the cut‑off moves to the next day.
{% endhint %}

### Examples

After cut‑off (same week)

* Inputs
  * Request timestamp (UTC): 2025‑03‑18 17:30
  * Personalization center time zone: UTC+1
  * Daily cut‑off: 18:00 (local)
  * SLA: 2 working days
* Computation
  * Local request time: 18:30 (after cut‑off) → production request date = 2025‑03‑19
  * Add 2 working days → due date = 2025‑03‑21

Before cut‑off (crossing a weekend)

* Inputs
  * Request timestamp (UTC): 2025‑03‑14 13:00
  * Personalization center time zone: UTC+1
  * Daily cut‑off: 18:00 (local)
  * SLA: 2 working days
* Computation
  * Local request time: 14:00 (before cut‑off) → production request date = 2025‑03‑14 (Friday)
  * Add 2 working days (Mon, Tue) → due date = 2025‑03‑18


# Card Order Tracking

D1 sends real-time production and shipment updates for physical cards to the issuer backend. You can receive updates asynchronously through notifications (webhooks) or retrieve the latest status on demand.

<figure><img src="/spaces/ol7FqojHqm5it3effNc4/files/ZiW533QdMUiI5yTqMvqo" alt=""><figcaption><p>High-level flow of physical card production and shipment events.</p></figcaption></figure>

### How it works

Use one or both approaches:

{% tabs %}
{% tab title="Notifications (recommended)" %}

* Receive webhook notifications for each production step and shipment update.
* Handle at-least-once delivery. Expect retries and duplicate events.
* Implement the callback endpoint defined by [D1 event & message notification](https://thales-dis-dbp.stoplight.io/docs/d1-caas/a8zmsn12frq0k-event-and-message-notification).
* Expose the [Notify Card Operations](https://thales-dis-dbp.stoplight.io/docs/d1-caas/cg9inziqvzvgb-notify-card-operations) API on your issuer backend.
  {% endtab %}

{% tab title="On-demand" %}

* Query the current production/shipment status at any time.
* Call the [Get Card Issuance Status](https://thales-dis-dbp.stoplight.io/docs/d1-caas/8f8c113ed3cff-get-card-issuance-status) API with the card identifier.
  {% endtab %}
  {% endtabs %}

### Recommended integration

{% stepper %}
{% step %}

### Persist status per card

Store the latest known `details.status` for each `cardId`.
{% endstep %}

{% step %}

### Process notifications first

Handle duplicates and out-of-order delivery. Use `operationId` plus timestamps for reconciliation.
{% endstep %}

{% step %}

### Reconcile on demand when needed

Call **Get Card Issuance Status** after missed events. Call it for user-driven refresh in the issuer application.
{% endstep %}

{% step %}

### Expose user-facing tracking

Show carrier tracking when `details.shipment.trackingUrl` is present. Fall back to internal status when it is not present.
{% endstep %}
{% endstepper %}

### Delivery and idempotency

Notifications can arrive out of order, and more than once.

* Use `operationId` to de-duplicate and correlate events.
* Use `startTime`/`endTime` to decide which event is the latest for a given operation.
* Use the on-demand API to reconcile state if you detect gaps.

### Common parameters

Each notification and on-demand response can include:

| Field             | Description                                                                        | Availability                         |
| ----------------- | ---------------------------------------------------------------------------------- | ------------------------------------ |
| `operationId`     | Unique identifier for the operation instance. Use for idempotency and correlation. | Always                               |
| `operation`       | Operation type. Always `PRODUCE` for physical issuance tracking.                   | Always                               |
| `status`          | Operation status: `PENDING`, `SUCCESSFUL`, or `FAILED`.                            | Always                               |
| `startTime`       | ISO 8601 timestamp when the operation started.                                     | Always                               |
| `endTime`         | ISO 8601 timestamp when the operation completed.                                   | Conditional (when completed)         |
| `cardId`          | Internal card identifier in D1.                                                    | Always                               |
| `details`         | Issuance-specific payload for the operation.                                       | Always                               |
| `errorCode`       | Machine-readable failure cause.                                                    | Conditional (on failure)             |
| `error`           | Short human-readable failure description.                                          | Conditional (on failure)             |
| `inputFileName`   | File name containing card issuance requests.                                       | Conditional (file-based orders only) |
| `issuerRequestId` | Request correlation identifier from the input file.                                | Conditional (file-based orders only) |

Top-level `status` is the operation status. `details.status` is the physical issuance status.

### Parameters specific to physical issuance (details)

The physical issuance payload is in `details` for the `PRODUCE` operation.

#### Physical card issuance status

<figure><img src="/spaces/ol7FqojHqm5it3effNc4/files/vVoWx8lIdO3ASSkytwo1" alt=""><figcaption><p>Status transition diagram for physical card issuance.</p></figcaption></figure>

| Status code           | Description                                                                                         |
| --------------------- | --------------------------------------------------------------------------------------------------- |
| `CARD_PROD_REQUESTED` | Card personalization has been requested via the D1 APIs.                                            |
| `DATA_PREPARED`       | Data has been successfully processed.                                                               |
| `CARD_PROD_READY`     | Data has been sent to the personalization center, and the card is ready for personalization.        |
| `CARD_PROD_ONGOING`   | Card personalization is in progress.                                                                |
| `CARD_SHIPPED`        | The card has been handed over to the carrier.                                                       |
| `DATA_EXCEPTION`      | An error occurred during data processing.                                                           |
| `CARD_PROD_EXCEPTION` | Card personalization encountered an issue.                                                          |
| `CARD_PROD_CANCELED`  | Card personalization was canceled by the issuer.                                                    |
| `CARD_PROD_ONHOLD`    | Card personalization is on hold, either by the issuer or due to an issue with the shipment address. |

#### Details object

| Field             | Description                                                                        | Availability                   |
| ----------------- | ---------------------------------------------------------------------------------- | ------------------------------ |
| `reason`          | Additional details in case of exception during data processing or card production. | On exceptions                  |
| `consumerId`      | Deprecated. Use your internal End user identifier.                                 | Deprecated                     |
| `dueDate`         | Estimated shipment date, calculated upon receipt of the card issuance request.     | After data processing          |
| `productionSite`  | The name of the personalization center handling the card personalization.          | After data processing          |
| `shipment`        | Shipment tracking details, available only when provided by the carrier.            | After shipment                 |
| `inputFileName`   | Name of the file containing card issuance requests.                                | Only for cards ordered by file |
| `issuerRequestId` | Unique identifier for the card issuance request from the input file.               | Only for cards ordered by file |

### Shipment object

When present, `details.shipment` can include:

* `carrier`: Lowercase carrier code (for example, `fedex`).
* `trackingNumber`: Carrier tracking reference.
* `status`: Carrier shipment status (when provided by the carrier).
* `message`: Human-readable carrier status (when provided by the carrier).
* `trackingUrl`: Direct URL to carrier tracking with the tracking number embedded.
* `redirectUrl`: Carrier landing page URL that may handle locale/consent flows.
* `pickupDate`: ISO 8601 timestamp when the carrier collected the parcel.
* `estimatedDeliveryDate`: ISO 8601 estimated delivery time.
* `lastUpdatedAt`: ISO 8601 timestamp of the last tracking event.
* `lastCheckpoint`:
  * `checkpointTime`: ISO 8601 timestamp.
  * `city`: Last checkpoint city.
  * `countryName`: Country of the last checkpoint.
  * `message`: Human-readable checkpoint status.

{% hint style="info" %}
`dueDate` (production estimate) differs from `estimatedDeliveryDate` (carrier estimate). Carrier fields are conditional and depend on the carrier integration.
{% endhint %}

### Examples by issuance status

{% tabs %}
{% tab title="CARD\_PROD\_REQUESTED" %}

```json
{
  "operations": [
    {
      "operationId": "01c5a05e-e197-11ec-8fea-0242ac120002",
      "operation": "PRODUCE",
      "status": "PENDING",
      "startTime": "2025-01-17T06:28:02.492Z",
      "cardId": "271b-6e47-8ec3-7f3f",
      "details": {
        "status": "CARD_PROD_REQUESTED"
      }
    }
  ]
}
```

{% endtab %}

{% tab title="DATA\_PREPARED" %}

```json
{
  "operations": [
    {
      "operationId": "01c5a05e-e197-11ec-8fea-0242ac120002",
      "operation": "PRODUCE",
      "status": "PENDING",
      "startTime": "2025-01-17T06:28:02.492Z",
      "cardId": "271b-6e47-8ec3-7f3f",
      "details": {
        "status": "DATA_PREPARED",
        "dueDate": "2025-01-21",
        "productionSite": "Gemenos"
      }
    }
  ]
}
```

{% endtab %}

{% tab title="DATA\_EXCEPTION" %}

```json
{
  "operations": [
    {
      "operationId": "01c5a05e-e197-11ec-8fea-0242ac120002",
      "operation": "PRODUCE",
      "status": "FAILED",
      "startTime": "2025-01-17T06:28:02.492Z",
      "endTime": "2025-01-21T09:28:12.492Z",
      "cardId": "271b-6e47-8ec3-7f3f",
      "details": {
        "status": "DATA_EXCEPTION"
      },
      "errorCode": "FIELD_INVALID_FORMAT",
      "error": "pan"
    }
  ]
}
```

{% endtab %}

{% tab title="CARD\_SHIPPED" %}

```json
{
  "operations": [
    {
      "operationId": "01c5a05e-e197-11ec-8fea-0242ac120002",
      "operation": "PRODUCE",
      "status": "SUCCESSFUL",
      "startTime": "2025-01-17T06:28:02.492Z",
      "endTime": "2025-01-21T09:28:12.492Z",
      "cardId": "271b-6e47-8ec3-7f3f",
      "details": {
        "status": "CARD_SHIPPED",
        "dueDate": "2025-01-21",
        "productionSite": "Gemenos",
        "shipment": {
          "estimatedDeliveryDate": "2025-01-21T17:32:28Z"
        }
      }
    }
  ]
}
```

{% endtab %}

{% tab title="CARD\_SHIPPED with tracking" %}

```json
{
  "operations": [
    {
      "operationId": "01c5a05e-e197-11ec-8fea-0242ac120002",
      "operation": "PRODUCE",
      "status": "SUCCESSFUL",
      "startTime": "2025-01-17T06:28:02.492Z",
      "endTime": "2025-01-21T09:28:12.492Z",
      "cardId": "271b-6e47-8ec3-7f3f",
      "details": {
        "status": "CARD_SHIPPED",
        "dueDate": "2025-01-21",
        "productionSite": "Gemenos",
        "shipment": {
          "pickupDate": "2025-01-21T17:32:28Z",
          "carrier": "fedex",
          "trackingNumber": "61293150000079650811",
          "status": "IN_TRANSIT",
          "message": "In transit",
          "trackingUrl": "https://www.fedex.com/apps/fedextrack/?tracknumbers=61293150000079650811&cntry_code=US",
          "redirectUrl": "https://www.fedex.com/apps/fedextrack/?action=track&tracknumbers=61293150000079650811&cntry_code=US",
          "estimatedDeliveryDate": "2025-01-21T17:32:28Z",
          "lastUpdatedAt": "2025-01-21T17:32:28Z",
          "lastCheckpoint": {
            "checkpointTime": "2025-01-21T17:32:28Z",
            "city": "New York",
            "countryName": "United States",
            "message": "Arrived at facility"
          }
        }
      }
    }
  ]
}
```

{% endtab %}
{% endtabs %}

### Sequence

This diagram shows typical transitions from request to shipment, including exception and on-hold paths.

<figure><img src="/spaces/ol7FqojHqm5it3effNc4/files/nWPsX4S7mnoomoA4vzqh" alt=""><figcaption><p>Status transitions including exceptions and on-hold states.</p></figcaption></figure>

<figure><img src="/spaces/ol7FqojHqm5it3effNc4/files/1cVz0s02KgHMWbhSaDyH" alt=""><figcaption><p>Operational view of issuance steps and state changes.</p></figcaption></figure>

<figure><img src="/spaces/ol7FqojHqm5it3effNc4/files/mR539AB9YqLrMKI0tnoN" alt=""><figcaption><p>Sequence diagram for notifications and status changes during physical card issuance.</p></figcaption></figure>

### Physical card issuance tracking on demand

The issuer backend can retrieve the card production status on demand using the [Get Card Issuance Status](https://thales-dis-dbp.stoplight.io/docs/d1-caas/8f8c113ed3cff-get-card-issuance-status) API.

<figure><img src="/spaces/ol7FqojHqm5it3effNc4/files/99PqxkcPDqcNiXky6JLk" alt=""><figcaption><p>High-level flow of physical card production and shipment events.</p></figcaption></figure>

#### On-demand status example

{% tabs %}
{% tab title="Request" %}
{% hint style="info" %}
Replace the placeholders with your environment values. Refer to the API reference for the exact endpoint path and authentication scheme.
{% endhint %}

```bash
curl -X GET \
  "https://{base_url}/{path-to-get-card-issuance-status}?cardId=271b-6e47-8ec3-7f3f" \
  -H "Authorization: Bearer {access_token}" \
  -H "Accept: application/json"
```

{% endtab %}
{% endtabs %}


# Pull and change

Use pull and change to request updates to a physical card order that D1 has received but not shipped.

### Flow

<figure><img src="/spaces/ol7FqojHqm5it3effNc4/files/tOKJrbng18rv6i1A8icL" alt=""><figcaption><p>Pull and change flow for physical card orders.</p></figcaption></figure>

### Sequence diagram

<figure><img src="/spaces/ol7FqojHqm5it3effNc4/files/weM2kjS1N5c5uS3my1B8" alt=""><figcaption></figcaption></figure>

### Change types

Common change types:

* `CANCEL`: Cancel the card order and destroy the card.
* `ACCELERATE`: Produce the card as soon as possible.
* `REDIRECT`: Change the shipment delivery address.
* `ACCELERATE_AND_REDIRECT`: Expedite production and change the shipment delivery address.

{% hint style="info" %}
Enum casing can vary by integration. Use the exact values defined in your API schema.
{% endhint %}

### How it works

1. The issuer backend submits a pull and change request.
2. D1 forwards the request to the personalization center producing the card.
3. The personalization center accepts or rejects the request based on the production stage.
4. D1 returns the outcome asynchronously via notifications.

### Request inputs

#### Required

* `type`: Type of change to apply to the card order.

#### Conditional

Provide `newDeliveryAddress` when `type` is `redirect` or `expediteAndRedirect`.

`newDeliveryAddress` fields:

* `title`: Name prefix (for example, `Mr`).
* `firstName`: First name.
* `lastName`: Last name.
* `companyName`: Company name.
* `line1`: Address line 1.
* `line2`: Address line 2.
* `line3`: Address line 3.
* `city`: City.
* `state`: State or region.
* `zipCode`: Postal code.
* `countryCode`: Country code (ISO 3166-1 alpha-2, for example `US`).
* `mobilePhoneNumber`: International phone number used for shipment contact.

#### Example (redirect)

```json
{
  "type": "REDIRECT",
  "newDeliveryAddress": {
    "title": "Ms",
    "firstName": "Alex",
    "lastName": "Chen",
    "companyName": "Example Co",
    "line1": "10 Main St",
    "line2": "Apt 3B",
    "city": "New York",
    "state": "NY",
    "zipCode": "10001",
    "countryCode": "US",
    "mobilePhoneNumber": "+12125550123"
  }
}
```

### Track the result

* Consume notifications to get the accepted or rejected outcome.
* For end-to-end production and shipment tracking, see [Card order tracking](broken://spaces/ol7FqojHqm5it3effNc4/pages/aOVR3onD0wGCbSmbySHe).


# Manage card life cycle

## Card life cycle and operations

The diagram below shows the different life cycle states of a card.

<figure><img src="/spaces/62lLFDcmLCeqqwmy4Fee/files/L9kY7F0TAewuShMgZ4YR" alt=""><figcaption><p>Card life cycle state diagram.</p></figcaption></figure>

In addition to the state, each card exposes an **ongoingOperation** property. This property indicates whether a card renewal has been initiated and activation of the reissued card is expected. The **ongoingOperation** property is available both in the D1 API and in the D1 SDK.

### Card life cycle operations <a href="#card-life-cycle-operation" id="card-life-cycle-operation"></a>

Card life cycle operations can be performed through the following channels:

* D1 REST API
* D1 SDK

### Life cycle operation reasons <a href="#life-cycle-operation-reason" id="life-cycle-operation-reason"></a>

A reason must be provided every time you perform a card life cycle operation. The tables below summarize, for each operation type, the available reasons, their meaning, and the impact on the card.

#### Suspend reasons <a href="#suspend-reason" id="suspend-reason"></a>

| Reason           | Description                                                                                                                                     |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| CARD\_LOST       | <p>The card has been reported as lost. You can:<br>- resume the card using the reason <code>CARD\_FOUND</code>.<br>- request a replacement.</p> |
| CARD\_STOLEN     | The card has been reported as stolen. The card remains suspended until you explicitly request a replacement.                                    |
| CARD\_BROKEN     | The card is damaged and no longer works. The card remains suspended until you explicitly request a replacement.                                 |
| FRAUD            | The card is compromised. The card remains suspended until you explicitly request a replacement.                                                 |
| USER\_DECISION   | The end user has decided to temporarily suspend the card. The card can be resumed with the reason `USER_DECISION` or `ISSUER_DECISION`.         |
| ISSUER\_DECISION | The issuer has decided to temporarily suspend the card. The card can be resumed with the reason `ISSUER_DECISION`.                              |

#### Resume reasons <a href="#resume-reason" id="resume-reason"></a>

| Reason           | Description                                                                                             |
| ---------------- | ------------------------------------------------------------------------------------------------------- |
| CARD\_FOUND      | The card has been found and was previously suspended with the reason `CARD_LOST`.                       |
| ISSUER\_DECISION | The issuer has decided to resume the card.                                                              |
| USER\_DECISION   | The end user has decided to resume the card and the card was previously suspended with `USER_DECISION`. |

#### Delete reasons <a href="#delete-reason" id="delete-reason"></a>

| Reason           | Description                                                                |
| ---------------- | -------------------------------------------------------------------------- |
| CLOSED\_ACCOUNT  | The end user has closed the account and the card must be deleted/canceled. |
| CLOSED\_CARD     | The card must be deleted/canceled.                                         |
| CARD\_LOST       | The card has been reported as lost and must be deleted/canceled.           |
| CARD\_STOLEN     | The card has been reported as stolen and must be deleted/canceled.         |
| CARD\_BROKEN     | The card is damaged and must be deleted/canceled.                          |
| FRAUD            | The card is compromised and must be deleted/canceled.                      |
| USER\_DECISION   | The end user has decided to delete the card.                               |
| ISSUER\_DECISION | The issuer has decided to delete the card.                                 |

#### Replacement reasons <a href="#replacement-reason" id="replacement-reason"></a>

| Reason           | Description                                 |
| ---------------- | ------------------------------------------- |
| CARD\_LOST       | The card has been reported as lost.         |
| CARD\_STOLEN     | The card has been reported as stolen.       |
| CARD\_BROKEN     | The card is damaged and no longer works.    |
| FRAUD            | The card is compromised.                    |
| ISSUER\_DECISION | The issuer has decided to replace the card. |

#### Renewal reasons <a href="#renewal-reason" id="renewal-reason"></a>

| Reason           | Description                                                             |
| ---------------- | ----------------------------------------------------------------------- |
| USER\_DECISION   | The end user has decided to renew the card.                             |
| ISSUER\_DECISION | The issuer has decided to renew the card.                               |
| CARD\_EXPIRED    | The card has been renewed because it has expired or is about to expire. |

## D1 REST API <a href="#d1-rest-api" id="d1-rest-api"></a>

### Renewal and replacement flows <a href="#renewal--replacement-flow" id="renewal--replacement-flow"></a>

#### Automatic renewal <a href="#automatic-renewal" id="automatic-renewal"></a>

Automatic renewal is available only for cards created with D1. D1 monitors the expiry date of each card created with D1 and can automatically trigger renewal a few weeks before expiration.

#### Manual renewal <a href="#and-manual-renewal" id="and-manual-renewal"></a>

Manual renewal is available for cards created with D1 and for registered cards. Manual renewal is triggered using the renew API.

If the card is registered (not created with D1), the new PAN and/or expiry date must be provided so that D1 stays up to date with the new card credentials.

#### Manual replacement flow <a href="#manual-replacement-flow" id="manual-replacement-flow"></a>

Manual replacement is available for cards created with D1 and for registered cards. Manual replacement is triggered using the replace API.

If the card is registered (not created with D1), the new PAN and/or expiry date must be provided so that D1 stays up to date with the new card credentials.

#### New card activation <a href="#new-card-activation" id="new-card-activation"></a>

Depending on the card product configuration, after renewal or replacement the new card may be created in the **INACTIVE** state. There are three ways to activate the card:

* **Activation at first card-present transaction with a valid PIN.** This is available only if the card was created via D1.
* **Manual activation using the D1 REST API (Not yet available).**
* **Manual activation from the issuer application using the D1 SDK (Not yet available)**.

## <mark style="color:$danger;">D1 Web UI</mark>

<mark style="color:$danger;">The D1 Web UI offer an in deep view of the managed by D1 Card Management Cystem.</mark>

<mark style="color:$danger;">The naming is sligthly different from default D1 naming:</mark>

* <mark style="color:$danger;">**Payment Instrument**</mark> <mark style="color:$danger;"></mark><mark style="color:$danger;">: reference a</mark> <mark style="color:$danger;"></mark><mark style="color:$danger;">**physical**</mark> <mark style="color:$danger;"></mark><mark style="color:$danger;">or a</mark> <mark style="color:$danger;"></mark><mark style="color:$danger;">**virtual card**</mark>
* <mark style="color:$danger;">**Client Code**</mark> <mark style="color:$danger;"></mark><mark style="color:$danger;">: reference the End User</mark> <mark style="color:$danger;"></mark><mark style="color:$danger;">**consumerId**</mark>

### Search Card&#x20;

D1 Web UI offer the possibility to find end user's card based on

* End user name (first and/or last name)
* End user technical identifier (consumerId)
* PAN value

<figure><img src="/files/7BZBAtnnr64lfoiF3yzn" alt=""><figcaption></figcaption></figure>

#### Change Card Status

D1 Web UI offer the possiblity to change the status of a card listed.

<figure><img src="/files/dZ5EZTCqHvzrWdTrAeeV" alt=""><figcaption></figcaption></figure>


# Integrate the D1 API


# D1 API reference


# Inbound API (to D1)


# OAuth2 API

## Get Authorization Token

> This request is used by the Issuer backend to get a Thales authorization token.

```json
{"openapi":"3.0.0","info":{"title":"D1 OAuth API","version":"1.0"},"servers":[{"url":"https://api.d1.thalescloud.io/authz/v1","description":"Production server"},{"url":"https://api.d1-stg.thalescloud.io/authz/v1","description":"Staging server"},{"url":"https://develop-api.d1-dev.thalescloud.io/authz/v1","description":"Develop server"}],"paths":{"/oauth2/token":{"post":{"description":"This request is used by the Issuer backend to get a Thales authorization token.","parameters":[{"$ref":"#/components/parameters/x-correlation-id"}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/auth2Request"}},"application/json":{"schema":{"$ref":"#/components/schemas/auth2Request"}}}},"responses":{"200":{"description":"Default allowed response","content":{"application/json":{"schema":{"properties":{"access_token":{"type":"string","description":"The access_token that will be used to call D1 Banking APIs."},"expires_in":{"type":"number","description":"Remaining time in seconds for the access_token to expire."},"scope":{"type":"string","description":"Scope of the access_token that will be used to call D1 Banking APIs."},"token_type":{"type":"string","description":"Type of the access_token that will be used to call D1 Banking APIs."}}}}}},"400":{"description":"Bad request"}},"summary":"Get Authorization Token","operationId":"getToken"}}},"components":{"parameters":{},"schemas":{"auth2Request":{"type":"object","title":"Authorization request body","properties":{"grant_type":{"description":"Describes the <b>flow</b>.<br/>In our case we have defined the JWT bearer flow, so you will have to set urn:ietf:params:oauth:grant-type:jwt-bearer","type":"string","enum":["urn:ietf:params:oauth:grant-type:jwt-bearer"]},"assertion":{"description":"The assertion is the entire JWT value.<br/>Please refer to [Get OAuth 2.0 Access token](../../../integrate-the-d1-api/get-oauth-2.0-access-token#generate-the-jwt) for more details on how to generate this JWT.<br/>The JWT must contain the following fields: <ul><li><b>iss:</b> Issuer of the JWT. It shall be the issuerId and it will be used to lookup the onboarded public key.</li><li><b>exp:</b> The validity must be the expiration time of the assertion within 15 minutes, expressed as the number of seconds from 1970-01-01T0:0:0Z measured in UTC.</li></ul>Supported alg: ES256.","type":"string"}},"required":["grant_type","assertion"]}}}}
```


# Consumer API

## Register consumer

> This request is used by the bank backend to request the registration of the end user with personal information.\
> \> #### Note\
> \> It is strongly recommended to provide the end user personal information such as first and last name, email, phone number, postal address.\
> \>Personal information is used in \`D1 Tokenization\` by the Decision Engine or in \`D1 Push\` when building the card information to push to OEM Wallet. \
> \
> \> #### Note\
> \> Some end user personal information are mandatory for issuers using \`D1 Click to Pay\` service. These mandatory personal information\
> \> such as mobilePhoneNumber or language are tagged bellow with \*"This field is mandatory for Click to Pay"\*. <br>

```json
{"openapi":"3.0.0","info":{"title":"D1 Inbound Consumer API","version":"2.0"},"tags":[{"name":"Consumer","description":"Different operations for end user (consumer) management."}],"servers":[{"url":"https://api.d1.thalescloud.io/banking/v2","description":"Production server"},{"url":"https://api.d1-stg.thalescloud.io/banking/v2","description":"Staging server"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"A JWT generated by the [Get Authorization Token API](oauth2-api).<br/>The server checks the validity of the provided token to control access to this protected resource. Please refer to [Get OAuth 2.0 access token](../../../integrate-the-d1-api/get-oauth-2.0-access-token) for more details on the flow and on how to get this JWT.","type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"consumerInfo":{"additionalProperties":false,"type":"object","title":"ConsumerInfo","description":"the following object represents the personal information of the end user.","properties":{"gender":{"type":"string","enum":["MALE","FEMALE","OTHER"]},"language":{"type":"string","description":"Language as defined by ISO 639-2 standard.\n<br/>**Note**: This field is mandatory for Click to Pay.\n<br/>List of languages accepted : abk, aar, afr, alb, amh, ara, arm, aze, bel, ben, bis, bos, bul, bur, cat, nya, chi, hrv, cze, dan, div, dut, dzo, eng, est, fij, fin, fre, geo, ger, gre, grn, hat, hau, heb, hin, hun, ice, ind, gle, ita, jpn, kaz, khm, kin, kor, kur, kir, lao, lat, lav, lit, ltz, mac, mlg, may, mlt, mao, mah, mon, nau, nep, nor, orm, oss, pus, per, pol, por, rum, roh, rus, smo, sag, srp, sin, slo, slv, som, spa, swa, swe, tgk, tam, tha, ton, tur, tuk, ukr, urd, uzb, vie,\n","minLength":3,"maxLength":3,"pattern":"^[a-z]{3}$"},"firstName":{"type":"string","description":"First name of the end user (Unicode characters allowed).<br/>**Note**: This field is mandatory for Click to Pay.","minLength":1,"maxLength":40,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,40}$"},"middleName":{"type":"string","description":"Middle name of the end user (Unicode characters allowed).","minLength":1,"maxLength":40,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,40}$"},"lastName":{"type":"string","description":"Last name of the end user (Unicode characters allowed).<br/>**Note**: This field is mandatory for Click to Pay.","minLength":1,"maxLength":40,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,40}$"},"secondLastName":{"type":"string","description":"Second Last name of the end user (Unicode characters allowed).","minLength":1,"maxLength":40,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,40}$"},"dateOfBirth":{"type":"string","description":"Date of Birth.","pattern":"^\\d{4}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[0-1])$"},"title":{"type":"string","description":"Title of the end user.<br/>By default D1 support the following title value<br/>- Mr.<br/>- Mrs.<br/>- Miss<br/>Please contact Thales integration team for the support of other value<br/>To not fill in if not applicable.","minLength":2,"maxLength":40,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,40}$"},"nationality":{"type":"string","description":"Main nationality of the end user in ISO 3166-1 Alpha-2 Code","minLength":2,"maxLength":2,"pattern":"^[A-Z]{2}$"},"email":{"type":"string","description":"Email of the end user.<br/>**Note**: This field is mandatory for Click to Pay with Mastercard.","minLength":5,"maxLength":256,"pattern":"^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,15}$"},"mobilePhoneNumber":{"additionalProperties":false,"description":"Phonenumber of the end user (consumer).  Shall respect the E-164 format.<br/>**Note**: This field is mandatory for Click to Pay.","type":"object","required":["countryCode","phoneNumber"],"properties":{"countryCode":{"type":"string","description":"Internantional country code of the end user's phonenumber. Shall start with the '+' sign.","minLength":1,"maxLength":10,"pattern":"^\\+[0-9]{1,10}$"},"phoneNumber":{"type":"string","description":"National phonenumber of the end user. Shall not contain the first '0' of the national phonenumber. If present as input parameter, D1 will ignore it.","minLength":1,"maxLength":14,"pattern":"^[0-9]{1,14}$"}}},"residencyAddress":{"additionalProperties":false,"type":"object","description":"Residency address of the end user (consumer).<br/>In the context of Click to Pay it will be used as \"billing address\" associated to each cards.<br/>**Note**: This field is mandatory for Click to Pay with Visa. When set for Click to Pay Mastercard, all fields inside the residencyAddress must be provided, in accordance with Mastercard specification.","required":["line1","city","state","zipCode","countryCode"],"properties":{"recipientName":{"type":"string","description":"Free text field containing the name of the recipient of post mail in case the name is different from first/last name (Unicode characters allowed).","minLength":1,"maxLength":64,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,64}$"},"line1":{"type":"string","description":"First line of the address (Unicode characters allowed).","minLength":1,"maxLength":64,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,64}$"},"line2":{"type":"string","description":"Second line of the address (Unicode characters allowed).","minLength":1,"maxLength":64,"pattern":"[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,64}$"},"line3":{"type":"string","description":"First line of the address (Unicode characters allowed).","minLength":1,"maxLength":64,"pattern":"[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,64}$"},"line4":{"type":"string","description":"Fourth line of the address (Unicode characters allowed).","minLength":1,"maxLength":64,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,64}$"},"city":{"type":"string","description":"City.","minLength":1,"maxLength":32,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,32}$"},"state":{"type":"string","description":"State.<br/><b>Note</b>: For Click to Pay, this field shall be the second part of ISO_3166-2 format in upper case, representing the state (country subdivision) based on the country.","minLength":1,"maxLength":40,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,40}$"},"zipCode":{"type":"string","description":"Zip Code.","minLength":1,"maxLength":10,"pattern":"^[0-9a-zA-Z -]{1,10}$"},"countryCode":{"type":"string","description":"Country code in ISO 3166-1 alpha-2.<br/>**Note**: This field is mandatory for Click to Pay.","minLength":2,"maxLength":2,"pattern":"^[A-Z]{2}$"}}}},"required":["firstName","lastName"]},"preferences":{"additionalProperties":false,"type":"object","title":"Preferences","description":"the following object represents the preferences of the end user","properties":{"notificationChannel":{"type":"array","description":"list by order of preference the communication channel D1 must use to send notification to user<br/>This do no superseded the restricted list of channel defined at message configuration level</br>if not provided, D1 manage to send the message with the following preference order:<br/>- IN_APP_NOTIFICATION<br/>- SMS<br/>- EMAIL","maxItems":3,"uniqueItems":true,"items":{"type":"string","enum":["SMS","EMAIL","IN_APP_NOTIFICATION"]}}}},"errorGeneric":{"additionalProperties":false,"type":"object","description":"Generic error returned by the APIs.","properties":{"errorCode":{"type":"string","description":"The type of the error"},"error":{"type":"string","description":"Provide more error details if possible.<br/>For example name of the field with invalid format.<br/>This field is for troubleshooting purposes only, it can change at any time so MUST NOT be parsed, and is not supposed to be human readable so CANNOT be displayed to end users."}}}},"responses":{"ServiceUnavailableError":{"description":"The service is temporarily unavailable. You may retry your request later."}}},"paths":{"/issuers/{issuerId}/consumers/{consumerId}":{"put":{"description":"This request is used by the bank backend to request the registration of the end user with personal information.\n> #### Note\n> It is strongly recommended to provide the end user personal information such as first and last name, email, phone number, postal address.\n>Personal information is used in `D1 Tokenization` by the Decision Engine or in `D1 Push` when building the card information to push to OEM Wallet. \n\n> #### Note\n> Some end user personal information are mandatory for issuers using `D1 Click to Pay` service. These mandatory personal information\n> such as mobilePhoneNumber or language are tagged bellow with *\"This field is mandatory for Click to Pay\"*. \n","tags":["Consumer"],"requestBody":{"content":{"application/json":{"schema":{"description":"The following object represent the end user (consumer).","additionalProperties":false,"type":"object","properties":{"personalInformation":{"$ref":"#/components/schemas/consumerInfo"},"preferences":{"$ref":"#/components/schemas/preferences"}}}}}},"responses":{"204":{"description":"Successful consumer registration."},"400":{"description":"Bad Request, Invalid request URI, header, paramters. The below table defines the possible 'Bad request' error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| FIELD_INVALID_FORMAT |  Contains the field in error (first found) | no | JSON not well formatted or<br>One field is not expected format as defined in this documentation |\n| FIELD_INVALID_VALUE  | - | no | One field value is not allowed for the given field |        \n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"401":{"description":"Unauthorized request, the provided Authorization header is missing or invalid. In the table below only the field \"error\" is provided.\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| AUTHORIZER_UNAUTHORIZED  | Unauthorized message | no | Access token not valid       |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"403":{"description":"Forbidden action, check the state of the linked consumer or card. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no | No error details available         |\n| AUTHORIZER_FORBIDDEN  | not\\_authorized error message | no | User\\_is\\_not\\_authorized\\_to\\_access\\_this\\_resource |\n| CONSUMER_INVALID_STATE  | contains the state of the resource  | no | Consumer already exists and is deleted |\n| MISSING_C2P_MANDATORY_INFORMATION  | contains the missing field  | no | All required fields for Click to Pay are not present (firstName, lastName, language, mobilePhoneNumber, countryCode, email) or residencyAddress.state length > 3 |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"404":{"description":"Ressource not found, Unknown issuerId or consumerId or card id'. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no | No error details available         |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"500":{"description":"Internal Server Error. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | yes | No error details available         |\n| INTERNAL_ERROR | Error details if any | no | The server has encountered an error when executing the request. |\n"},"503":{"$ref":"#/components/responses/ServiceUnavailableError"}},"summary":"Register consumer","operationId":"registerConsumer"}}}}
```

## Get Card List

> This request is used to request the end user card list.\
> It will return the cards & digital cards and associated accounts.

```json
{"openapi":"3.0.0","info":{"title":"D1 Inbound Consumer API","version":"2.0"},"tags":[{"name":"Consumer","description":"Different operations for end user (consumer) management."}],"servers":[{"url":"https://api.d1.thalescloud.io/banking/v2","description":"Production server"},{"url":"https://api.d1-stg.thalescloud.io/banking/v2","description":"Staging server"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"A JWT generated by the [Get Authorization Token API](oauth2-api).<br/>The server checks the validity of the provided token to control access to this protected resource. Please refer to [Get OAuth 2.0 access token](../../../integrate-the-d1-api/get-oauth-2.0-access-token) for more details on the flow and on how to get this JWT.","type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"cardId":{"type":"string","description":"Unique identifier of the card.","minLength":1,"maxLength":48,"pattern":"^[A-Za-z0-9_-]{1,48}$"},"newCardId":{"type":"string","description":"Unique identifier of the new card. Provided in case the card is in REPLACED state.","minLength":1,"maxLength":48,"pattern":"^[A-Za-z0-9_-]{1,48}$"},"cardProductId":{"type":"string","description":"Unique identifier of the type of card ( defined during the onboarding of D1)","minLength":1,"maxLength":48,"pattern":"^[A-Za-z0-9_-]{1,48}$"},"threeDSsupport":{"type":"boolean","description":"Determines if the card supports EMV 3-D Secure (3DS) flows."},"scheme":{"description":"The card scheme","enum":["MASTERCARD","VISA","AMEX"],"type":"string"},"auxiliaryScheme":{"description":"The card auxiliary scheme","enum":["DANKORT"]},"cardLast4":{"type":"string","pattern":"^\\d{4}$","description":"Last 4 digits of the PAN"},"cardExpiryDate":{"type":"string","description":"Expiry date of the card in MMYY format","pattern":"^(0[1-9]|1[0-2])\\d{2}$"},"newCardExpiryDate":{"type":"string","description":"New Expiry date of the card in MMYY format. Provided in case of ongoing RENEWAL operation.","pattern":"^(0[1-9]|1[0-2])\\d{2}$"},"cardState":{"type":"string","description":"the state of the card","enum":["INACTIVE","ACTIVE","SUSPENDED","DELETED","REPLACED"]},"creationDate":{"type":"string","title":"Creation date","description":"The time the resource has been created.\nFormat ISO 8601 YYYY-MM-DDThh:mm:ssTZD","minLength":1,"maxLength":64,"pattern":"^[0-9]{4}-((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01])|(0[469]|11)-(0[1-9]|[12][0-9]|30)|02-(0[1-9]|[12][0-9]))T([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](\\.[0-9]{3}Z|\\.[0-9]{2}([\\+\\-](0[1-9]|1[0-2])):00)$"},"lastUpdate":{"type":"string","title":"Last update date","description":"The time the resource has been last updated.\nFormat ISO 8601 YYYY-MM-DDThh:mm:ssTZD","minLength":1,"maxLength":64,"pattern":"^[0-9]{4}-((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01])|(0[469]|11)-(0[1-9]|[12][0-9]|30)|02-(0[1-9]|[12][0-9]))T([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](\\.[0-9]{3}Z|\\.[0-9]{2}([\\+\\-](0[1-9]|1[0-2])):00)$"},"AccountInformation":{"additionalProperties":false,"type":"object","required":["default","number","currencyCode"],"properties":{"default":{"type":"boolean","description":"true if the account is the default consumer account"},"type":{"type":"string","description":"Type of the Account. By default if not provided, it is a 'CHECKING' account.","enum":["CHECKING","SAVINGS"]},"number":{"type":"string","minLength":2,"maxLength":24,"pattern":"^[a-zA-Z0-9_]{2,24}$","description":"Account number used for posting to Core Banking System"},"currencyCode":{"$ref":"#/components/schemas/currencyCode"}}},"currencyCode":{"type":"string","pattern":"^[A-Z]{3}$","description":"Currency Code in ISO 4217 alpha code format"},"errorGeneric":{"additionalProperties":false,"type":"object","description":"Generic error returned by the APIs.","properties":{"errorCode":{"type":"string","description":"The type of the error"},"error":{"type":"string","description":"Provide more error details if possible.<br/>For example name of the field with invalid format.<br/>This field is for troubleshooting purposes only, it can change at any time so MUST NOT be parsed, and is not supposed to be human readable so CANNOT be displayed to end users."}}}},"responses":{"ServiceUnavailableError":{"description":"The service is temporarily unavailable. You may retry your request later."}}},"paths":{"/issuers/{issuerId}/consumers/{consumerId}/cards":{"get":{"description":"This request is used to request the end user card list.\nIt will return the cards & digital cards and associated accounts.","tags":["Consumer"],"responses":{"200":{"description":"Successful get end user card list","content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","properties":{"cards":{"type":"array","description":"list of cards that are associated to the end user","items":{"additionalProperties":false,"type":"object","required":["cardId","cardProductId","scheme","panSuffix","exp","state","ongoingOperation","creationTime"],"properties":{"cardId":{"$ref":"#/components/schemas/cardId"},"newCardId":{"$ref":"#/components/schemas/newCardId"},"cardProductId":{"$ref":"#/components/schemas/cardProductId"},"threeDSsupport":{"$ref":"#/components/schemas/threeDSsupport"},"scheme":{"$ref":"#/components/schemas/scheme"},"auxiliaryScheme":{"$ref":"#/components/schemas/auxiliaryScheme"},"panSuffix":{"$ref":"#/components/schemas/cardLast4"},"exp":{"$ref":"#/components/schemas/cardExpiryDate"},"newExp":{"$ref":"#/components/schemas/newCardExpiryDate"},"state":{"$ref":"#/components/schemas/cardState"},"stateReason":{"description":"reason associated to the state","type":"string","enum":["CLOSED_ACCOUNT","CLOSED_CARD","CARD_LOST","CARD_FOUND","CARD_STOLEN","CARD_BROKEN","CARD_NOT_RECEIVED","FRAUD","USER_DECISION","ISSUER_DECISION","CVV2_LOCKED","EXPIRY_DATE_LOCKED","PIN_LOCKED"]},"ongoingOperation":{"type":"string","enum":["NONE","RENEWAL"]},"creationTime":{"$ref":"#/components/schemas/creationDate"},"lastUpdateTime":{"$ref":"#/components/schemas/lastUpdate"},"accountList":{"type":"array","description":"This represent the list of account the card will be attached to.<br/>This list is used for the posting","items":{"$ref":"#/components/schemas/AccountInformation"}}}}}}}}}},"400":{"description":"Bad Request, Invalid request URI, header, paramters. The below table defines the possible 'Bad request' error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| FIELD_INVALID_FORMAT |  Contains the field in error (first found) | no | JSON not well formatted or<br>One field is not expected format as defined in this documentation |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"401":{"description":"Unauthorized request, the provided Authorization header is missing or invalid. In the table below only the field \"error\" is provided.\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| AUTHORIZER_UNAUTHORIZED  | Unauthorized message | no | Access token not valid       |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"403":{"description":"Forbidden action detected by WAF or the application.<br>\nThe below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| AUTHORIZER_FORBIDDEN  | not authorized error message | no | User is not authorized to access this resource |\n| CONSUMER_INVALID_STATE | Deleted consumer message | no | Consumer is in DELETED state |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"404":{"description":"Ressource not found, Unknown issuerId or consumerId or card id'. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no | No error details available         |\n| UNKNOWN_CONSUMER  | -        | no | Consumer does not exist |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"500":{"description":"Internal Server Error. The below table defines the possible error:\n|errorCode       | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| INTERNAL_ERROR | error details if any | no | The server has encountered an error when executing the request.  |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"503":{"$ref":"#/components/responses/ServiceUnavailableError"}},"summary":"Get Card List","operationId":"getConsumer"}}}}
```

## Delete

> This request is used by the bank backend to request the deletion of an end user.\<br/>It will also in cascade delete all the accounts, cards and digital cards owned by the end user.\<br/>\<b>Note:\</b> The deletion of the end user cannot be reverted. If the same end user is willing to reuse the solution, we will require a new end user registration with a new consumerId.

```json
{"openapi":"3.0.0","info":{"title":"D1 Inbound Consumer API","version":"2.0"},"tags":[{"name":"Consumer Operations","description":"Different operations that can be done on a end user."}],"servers":[{"url":"https://api.d1.thalescloud.io/banking/v2","description":"Production server"},{"url":"https://api.d1-stg.thalescloud.io/banking/v2","description":"Staging server"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"A JWT generated by the [Get Authorization Token API](oauth2-api).<br/>The server checks the validity of the provided token to control access to this protected resource. Please refer to [Get OAuth 2.0 access token](../../../integrate-the-d1-api/get-oauth-2.0-access-token) for more details on the flow and on how to get this JWT.","type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"reason":{"type":"string","title":"reason","pattern":"^[a-zA-Z0-9 ]{1,64}$","description":"The reason why the action is performed. \n\nThis a free text field in case the bank wants to send details, that will be returned in the operations list. "},"operationId":{"type":"string","description":"Unique identifier of the operation","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]{1,64}$"},"errorGeneric":{"additionalProperties":false,"type":"object","description":"Generic error returned by the APIs.","properties":{"errorCode":{"type":"string","description":"The type of the error"},"error":{"type":"string","description":"Provide more error details if possible.<br/>For example name of the field with invalid format.<br/>This field is for troubleshooting purposes only, it can change at any time so MUST NOT be parsed, and is not supposed to be human readable so CANNOT be displayed to end users."}}}},"responses":{"ServiceUnavailableError":{"description":"The service is temporarily unavailable. You may retry your request later."}}},"paths":{"/issuers/{issuerId}/consumers/{consumerId}/operations:delete":{"post":{"description":"This request is used by the bank backend to request the deletion of an end user.<br/>It will also in cascade delete all the accounts, cards and digital cards owned by the end user.<br/><b>Note:</b> The deletion of the end user cannot be reverted. If the same end user is willing to reuse the solution, we will require a new end user registration with a new consumerId.","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","properties":{"reason":{"$ref":"#/components/schemas/reason"}}}}}},"responses":{"200":{"description":"End user was deleted Successfully","content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","properties":{"operationId":{"$ref":"#/components/schemas/operationId"}}}}}},"400":{"description":"Bad Request, Invalid request URI, header, paramters. The below table defines the possible 'Bad request' error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| FIELD_INVALID_FORMAT |  Contains the field in error (first found) | no | JSON not well formatted or<br>One field is not expected format as defined in this documentation |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"401":{"description":"Unauthorized request, the provided Authorization header is missing or invalid. In the table below only the field \"error\" is provided.\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| AUTHORIZER_UNAUTHORIZED  | Unauthorized message | no | Access token not valid       |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"403":{"description":"Forbidden action detected by WAF or the application.<br>\nThe below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| AUTHORIZER_FORBIDDEN  | not authorized error message | no | User is not authorized to access this resource |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"404":{"description":"Ressource not found, Unknown issuerId or consumerId or card id'. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no | No error details available         |\n| UNKNOWN_CONSUMER  | -        | no | Consumer does not exist |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"500":{"description":"Internal Server Error. The below table defines the possible error:\n|errorCode       | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| INTERNAL_ERROR | error details if any | no | The server has encountered an error when executing the request.  |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"503":{"$ref":"#/components/responses/ServiceUnavailableError"}},"summary":"Delete","tags":["Consumer Operations"],"operationId":"deleteConsumer-v2"}}}}
```

## Update consumer information

> This request is used by the bank backend to request the update of the consumer information.\
> \> #### Note\
> \> Some end user personal information are mandatory for issuers using \`D1 Click to Pay\` service. These mandatory personal information\
> \> such as mobilePhoneNumber or language are tagged bellow with \*"This field is mandatory for Click to Pay"\*. <br>

```json
{"openapi":"3.0.0","info":{"title":"D1 Inbound Consumer API","version":"2.0"},"tags":[{"name":"Consumer Operations","description":"Different operations that can be done on a end user."}],"servers":[{"url":"https://api.d1.thalescloud.io/banking/v2","description":"Production server"},{"url":"https://api.d1-stg.thalescloud.io/banking/v2","description":"Staging server"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"A JWT generated by the [Get Authorization Token API](oauth2-api).<br/>The server checks the validity of the provided token to control access to this protected resource. Please refer to [Get OAuth 2.0 access token](../../../integrate-the-d1-api/get-oauth-2.0-access-token) for more details on the flow and on how to get this JWT.","type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"consumerInfoForUpdate":{"additionalProperties":false,"type":"object","title":"ConsumerInfo","description":"the following object represents the personal information of the end user.","properties":{"gender":{"type":"string","enum":["MALE","FEMALE","OTHER"]},"language":{"type":"string","description":"Language as defined by ISO 639-2 standard.\n<br/>**Note**: This field is mandatory for Click to Pay.\n<br/>List of languages accepted : abk, aar, afr, alb, amh, ara, arm, aze, bel, ben, bis, bos, bul, bur, cat, nya, chi, hrv, cze, dan, div, dut, dzo, eng, est, fij, fin, fre, geo, ger, gre, grn, hat, hau, heb, hin, hun, ice, ind, gle, ita, jpn, kaz, khm, kin, kor, kur, kir, lao, lat, lav, lit, ltz, mac, mlg, may, mlt, mao, mah, mon, nau, nep, nor, orm, oss, pus, per, pol, por, rum, roh, rus, smo, sag, srp, sin, slo, slv, som, spa, swa, swe, tgk, tam, tha, ton, tur, tuk, ukr, urd, uzb, vie,\n","minLength":3,"maxLength":3,"pattern":"^[a-z]{3}$"},"firstName":{"type":"string","description":"First name of the end user (Unicode characters allowed).<br/>**Note**: This field is mandatory for Click to Pay.","minLength":1,"maxLength":40,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,40}$"},"middleName":{"type":"string","description":"Middle name of the end user (Unicode characters allowed).","minLength":1,"maxLength":40,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,40}$"},"lastName":{"type":"string","description":"Last name of the end user (Unicode characters allowed).<br/>**Note**: This field is mandatory for Click to Pay.","minLength":1,"maxLength":40,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,40}$"},"secondLastName":{"type":"string","description":"Second Last name of the end user (Unicode characters allowed).","minLength":1,"maxLength":40,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,40}$"},"dateOfBirth":{"type":"string","description":"Date of Birth.","pattern":"^\\d{4}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[0-1])$"},"title":{"type":"string","description":"Title of the end user.<br/>By default D1 support the following title value<br/>- Mr.<br/>- Mrs.<br/>- Miss<br/>Please contact Thales integration team for the support of other value<br/>To not fill in if not applicable.","minLength":2,"maxLength":40,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,40}$"},"nationality":{"type":"string","description":"Main nationality of the end user in ISO 3166-1 Alpha-2 Code","minLength":2,"maxLength":2,"pattern":"^[A-Z]{2}$"},"email":{"type":"string","description":"Email of the end user.<br/>**Note**: This field is mandatory for Click to Pay with Mastercard.","minLength":5,"maxLength":256,"pattern":"^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,15}$"},"mobilePhoneNumber":{"additionalProperties":false,"description":"Phonenumber of the end user (consumer). Shall respect the E-164 format.<br/>**Note**: This field is mandatory for Click to Pay.","type":"object","required":["countryCode","phoneNumber"],"properties":{"countryCode":{"type":"string","description":"Internantional country code of the end user's phonenumber. Shall start with the '+' sign.","minLength":1,"maxLength":10,"pattern":"^\\+[0-9]{1,10}$"},"phoneNumber":{"type":"string","description":"National phonenumber of the end user. Shall not contain the first '0' of the national phonenumber. If present as input parameter, D1 will ignore it.","minLength":1,"maxLength":14,"pattern":"^[0-9]{1,14}$"}}},"residencyAddress":{"additionalProperties":false,"type":"object","description":"Residency address of the end user (consumer).<br/>In the context of Click to Pay it will be used as \"billing address\" associated to each cards.<br/>**Note**: When set for Click to Pay Mastercard, all fields inside the residencyAddress must be provided, in accordance with Mastercard specification.","required":["line1","city","state","zipCode","countryCode"],"properties":{"recipientName":{"type":"string","description":"Free text field containing the name of the recipient of post mail in case the name is different from first/last name (Unicode characters allowed).","minLength":1,"maxLength":64,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,64}$"},"line1":{"type":"string","description":"First line of the address (Unicode characters allowed).","minLength":1,"maxLength":64,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,64}$"},"line2":{"type":"string","description":"Second line of the address (Unicode characters allowed).","minLength":1,"maxLength":64,"pattern":"[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,64}$"},"line3":{"type":"string","description":"First line of the address (Unicode characters allowed).","minLength":1,"maxLength":64,"pattern":"[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,64}$"},"line4":{"type":"string","description":"Fourth line of the address (Unicode characters allowed).","minLength":1,"maxLength":64,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,64}$"},"city":{"type":"string","description":"City.","minLength":1,"maxLength":32,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,32}$"},"state":{"type":"string","description":"State.<br/><b>Note</b>: For Click to Pay, this field shall be the second part of ISO_3166-2 format in upper case, representing the state (country subdivision) based on the country.","minLength":1,"maxLength":40,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,40}$"},"zipCode":{"type":"string","description":"Zip Code.","minLength":1,"maxLength":10,"pattern":"^[0-9a-zA-Z -]{1,10}$"},"countryCode":{"type":"string","description":"Country code in ISO 3166-1 alpha-2.<br/>**Note**: This field is mandatory for Click to Pay.","minLength":2,"maxLength":2,"pattern":"^[A-Z]{2}$"}}}},"required":["firstName","lastName"]},"preferences":{"additionalProperties":false,"type":"object","title":"Preferences","description":"the following object represents the preferences of the end user","properties":{"notificationChannel":{"type":"array","description":"list by order of preference the communication channel D1 must use to send notification to user<br/>This do no superseded the restricted list of channel defined at message configuration level</br>if not provided, D1 manage to send the message with the following preference order:<br/>- IN_APP_NOTIFICATION<br/>- SMS<br/>- EMAIL","maxItems":3,"uniqueItems":true,"items":{"type":"string","enum":["SMS","EMAIL","IN_APP_NOTIFICATION"]}}}},"operationId":{"type":"string","description":"Unique identifier of the operation","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]{1,64}$"},"errorGeneric":{"additionalProperties":false,"type":"object","description":"Generic error returned by the APIs.","properties":{"errorCode":{"type":"string","description":"The type of the error"},"error":{"type":"string","description":"Provide more error details if possible.<br/>For example name of the field with invalid format.<br/>This field is for troubleshooting purposes only, it can change at any time so MUST NOT be parsed, and is not supposed to be human readable so CANNOT be displayed to end users."}}}},"responses":{"ServiceUnavailableError":{"description":"The service is temporarily unavailable. You may retry your request later."}}},"paths":{"/issuers/{issuerId}/consumers/{consumerId}/operations:update":{"post":{"description":"This request is used by the bank backend to request the update of the consumer information.\n> #### Note\n> Some end user personal information are mandatory for issuers using `D1 Click to Pay` service. These mandatory personal information\n> such as mobilePhoneNumber or language are tagged bellow with *\"This field is mandatory for Click to Pay\"*. \n","tags":["Consumer Operations"],"requestBody":{"content":{"application/json":{"schema":{"description":"The following object represent the information of the consumer or cardholder.","additionalProperties":false,"type":"object","properties":{"personalInformation":{"$ref":"#/components/schemas/consumerInfoForUpdate"},"preferences":{"$ref":"#/components/schemas/preferences"}}}}}},"responses":{"200":{"description":"Consumer successfully updated.","content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","properties":{"operationId":{"$ref":"#/components/schemas/operationId"}}}}}},"400":{"description":"Bad Request, Invalid request URI, header, paramters. The below table defines the possible 'Bad request' error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| FIELD_INVALID_FORMAT |  Contains the field in error (first found) | no | JSON not well formatted or<br>One field is not expected format as defined in this documentation |   \n| FIELD_INVALID_VALUE   | - | no | One field value is not allowed for the given field |     \n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"401":{"description":"Unauthorized request, the provided Authorization header is missing or invalid. In the table below only the field \"error\" is provided.\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| AUTHORIZER_UNAUTHORIZED  | Unauthorized message | no | Access token not valid       |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"403":{"description":"Forbidden action, check the state of the linked consumer or card. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no | No error details available         |\n| AUTHORIZER_FORBIDDEN  | not\\_authorized error message | no | User\\_is\\_not\\_authorized\\_to\\_access\\_this\\_resource |\n| CONSUMER_INVALID_STATE  | contains the state of the resource  | no | Consumer already exists and is deleted |\n| MISSING_C2P_MANDATORY_INFORMATION  | contains the missing field  | no | All required fields for Click to Pay are not present (firstName, lastName, language, mobilePhoneNumber, countryCode, email) or residencyAddress.state length > 3 |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"404":{"description":"Ressource not found, Unknown issuerId or consumerId or card id'. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no | No error details available         |\n| UNKNOWN_CONSUMER  | -        | no | Consumer does not exist |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"500":{"description":"Internal Server Error. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no | No error details available         |\n| INTERNAL_ERROR | Error details if any | no | The server has encountered an error when executing the request. |\n"},"503":{"$ref":"#/components/responses/ServiceUnavailableError"}},"summary":"Update consumer information","operationId":"editConsumer"}}}}
```

## Get Consumer Information

> This request is used to request consumer information.

```json
{"openapi":"3.0.0","info":{"title":"D1 Inbound Consumer API","version":"2.0"},"tags":[{"name":"Consumer","description":"Different operations for end user (consumer) management."}],"servers":[{"url":"https://api.d1.thalescloud.io/banking/v2","description":"Production server"},{"url":"https://api.d1-stg.thalescloud.io/banking/v2","description":"Staging server"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"A JWT generated by the [Get Authorization Token API](oauth2-api).<br/>The server checks the validity of the provided token to control access to this protected resource. Please refer to [Get OAuth 2.0 access token](../../../integrate-the-d1-api/get-oauth-2.0-access-token) for more details on the flow and on how to get this JWT.","type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"consumerState":{"type":"string","description":"the state of the consumer","enum":["ACTIVE","DELETED"]},"preferences":{"additionalProperties":false,"type":"object","title":"Preferences","description":"the following object represents the preferences of the end user","properties":{"notificationChannel":{"type":"array","description":"list by order of preference the communication channel D1 must use to send notification to user<br/>This do no superseded the restricted list of channel defined at message configuration level</br>if not provided, D1 manage to send the message with the following preference order:<br/>- IN_APP_NOTIFICATION<br/>- SMS<br/>- EMAIL","maxItems":3,"uniqueItems":true,"items":{"type":"string","enum":["SMS","EMAIL","IN_APP_NOTIFICATION"]}}}},"creationDate":{"type":"string","title":"Creation date","description":"The time the resource has been created.\nFormat ISO 8601 YYYY-MM-DDThh:mm:ssTZD","minLength":1,"maxLength":64,"pattern":"^[0-9]{4}-((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01])|(0[469]|11)-(0[1-9]|[12][0-9]|30)|02-(0[1-9]|[12][0-9]))T([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](\\.[0-9]{3}Z|\\.[0-9]{2}([\\+\\-](0[1-9]|1[0-2])):00)$"},"lastUpdate":{"type":"string","title":"Last update date","description":"The time the resource has been last updated.\nFormat ISO 8601 YYYY-MM-DDThh:mm:ssTZD","minLength":1,"maxLength":64,"pattern":"^[0-9]{4}-((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01])|(0[469]|11)-(0[1-9]|[12][0-9]|30)|02-(0[1-9]|[12][0-9]))T([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](\\.[0-9]{3}Z|\\.[0-9]{2}([\\+\\-](0[1-9]|1[0-2])):00)$"},"errorGeneric":{"additionalProperties":false,"type":"object","description":"Generic error returned by the APIs.","properties":{"errorCode":{"type":"string","description":"The type of the error"},"error":{"type":"string","description":"Provide more error details if possible.<br/>For example name of the field with invalid format.<br/>This field is for troubleshooting purposes only, it can change at any time so MUST NOT be parsed, and is not supposed to be human readable so CANNOT be displayed to end users."}}}},"responses":{"ServiceUnavailableError":{"description":"The service is temporarily unavailable. You may retry your request later."}}},"paths":{"/issuers/{issuerId}/consumers/{consumerId}":{"get":{"description":"This request is used to request consumer information.","tags":["Consumer"],"responses":{"200":{"description":"Successful get consumer information","content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","properties":{"state":{"$ref":"#/components/schemas/consumerState"},"preferences":{"$ref":"#/components/schemas/preferences"},"creationTime":{"$ref":"#/components/schemas/creationDate"},"lastUpdateTime":{"$ref":"#/components/schemas/lastUpdate"}}}}}},"400":{"description":"Bad Request, Invalid request URI, header, paramters. The below table defines the possible 'Bad request' error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| FIELD_INVALID_FORMAT |  Contains the field in error (first found) | no | JSON not well formatted or<br>One field is not expected format as defined in this documentation |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"401":{"description":"Unauthorized request, the provided Authorization header is missing or invalid. In the table below only the field \"error\" is provided.\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| AUTHORIZER_UNAUTHORIZED  | Unauthorized message | no | Access token not valid       |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"403":{"description":"Forbidden action detected by WAF or the application.<br>\nThe below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| AUTHORIZER_FORBIDDEN  | not authorized error message | no | User is not authorized to access this resource |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"404":{"description":"Ressource not found, Unknown issuerId or consumerId or card id'. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no | No error details available         |\n| UNKNOWN_CONSUMER  | -        | no | Consumer does not exist |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"500":{"description":"Internal Server Error. The below table defines the possible error:\n|errorCode       | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| INTERNAL_ERROR | error details if any | no | The server has encountered an error when executing the request.  |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"503":{"$ref":"#/components/responses/ServiceUnavailableError"}},"summary":"Get Consumer Information","operationId":"getConsumerInformation"}}}}
```


# Card API

## Create and order a physical card

> This request is used by the bank backend to create a physical card and trigger its production order.\
> The card creation registers the card with the processor (CMS and D1 Card Manager).\
> The production order is sent to the personalization center based on the \`distributionChannel\`:\
> \- \`THALES\`: Thales personalization center — requires \`shipment\`\
> \- \`INSTANT\`: Instant issuance in branch — requires \`persoStation\`, no shipment\
> \- \`CENTRAL\`: Bank or partner center — requires \`persoCenter\` and \`shipment\`<br>

```json
{"openapi":"3.0.0","info":{"title":"D1 Inbound Card API","version":"2.0"},"tags":[],"servers":[{"url":"https://api.d1.thalescloud.io/banking","description":"Production server"},{"url":"https://api.d1-stg.thalescloud.io/banking","description":"Staging server"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"A JWT generated by the [Get Authorization Token API](oauth2-api).<br/>The server checks the validity of the provided token to control access to this protected resource. Please refer to [Get OAuth 2.0 access token](../../../integrate-the-d1-api/get-oauth-2.0-access-token) for more details on the flow and on how to get this JWT.","type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"createAndOrderPhysicalCardRequest":{"oneOf":[{"$ref":"#/components/schemas/physicalCardRequestThales"},{"$ref":"#/components/schemas/physicalCardRequestInstant"},{"$ref":"#/components/schemas/physicalCardRequestCentral"}]},"physicalCardRequestThales":{"title":"distributionChannel = THALES","additionalProperties":false,"type":"object","required":["distributionChannel","consumerId","cardProductId","name","accountList","services","shipment"],"properties":{"distributionChannel":{"type":"string","description":"Channel used to personalize the card","enum":["THALES"]},"consumerId":{"type":"string","description":"The unique identifier of the consumer.","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]{1,64}$"},"cardProductId":{"type":"string","description":"The unique identifier of the card product.","minLength":1,"maxLength":64},"state":{"type":"string","description":"Initial state of the card.","enum":["ACTIVE","INACTIVE"],"default":"INACTIVE"},"name":{"type":"string","minLength":0,"maxLength":26,"pattern":"^[a-zA-Z. -]{0,26}$","description":"Name of the card holder as it will be embossed on the card."},"secondName":{"type":"string","minLength":0,"maxLength":26,"pattern":"^[a-zA-Z. -]{0,26}$","description":"Optional second card holder name embossed on the card."},"statusReason":{"type":"string","minLength":0,"maxLength":2,"default":"IN","pattern":"^[a-zA-Z]{0,2}$","description":"Reason code for the card state."},"accountList":{"type":"array","description":"List of accounts the card will be attached to.","items":{"$ref":"#/components/schemas/physicalAccountInformation"}},"issuerRequestId":{"type":"string","description":"Identifier provided by the issuer to identify the card production request.","pattern":"^[a-zA-Z0-9_-]{1,64}$"},"services":{"$ref":"#/components/schemas/physicalServices"},"cardDesign":{"$ref":"#/components/schemas/physicalCardDesign"},"cardCarrierConfig":{"$ref":"#/components/schemas/physicalCardCarrierConfig"},"packagingConfig":{"$ref":"#/components/schemas/physicalPackagingConfig"},"shipment":{"$ref":"#/components/schemas/physicalShipment"}}},"physicalAccountInformation":{"type":"object","additionalProperties":false,"required":["number","currencyCode","default"],"properties":{"default":{"type":"boolean","description":"Indicates if this is the default account."},"type":{"type":"string","description":"Type of the Account. By default if not provided, it is a 'CHECKING' account.","enum":["CHECKING","SAVINGS"]},"number":{"type":"string","description":"Account number.","minLength":2,"maxLength":24,"pattern":"^[a-zA-Z0-9_]{2,24}$"},"name":{"type":"string","description":"Name of the account holder."},"currencyCode":{"type":"string","description":"Currency code in ISO 4217 alpha-3 format.","minLength":3,"maxLength":3}}},"physicalServices":{"type":"object","additionalProperties":false,"properties":{"priority":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,64}$","description":"The level of priority for card production. Must be one of the identifiers configured during onboarding."},"delivery":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,64}$","default":"NO_SHIPMENT","description":"The shipment method. Must be one of the identifiers configured during onboarding."},"packaging":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,64}$","default":"NO_PACK","description":"Unique identifier of the packaging. Must be one of the identifiers configured during onboarding."},"cardCarrier":{"type":"string","default":"NO_CARRIER","pattern":"^[a-zA-Z0-9_-]{1,64}$","description":"Unique identifier of the card carrier. Must be one of the identifiers configured during onboarding."},"pinMailer":{"type":"boolean","default":false,"description":"Enable the option to send the PIN value to the consumer via post mail."},"alphaCard":{"type":"boolean","default":false,"description":"Enable the option to produce a sample card in the production environment."}}},"physicalCardDesign":{"type":"object","additionalProperties":false,"properties":{"artworkId":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$","description":"Unique identifier of the physical card artwork."},"memberId":{"type":"string","description":"MemberId printed onto the card.","pattern":"^[A-Za-z0-9_\\/.+-]{1,48}$"},"images":{"description":"List of additional images that can be printed on the card (max 5).","type":"array","minItems":0,"maxItems":5,"default":[],"items":{"type":"string","pattern":"^[A-Za-z0-9_.\\-\\\\/%\\^?=]{0,64}$"}},"customLines":{"description":"List of additional texts that can be printed on the card (max 10).","type":"array","minItems":0,"maxItems":10,"default":[],"items":{"type":"string","pattern":"^[\\p{L}\\p{N}@ ,.\\'_#;:\\\\/\\-?=%\\\\^+&]{0,256}$"}}}},"physicalCardCarrierConfig":{"type":"object","additionalProperties":false,"properties":{"language":{"description":"The language of the card carrier (ISO 639-1 alpha-2 format).","type":"string","minLength":2,"maxLength":2,"pattern":"^[A-Z]{2}$"},"images":{"description":"List of additional images for the card carrier (max 5).","type":"array","minItems":0,"maxItems":5,"default":[],"items":{"type":"string","pattern":"^[A-Za-z0-9_.\\-\\\\/%\\^?=]{0,64}$"}},"customLines":{"description":"List of additional texts for the card carrier (max 10).","type":"array","minItems":0,"maxItems":10,"default":[],"items":{"type":"string","pattern":"^[\\p{L}\\p{N}@ ,.\\'_#;:\\\\/\\-?=%\\\\^+&]{0,256}$"}},"multiCardId":{"description":"All cards with the same identifier will be grouped on the same card carrier.","type":"string","minLength":1,"maxLength":48,"pattern":"^[A-Za-z0-9_-]{1,48}$"},"multiCardOrder":{"description":"Order of the card on the carrier compared to other cards.","type":"string","minLength":1,"maxLength":2,"pattern":"^[0-9]{1,2}$"}}},"physicalPackagingConfig":{"type":"object","additionalProperties":false,"properties":{"inserts":{"type":"array","minItems":0,"maxItems":10,"items":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,48}$"},"description":"List of insert identifiers."}}},"physicalShipment":{"oneOf":[{"$ref":"#/components/schemas/physicalShipmentIndividual"},{"$ref":"#/components/schemas/physicalShipmentBulk"}]},"physicalShipmentIndividual":{"title":"type = INDIVIDUAL","type":"object","additionalProperties":false,"required":["type","deliveryAddress"],"properties":{"type":{"type":"string","enum":["INDIVIDUAL"],"description":"Send the card individually to the consumer's address."},"deliveryAddress":{"description":"The recipient's address.","$ref":"#/components/schemas/physicalAddress"}}},"physicalAddress":{"type":"object","additionalProperties":false,"required":["lastName","line1","zipCode","city","countryCode"],"properties":{"title":{"type":"string","description":"The title.","minLength":1,"maxLength":40,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.\\'_#;:\\/-]{1,40}$"},"firstName":{"type":"string","description":"The first name.","minLength":1,"maxLength":40,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.\\'_#;:\\/-]{1,40}$"},"lastName":{"type":"string","description":"The last name.","minLength":1,"maxLength":40,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.\\'_#;:\\/-]{1,40}$"},"companyName":{"type":"string","description":"The name of the company.","minLength":1,"maxLength":64,"pattern":"^[\\p{L}\\p{N}\\p{M} '_#;:.,-\\/+&]{1,64}$"},"line1":{"type":"string","description":"The first line of the address.","minLength":1,"maxLength":64,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.\\'_#;:\\/-]{1,64}$"},"line2":{"type":"string","description":"The second line of the address.","minLength":1,"maxLength":64,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.\\'_#;:\\/-]{1,64}$"},"line3":{"type":"string","description":"The third line of the address.","minLength":1,"maxLength":64,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.\\'_#;:\\/-]{1,64}$"},"city":{"type":"string","description":"The city name.","minLength":1,"maxLength":32,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.\\'_#;:\\/-]{1,32}$"},"state":{"type":"string","description":"The state.","minLength":1,"maxLength":30,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.\\'_#;:\\/-]{1,30}$"},"zipCode":{"type":"string","description":"The postal code or ZIP Code.","minLength":1,"maxLength":10,"pattern":"^[0-9A-Z- ]{1,10}$"},"countryCode":{"type":"string","description":"The country code (ISO 3166-1 alpha-2 format).","minLength":2,"maxLength":2,"pattern":"^[A-Z]{2}$"},"mobilePhoneNumber":{"type":"object","required":["countryCode","phoneNumber"],"description":"International phone number for shipment contact.","properties":{"countryCode":{"type":"string","description":"The country calling code.","pattern":"^\\+[0-9]{1,10}$"},"phoneNumber":{"type":"string","description":"The local phone number.","pattern":"^[0-9]{1,14}$"}}},"email":{"type":"string","description":"Email for shipment contact.","minLength":1,"maxLength":255,"pattern":"^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,15}$"}}},"physicalShipmentBulk":{"title":"type = BULK","type":"object","additionalProperties":false,"required":["type","deliveryAddress"],"properties":{"type":{"type":"string","enum":["BULK"],"description":"Send the card in bulk to an agency. Cards with the same delivery address shipped the same day are grouped automatically."},"deliveryAddress":{"description":"The recipient's address.","$ref":"#/components/schemas/physicalAddress"},"individualAddress":{"description":"The consumer address. Required only for BULK + card carrier required.","$ref":"#/components/schemas/physicalAddress"},"groupId":{"type":"string","minLength":1,"maxLength":64,"description":"First level of grouping for BULK shipment. All cards with the same groupId are put in the same box."},"orderId":{"type":"string","minLength":1,"maxLength":64,"description":"Second level of grouping for BULK shipment."}}},"physicalCardRequestInstant":{"title":"distributionChannel = INSTANT","additionalProperties":false,"type":"object","required":["distributionChannel","consumerId","cardProductId","name","accountList","services","persoStation"],"properties":{"distributionChannel":{"type":"string","description":"Channel used to personalize the card","enum":["INSTANT"]},"consumerId":{"type":"string","description":"The unique identifier of the consumer.","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]{1,64}$"},"cardProductId":{"type":"string","description":"The unique identifier of the card product.","minLength":1,"maxLength":64},"state":{"type":"string","description":"Initial state of the card.","enum":["ACTIVE","INACTIVE"],"default":"INACTIVE"},"name":{"type":"string","minLength":0,"maxLength":26,"pattern":"^[a-zA-Z. -]{0,26}$","description":"Name of the card holder as it will be embossed on the card."},"secondName":{"type":"string","minLength":0,"maxLength":26,"pattern":"^[a-zA-Z. -]{0,26}$","description":"Optional second card holder name embossed on the card."},"statusReason":{"type":"string","minLength":0,"maxLength":2,"default":"IN","pattern":"^[a-zA-Z]{0,2}$","description":"Reason code for the card state."},"accountList":{"type":"array","description":"List of accounts the card will be attached to.","items":{"$ref":"#/components/schemas/physicalAccountInformation"}},"persoStation":{"type":"string","description":"Unique identifier of the station used for card personalization.","pattern":"^[a-zA-Z0-9_-]{1,64}$"},"services":{"$ref":"#/components/schemas/physicalServices"},"cardDesign":{"$ref":"#/components/schemas/physicalCardDesign"},"cardCarrierConfig":{"$ref":"#/components/schemas/physicalCardCarrierConfig"}}},"physicalCardRequestCentral":{"title":"distributionChannel = CENTRAL","additionalProperties":false,"type":"object","required":["distributionChannel","consumerId","cardProductId","name","accountList","services","shipment"],"properties":{"distributionChannel":{"type":"string","description":"Channel used to personalize the card","enum":["CENTRAL"]},"consumerId":{"type":"string","description":"The unique identifier of the consumer.","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]{1,64}$"},"cardProductId":{"type":"string","description":"The unique identifier of the card product.","minLength":1,"maxLength":64},"state":{"type":"string","description":"Initial state of the card.","enum":["ACTIVE","INACTIVE"],"default":"INACTIVE"},"name":{"type":"string","minLength":0,"maxLength":26,"pattern":"^[a-zA-Z. -]{0,26}$","description":"Name of the card holder as it will be embossed on the card."},"secondName":{"type":"string","minLength":0,"maxLength":26,"pattern":"^[a-zA-Z. -]{0,26}$","description":"Optional second card holder name embossed on the card."},"statusReason":{"type":"string","minLength":0,"maxLength":2,"default":"IN","pattern":"^[a-zA-Z]{0,2}$","description":"Reason code for the card state."},"accountList":{"type":"array","description":"List of accounts the card will be attached to.","items":{"$ref":"#/components/schemas/physicalAccountInformation"}},"persoCenter":{"type":"string","description":"Unique identifier of the personalization center.","pattern":"^[a-zA-Z0-9_-]{1,64}$"},"services":{"$ref":"#/components/schemas/physicalServices"},"cardDesign":{"$ref":"#/components/schemas/physicalCardDesign"},"cardCarrierConfig":{"$ref":"#/components/schemas/physicalCardCarrierConfig"},"shipment":{"$ref":"#/components/schemas/physicalShipment"}}},"createAndOrderPhysicalCardResponse":{"type":"object","required":["cardId","operationId"],"properties":{"cardId":{"type":"string","description":"The unique identifier of the created card.","minLength":1,"maxLength":48},"operationId":{"type":"string","description":"The unique identifier of the operation."}}},"errorGeneric":{"additionalProperties":false,"type":"object","description":"Generic error returned by the APIs.","properties":{"errorCode":{"type":"string","description":"The type of the error"},"error":{"type":"string","description":"Provide more error details if possible.<br/>For example name of the field with invalid format.<br/>This field is for troubleshooting purposes only, it can change at any time so MUST NOT be parsed, and is not supposed to be human readable so CANNOT be displayed to end users."}}}}},"paths":{"/v2/issuers/{issuerId}/cards/physical":{"post":{"summary":"Create and order a physical card","operationId":"createAndOrderPhysicalCard","tags":["Physical Card"],"description":"This request is used by the bank backend to create a physical card and trigger its production order.\nThe card creation registers the card with the processor (CMS and D1 Card Manager).\nThe production order is sent to the personalization center based on the `distributionChannel`:\n- `THALES`: Thales personalization center — requires `shipment`\n- `INSTANT`: Instant issuance in branch — requires `persoStation`, no shipment\n- `CENTRAL`: Bank or partner center — requires `persoCenter` and `shipment`\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/createAndOrderPhysicalCardRequest"}}}},"responses":{"201":{"description":"Successful physical card creation and production order submitted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/createAndOrderPhysicalCardResponse"}}}},"400":{"description":"Bad Request. Invalid request URI, header, or parameters.\n| errorCode | error | Retryable | Comments |\n| --- | --- | --- | --- |\n| - | - | no | No error details available |\n| FIELD_INVALID_FORMAT | Contains the field in error (first found) | no | JSON not well formatted or one field is not in expected format |\n| FIELD_INVALID_VALUE | Contains the field in error (first found) | no | One field value is not allowed for the given field |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"401":{"description":"Unauthorized request.\n| errorCode | error | Retryable | Comments |\n| --- | --- | --- | --- |\n| AUTHORIZER_UNAUTHORIZED | Unauthorized message | no | Access token not valid |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"403":{"description":"Forbidden.\n| errorCode | error | Retryable | Comments |\n| --- | --- | --- | --- |\n| - | - | no | No error details available |\n| AUTHORIZER_FORBIDDEN | not authorized error message | no | User is not authorized to access this resource |\n| CARD_CREATION_COUNT_EXCEEDED | - | no | The maximum number of cards for the consumer is reached |\n| OPERATION_NOT_ALLOWED | Name of the operation/field that is not allowed | no | Card creation is not allowed for this card product |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"404":{"description":"Resource not found.\n| errorCode | error | Retryable | Comments |\n| --- | --- | --- | --- |\n| - | - | no | No error details available |\n| UNKNOWN_CONSUMER | - | no | Consumer does not exist |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"500":{"description":"Internal Server Error.\n| errorCode | error | Retryable | Comments |\n| --- | --- | --- | --- |\n| - | - | yes | No error details available |\n| INTERNAL_ERROR | error details if any | no | The server has encountered an error when executing the request |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"503":{"description":"Service temporarily unavailable. The request may be retried."}}}}}}
```

## Create

> This request is used by the bank backend to request the creation of a card (virtual or physical) with the processor.

```json
{"openapi":"3.0.0","info":{"title":"D1 Inbound Card API","version":"2.0"},"tags":[{"name":"Card","description":"Card APIs."}],"servers":[{"url":"https://api.d1.thalescloud.io/banking","description":"Production server"},{"url":"https://api.d1-stg.thalescloud.io/banking","description":"Staging server"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"A JWT generated by the [Get Authorization Token API](oauth2-api).<br/>The server checks the validity of the provided token to control access to this protected resource. Please refer to [Get OAuth 2.0 access token](../../../integrate-the-d1-api/get-oauth-2.0-access-token) for more details on the flow and on how to get this JWT.","type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"consumerId":{"type":"string","description":"Unique identifier of the consumer. ","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]{1,64}$"},"cardProductId":{"type":"string","description":"Unique identifier of the type of card ( defined during the onboarding of D1)","minLength":1,"maxLength":48,"pattern":"^[A-Za-z0-9_-]{1,48}$"},"createState":{"description":"The state of the card<br/>If not provided, the card is considered ACTIVE","type":"string","enum":["ACTIVE","INACTIVE"]},"AccountInformation":{"additionalProperties":false,"type":"object","required":["default","number","currencyCode"],"properties":{"default":{"type":"boolean","description":"true if the account is the default consumer account"},"type":{"type":"string","description":"Type of the Account. By default if not provided, it is a 'CHECKING' account.","enum":["CHECKING","SAVINGS"]},"number":{"type":"string","minLength":2,"maxLength":24,"pattern":"^[a-zA-Z0-9_]{2,24}$","description":"Account number used for posting to Core Banking System"},"currencyCode":{"$ref":"#/components/schemas/currencyCode"}}},"currencyCode":{"type":"string","pattern":"^[A-Z]{3}$","description":"Currency Code in ISO 4217 alpha code format"},"cardId":{"type":"string","description":"Unique identifier of the card.","minLength":1,"maxLength":48,"pattern":"^[A-Za-z0-9_-]{1,48}$"},"errorGeneric":{"additionalProperties":false,"type":"object","description":"Generic error returned by the APIs.","properties":{"errorCode":{"type":"string","description":"The type of the error"},"error":{"type":"string","description":"Provide more error details if possible.<br/>For example name of the field with invalid format.<br/>This field is for troubleshooting purposes only, it can change at any time so MUST NOT be parsed, and is not supposed to be human readable so CANNOT be displayed to end users."}}}},"responses":{"ServiceUnavailableError":{"description":"The service is temporarily unavailable. You may retry your request later."}}},"paths":{"/v2/issuers/{issuerId}/cards":{"post":{"description":"This request is used by the bank backend to request the creation of a card (virtual or physical) with the processor.","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","properties":{"consumerId":{"$ref":"#/components/schemas/consumerId"},"cardProductId":{"$ref":"#/components/schemas/cardProductId"},"state":{"$ref":"#/components/schemas/createState"},"name":{"type":"string","minLength":0,"maxLength":26,"pattern":"^[a-zA-Z. -]{0,26}$","description":"Name of the card holder as it will be printed/embossed on the card.<br/>For virtual card this value will be used exclusively for card display.<br/>Empty string supported."},"secondName":{"type":"string","minLength":0,"maxLength":26,"pattern":"^[a-zA-Z. -]{0,26}$","description":"Optional second card holder name as it will be printed/embossed on the card under the first card holder name.<br/>Not used in case of virtual card."},"statusReason":{"type":"string","minLength":0,"maxLength":2,"default":"IN","pattern":"^[a-zA-Z]{0,2}$","description":"This indicates the state of the card once it's created"},"accountList":{"type":"array","description":"This represent the list of account the card will be attached to.<br/>This list is used for the posting","items":{"$ref":"#/components/schemas/AccountInformation"}}},"required":["consumerId","accountList","cardProductId","name"]}}}},"responses":{"201":{"description":"Successful card creation","content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","description":"Information related to the created card.","required":["cardId"],"properties":{"cardId":{"$ref":"#/components/schemas/cardId"}}}}}},"400":{"description":"Bad Request, Invalid request URI, header, paramters. The below table defines the possible 'Bad request' error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| FIELD_INVALID_FORMAT |  Contains the field in error (first found) | no | JSON not well formatted or<br>One field is not expected format as defined in this documentation |\n| FIELD_INVALID_VALUE  |  Contains the field in error (first found) | no | One field value is not allowed for the given field  |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"401":{"description":"Unauthorized request, the provided Authorization header is missing or invalid. In the table below only the field \"error\" is provided.\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| AUTHORIZER_UNAUTHORIZED  | Unauthorized message | no | Access token not valid       |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"403":{"description":"Forbidden action detected by WAF or the application.<br>\nThe below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| AUTHORIZER_FORBIDDEN  | not authorized error message | no | User is not authorized to access this resource |\n| CARD_CREATION_COUNT_EXCEEDED  | -        | no | The maximum number of cards for the consumer is reached. Creation of additional card is not possible. |\n | OPERATION_NOT_ALLOWED | Name of the operation/field that is not allowed in this operation | no | Card creation is not allowed for this card product |","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"404":{"description":"Ressource not found, Unknown issuerId or consumerId or card id'. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no | No error details available         |\n| UNKNOWN_CONSUMER  | -        | no | Consumer does not exist |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"500":{"description":"Internal Server Error. The below table defines the possible error:\n|errorCode       | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | yes        | No error details available         |\n| INTERNAL_ERROR | error details if any | no | The server has encountered an error when executing the request.  |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"503":{"$ref":"#/components/responses/ServiceUnavailableError"}},"summary":"Create","operationId":"createCard","tags":["Card"]}}}}
```

## Get card details

> This request is used by the bank backend to request card details.

```json
{"openapi":"3.0.0","info":{"title":"D1 Inbound Card API","version":"2.0"},"tags":[{"name":"Card","description":"Card APIs."}],"servers":[{"url":"https://api.d1.thalescloud.io/banking","description":"Production server"},{"url":"https://api.d1-stg.thalescloud.io/banking","description":"Staging server"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"A JWT generated by the [Get Authorization Token API](oauth2-api).<br/>The server checks the validity of the provided token to control access to this protected resource. Please refer to [Get OAuth 2.0 access token](../../../integrate-the-d1-api/get-oauth-2.0-access-token) for more details on the flow and on how to get this JWT.","type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"consumerId":{"type":"string","description":"Unique identifier of the consumer. ","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]{1,64}$"},"cardId":{"type":"string","description":"Unique identifier of the card.","minLength":1,"maxLength":48,"pattern":"^[A-Za-z0-9_-]{1,48}$"},"newCardId":{"type":"string","description":"Unique identifier of the new card. Provided in case the card is in REPLACED state.","minLength":1,"maxLength":48,"pattern":"^[A-Za-z0-9_-]{1,48}$"},"cardProductId":{"type":"string","description":"Unique identifier of the type of card ( defined during the onboarding of D1)","minLength":1,"maxLength":48,"pattern":"^[A-Za-z0-9_-]{1,48}$"},"threeDSsupport":{"type":"boolean","description":"Determines if the card supports EMV 3-D Secure (3DS) flows."},"scheme":{"description":"The card scheme","enum":["MASTERCARD","VISA","AMEX"],"type":"string"},"auxiliaryScheme":{"description":"The card auxiliary scheme","enum":["DANKORT"]},"cardLast4":{"type":"string","pattern":"^\\d{4}$","description":"Last 4 digits of the PAN"},"cardExpiryDate":{"type":"string","description":"Expiry date of the card in MMYY format","pattern":"^(0[1-9]|1[0-2])\\d{2}$"},"newCardExpiryDate":{"type":"string","description":"New Expiry date of the card in MMYY format. Provided in case of ongoing RENEWAL operation.","pattern":"^(0[1-9]|1[0-2])\\d{2}$"},"cardState":{"type":"string","description":"the state of the card","enum":["INACTIVE","ACTIVE","SUSPENDED","DELETED","REPLACED"]},"creationDate":{"type":"string","title":"Creation date","description":"The time the resource has been created.\nFormat ISO 8601 YYYY-MM-DDThh:mm:ssTZD","minLength":1,"maxLength":64,"pattern":"^[0-9]{4}-((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01])|(0[469]|11)-(0[1-9]|[12][0-9]|30)|02-(0[1-9]|[12][0-9]))T([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](\\.[0-9]{3}Z|\\.[0-9]{2}([\\+\\-](0[1-9]|1[0-2])):00)$"},"lastUpdate":{"type":"string","title":"Last update date","description":"The time the resource has been last updated.\nFormat ISO 8601 YYYY-MM-DDThh:mm:ssTZD","minLength":1,"maxLength":64,"pattern":"^[0-9]{4}-((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01])|(0[469]|11)-(0[1-9]|[12][0-9]|30)|02-(0[1-9]|[12][0-9]))T([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](\\.[0-9]{3}Z|\\.[0-9]{2}([\\+\\-](0[1-9]|1[0-2])):00)$"},"AccountInformation":{"additionalProperties":false,"type":"object","required":["default","number","currencyCode"],"properties":{"default":{"type":"boolean","description":"true if the account is the default consumer account"},"type":{"type":"string","description":"Type of the Account. By default if not provided, it is a 'CHECKING' account.","enum":["CHECKING","SAVINGS"]},"number":{"type":"string","minLength":2,"maxLength":24,"pattern":"^[a-zA-Z0-9_]{2,24}$","description":"Account number used for posting to Core Banking System"},"currencyCode":{"$ref":"#/components/schemas/currencyCode"}}},"currencyCode":{"type":"string","pattern":"^[A-Z]{3}$","description":"Currency Code in ISO 4217 alpha code format"},"digitalCardId":{"type":"string","description":"Unique identifier of the digital card.","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]{1,64}$"},"digitalCardState":{"type":"string","description":"the state of the digital card (token)","enum":["ACTIVE","INACTIVE","DELETED","DEPLOYMENT_ONGOING","PENDING_ACTIVATION"],"title":"digitalCardState"},"walletRecommendation":{"type":"string","description":"Wallet/Digital Card Requestor colour recommended during the card tokenization request\n\nPlease note that in certain situations a recommendation might be not provided by the wallet.","enum":["NOT_APPLICABLE","GREEN","YELLOW","ORANGE","RED"]},"errorGeneric":{"additionalProperties":false,"type":"object","description":"Generic error returned by the APIs.","properties":{"errorCode":{"type":"string","description":"The type of the error"},"error":{"type":"string","description":"Provide more error details if possible.<br/>For example name of the field with invalid format.<br/>This field is for troubleshooting purposes only, it can change at any time so MUST NOT be parsed, and is not supposed to be human readable so CANNOT be displayed to end users."}}}},"responses":{"ServiceUnavailableError":{"description":"The service is temporarily unavailable. You may retry your request later."}}},"paths":{"/v2/issuers/{issuerId}/cards/{cardId}":{"get":{"description":"This request is used by the bank backend to request card details.","responses":{"200":{"description":"Successful get card details","content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","required":["consumerId","cardId","cardProductId","scheme","panSuffix","exp","state","ongoingOperation","creationTime"],"properties":{"consumerId":{"$ref":"#/components/schemas/consumerId"},"cardId":{"$ref":"#/components/schemas/cardId"},"newCardId":{"$ref":"#/components/schemas/newCardId"},"cardProductId":{"$ref":"#/components/schemas/cardProductId"},"threeDSsupport":{"$ref":"#/components/schemas/threeDSsupport"},"scheme":{"$ref":"#/components/schemas/scheme"},"auxiliaryScheme":{"$ref":"#/components/schemas/auxiliaryScheme"},"panSuffix":{"$ref":"#/components/schemas/cardLast4"},"exp":{"$ref":"#/components/schemas/cardExpiryDate"},"newExp":{"$ref":"#/components/schemas/newCardExpiryDate"},"state":{"$ref":"#/components/schemas/cardState"},"stateReason":{"description":"reason associated to the state","type":"string","enum":["CLOSED_ACCOUNT","CLOSED_CARD","CARD_LOST","CARD_FOUND","CARD_STOLEN","CARD_BROKEN","CARD_NOT_RECEIVED","FRAUD","USER_DECISION","ISSUER_DECISION","CVV2_LOCKED","EXPIRY_DATE_LOCKED","PIN_LOCKED"]},"ongoingOperation":{"type":"string","enum":["NONE","RENEWAL"]},"creationTime":{"$ref":"#/components/schemas/creationDate"},"lastUpdateTime":{"$ref":"#/components/schemas/lastUpdate"},"accountList":{"type":"array","description":"This represent the list of account the card will be attached to.<br/>This list is used for the posting","items":{"$ref":"#/components/schemas/AccountInformation"}},"digitalCards":{"type":"array","description":"List of digital cards associated to the card.","items":{"additionalProperties":false,"type":"object","properties":{"id":{"$ref":"#/components/schemas/digitalCardId"},"state":{"$ref":"#/components/schemas/digitalCardState"},"recommendation":{"$ref":"#/components/schemas/walletRecommendation"}}}}}}}}},"400":{"description":"Bad Request, Invalid request URI, header, paramters. The below table defines the possible 'Bad request' error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | yes        | No error details available         |\n| FIELD_INVALID_FORMAT |  Contains the field in error (first found) | no | One field is not expected format as defined in this documentation |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"401":{"description":"Unauthorized request, the provided Authorization header is missing or invalid. In the table below only the field \"error\" is provided.\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| AUTHORIZER_UNAUTHORIZED  | Unauthorized message | no | Access token not valid       |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"403":{"description":"Forbidden action detected by WAF or the application.<br>\nThe below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| AUTHORIZER_FORBIDDEN  | not authorized error message | no | User is not authorized to access this resource |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"404":{"description":"Ressource not found, Unknown issuerId or consumerId or card id'. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no | No error details available         |\n| UNKNOWN_CARD  | -        | no | Unknown cardId |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"500":{"description":"Internal Server Error. The below table defines the possible error:\n|errorCode       | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | yes        | No error details available         |\n| INTERNAL_ERROR | error details if any | no | The server has encountered an error when executing the request.  |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"503":{"$ref":"#/components/responses/ServiceUnavailableError"}},"summary":"Get card details","operationId":"getCardDetails","tags":["Card"]}}}}
```

## Get Card Credentials

> This request is used by the bank backend to retrieve the card credentials.\<br>\
> If the card supports Dynamic CVV2 (DCVV2), a new DCVV2 is generated at each request and is provided in the encrypted card credentials using cvv parameter value.\<br>\
> The Dynamic CVV2 support is defined in card product definition during onboarding.

```json
{"openapi":"3.0.0","info":{"title":"D1 Inbound Card API","version":"2.0"},"tags":[{"name":"Card Credentials","description":"API to get and verify card credentials."}],"servers":[{"url":"https://api.d1.thalescloud.io/banking","description":"Production server"},{"url":"https://api.d1-stg.thalescloud.io/banking","description":"Staging server"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"A JWT generated by the [Get Authorization Token API](oauth2-api).<br/>The server checks the validity of the provided token to control access to this protected resource. Please refer to [Get OAuth 2.0 access token](../../../integrate-the-d1-api/get-oauth-2.0-access-token) for more details on the flow and on how to get this JWT.","type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"errorGeneric":{"additionalProperties":false,"type":"object","description":"Generic error returned by the APIs.","properties":{"errorCode":{"type":"string","description":"The type of the error"},"error":{"type":"string","description":"Provide more error details if possible.<br/>For example name of the field with invalid format.<br/>This field is for troubleshooting purposes only, it can change at any time so MUST NOT be parsed, and is not supposed to be human readable so CANNOT be displayed to end users."}}}},"responses":{"ServiceUnavailableError":{"description":"The service is temporarily unavailable. You may retry your request later."}}},"paths":{"/v2/issuers/{issuerId}/cards/{cardId}/credentials":{"get":{"description":"This request is used by the bank backend to retrieve the card credentials.<br>\nIf the card supports Dynamic CVV2 (DCVV2), a new DCVV2 is generated at each request and is provided in the encrypted card credentials using cvv parameter value.<br>\nThe Dynamic CVV2 support is defined in card product definition during onboarding.","responses":{"200":{"description":"Successful get card credentials","content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","required":["encryptedData"],"properties":{"encryptedData":{"type":"string","maxLength":8192,"pattern":"^(?:[\\x20-\\x2D\\x2F-\\x7F]*\\.){4}(?:[\\x20-\\x2D\\x2F-\\x7F]*)$","description":"The encryptedData is the encrypted json (cf http://www.json.org/) representation of the Card information.\nThis value is encrypted using the JWE encryption (please refer to the **[Encrypt sensitive data](../../../integrate-the-d1-api/encrypt-sensitive-data)** for more details)\n<br/><br/>Content\n<br/>Once deciphered, the plaintext contains a json structure with:\n|JSON field parameter name|description|MOC|Format|\n|-------|-------|-------|-------|\n|pan|The pan value.|M|string - up to 19 digits|\n|exp|The expiry date of the card.|M|string - 4 digits, following the format MMYY|\n|name|The card holder name.|O|string - up to 26 characters |\n|cvv|The CVV2 or DCVV2 value of the card<br>|M|string - 3 or 4 digits|"}}}}}},"400":{"description":"Bad Request, Invalid request URI, header, paramters. The below table defines the possible 'Bad request' error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| FIELD_INVALID_FORMAT |  Contains the field in error (first found) | no | One field is not expected format as defined in this documentation |","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"401":{"description":"Unauthorized request, the provided Authorization header is missing or invalid. \nIn the table below only the field \\\"error\\\" is provided.<br>\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -------------------------------------|\n| AUTHORIZER_UNAUTHORIZED  | Unauthorized_message | no | Access token not valid   |","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"403":{"description":"Forbidden action detected by WAF or the application.<br>\nThe below table defines the possible error:\n  | errorCode      | error       | Retryable | Comments                           |\n  | -------------- | ------------| ----------| -----------------------------------|\n  | -              | -           | no        | No error details available         |\n  | AUTHORIZER_FORBIDDEN  | not_authorized error message | no | User is not authorized to access this resource |\n  | CARD_INVALID_STATE    | - | no | Impossible to get card credentials as the card is DELETED, SUSPENDED or REPLACED. |","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"404":{"description":"Ressource not found, Unknown issuerId or consumerId or card id'. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no | No error details available         |\n| UNKNOWN_CARD  | -        | no | Unknown cardId |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"500":{"description":"Internal Server Error. The below table defines the possible error:\n|errorCode       | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | yes        | No error details available         |\n| INTERNAL_ERROR | error details if any | no | The server has encountered an error when executing the request.  |\n| WRONG_CONFIGURATION | Missing key configuration for encryption | The server is not configured to performe the encryption of card information | \n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"503":{"$ref":"#/components/responses/ServiceUnavailableError"}},"summary":"Get Card Credentials","operationId":"getCardCredentials","tags":["Card Credentials"]}}}}
```

## Verify Card Credentials

> This request is used by the bank backend to verify the card credentials.\
> \<br>\
> The request is successful if all parameters from encrypted card details (pan, expiry date or cvv) are valid.\
> \<br>\
> If the cardId is provided, then D1 will first retreive the card credentials using the cardId and then compare with provided card credentials.\
> \<br> \
> If the card supports Dynamic CVV2 (DCVV2), the cvv parameter value from encrypted card credentials must equal an actvive DCVV2.\<br>\
> A DCVV2 is active when a DCVV2 has been generated, not expired and not used for any type of transaction.\<br>\
> The Dynamic CVV2 support is defined in the card product definition during onboarding.<br>

```json
{"openapi":"3.0.0","info":{"title":"D1 Inbound Card API","version":"2.0"},"tags":[{"name":"Card Credentials","description":"API to get and verify card credentials."}],"servers":[{"url":"https://api.d1.thalescloud.io/banking","description":"Production server"},{"url":"https://api.d1-stg.thalescloud.io/banking","description":"Staging server"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"A JWT generated by the [Get Authorization Token API](oauth2-api).<br/>The server checks the validity of the provided token to control access to this protected resource. Please refer to [Get OAuth 2.0 access token](../../../integrate-the-d1-api/get-oauth-2.0-access-token) for more details on the flow and on how to get this JWT.","type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"cardId":{"type":"string","description":"Unique identifier of the card.","minLength":1,"maxLength":48,"pattern":"^[A-Za-z0-9_-]{1,48}$"},"errorGeneric":{"additionalProperties":false,"type":"object","description":"Generic error returned by the APIs.","properties":{"errorCode":{"type":"string","description":"The type of the error"},"error":{"type":"string","description":"Provide more error details if possible.<br/>For example name of the field with invalid format.<br/>This field is for troubleshooting purposes only, it can change at any time so MUST NOT be parsed, and is not supposed to be human readable so CANNOT be displayed to end users."}}}},"responses":{"ServiceUnavailableError":{"description":"The service is temporarily unavailable. You may retry your request later."}}},"paths":{"/v2/issuers/{issuerId}/cards/credentials":{"post":{"description":"This request is used by the bank backend to verify the card credentials.\n<br>\nThe request is successful if all parameters from encrypted card details (pan, expiry date or cvv) are valid.\n<br>\nIf the cardId is provided, then D1 will first retreive the card credentials using the cardId and then compare with provided card credentials.\n<br> \nIf the card supports Dynamic CVV2 (DCVV2), the cvv parameter value from encrypted card credentials must equal an actvive DCVV2.<br>\nA DCVV2 is active when a DCVV2 has been generated, not expired and not used for any type of transaction.<br>\nThe Dynamic CVV2 support is defined in the card product definition during onboarding.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"cardId":{"$ref":"#/components/schemas/cardId"},"encryptedData":{"type":"string","title":"encryptedData","maxLength":8192,"pattern":"^(?:[\\x20-\\x2D\\x2F-\\x7F]*\\.){4}(?:[\\x20-\\x2D\\x2F-\\x7F]*)$","description":"The encryptedData is the encrypted json (cf http://www.json.org/) representation of the Card information.\nThis value is encrypted using the JWE encryption (please refer to the **[Encrypt sensitive data](../../../integrate-the-d1-api/encrypt-sensitive-data)** for more details)\n<br/>Content\n<br/><br/>Once deciphered, the plaintext contains a json structure with:\n|JSON field parameter name|description|MOC|Format|\n|-------|-------|-------|-------|\n|pan|The  pan value.|M|string - up to 19 digits|\n|exp|The expiry date of the card.|M|string - 4 digits, following the format MMYY|\n|cvv|The CVV2 or DCVV2 of the card.|M|string - 3 or 4 digits|\n"}},"required":["encryptedData"]}}}},"responses":{"200":{"description":"Successful card verification.","content":{"application/json":{"schema":{"additionalProperties":false,"description":"The cardId of the card that has been successfully verified.","type":"object","required":["cardId"],"properties":{"cardId":{"$ref":"#/components/schemas/cardId"}}}}}},"400":{"description":"Bad Request, Invalid request URI, header, paramters. The below table defines the possible 'Bad request' error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| FIELD_INVALID_FORMAT |  Contains the field in error (first found) | no | One field is not expected format as defined in this documentation |\n| CRYPTO_ERROR  | - | no | Not possible to decrypt the provided encrypted data |\n| INVALID_PAN   | pan value is not verified | no | The pan from encrypted card information is not matching the referenced card pan |\n| INVALID_EXPIRY_DATE   | exp value is not verified | no | The exp from encrypted card information is not matching the referenced card expiry date |\n| INVALID_CVV2   | cvv2 value is not verified | no | The cvv from encrypted card information is not matching the referenced card CVV2 or active DCVV2  |\n| NO_ACTIVE_DCVV2   | cvv2/dcvv2 not provided from referenced card | no | The cvv from referenced card CVV2 or active DCVV2 is empty  |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"401":{"description":"Unauthorized request, the provided Authorization header is missing or invalid. \nIn the table below only the field \\\"error\\\" is provided.<br>\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -------------------------------------|\n| AUTHORIZER_UNAUTHORIZED  | Unauthorized_message | no | Access token not valid   |","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"403":{"description":"Forbidden action detected by WAF or the application.<br>\nThe below table defines the possible error:\n  | errorCode      | error       | Retryable | Comments                           |\n  | -------------- | ------------| ----------| -----------------------------------|\n  | -              | -           | no        | No error details available         |\n  | AUTHORIZER_FORBIDDEN  | not_authorized error message | no | User is not authorized to access this resource |\n  | CARD_INVALID_STATE    | - | no | Impossible to get card credentials as the card is DELETED, SUSPENDED or REPLACED. |","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"404":{"description":"Ressource not found, Unknown issuerId or consumerId or card id'. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no | No error details available         |\n| UNKNOWN_CARD  | -        | no | Unknown cardId |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"500":{"description":"Internal Server Error. The below table defines the possible error:\n|errorCode       | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | yes        | No error details available         |\n| INTERNAL_ERROR | error details if any | no | The server has encountered an error when executing the request.  |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"503":{"$ref":"#/components/responses/ServiceUnavailableError"}},"summary":"Verify Card Credentials","operationId":"verifyCardCredentials","tags":["Card Credentials"]}}}}
```

## Get Card Settings

> This request is used by the bank backend to retrieve card settings.

```json
{"openapi":"3.0.0","info":{"title":"D1 Inbound Card API","version":"2.0"},"tags":[{"name":"Card Settings","description":"API to get and update card settings."}],"servers":[{"url":"https://api.d1.thalescloud.io/banking","description":"Production server"},{"url":"https://api.d1-stg.thalescloud.io/banking","description":"Staging server"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"A JWT generated by the [Get Authorization Token API](oauth2-api).<br/>The server checks the validity of the provided token to control access to this protected resource. Please refer to [Get OAuth 2.0 access token](../../../integrate-the-d1-api/get-oauth-2.0-access-token) for more details on the flow and on how to get this JWT.","type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"cardControls":{"additionalProperties":false,"description":"Container to hold the domain controls available.","type":"object","required":["onlinePayment","abroadPayment","deniedCurrencies","geography","merchants"],"properties":{"onlinePayment":{"description":"Is online payment (eCommerce) enabled or not for this card.","type":"boolean"},"contactless":{"description":"Is contactless payment enabled or not for the card.<br/>Not provided if control is not available (card product definition)","type":"boolean"},"magstripe":{"description":"Is magstripe payment enabled or not for the card.<br/>Not provided if control is not available (card product definition)","type":"boolean"},"withdrawal":{"description":"Is ATM withdrawal enabled or not for the card.<br/>Not provided if control is not available (card product definition)","type":"boolean"},"abroadPayment":{"description":"Is payment abroad enabled or not for the card","type":"boolean"},"deniedCurrencies":{"description":"List of currencies that will be declined for authorization in ISO 4217 alpha code format","type":"array","items":{"$ref":"#/components/schemas/currencyCode"}},"geography":{"additionalProperties":false,"description":"Contains the list of countries and regions that the card is allowed to use.<br/>if georgraphy is not defined then no geography control is performed; the card can be used all around the world","type":"object","required":["regions","countries"],"properties":{"regions":{"type":"array","description":"List of included Region purchase/withdrawal is allowed","items":{"$ref":"#/components/schemas/Regions"}},"countries":{"type":"array","description":"List of included Country code in ISO 3166-1 alpha-2 format purchase/withdrawal is allowed","items":{"$ref":"#/components/schemas/countryCode"}}}},"merchants":{"additionalProperties":false,"description":"Set of controls applied on merchant category","type":"object","required":["gambling","adult","risky"],"properties":{"gambling":{"description":"If payment is enabled with merchant that has gambling activities","type":"boolean"},"adult":{"description":"If payment is enabled with merchant that has adult activities","type":"boolean"},"risky":{"description":"If payment is enabled with merchant that has been categorised as risky by the scheme","type":"boolean"}}}}},"currencyCode":{"type":"string","pattern":"^[A-Z]{3}$","description":"Currency Code in ISO 4217 alpha code format"},"Regions":{"type":"string","enum":["SCHENGEN_AREA","EASTERN_EUROPE","WESTERN_EUROPE","NORTHERN_EUROPE","SOUTHERN_EUROPE","MIDDLE_EAST","NORTH_AFRICA","EAST_AFRICA","CENTRAL_AFRICA","SOUTHERN_AFRICA","WEST_AFRICA","CENTRAL_ASIA","EAST_ASIA","WEST_ASIA","SOUTH_ASIA","SOUTHEAST_ASIA","OCEANIA","CARIBBEAN","CENTRAL_AMERICA","NORTH_AMERICA","SOUTH_AMERICA"]},"countryCode":{"type":"string","description":"Country code in ISO 3166-1 alpha-2 format","minLength":2,"maxLength":2,"pattern":"^[A-Z]{2}$"},"cardLimits":{"additionalProperties":false,"description":"Container to hold all available limits defined at card product.<br> Not provided if no limits defined.","type":"object","properties":{"currencyCode":{"$ref":"#/components/schemas/currencyCode"},"purchase":{"$ref":"#/components/schemas/cardLimitPurchases"},"withdrawal":{"$ref":"#/components/schemas/cardLimitWithdrawal"}}},"cardLimitPurchases":{"additionalProperties":false,"description":"Container to hold all available purchases limits defined at card product.<br> Not provided if no purchase limits defined.","type":"object","properties":{"daily":{"$ref":"#/components/schemas/cardLimit"},"weekly":{"$ref":"#/components/schemas/cardLimitByPeriod"},"monthly":{"$ref":"#/components/schemas/cardLimitByPeriod"},"yearly":{"$ref":"#/components/schemas/cardLimitByPeriod"}}},"cardLimit":{"type":"object","required":["limit","maxLimit","currentAmount"],"properties":{"limit":{"type":"integer","description":"Current limit set by the user/issuer on the card. Limit the end-user can update and could not exceed the max limit set by issuer.","minimum":0,"maximum":999999999999},"maxLimit":{"type":"integer","description":"Max limit set by the issuer, it represent the maximum limit the end-user can set for its own card limit.","minimum":0,"maximum":999999999999},"currentAmount":{"type":"number","description":"Current amount of money already spent in this limit (amount with digits after decimal point is possible).","minimum":0,"maximum":999999999999}}},"cardLimitByPeriod":{"allOf":[{"type":"object","required":["periodType"],"properties":{"periodType":{"type":"string","enum":["fixed","rolling"]},"periodIndex":{"type":"integer","description":"Only provided in case of Weekly, Monthly or Yearly Fixed period.<br/>- For weekly fixed period, the allowed values are 1 to 7 and it represents the start day of the week (1 for Monday, 2 for tuesday, etc..)<br/>- For monthly fixed period, the allowed values are 1 to 31 and it represents the start day of the monthly period<br/>- For yearly fixed period, allowed values are 1 to 12 and it represents the start month of yearly period.","minimum":1,"maximum":31}}},{"$ref":"#/components/schemas/cardLimit"}]},"cardLimitWithdrawal":{"additionalProperties":false,"description":"Container to hold all available withdrawal limits defined at card product.<br>  Not provided if no withdraw limits defined.","type":"object","properties":{"daily":{"$ref":"#/components/schemas/cardLimit"},"weekly":{"$ref":"#/components/schemas/cardLimitByPeriod"},"monthly":{"$ref":"#/components/schemas/cardLimitByPeriod"},"yearly":{"$ref":"#/components/schemas/cardLimitByPeriod"}}},"errorGeneric":{"additionalProperties":false,"type":"object","description":"Generic error returned by the APIs.","properties":{"errorCode":{"type":"string","description":"The type of the error"},"error":{"type":"string","description":"Provide more error details if possible.<br/>For example name of the field with invalid format.<br/>This field is for troubleshooting purposes only, it can change at any time so MUST NOT be parsed, and is not supposed to be human readable so CANNOT be displayed to end users."}}}},"responses":{"ServiceUnavailableError":{"description":"The service is temporarily unavailable. You may retry your request later."}}},"paths":{"/v2/issuers/{issuerId}/cards/{cardId}/settings":{"get":{"description":"This request is used by the bank backend to retrieve card settings.","responses":{"200":{"description":"Successful get card settings","content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","required":["controls","limits"],"properties":{"controls":{"$ref":"#/components/schemas/cardControls"},"limits":{"$ref":"#/components/schemas/cardLimits"}}}}}},"400":{"description":"Bad Request, Invalid request URI, header, paramters. The below table defines the possible 'Bad request' error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| FIELD_INVALID_FORMAT |  Contains the field in error (first found) | no | One field is not expected format as defined in this documentation |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"401":{"description":"Unauthorized request, the provided Authorization header is missing or invalid. In the table below only the field \"error\" is provided.\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| AUTHORIZER_UNAUTHORIZED  | Unauthorized message | no | Access token not valid       |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"403":{"description":"Forbidden action detected by WAF or the application.<br>\nThe below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| AUTHORIZER_FORBIDDEN  | not authorized error message | no | User is not authorized to access this resource |\n| CARD_INVALID_STATE  | - | no | Impossible to get card settings as the card is DELETED. |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"404":{"description":"Ressource not found, Unknown issuerId or consumerId or card id'. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | yes | No error details available         |\n| UNKNOWN_CARD  | -        | no | Unknown cardId |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"500":{"description":"Internal Server Error. The below table defines the possible error:\n|errorCode       | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| INTERNAL_ERROR | error details if any | no | The server has encountered an error when executing the request.  |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"503":{"$ref":"#/components/responses/ServiceUnavailableError"}},"summary":"Get Card Settings","operationId":"getCardSettings","tags":["Card Settings"]}}}}
```

## Update Card Controls

> This request is used by the bank backend to update card domain controls.

```json
{"openapi":"3.0.0","info":{"title":"D1 Inbound Card API","version":"2.0"},"tags":[{"name":"Card Settings","description":"API to get and update card settings."}],"servers":[{"url":"https://api.d1.thalescloud.io/banking","description":"Production server"},{"url":"https://api.d1-stg.thalescloud.io/banking","description":"Staging server"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"A JWT generated by the [Get Authorization Token API](oauth2-api).<br/>The server checks the validity of the provided token to control access to this protected resource. Please refer to [Get OAuth 2.0 access token](../../../integrate-the-d1-api/get-oauth-2.0-access-token) for more details on the flow and on how to get this JWT.","type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"cardControlsUpdate":{"additionalProperties":false,"type":"object","properties":{"onlinePayment":{"description":"Set online payment (eCommerce) enabled or not for this card.","type":"boolean"},"contactless":{"description":"Set contactless payment enabled or not for the card.<br/>To not provide if this control is not available (card product definition)","type":"boolean"},"magstripe":{"description":"Set magstripe payment enabled or not for the card.<br/>To not provide if this control is not available (card product definition)","type":"boolean"},"withdrawal":{"description":"Set ATM withdraw enabled or not for the card.<br/>To not provide if this control is not available (card product definition)","type":"boolean"},"abroadPayment":{"description":"Set payment abroad enabled or not for the card","type":"boolean"},"deniedCurrencies":{"description":"Define the list of currencies that will be declined for authorization in ISO 4217 alpha code format","type":"array","items":{"$ref":"#/components/schemas/currencyCode"}},"geography":{"additionalProperties":false,"description":"Define the list of countries and regions where the card is allowed to be used<br/>If geography is not defined, no geography controls are applied, and the card can be used worldwide<br />Geography controls are applicable only when <strong>abroad payment</strong> is set to true","type":"object","required":["regions","countries"],"properties":{"regions":{"type":"array","description":"List of included Region purchase/withdrawal is allowed","items":{"$ref":"#/components/schemas/Regions"}},"countries":{"type":"array","description":"List of included Country code in ISO 3166-1 alpha-2 format payment/withdraw is allowed","items":{"$ref":"#/components/schemas/countryCode"}}}},"merchants":{"additionalProperties":false,"description":"set of control applied on merchant category","type":"object","required":["gambling","adult","risky"],"properties":{"gambling":{"description":"If payment is enabled with merchant that has gambling activities","type":"boolean"},"adult":{"description":"If payment is enabled with merchant that has adult activities","type":"boolean"},"risky":{"description":"If payment is enabled with merchant that has been categorised as risky by the scheme","type":"boolean"}}}}},"currencyCode":{"type":"string","pattern":"^[A-Z]{3}$","description":"Currency Code in ISO 4217 alpha code format"},"Regions":{"type":"string","enum":["SCHENGEN_AREA","EASTERN_EUROPE","WESTERN_EUROPE","NORTHERN_EUROPE","SOUTHERN_EUROPE","MIDDLE_EAST","NORTH_AFRICA","EAST_AFRICA","CENTRAL_AFRICA","SOUTHERN_AFRICA","WEST_AFRICA","CENTRAL_ASIA","EAST_ASIA","WEST_ASIA","SOUTH_ASIA","SOUTHEAST_ASIA","OCEANIA","CARIBBEAN","CENTRAL_AMERICA","NORTH_AMERICA","SOUTH_AMERICA"]},"countryCode":{"type":"string","description":"Country code in ISO 3166-1 alpha-2 format","minLength":2,"maxLength":2,"pattern":"^[A-Z]{2}$"},"errorGeneric":{"additionalProperties":false,"type":"object","description":"Generic error returned by the APIs.","properties":{"errorCode":{"type":"string","description":"The type of the error"},"error":{"type":"string","description":"Provide more error details if possible.<br/>For example name of the field with invalid format.<br/>This field is for troubleshooting purposes only, it can change at any time so MUST NOT be parsed, and is not supposed to be human readable so CANNOT be displayed to end users."}}}},"responses":{"ServiceUnavailableError":{"description":"The service is temporarily unavailable. You may retry your request later."}}},"paths":{"/v2/issuers/{issuerId}/cards/{cardId}/controls":{"patch":{"description":"This request is used by the bank backend to update card domain controls.","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","required":["controls"],"properties":{"controls":{"$ref":"#/components/schemas/cardControlsUpdate"}}}}}},"responses":{"200":{"description":"Successful card setting update"},"400":{"description":"Bad Request, Invalid request URI, header, paramters. The below table defines the possible 'Bad request' error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| FIELD_INVALID_FORMAT |  Contains the field in error (first found) | no | JSON not well formatted or<br>One field is not expected format as defined in this documentation |\n| FIELD_INVALID_VALUE  |  Contains the field in error (first found) | no | One field value is not allowed for the given field  |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"401":{"description":"Unauthorized request, the provided Authorization header is missing or invalid. In the table below only the field \"error\" is provided.\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| AUTHORIZER_UNAUTHORIZED  | Unauthorized message | no | Access token not valid       |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"403":{"description":"Forbidden action detected by WAF or the application.\nThe below table defines the possible error:\n  | errorCode      | error       | Retryable | Comments                           |\n  | -------------- | ------------| ----------| -----------------------------------|\n  | -              | -           | no        | No error details available         |\n  | AUTHORIZER_FORBIDDEN  | not\\_authorized error message | no | User\\_is\\_not\\_authorized\\_to\\_access\\_this\\_resource |\n  | CARD_INVALID_STATE    | - | no | CardId already registered in the solution and has an invalid card state (REPLACED or DELETED)  |\n  | OPERATION_NOT_ALLOWED | Name of the operation/field that is not allowed in this operation | no | Try to update a control not defined at card product |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"404":{"description":"Ressource not found, Unknown issuerId or consumerId or card id'. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no | No error details available         |\n| UNKNOWN_CARD  | -        | no | Unknown cardId |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"500":{"description":"Internal Server Error. The below table defines the possible error:\n|errorCode       | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | yes        | No error details available         |\n| INTERNAL_ERROR | error details if any | no | The server has encountered an error when executing the request.  |\n"},"503":{"$ref":"#/components/responses/ServiceUnavailableError"}},"summary":"Update Card Controls","operationId":"updateCardControls","tags":["Card Settings"]}}}}
```

## Update Card Limits

> This request is used by the bank backend to update card settings.

```json
{"openapi":"3.0.0","info":{"title":"D1 Inbound Card API","version":"2.0"},"tags":[{"name":"Card Settings","description":"API to get and update card settings."}],"servers":[{"url":"https://api.d1.thalescloud.io/banking","description":"Production server"},{"url":"https://api.d1-stg.thalescloud.io/banking","description":"Staging server"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"A JWT generated by the [Get Authorization Token API](oauth2-api).<br/>The server checks the validity of the provided token to control access to this protected resource. Please refer to [Get OAuth 2.0 access token](../../../integrate-the-d1-api/get-oauth-2.0-access-token) for more details on the flow and on how to get this JWT.","type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"cardLimitsUpdate":{"additionalProperties":false,"type":"object","properties":{"purchase":{"$ref":"#/components/schemas/CardLimitPurchasesUpdate"},"withdrawal":{"$ref":"#/components/schemas/CardLimitWithdrawalUpdate"}}},"CardLimitPurchasesUpdate":{"additionalProperties":false,"description":"Provide this container to update one or several purchase limits<br>Only available purchase limits defined at card product are updatable.","type":"object","properties":{"daily":{"$ref":"#/components/schemas/cardLimitUpdate"},"weekly":{"$ref":"#/components/schemas/cardLimitUpdate"},"monthly":{"$ref":"#/components/schemas/cardLimitUpdate"},"yearly":{"$ref":"#/components/schemas/cardLimitUpdate"}}},"cardLimitUpdate":{"additionalProperties":false,"description":"Allow to update the limits (if available limits).","type":"object","properties":{"limit":{"type":"integer","description":"Current limit set by the user/issuer on the card. Limit the end-user can update and could not exceed the max limit set by issuer.","minimum":0,"maximum":999999999999},"maxLimit":{"type":"integer","description":"Max limit set by the issuer, it represent the maximum limit the user can set for its own card limit.","minimum":0,"maximum":999999999999}}},"CardLimitWithdrawalUpdate":{"additionalProperties":false,"type":"object","description":"Provide this container to update one or several purchase limits<br>Only available withdrawal limits defined at card product are updatable.","properties":{"daily":{"$ref":"#/components/schemas/cardLimitUpdate"},"weekly":{"$ref":"#/components/schemas/cardLimitUpdate"},"monthly":{"$ref":"#/components/schemas/cardLimitUpdate"},"yearly":{"$ref":"#/components/schemas/cardLimitUpdate"}}},"errorGeneric":{"additionalProperties":false,"type":"object","description":"Generic error returned by the APIs.","properties":{"errorCode":{"type":"string","description":"The type of the error"},"error":{"type":"string","description":"Provide more error details if possible.<br/>For example name of the field with invalid format.<br/>This field is for troubleshooting purposes only, it can change at any time so MUST NOT be parsed, and is not supposed to be human readable so CANNOT be displayed to end users."}}}},"responses":{"ServiceUnavailableError":{"description":"The service is temporarily unavailable. You may retry your request later."}}},"paths":{"/v2/issuers/{issuerId}/cards/{cardId}/limits":{"patch":{"description":"This request is used by the bank backend to update card settings.","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","required":["limits"],"properties":{"limits":{"$ref":"#/components/schemas/cardLimitsUpdate"}}}}}},"responses":{"200":{"description":"Successful card setting update"},"400":{"description":"Bad Request, Invalid request URI, header, paramters. The below table defines the possible 'Bad request' error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| FIELD_INVALID_FORMAT |  Contains the field in error (first found) | no | JSON not well formatted or<br>One field is not expected format as defined in this documentation |\n| FIELD_INVALID_VALUE  |  Contains the field in error (first found) | no | One field value is not allowed for the given field  |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"401":{"description":"Unauthorized request, the provided Authorization header is missing or invalid. In the table below only the field \"error\" is provided.\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| AUTHORIZER_UNAUTHORIZED  | Unauthorized message | no | Access token not valid       |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"403":{"description":"Forbidden action detected by WAF or the application.\nThe below table defines the possible error:\n  | errorCode      | error       | Retryable | Comments                           |\n  | -------------- | ------------| ----------| -----------------------------------|\n  | -              | -           | no        | No error details available         |\n  | AUTHORIZER_FORBIDDEN  | not\\_authorized error message | no | User\\_is\\_not\\_authorized\\_to\\_access\\_this\\_resource |\n  | CARD_INVALID_STATE    | - | no | CardId already registered in the solution and has an invalid card state (REPLACED or DELETED)  |\n  | OPERATION_NOT_ALLOWED | Name of the operation/field that is not allowed in this operation | no | Try to update a control not defined at card product |\n"},"404":{"description":"Ressource not found, Unknown issuerId or consumerId or card id'. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no | No error details available         |\n| UNKNOWN_CARD  | -        | no | Unknown cardId |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"500":{"description":"Internal Server Error. The below table defines the possible error:\n|errorCode       | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | yes        | No error details available         |\n| INTERNAL_ERROR | error details if any | no | The server has encountered an error when executing the request.  |\n"},"503":{"$ref":"#/components/responses/ServiceUnavailableError"}},"summary":"Update Card Limits","operationId":"updateCardLimits","tags":["Card Settings"]}}}}
```

## Resume

> This request is used by the bank backend to request the reactivation of a card that has been suspended.\
> The card could have been suspended\
> \- by the bank's backend\
> \- by customer agent\
> \- by end user using the mobile banking application\
> \- or automatically by authorisation system when a payment validation failure retry counter has been exceeded (PIN locked, CVV2 locked or expiry date locked)\
> \
> If the card is locked (PIN locked, CVV2 locked or expiry date), D1 will unlock the card whatever the reason.\
> \
> \*\*Note:\*\* It cannot be used to activate a physical card for the really first time. \
> Please refer to \[activatePhysicalCard]\(<https://thales-dis-dbp.stoplight.io/docs/d1-developer-portal/a2ebfce648687-card-activation>)

```json
{"openapi":"3.0.0","info":{"title":"D1 Inbound Card API","version":"2.0"},"tags":[{"name":"Card Operations","description":"Different operations that can be done on a card."}],"servers":[{"url":"https://api.d1.thalescloud.io/banking","description":"Production server"},{"url":"https://api.d1-stg.thalescloud.io/banking","description":"Staging server"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"A JWT generated by the [Get Authorization Token API](oauth2-api).<br/>The server checks the validity of the provided token to control access to this protected resource. Please refer to [Get OAuth 2.0 access token](../../../integrate-the-d1-api/get-oauth-2.0-access-token) for more details on the flow and on how to get this JWT.","type":"http","scheme":"bearer","bearerFormat":"JWT"}},"parameters":{"issuer-id-path":{"description":"The id of the issuer","in":"path","name":"issuerId","required":true,"schema":{"$ref":"#/components/schemas/issuerId"}},"card-id-path":{"description":"The id of the card","in":"path","name":"cardId","required":true,"schema":{"$ref":"#/components/schemas/cardId"}}},"schemas":{"issuerId":{"maxLength":10,"minLength":10,"type":"string"},"cardId":{"type":"string","description":"Unique identifier of the card.","minLength":1,"maxLength":48,"pattern":"^[A-Za-z0-9_-]{1,48}$"},"reason":{"type":"string","title":"reason","pattern":"^[a-zA-Z0-9 ]{1,64}$","description":"The reason why the action is performed. \n\nThis a free text field in case the bank wants to send details, that will be returned in the operations list. "},"operationId":{"type":"string","description":"Unique identifier of the operation","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]{1,64}$"},"errorGeneric":{"additionalProperties":false,"type":"object","description":"Generic error returned by the APIs.","properties":{"errorCode":{"type":"string","description":"The type of the error"},"error":{"type":"string","description":"Provide more error details if possible.<br/>For example name of the field with invalid format.<br/>This field is for troubleshooting purposes only, it can change at any time so MUST NOT be parsed, and is not supposed to be human readable so CANNOT be displayed to end users."}}}},"responses":{"ServiceUnavailableError":{"description":"The service is temporarily unavailable. You may retry your request later."}}},"paths":{"/v2/issuers/{issuerId}/cards/{cardId}/operations:resume":{"post":{"description":"This request is used by the bank backend to request the reactivation of a card that has been suspended.\nThe card could have been suspended\n- by the bank's backend\n- by customer agent\n- by end user using the mobile banking application\n- or automatically by authorisation system when a payment validation failure retry counter has been exceeded (PIN locked, CVV2 locked or expiry date locked)\n\nIf the card is locked (PIN locked, CVV2 locked or expiry date), D1 will unlock the card whatever the reason.\n\n**Note:** It cannot be used to activate a physical card for the really first time. \nPlease refer to [activatePhysicalCard](https://thales-dis-dbp.stoplight.io/docs/d1-developer-portal/a2ebfce648687-card-activation)","parameters":[{"$ref":"#/components/parameters/issuer-id-path"},{"$ref":"#/components/parameters/card-id-path"},{"$ref":"#/components/parameters/x-correlation-id"},{"$ref":"#/components/parameters/x-user-id"}],"requestBody":{"content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","properties":{"reason":{"$ref":"#/components/schemas/reason"},"stateReason":{"type":"string","description":"The reason why the action has been performed. If not provided, default reason code is ISSUER_DECISION.","enum":["ISSUER_DECISION","USER_DECISION","CARD_FOUND"]}}}}}},"responses":{"200":{"description":"Card resumed Successfully","content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","properties":{"operationId":{"$ref":"#/components/schemas/operationId"}}}}}},"400":{"description":"Bad Request, Invalid request URI, header, paramters. The below table defines the possible 'Bad request' error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| FIELD_INVALID_FORMAT |  Contains the field in error (first found) | no | JSON not well formatted or<br>One field is not expected format as defined in this documentation |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"401":{"description":"Unauthorized request, the provided Authorization header is missing or invalid. In the table below only the field \"error\" is provided.\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| AUTHORIZER_UNAUTHORIZED  | Unauthorized message | no | Access token not valid       |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"403":{"description":"Forbidden action detected by WAF or the application.<br>\nThe below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| AUTHORIZER_FORBIDDEN  | not authorized error message | no | User is not authorized to access this resource |\n| CARD_INVALID_STATE | -           | no    | Resume with this state reason is not allowed      |\n"},"404":{"description":"Ressource not found, Unknown issuerId or consumerId or card id'. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no | No error details available         |\n| UNKNOWN_CARD   | -           | no | Unknown cardId |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"500":{"description":"Internal Server Error. The below table defines the possible error:\n|errorCode       | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | yes        | No error details available         |\n| INTERNAL_ERROR | error details if any | no | The server has encountered an error when executing the request.  |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"503":{"$ref":"#/components/responses/ServiceUnavailableError"}},"summary":"Resume","tags":["Card Operations"],"operationId":"resumeCard"}}}}
```

## Suspend

> This request is used by the bank backend to request the suspention of a card.\<br>\
> When a card is suspended:\
> &#x20; \+ authorization will be declined by the system.\
> &#x20; \+ end user will not be alble to digitize the card.\
> &#x20; \+ But authorization with digital card will be still approved by the system.<br>

```json
{"openapi":"3.0.0","info":{"title":"D1 Inbound Card API","version":"2.0"},"tags":[{"name":"Card Operations","description":"Different operations that can be done on a card."}],"servers":[{"url":"https://api.d1.thalescloud.io/banking","description":"Production server"},{"url":"https://api.d1-stg.thalescloud.io/banking","description":"Staging server"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"A JWT generated by the [Get Authorization Token API](oauth2-api).<br/>The server checks the validity of the provided token to control access to this protected resource. Please refer to [Get OAuth 2.0 access token](../../../integrate-the-d1-api/get-oauth-2.0-access-token) for more details on the flow and on how to get this JWT.","type":"http","scheme":"bearer","bearerFormat":"JWT"}},"parameters":{"issuer-id-path":{"description":"The id of the issuer","in":"path","name":"issuerId","required":true,"schema":{"$ref":"#/components/schemas/issuerId"}},"card-id-path":{"description":"The id of the card","in":"path","name":"cardId","required":true,"schema":{"$ref":"#/components/schemas/cardId"}}},"schemas":{"issuerId":{"maxLength":10,"minLength":10,"type":"string"},"cardId":{"type":"string","description":"Unique identifier of the card.","minLength":1,"maxLength":48,"pattern":"^[A-Za-z0-9_-]{1,48}$"},"reason":{"type":"string","title":"reason","pattern":"^[a-zA-Z0-9 ]{1,64}$","description":"The reason why the action is performed. \n\nThis a free text field in case the bank wants to send details, that will be returned in the operations list. "},"operationId":{"type":"string","description":"Unique identifier of the operation","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]{1,64}$"},"errorGeneric":{"additionalProperties":false,"type":"object","description":"Generic error returned by the APIs.","properties":{"errorCode":{"type":"string","description":"The type of the error"},"error":{"type":"string","description":"Provide more error details if possible.<br/>For example name of the field with invalid format.<br/>This field is for troubleshooting purposes only, it can change at any time so MUST NOT be parsed, and is not supposed to be human readable so CANNOT be displayed to end users."}}}},"responses":{"ServiceUnavailableError":{"description":"The service is temporarily unavailable. You may retry your request later."}}},"paths":{"/v2/issuers/{issuerId}/cards/{cardId}/operations:suspend":{"post":{"description":"This request is used by the bank backend to request the suspention of a card.<br>\nWhen a card is suspended:\n  + authorization will be declined by the system.\n  + end user will not be alble to digitize the card.\n  + But authorization with digital card will be still approved by the system.\n","parameters":[{"$ref":"#/components/parameters/issuer-id-path"},{"$ref":"#/components/parameters/card-id-path"},{"$ref":"#/components/parameters/x-correlation-id"},{"$ref":"#/components/parameters/x-user-id"}],"requestBody":{"content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","properties":{"reason":{"$ref":"#/components/schemas/reason"},"stateReason":{"type":"string","description":"The reason why the action has been performed. If not provided, default reason code is ISSUER_DECISION.","enum":["CARD_LOST","CARD_STOLEN","CARD_BROKEN","FRAUD","USER_DECISION","ISSUER_DECISION"]}}}}}},"responses":{"200":{"description":"Card was suspended Successfully","content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","properties":{"operationId":{"$ref":"#/components/schemas/operationId"}}}}}},"400":{"description":"Bad Request, Invalid request URI, header, paramters. The below table defines the possible 'Bad request' error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| FIELD_INVALID_FORMAT |  Contains the field in error (first found) | no | JSON not well formatted or<br>One field is not expected format as defined in this documentation |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"401":{"description":"Unauthorized request, the provided Authorization header is missing or invalid. In the table below only the field \"error\" is provided.\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| AUTHORIZER_UNAUTHORIZED  | Unauthorized message | no | Access token not valid       |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"403":{"description":"Forbidden action detected by WAF or the application. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| AUTHORIZER_FORBIDDEN  | not authorized error message | no | User is not authorized to access this resource \n| CARD_INVALID_STATE    | -           | no    | Suspension with this state reason is not allowed      |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"404":{"description":"Ressource not found, Unknown issuerId or consumerId or card id'. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no | No error details available         |\n| UNKNOWN_CARD   | -           | no | Unknown cardId |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"500":{"description":"Internal Server Error. The below table defines the possible error:\n|errorCode       | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | yes        | No error details available         |\n| INTERNAL_ERROR | error details if any | no | The server has encountered an error when executing the request.  |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"503":{"$ref":"#/components/responses/ServiceUnavailableError"}},"summary":"Suspend","tags":["Card Operations"],"operationId":"suspendCard"}}}}
```

## Delete

> This request is used by the bank backend to request the deletion of a card. \
> \
> For cards managed by D1 (in oposition to legacy cards that are managed by the issuer), D1 will propagate the deletion/revocation to the processor.\
> \
> \<b>Note:\</b> The deletion of the card cannot be reverted. In case of card lost consider using the suspend operation first.

```json
{"openapi":"3.0.0","info":{"title":"D1 Inbound Card API","version":"2.0"},"tags":[{"name":"Card Operations","description":"Different operations that can be done on a card."}],"servers":[{"url":"https://api.d1.thalescloud.io/banking","description":"Production server"},{"url":"https://api.d1-stg.thalescloud.io/banking","description":"Staging server"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"A JWT generated by the [Get Authorization Token API](oauth2-api).<br/>The server checks the validity of the provided token to control access to this protected resource. Please refer to [Get OAuth 2.0 access token](../../../integrate-the-d1-api/get-oauth-2.0-access-token) for more details on the flow and on how to get this JWT.","type":"http","scheme":"bearer","bearerFormat":"JWT"}},"parameters":{"issuer-id-path":{"description":"The id of the issuer","in":"path","name":"issuerId","required":true,"schema":{"$ref":"#/components/schemas/issuerId"}},"card-id-path":{"description":"The id of the card","in":"path","name":"cardId","required":true,"schema":{"$ref":"#/components/schemas/cardId"}}},"schemas":{"issuerId":{"maxLength":10,"minLength":10,"type":"string"},"cardId":{"type":"string","description":"Unique identifier of the card.","minLength":1,"maxLength":48,"pattern":"^[A-Za-z0-9_-]{1,48}$"},"reason":{"type":"string","title":"reason","pattern":"^[a-zA-Z0-9 ]{1,64}$","description":"The reason why the action is performed. \n\nThis a free text field in case the bank wants to send details, that will be returned in the operations list. "},"operationId":{"type":"string","description":"Unique identifier of the operation","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]{1,64}$"},"errorGeneric":{"additionalProperties":false,"type":"object","description":"Generic error returned by the APIs.","properties":{"errorCode":{"type":"string","description":"The type of the error"},"error":{"type":"string","description":"Provide more error details if possible.<br/>For example name of the field with invalid format.<br/>This field is for troubleshooting purposes only, it can change at any time so MUST NOT be parsed, and is not supposed to be human readable so CANNOT be displayed to end users."}}}},"responses":{"ServiceUnavailableError":{"description":"The service is temporarily unavailable. You may retry your request later."}}},"paths":{"/v2/issuers/{issuerId}/cards/{cardId}/operations:delete":{"post":{"description":"This request is used by the bank backend to request the deletion of a card. \n\nFor cards managed by D1 (in oposition to legacy cards that are managed by the issuer), D1 will propagate the deletion/revocation to the processor.\n\n<b>Note:</b> The deletion of the card cannot be reverted. In case of card lost consider using the suspend operation first.","parameters":[{"$ref":"#/components/parameters/issuer-id-path"},{"$ref":"#/components/parameters/card-id-path"},{"$ref":"#/components/parameters/x-correlation-id"},{"$ref":"#/components/parameters/x-user-id"}],"requestBody":{"content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","properties":{"reason":{"$ref":"#/components/schemas/reason"},"stateReason":{"type":"string","description":"The reason why the action has been performed. If not provided, default reason code is ISSUER_DECISION.","enum":["CLOSED_ACCOUNT","CLOSED_CARD","CARD_LOST","CARD_STOLEN","CARD_BROKEN","CARD_NOT_RECEIVED","FRAUD","ISSUER_DECISION"]}}}}}},"responses":{"200":{"description":"Card was deleted Successfully","content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","properties":{"operationId":{"$ref":"#/components/schemas/operationId"}}}}}},"400":{"description":"Bad Request, Invalid request URI, header, paramters. The below table defines the possible 'Bad request' error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| FIELD_INVALID_FORMAT |  Contains the field in error (first found) | no | JSON not well formatted or<br>One field is not expected format as defined in this documentation |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"401":{"description":"Unauthorized request, the provided Authorization header is missing or invalid. In the table below only the field \"error\" is provided.\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| AUTHORIZER_UNAUTHORIZED  | Unauthorized message | no | Access token not valid       |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"403":{"description":"Forbidden action detected by WAF or the application.<br>\nThe below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| AUTHORIZER_FORBIDDEN  | not authorized error message | no | User is not authorized to access this resource |\n| CARD_INVALID_STATE | -           | no    | Possible error is card already deleted with an other reason     |\n"},"404":{"description":"Ressource not found, Unknown issuerId or consumerId or card id'. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no | No error details available         |\n| UNKNOWN_CARD   | -           | no | Unknown cardId |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"500":{"description":"Internal Server Error. The below table defines the possible error:\n|errorCode       | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | yes        | No error details available         |\n| INTERNAL_ERROR | error details if any | no | The server has encountered an error when executing the request.  |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"503":{"$ref":"#/components/responses/ServiceUnavailableError"}},"summary":"Delete","tags":["Card Operations"],"operationId":"deleteCard-v2"}}}}
```

## Replace

> End user can request the bank a replacement of an existing card because the card has been lost or damaged.\<br>\
> The replaced card is blocked until the new card is activated.\<br> \
> The new card has a new cardId and a new card credentials (PAN and expiry date).\<br>\
> In the particular case of Virtual Card, the new Virtual Card is automaticaly activated.\
> \
> \
> D1 manages to re-link automatically digital card from the old card to the new card upon activation.\
> \
> For card registered in D1, the bank backend shall provide new cardId and new card credentials when calling the API.\
> The new cardId used to replace the card shall be unique. The new cardId can be reused from another card (having a different PAN) under several conditions :\
> &#x20; \- The cardId to be reused is linked with a DELETED or REPLACED card (thus it's not possible to use the current cardId as newCardID when doing a replace)\
> &#x20; \- The cardId to be reused is not associated to a card issued by D1 (a card created using the CREATE card API).\
> &#x20; \- The cardId to be reused is not associated with a card product used for making transactions\
> &#x20; \- In any case, it is not possible to use a card PAN already deleted or replaced. Even by reusing a cardId.\
> Reusing a cardId for another consumer is not recommanded. Since the cardId will disappear from the previous consumer cards list. \
> \
> \
> For card created by D1, D1 will generate a new cardId and new card credentials. Thus the newCardId shall not be provided by the issuer when calling this API.

```json
{"openapi":"3.0.0","info":{"title":"D1 Inbound Card API","version":"2.0"},"tags":[{"name":"Card Operations","description":"Different operations that can be done on a card."}],"servers":[{"url":"https://api.d1.thalescloud.io/banking","description":"Production server"},{"url":"https://api.d1-stg.thalescloud.io/banking","description":"Staging server"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"A JWT generated by the [Get Authorization Token API](oauth2-api).<br/>The server checks the validity of the provided token to control access to this protected resource. Please refer to [Get OAuth 2.0 access token](../../../integrate-the-d1-api/get-oauth-2.0-access-token) for more details on the flow and on how to get this JWT.","type":"http","scheme":"bearer","bearerFormat":"JWT"}},"parameters":{"issuer-id-path":{"description":"The id of the issuer","in":"path","name":"issuerId","required":true,"schema":{"$ref":"#/components/schemas/issuerId"}},"card-id-path":{"description":"The id of the card","in":"path","name":"cardId","required":true,"schema":{"$ref":"#/components/schemas/cardId"}}},"schemas":{"issuerId":{"maxLength":10,"minLength":10,"type":"string"},"cardId":{"type":"string","description":"Unique identifier of the card.","minLength":1,"maxLength":48,"pattern":"^[A-Za-z0-9_-]{1,48}$"},"newCardId":{"type":"string","description":"Unique identifier of the new card. Provided in case the card is in REPLACED state.","minLength":1,"maxLength":48,"pattern":"^[A-Za-z0-9_-]{1,48}$"},"reason":{"type":"string","title":"reason","pattern":"^[a-zA-Z0-9 ]{1,64}$","description":"The reason why the action is performed. \n\nThis a free text field in case the bank wants to send details, that will be returned in the operations list. "},"operationId":{"type":"string","description":"Unique identifier of the operation","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]{1,64}$"},"errorGeneric":{"additionalProperties":false,"type":"object","description":"Generic error returned by the APIs.","properties":{"errorCode":{"type":"string","description":"The type of the error"},"error":{"type":"string","description":"Provide more error details if possible.<br/>For example name of the field with invalid format.<br/>This field is for troubleshooting purposes only, it can change at any time so MUST NOT be parsed, and is not supposed to be human readable so CANNOT be displayed to end users."}}}},"responses":{"ServiceUnavailableError":{"description":"The service is temporarily unavailable. You may retry your request later."}}},"paths":{"/v2/issuers/{issuerId}/cards/{cardId}/operations:replace":{"post":{"description":"End user can request the bank a replacement of an existing card because the card has been lost or damaged.<br>\nThe replaced card is blocked until the new card is activated.<br> \nThe new card has a new cardId and a new card credentials (PAN and expiry date).<br>\nIn the particular case of Virtual Card, the new Virtual Card is automaticaly activated.\n\n\nD1 manages to re-link automatically digital card from the old card to the new card upon activation.\n\nFor card registered in D1, the bank backend shall provide new cardId and new card credentials when calling the API.\nThe new cardId used to replace the card shall be unique. The new cardId can be reused from another card (having a different PAN) under several conditions :\n  - The cardId to be reused is linked with a DELETED or REPLACED card (thus it's not possible to use the current cardId as newCardID when doing a replace)\n  - The cardId to be reused is not associated to a card issued by D1 (a card created using the CREATE card API).\n  - The cardId to be reused is not associated with a card product used for making transactions\n  - In any case, it is not possible to use a card PAN already deleted or replaced. Even by reusing a cardId.\nReusing a cardId for another consumer is not recommanded. Since the cardId will disappear from the previous consumer cards list. \n\n\nFor card created by D1, D1 will generate a new cardId and new card credentials. Thus the newCardId shall not be provided by the issuer when calling this API.","parameters":[{"$ref":"#/components/parameters/issuer-id-path"},{"$ref":"#/components/parameters/card-id-path"},{"$ref":"#/components/parameters/x-correlation-id"},{"$ref":"#/components/parameters/x-user-id"}],"requestBody":{"content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","properties":{"newCardId":{"$ref":"#/components/schemas/newCardId"},"encryptedData":{"type":"string","title":"encryptedData","maxLength":8192,"pattern":"^(?:[\\x20-\\x2D\\x2F-\\x7F]*\\.){4}(?:[\\x20-\\x2D\\x2F-\\x7F]*)$","description":"The encryptedData has to be provided in case of card registered in D1. It is not needed for card created by D1.<br>\nThe encryptedData is the encrypted json (cf http://www.json.org/) representation of the Card information.\nThis value is encrypted using the JWE encryption (please refer to the **[Encrypt sensitive data](../../../integrate-the-d1-api/encrypt-sensitive-data)** for more details)\n<br/><br/>Once deciphered, the plaintext contains a json structure with:\n|JSON field parameter name|description|MOC|Format|\n|-------|-------|-------|-------|\n|pan|The funding pan value.|M|string - up to 19 digits|\n|exp|The expiry date of the card.|M|string - 4 digits, following the format MMYY|\n|auxiliaryPan|The auxiliary funding pan value. It shall be provided when cobadge is supported and if the card has an auxiliary pan.|C|string - up to 19 digits|\n|auxiliaryExp|The auxiliary expiry date of the card. It shall be provided when cobadge is supported and if the card has an auxiliary pan.|C|string - 4 digits, following the format MMYY|\n\n<br>\n<br>                \n"},"reason":{"$ref":"#/components/schemas/reason"},"stateReason":{"type":"string","description":"The reason why the action has been performed. If not provided, default reason code is ISSUER_DECISION.","enum":["CARD_LOST","CARD_STOLEN","CARD_BROKEN","CARD_NOT_RECEIVED","FRAUD","ISSUER_DECISION"]}},"required":["reason","stateReason"]}}}},"responses":{"200":{"description":"Card was replaced Successfully","content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","required":["newCardId"],"properties":{"operationId":{"$ref":"#/components/schemas/operationId"},"newCardId":{"$ref":"#/components/schemas/cardId"}}}}}},"400":{"description":"Bad Request, Invalid request URI, header, paramters. The below table defines the possible 'Bad request' error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| FIELD_INVALID_FORMAT |  Contains the field in error (first found) | no | JSON not well formatted or<br>One field is not expected format as defined in this documentation |\n| FIELD_INVALID_VALUE  |  Contains the field in error (first found) | no | One field value is not allowed for the given field  |\n| CRYPTO_ERROR | - | no | Not possible to decrypt the provided encrypted data |\n| INVALID_PAN | - | no | PAN is invalid |\n| INVALID_EXPIRY_DATE |  Expiry date is invalid |            \n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"401":{"description":"Unauthorized request, the provided Authorization header is missing or invalid. In the table below only the field \"error\" is provided.\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| AUTHORIZER_UNAUTHORIZED  | Unauthorized message | no | Access token not valid       |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"403":{"description":"Forbidden action detected by WAF or the application. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| AUTHORIZER_FORBIDDEN  | not authorized error message | no | User is not authorized to access this resource \n| CARD_INVALID_STATE    | -           | no    | The card to replace is in invalid state (DELETED, REPLACED)      |\n| CARD_ALREADY_EXISTS   | -           | no    | The new card referenced by newCardId or new PAN already exists in the solution |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"404":{"description":"Ressource not found, Unknown issuerId or consumerId or card id'. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no | No error details available         |\n| UNKNOWN_CARD   | -           | no | Unknown cardId |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"500":{"description":"Internal Server Error. The below table defines the possible error:\n|errorCode       | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | yes        | No error details available         |\n| INTERNAL_ERROR | error details if any | no | The server has encountered an error when executing the request.  |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"503":{"$ref":"#/components/responses/ServiceUnavailableError"}},"summary":"Replace","tags":["Card Operations"],"operationId":"replaceCard-v2"}}}}
```

## Renew

> Card renewal is the process where a new card is provided to end-user. The new card has new expiry date, but cardId and PAN are remaining the same.\
> \
> For card registered in D1, this request is used by the bank backend to inform that card has been renewed. In such case the new expiry date shall be provided. Moreover, the auxiliary expiry date of the card shall also be provided for cobadged cards that have an auxiliary pan. \
> \
> For card created by D1, this request is used by the bank backend to manualy request the renewal of an existing card (a new expiry date will be generated by D1).\
> \
> In the particular case of the Virtual Card, the Virtual Card is automaticaly activated.\
> For Physical Card, the renewed card will remain active until:\
> &#x20; \- an explicit activation perfomed using the activation operation using the same cardId as the renew card \
> &#x20; \- an implicit activation following a valid card present transaction (if card product is configured as such)

```json
{"openapi":"3.0.0","info":{"title":"D1 Inbound Card API","version":"2.0"},"tags":[{"name":"Card Operations","description":"Different operations that can be done on a card."}],"servers":[{"url":"https://api.d1.thalescloud.io/banking","description":"Production server"},{"url":"https://api.d1-stg.thalescloud.io/banking","description":"Staging server"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"A JWT generated by the [Get Authorization Token API](oauth2-api).<br/>The server checks the validity of the provided token to control access to this protected resource. Please refer to [Get OAuth 2.0 access token](../../../integrate-the-d1-api/get-oauth-2.0-access-token) for more details on the flow and on how to get this JWT.","type":"http","scheme":"bearer","bearerFormat":"JWT"}},"parameters":{"issuer-id-path":{"description":"The id of the issuer","in":"path","name":"issuerId","required":true,"schema":{"$ref":"#/components/schemas/issuerId"}},"card-id-path":{"description":"The id of the card","in":"path","name":"cardId","required":true,"schema":{"$ref":"#/components/schemas/cardId"}}},"schemas":{"issuerId":{"maxLength":10,"minLength":10,"type":"string"},"cardId":{"type":"string","description":"Unique identifier of the card.","minLength":1,"maxLength":48,"pattern":"^[A-Za-z0-9_-]{1,48}$"},"cardExpiryDate":{"type":"string","description":"Expiry date of the card in MMYY format","pattern":"^(0[1-9]|1[0-2])\\d{2}$"},"reason":{"type":"string","title":"reason","pattern":"^[a-zA-Z0-9 ]{1,64}$","description":"The reason why the action is performed. \n\nThis a free text field in case the bank wants to send details, that will be returned in the operations list. "},"operationId":{"type":"string","description":"Unique identifier of the operation","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]{1,64}$"},"errorGeneric":{"additionalProperties":false,"type":"object","description":"Generic error returned by the APIs.","properties":{"errorCode":{"type":"string","description":"The type of the error"},"error":{"type":"string","description":"Provide more error details if possible.<br/>For example name of the field with invalid format.<br/>This field is for troubleshooting purposes only, it can change at any time so MUST NOT be parsed, and is not supposed to be human readable so CANNOT be displayed to end users."}}}},"responses":{"ServiceUnavailableError":{"description":"The service is temporarily unavailable. You may retry your request later."}}},"paths":{"/v2/issuers/{issuerId}/cards/{cardId}/operations:renew":{"post":{"description":"Card renewal is the process where a new card is provided to end-user. The new card has new expiry date, but cardId and PAN are remaining the same.\n\nFor card registered in D1, this request is used by the bank backend to inform that card has been renewed. In such case the new expiry date shall be provided. Moreover, the auxiliary expiry date of the card shall also be provided for cobadged cards that have an auxiliary pan. \n\nFor card created by D1, this request is used by the bank backend to manualy request the renewal of an existing card (a new expiry date will be generated by D1).\n\nIn the particular case of the Virtual Card, the Virtual Card is automaticaly activated.\nFor Physical Card, the renewed card will remain active until:\n  - an explicit activation perfomed using the activation operation using the same cardId as the renew card \n  - an implicit activation following a valid card present transaction (if card product is configured as such)","parameters":[{"$ref":"#/components/parameters/issuer-id-path"},{"$ref":"#/components/parameters/card-id-path"},{"$ref":"#/components/parameters/x-correlation-id"},{"$ref":"#/components/parameters/x-user-id"}],"requestBody":{"content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","properties":{"newExp":{"$ref":"#/components/schemas/cardExpiryDate"},"newAuxiliaryExp":{"$ref":"#/components/schemas/cardExpiryDate"},"reason":{"$ref":"#/components/schemas/reason"},"stateReason":{"type":"string","description":"The reason why the action has been performed. If not provided, default reason code is ISSUER_DECISION.","enum":["ISSUER_DECISION","USER_DECISION","CARD_EXPIRED"]}}}}}},"responses":{"200":{"description":"Card was renewed Successfully","content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","properties":{"operationId":{"$ref":"#/components/schemas/operationId"}}}}}},"400":{"description":"Bad Request, Invalid request URI, header, paramters. The below table defines the possible 'Bad request' error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| FIELD_INVALID_FORMAT |  Contains the field in error (first found) | no | JSON not well formatted or<br>One field is not expected format as defined in this documentation |\n| FIELD_INVALID_VALUE  |  Contains the field in error (first found) | no | One field is  |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"401":{"description":"Unauthorized request, the provided Authorization header is missing or invalid. In the table below only the field \"error\" is provided.\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| AUTHORIZER_UNAUTHORIZED  | Unauthorized message | no | Access token not valid       |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"403":{"description":"Forbidden action detected by WAF or the application. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| AUTHORIZER_FORBIDDEN  | not authorized error message | no | User is not authorized to access this resource \n| CARD_INVALID_STATE    | -           | no    | Renewal with this state reason is not allowed      |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"404":{"description":"Ressource not found, Unknown issuerId or consumerId or card id'. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no | No error details available         |\n| UNKNOWN_CARD   | -           | no | Unknown cardId |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"500":{"description":"Internal Server Error. The below table defines the possible error:\n|errorCode       | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | yes        | No error details available         |\n| INTERNAL_ERROR | error details if any | no | The server has encountered an error when executing the request.  |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"503":{"$ref":"#/components/responses/ServiceUnavailableError"}},"summary":"Renew","tags":["Card Operations"],"operationId":"renewCard-v2"}}}}
```

## Get All Card Authorisation Operations

> This request is used by the core banking system to retrieve all the authorisations related to a card and its linked digital card.\
> The API specifies the starting point (offset) and the number of authorization (limit) to be retrieved:\<br>\
> \- Offset 0 (the default) corresponds to the most recent operation. \
> \- Use a stricly positive number and multipe of limit number to get older operations. Attention D1 will reject the reqest if offset is not a mulitpe of limit.\
> For example in case of limit of 10:\
> \- Use offset of 0 to get the last 10 most recents operations (0 to 10)\
> \- Use offset of 10 to get the next 10 operations (10 to 20)\
> \- Use offset of 20 to get the next 10 operations (20 to 30)\
> \- If you use 9 or 11 as offset, the request will be rejected by D1.\
> \
> Optionally, the request can filter operations for a given period using startDate and endDate parameters.\
> \
> Search authorisations by operation id is also possible.

```json
{"openapi":"3.0.0","info":{"title":"D1 Inbound Card API","version":"2.0"},"tags":[{"name":"Card Operations","description":"Different operations that can be done on a card."}],"servers":[{"url":"https://api.d1.thalescloud.io/banking","description":"Production server"},{"url":"https://api.d1-stg.thalescloud.io/banking","description":"Staging server"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"description":"A JWT generated by the [Get Authorization Token API](oauth2-api).<br/>The server checks the validity of the provided token to control access to this protected resource. Please refer to [Get OAuth 2.0 access token](../../../integrate-the-d1-api/get-oauth-2.0-access-token) for more details on the flow and on how to get this JWT.","type":"http","scheme":"bearer","bearerFormat":"JWT"}},"parameters":{"issuer-id-path":{"description":"The id of the issuer","in":"path","name":"issuerId","required":true,"schema":{"$ref":"#/components/schemas/issuerId"}},"card-id-path":{"description":"The id of the card","in":"path","name":"cardId","required":true,"schema":{"$ref":"#/components/schemas/cardId"}},"limit-query":{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50,"default":10},"description":"Upper limit of the query"},"offset-query-no-max":{"name":"offset","in":"query","schema":{"type":"integer","minimum":0},"description":"Index from which the query starts returning operations (default value: 0)"},"start-date":{"name":"startDate","in":"query","schema":{"$ref":"#/components/schemas/date"},"description":"Start date for the search criteria"},"end-date":{"name":"endDate","in":"query","schema":{"$ref":"#/components/schemas/date"},"description":"End date for the search criteria"},"authorisationCard-operation-id-query":{"in":"query","name":"operationId","schema":{"$ref":"#/components/schemas/authorisationCard-operationId"}}},"schemas":{"issuerId":{"maxLength":10,"minLength":10,"type":"string"},"cardId":{"type":"string","description":"Unique identifier of the card.","minLength":1,"maxLength":48,"pattern":"^[A-Za-z0-9_-]{1,48}$"},"date":{"type":"string","title":"Date","minLength":1,"maxLength":64,"pattern":"^[0-9]{4}-((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01])|(0[469]|11)-(0[1-9]|[12][0-9]|30)|02-(0[1-9]|[12][0-9]))T([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](\\.[0-9]{3}Z|\\.[0-9]{2}([\\+\\-](0[1-9]|1[0-2])):00)$"},"authorisationCard-operationId":{"type":"string","minLength":1,"maxLength":12,"description":"Id corresponding to Retrieval Reference Number (ISO-8583 SID / Field No 37)."},"authorisationCard-operation":{"allOf":[{"$ref":"#/components/schemas/authorisationCard-operation-model"},{"type":"object","required":["details"],"properties":{"details":{"$ref":"#/components/schemas/authorisationCard-details"}}}]},"authorisationCard-operation-model":{"type":"object","required":["operationId","operation","status","startTime"],"properties":{"operationId":{"$ref":"#/components/schemas/authorisationCard-operationId"},"operation":{"type":"string","enum":["PURCHASE","WITHDRAWAL","REFUND","PAYMENT","OTHER"],"description":"operation defines the auhtorisation type. Computed from processing code (ISO-8583 SID / Field No 3) transaction type (Postions 1-2)."},"status":{"type":"string","enum":["APPROVED","PARTIALLY_APPROVED","REVERSED","DECLINED"],"description":"The operation status. Interpreted value of Action Code (ISO-8583 SID / Field No 39)."},"startTime":{"type":"string","description":"Transaction local date and time (ISO-8583 / Field No 12)<br>\nFormat ISO 8601 YYYY-MM-DDThh:mm:ssTZD","minLength":1,"maxLength":64,"pattern":"^[0-9]{4}-((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01])|(0[469]|11)-(0[1-9]|[12][0-9]|30)|02-(0[1-9]|[12][0-9]))T([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](\\.[0-9]{3}Z|\\.[0-9]{2}([\\+\\-](0[1-9]|1[0-2])):00)$"},"errorCode":{"type":"string","description":"error code , only present in case of DECLINED operation/authorisation","enum":["INVALID_CARD_STATE","INVALID_CARD_DATA","CONTROL_FAIL","VELOCITY_CHECK_FAIL","BALANCE_CHECK_FAIL","FRAUD_DETECTED","TECHNICAL_ERROR","ISSUER_ERROR","DOMAIN_CONTROL_FAIL"]}}},"authorisationCard-details":{"type":"object","required":["isoMessageType","transactionDate","transmissionDate","retrievalReferenceNumber","stan","internalStan","actionCode","amount","currencyCode","functionCode","merchant"],"properties":{"isoMessageType":{"type":"string","description":"The ISO Message type of the request/advice sent by the switch.<br>Value '1100' represents an authorisation request.","minLength":4,"maxLength":4,"pattern":"^[\\d]{4}$"},"transactionDate":{"type":"string","description":"Transaction local date and time (ISO-8583 SID / Field No 12)<br>\nFormat ISO 8601 YYYY-MM-DDThh:mm:ssTZD","minLength":1,"maxLength":64,"pattern":"^[0-9]{4}-((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01])|(0[469]|11)-(0[1-9]|[12][0-9]|30)|02-(0[1-9]|[12][0-9]))T([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](\\.[0-9]{3}Z|\\.[0-9]{2}([\\+\\-](0[1-9]|1[0-2])):00)$"},"transmissionDate":{"type":"string","description":"Transmission date and time (ISO-8583 SID / Field No 7)<br>\nFormat ISO 8601 YYYY-MM-DDThh:mm:ssTZD","minLength":1,"maxLength":64,"pattern":"^[0-9]{4}-((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01])|(0[469]|11)-(0[1-9]|[12][0-9]|30)|02-(0[1-9]|[12][0-9]))T([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](\\.[0-9]{3}Z|\\.[0-9]{2}([\\+\\-](0[1-9]|1[0-2])):00)$"},"retrievalReferenceNumber":{"type":"string","minLength":1,"maxLength":12,"description":"Retrieval Reference Number (ISO-8583 SID / Field No 37)."},"stan":{"type":"string","description":"System Trace Audit Number (ISO-8583 SID / Field No 11)","minLength":1,"maxLength":6},"internalStan":{"type":"string","description":"The internal System Trace Audit Number generated by the solution.","minLength":1,"maxLength":6},"actionCode":{"type":"string","minLength":3,"maxLength":3,"pattern":"^[\\d]{3}$","description":"The none interpreted Action Code return by the authorisation host (ISO-8583 SID / Field No 39).<br>\nFor example '000' for APPROVED, '002' for PARTIAL APPROVE"},"declinedReason":{"type":"string","description":"The declined reason of the operation, present only is the authorisation has been DECLINED by Auhtorisation host.","enum":["INVALID_CARD_STATE","INVALID_CARD_DATA","CONTROL_FAIL","VELOCITY_CHECK_FAIL","BALANCE_CHECK_FAIL","FRAUD_DETECTED","TECHNICAL_ERROR","ISSUER_ERROR","DOMAIN_CONTROL_FAIL"]},"declinedDetails":{"type":"string","enum":["INVALID_CVV2","INVALID_DCVV2","INVALID_EXPIRY_DATE","INVALID_RETRYABLE_DCVV2","NO_ACTIVE_DCVV2","CARD_DELETED","CARD_EXPIRED","CARD_REPLACED","CARD_SUSPENDED","CONTACTLESS_DISABLED","CVV2_LOCKED","EXPIRY_DATE_LOCKED","PIN_LOCKED","COUNTRY_NOT_ALLOWED","CURRENCY_NOT_ALLOWED","MAGSTRIPE_DISABLED","MERCHANT_TYPE_NOT_ALLOWED","ONLINE_PAYMENT_DISABLED","WITHDRAWAL_DISABLED","EMV_AUTHORIZATION_VERIFICATION_FAIL","INVALID_PIN","ABOVE_MAX_AMOUNT","BELOW_MIN_AMOUNT","MAX_AMOUNT_LIMIT_REACHED","MAX_TRANSACTION_LIMIT_REACHED","NOT_ENOUGH_FUND","INVALID_MERCHANT","SUSPECTED_FRAUD","ACCOUNT_NOT_FOUND","FUND_CHECK_FAILED","TECHNICAL_ERROR"],"description":"Additional details for declined Reason if available. In table below you will find the possible details for each declined reason\n| Declined reason      | possible declined details       |\n| -------------------- | ------------------------|\n| INVALID_CARD_DATA    | INVALID_CVV2<br>INVALID_DCVV2<br>INVALID_EXPIRY_DATE<br>INVALID_RETRYABLE_DCVV2<br>NO_ACTIVE_DCVV2 |\n| INVALID_CARD_STATE   | CARD_DELETED<br>CARD_EXPIRED<br>CARD_REPLACED<br>CARD_SUSPENDED<br>CONTACTLESS_DISABLED<br>CVV2_LOCKED<br>EXPIRY_DATE_LOCKED<br>PIN_LOCKED |\n| DOMAIN_CONTROL_FAIL  | CONTACTLESS_DISABLED<br>COUNTRY_NOT_ALLOWED<br>CURRENCY_NOT_ALLOWED<br>MAGSTRIPE_DISABLED<br>MERCHANT_TYPE_NOT_ALLOWED<br>ONLINE_PAYMENT_DISABLED<br>WITHDRAWAL_DISABLED |\n| CONTROL_FAIL         | EMV_AUTHORIZATION_VERIFICATION_FAIL<br>INVALID_PIN |\n| VELOCITY_CHECK_FAIL  | ABOVE_MAX_AMOUNT<br>BELOW_MIN_AMOUNT<br>MAX_AMOUNT_LIMIT_REACHED<br>MAX_TRANSACTION_LIMIT_REACHED |\n| BALANCE_CHECK_FAIL   | NOT_ENOUGH_FUND |\n| FRAUD_DETECTED       | INVALID_MERCHANT<br>SUSPECTED_FRAUD |\n| ISSUER_ERROR         | ACCOUNT_NOT_FOUND<br>FUND_CHECK_FAILED |"},"amount":{"type":"number","minimum":0,"maximum":999999999999,"description":"The nominal transaction amount value (ISO-8583 SID / Field No 04).<br>\nValue without decimal separator, use the currency exponent to determine the number of decimal.<br>\nFor example, an amount in euro of €21 is returned 2100."},"currencyCode":{"$ref":"#/components/schemas/currencyCode"},"billingAmount":{"type":"number","minimum":0,"maximum":999999999999,"description":"The billing amount value from Authorisation (ISO-8583 SID / Field No 06)<br>\nValue without decimal separator, use the currency exponent to determine the number of decimal.<br>\nFor example, an amount in euro of €21 is returned 2100."},"billingCurrencyCode":{"$ref":"#/components/schemas/currencyCode"},"conversionRate":{"type":"number","description":"Cardholder billing exchange rate from Auhtorization (ISO-8583 SID / Field No 10)<br>Or used by the solution during conversion.","minimum":0,"maximum":9999999},"replacementAmount":{"type":"number","minimum":0,"maximum":999999999999,"description":"The replacement amount value from Authorisation (ISO-8583 SID / Field No 30)<br>\nValue without decimal separator, use the currency exponent to determine the number of decimal.<br>\nFor example, an amount in euro of €21 is returned 2100."},"replacementCurrencyCode":{"$ref":"#/components/schemas/currencyCode"},"accountNumber":{"type":"string","maxLength":24,"description":"Account number used when posting with Core Banking System"},"standInProcessing":{"type":"boolean","description":"Specify if STAND-In processing has been used or not by D1 Authorisation host.\n  - true if the authorization has been approvded on behalf of the Core Banking System (STAND-IN processing)\n  - false if financial authorization has been approved by the Core Banking system."},"functionCode":{"type":"string","description":"Function code (ISO-8583 SID - Field No 24)","minLength":3,"maxLength":3,"pattern":"^[\\d]{3}$"},"messageReasonCode":{"type":"string","description":"Function code (ISO-8583 SID - Field No 25)","minLength":4,"maxLength":4,"pattern":"^[\\d]{4}$"},"cardPresent":{"type":"boolean","description":"Point of service data code (ISO-8583 SID / Field No 22) Card Present indicator (Postion 06)."},"cardDataInputMode":{"type":"string","description":"Point of service data code (ISO-8583 SID / Field No 22) Card Data Input Mode (Postion 07).<br> See ISO-8583 SID for the list of possible values.","minLength":1,"maxLength":1},"initiatingParty":{"type":"string","enum":["CARDHOLDER","MERCHANT"],"description":"Merchant or Cardholder initiated transaction<br>TAG P64 in Additional private data (ISO-8583 SID / Field No 48) Initating-Party (Postion 04)."},"acquirerCountryCode":{"type":"string","description":"Acquiring institution country code (ISO-8583 SID / Field No 19).<br>\nCountry code in ISO 3166-1 alpha-2.","minLength":2,"maxLength":2,"pattern":"^[A-Z]{2}$"},"merchant":{"$ref":"#/components/schemas/authorisationCardDetails-merchant"},"digitalCard":{"$ref":"#/components/schemas/authorisationCardDetails-digitalCard"}}},"currencyCode":{"type":"string","pattern":"^[A-Z]{3}$","description":"Currency Code in ISO 4217 alpha code format"},"authorisationCardDetails-merchant":{"additionalProperties":false,"type":"object","description":"merchant information as provided from Authorisation (ISO-8583 SID / Field No 42 & 43)","required":["merchantId","merchantNameAddress"],"properties":{"merchantId":{"type":"string","minLength":1,"maxLength":15,"description":"Card acceptor identification code (ISO-8583 SID / Field No 42)."},"merchantNameAddress":{"type":"string","minLength":1,"maxLength":40,"description":"Card acceptor name and address (ISO-8583 SID / Field No 43)."},"merchantName":{"type":"string","minLength":1,"maxLength":24,"description":"merchant accronym  (positions 1-24) of Card acceptor name and address (ISO-8583 SID / Field No 43)."},"city":{"type":"string","minLength":1,"maxLength":13,"description":"merchant city (positions 25-37) of Card acceptor name and address (ISO-8583 SID / Field No 43)."},"countryCode":{"type":"string","description":"merchant country (positions 38-40) of Card acceptor name and address (ISO-8583 SID / Field No 43)<br>\nCountry code in ISO 3166-1 alpha-2.","minLength":2,"maxLength":2,"pattern":"^[A-Z]{2}$"},"merchantType":{"type":"string","description":"MCC / Merchant type (ISO-8583 SID / Field No 18). (not provided for an operation having a status=REVERSED)","minLength":4,"maxLength":4,"pattern":"^[\\d]{4}$"}}},"authorisationCardDetails-digitalCard":{"additionalProperties":false,"type":"object","description":"Provided in case Authorisation with a digital card.<br>\nInformation extracted in Tag P55 (Token Data) from Additional Private Data (ISO-8583 SID / Field No 48)","required":["digitalCardId","digitalCardRequestorId"],"properties":{"digitalCardId":{"$ref":"#/components/schemas/digitalCardId"},"digitalCardRequestorId":{"type":"string","description":"Digital Card requestor identifier. This is provided by the TSP itself.","minLength":11,"maxLength":11}}},"digitalCardId":{"type":"string","description":"Unique identifier of the digital card.","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_-]{1,64}$"},"errorGeneric":{"additionalProperties":false,"type":"object","description":"Generic error returned by the APIs.","properties":{"errorCode":{"type":"string","description":"The type of the error"},"error":{"type":"string","description":"Provide more error details if possible.<br/>For example name of the field with invalid format.<br/>This field is for troubleshooting purposes only, it can change at any time so MUST NOT be parsed, and is not supposed to be human readable so CANNOT be displayed to end users."}}}},"responses":{"ServiceUnavailableError":{"description":"The service is temporarily unavailable. You may retry your request later."}}},"paths":{"/v2/issuers/{issuerId}/cards/{cardId}/authorisations/operations":{"get":{"summary":"Get All Card Authorisation Operations","description":"This request is used by the core banking system to retrieve all the authorisations related to a card and its linked digital card.\nThe API specifies the starting point (offset) and the number of authorization (limit) to be retrieved:<br>\n- Offset 0 (the default) corresponds to the most recent operation. \n- Use a stricly positive number and multipe of limit number to get older operations. Attention D1 will reject the reqest if offset is not a mulitpe of limit.\nFor example in case of limit of 10:\n- Use offset of 0 to get the last 10 most recents operations (0 to 10)\n- Use offset of 10 to get the next 10 operations (10 to 20)\n- Use offset of 20 to get the next 10 operations (20 to 30)\n- If you use 9 or 11 as offset, the request will be rejected by D1.\n\nOptionally, the request can filter operations for a given period using startDate and endDate parameters.\n\nSearch authorisations by operation id is also possible.","parameters":[{"$ref":"#/components/parameters/issuer-id-path"},{"$ref":"#/components/parameters/card-id-path"},{"$ref":"#/components/parameters/x-user-id"},{"$ref":"#/components/parameters/x-correlation-id"},{"$ref":"#/components/parameters/limit-query"},{"$ref":"#/components/parameters/offset-query-no-max"},{"$ref":"#/components/parameters/start-date"},{"$ref":"#/components/parameters/end-date"},{"$ref":"#/components/parameters/authorisationCard-operation-id-query"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","properties":{"operations":{"type":"array","items":{"$ref":"#/components/schemas/authorisationCard-operation"}}}}}}},"400":{"description":"Bad Request, Invalid request URI, header, paramters. The below table defines the possible 'Bad request' error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| FIELD_INVALID_VALUE |  Contains the field in error (first found) | no | One field is not expected format as defined in this documentation |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"401":{"description":"Unauthorized request, the provided Authorization header is missing or invalid. In the table below only the field \"error\" is provided.\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| AUTHORIZER_UNAUTHORIZED  | Unauthorized message | no | Access token not valid       |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"403":{"description":"Forbidden action detected by WAF or the application. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no        | No error details available         |\n| AUTHORIZER_FORBIDDEN  | not authorized error message | no | User is not authorized to access this resource \n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"404":{"description":"Ressource not found, Unknown issuerId or consumerId or card id'. The below table defines the possible error:\n| errorCode      | error       | Retryable | Comments                             |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | no | No error details available         |\n| UNKNOWN_CARD   | -           | no | Unknown cardId |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"500":{"description":"Internal Server Error. The below table defines the possible error:\n|errorCode       | error       | Retryable | Comments                           |\n| -------------- | ------------| ----------| -----------------------------------|\n| -              | -           | yes        | No error details available         |\n| INTERNAL_ERROR | error details if any | no | The server has encountered an error when executing the request.  |\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGeneric"}}}},"503":{"$ref":"#/components/responses/ServiceUnavailableError"}},"tags":["Card Operations"],"operationId":"getAllAuthorisations"}}}}
```


# Outbound API (from D1)


# Card API

## Notify Card Operations

> This request is used by D1 to notify the system of the bank about any card status update.\<br>\
> There is a retry mechanism in case the notification has not been sent.\
> Thus the bank system can use this notification to synchronize card status with their card repository.\<br>\
> The number max of card status update in the notification is defined at onboarding time according to bank's system capability.\<br>\
> Each update is linked to a given card id, and can contain a message dedicated for the final end-user.

````json
{"openapi":"3.0.0","info":{"title":"Outbound Card API","version":"2.0"},"servers":[{"url":"https://YOUR_DOMAIN_NAME"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","description":"A JWT generated by the [Get Authorization Token API](oauth2-api).<br/>The server checks the validity of the provided token to control access to this protected resource. Please refer to [Get OAuth 2.0 access token](../../../integrate-the-d1-api/get-oauth-2.0-access-token) for more details on the flow and on how to get this JWT.","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"CardStatus-operation-notification":{"type":"object","required":["operationId","operation","status","startTime","cardId"],"properties":{"operationId":{"type":"string","minLength":1,"maxLength":64,"pattern":"[A-Za-z0-9_-]{1,64}","description":"Unique identifier of the operation."},"operation":{"type":"string","enum":["CREATE","REGISTER","ACTIVATE","SUSPEND","RESUME","DELETE","DIGITIZE","RENEW","REPLACE","PRODUCE","STANDALONE_TRACKING","CLICK_TO_PAY_ENROLMENT","CLICK_TO_PAY_UPDATE","CLICK_TO_PAY_OPTOUT","UPDATE_ORDER","PASSKEY_ENROLMENT"],"description":"card status operation"},"status":{"type":"string","enum":["PENDING","SUCCESSFUL","FAILED"],"description":"The operation status"},"startTime":{"type":"string","description":"Time of the operation.","minLength":1,"maxLength":64},"endTime":{"type":"string","description":"End time of the operation","minLength":1,"maxLength":64},"cardId":{"$ref":"#/components/schemas/cardId"},"details":{"oneOf":[{"$ref":"#/components/schemas/CardStatusDetails"},{"$ref":"#/components/schemas/ProduceDetails"},{"$ref":"#/components/schemas/PasskeyEnrollmentDetails"},{"$ref":"#/components/schemas/DigitizeDetails"},{"$ref":"#/components/schemas/pullOperation"},{"$ref":"#/components/schemas/trackingOperation"}]},"message":{"type":"object","properties":{"format":{"type":"string","description":"Format of the message","enum":["TEXT","HTML"]},"title":{"type":"string","description":"Title of the notification"},"content":{"type":"string","description":"Message to be displayed"}}},"errorCode":{"type":"string","description":"The type of the error"},"error":{"type":"string","description":"Provide more error details if possible.<br/>For example name of the field with invalid format."}}},"cardId":{"type":"string","description":"Unique identifier of the card.","minLength":1,"maxLength":48,"pattern":"^[A-Za-z0-9_-]{1,48}$"},"CardStatusDetails":{"type":"object","title":"CREATE, REGISTER, ACTIVATE, SUSPEND, RESUME, DELETE, RENEW, REPLACE operations","description":"Card Status Details","properties":{"cardProductId":{"type":"string","description":"Card Product identifier of the card"},"cardState":{"$ref":"#/components/schemas/cardState"},"reasonState":{"type":"string","description":"Optional reason associated to the state of the card","enum":["CLOSED_ACCOUNT","CLOSED_CARD","CARD_LOST","CARD_FOUND","CARD_STOLEN","CARD_BROKEN","CARD_NOT_RECEIVED","FRAUD","USER_DECISION","ISSUER_DECISION","CVV2_LOCKED","EXPIRY_DATE_LOCKED","PIN_LOCKED"]},"newCardId":{"type":"string","description":"In case of card replacement, this field correspond to the cardId of the new card"},"encryptedData":{"type":"string","maxLength":8192,"pattern":"^(?:[\\x20-\\x2D\\x2F-\\x7F]*\\.){4}(?:[\\x20-\\x2D\\x2F-\\x7F]*)$","description":"Encrypted card information that can be provided in case of operation 'CREATE', 'REGISTER', 'RENEW' and 'REPLACE' (Receiver shall be configured accordingly during the onboarding)<br>\nIn case of 'REPLACE', this is the encrypted information of 'newCardId'<br>\nThe encryptedData is the encrypted json (cf http://www.json.org/) representation of the Card information.\nThis value is encrypted using the JWE encryption (please refer to the **[Encrypt sensitive data](../../../integrate-the-d1-api/encrypt-sensitive-data)** for more details)\n<br/><br/>Once deciphered, the plaintext contains a json structure with:\n|JSON field parameter name|description|MOC|Format|\n|-------|-------|-------|-------|\n|pan|The funding pan value.|M|string - up to 19 digits|\n|exp|The expiry date of the card.|M|string - 4 digits, following the format MMYY|"}}},"cardState":{"type":"string","description":"the state of the card","enum":["INACTIVE","ACTIVE","SUSPENDED","DELETED","REPLACED"]},"ProduceDetails":{"type":"object","title":"PRODUCE operation","description":"The card production status notifcation details","required":["status"],"properties":{"status":{"$ref":"#/components/schemas/productionStatusInNotification"},"reason":{"type":"string","description":"Additional details in case of exception during data processing or card production"},"consumerId":{"type":"string","description":"The consumer ID (card holder)."},"dueDate":{"type":"string","format":"date","description":"The estimated card production date. It uses the format ```YYYY-MM-DD```."},"productionSite":{"maxLength":50,"minLength":0,"type":"string","description":"The factory where the card is produced."},"shipment":{"$ref":"#/components/schemas/shipment"},"name":{"maxLength":50,"minLength":0,"description":"The card holder name printed on the card.\n","type":"string"},"maskedPan":{"maxLength":19,"minLength":12,"description":"The masked PAN value (Primary Account Number).\n","type":"string","pattern":"^[0-9xX\\*]{12,19}$"},"orderId":{"description":"The unique identifier of order used for card production.\n","type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"},"packageId":{"description":"The unique identifier of the package used for card production.\n","type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"},"services":{"$ref":"#/components/schemas/services"},"inputFileName":{"type":"string","minLength":1,"maxLength":256,"description":"Name of the input file in case of hybrid mode."},"cardPackageDetails":{"$ref":"#/components/schemas/cardPackageDetails"},"deliveryAddress":{"description":"The recipient's address.\n","$ref":"#/components/schemas/addressInProduceNotification"}}},"productionStatusInNotification":{"type":"string","enum":["CARD_PROD_REQUESTED","DATA_PREPARED","CARD_PROD_READY","CARD_PROD_ONGOING","CARD_PROD_DONE","CARD_SHIPPED","CARD_PROD_CANCELED","CARD_PROD_ONHOLD","DATA_EXCEPTION","CARD_PROD_EXCEPTION"],"description":"The current status of card production.\n"},"shipment":{"type":"object","properties":{"pickupDate":{"type":"string","description":"The date and time the shipment was picked up by the carrier. It is in the format ```YYYY-MM-DDThh:mm:ssZ``` for the timezone where the pickup occured.","format":"date-time"},"carrier":{"type":"string","description":"Unique carrier code.\n\n|Carrier Code|Carrier Name|\n|----|----|\n|chronopost-france|Chronopost France|\n|dhl|DHL Express|\n|fedex|FedEx®|\n|la-poste-colissimo|La Poste|AvailableForPickup|\n|spain-correos-es|Correos de España|\n|ups|UPS|\n|usps|USPS| |\n"},"trackingNumber":{"type":"string","pattern":"^[A-Za-z0-9 _\\-\\.\\/]{1,64}$","description":"The tracking number."},"status":{"maxLength":50,"minLength":0,"type":"string","enum":["INFO_RECEIVED","IN_TRANSIT","OUT_FOR_DELIVERY","FAILED_ATTEMPT","DELIVERED","AVAILABLE_FOR_PICKUP","EXCEPTION","EXPIRED","PENDING"],"description":"Current status of tracking.\n\n|status code                | description                                                                                                       |\n|---------------------------|-------------------------------------------------------------------------------------------------------------------|\n|INFO_RECEIVED              | Carrier has received request from shipper and is about to pick up the shipment.                                   |\n|IN_TRANSIT                 | Carrier has accepted or picked up shipment from shipper. The shipment is on the way.                              |\n|OUT_FOR_DELIVERY           | Carrier is about to deliver the shipment, or it is ready to pickup.                                               |\n|FAILED_ATTEMPT             | Carrier attempted to deliver but failed, and usually leaves a notice and will try to deliver again.               |\n|DELIVERED                  | The shipment was delivered successfully.                                                                          |\n|AVAILABLE_FOR_PICKUP       | The package arrived at a pickup point near you and is available for pickup.                                       |\n|EXCEPTION                  | Custom hold, undelivered, returned shipment to sender or any shipping exceptions.                                 |\n|EXPIRED                    | Shipment has no tracking information for 30 days since added.                                                     |\n|PENDING                    | Tracking information not available yet.                                                                           |                                                                    |\n"},"message":{"minLength":1,"type":"string","description":"Normalized tracking message.\n\n|Message|Description|Shipment Status|\n|----|----|----|\n|DELIVERED|Shipment delivered successfully|DELIVERED|\n|Picked up by the customer|Package picked up by the customer|DELIVERED|\n|Sign by customer|Package delivered to and signed by the customer|DELIVERED|\n|Delivered and received cash on delivery|Package delivered to the customer and cash collected on delivery|DELIVERED|\n|Available for pickup|The package arrived at a pickup point near you and is available for pickup|AVAILABLE_FOR_PICKUP|\n|EXCEPTION|Delivery of the package failed due to some shipping exception|EXCEPTION|\n|Customer moved|Delivery of the package failed as the customer relocated|EXCEPTION|\n|Customer refused delivery|Delivery of the package failed as the recipient refused to take the package due to some reason|EXCEPTION|\n|Delayed (Customs clearance)|Package delayed due to some issues during the customs clearance|EXCEPTION|\n|Delayed (External factors)|Package delayed due to some unforeseen reasons|EXCEPTION|\n|Held for payment|The package being held due to pending payment from the customer's end|EXCEPTION|\n|Incorrect Address|Package not delivered due to incorrect recipient address|EXCEPTION|\n|Pick up missed|Package available for the pickup but not collected by the customer|EXCEPTION|\n|Rejected by carrier|Package rejected by the carrier due to noncompliance with its guidelines|EXCEPTION|\n|Returning to sender|The package is on its way back to the sender|EXCEPTION|\n|Returned to sender|The return package has been successfully received by the sender|EXCEPTION|\n|Shipment damage|Shipment damaged|EXCEPTION|\n|Shipment lost|Delivery of the package failed as it got lost|EXCEPTION|\n|Failed Attempt|The delivery of the package failed due to some reason. Courier usually leaves a notice and will try to deliver again|FAILED_ATTEMPT|\n|Addressee not available|Recipient not available at the given address|FAILED_ATTEMPT|\n|Business Closed|Business is closed at the time of delivery|FAILED_ATTEMPT|\n|In Transit|Shipment on the way|IN_TRANSIT|\n|Acceptance scan|Shipment accepted by the carrier|IN_TRANSIT|\n|Arrival scan|Shipment arrived at a hub or sorting center|IN_TRANSIT|\n|Arrived at the destination country/region|International shipment arrived at the destination country/region|IN_TRANSIT|\n|Customs clearance completed|Customs clearance completed|IN_TRANSIT|\n|Customs clearance started|Package handed over to customs for clearance|IN_TRANSIT|\n|Departure Scan|Package departed from the facility|IN_TRANSIT|\n|Problem resolved|Problem resolved and shipment in transit|IN_TRANSIT|\n|Forwarded to a different delivery address|Shipment forwarded to a different delivery address|IN_TRANSIT|\n|Info Received|The carrier received a request from the shipper and is about to pick up the shipment|INFO_RECEIVED|\n|Out for Delivery|The package is out for delivery|OUT_FOR_DELIVERY|\n|Customer contacted|The customer is contacted before the final delivery|OUT_FOR_DELIVERY|\n|Delivery appointment scheduled|A delivery appointment is scheduled|OUT_FOR_DELIVERY|\n|PENDING|No information available on the carrier website or the tracking number is yet to be tracked|PENDING|\n|Carrier account not connected|It represents the shipments are pending due to no connection with carrier accounts|PENDING|\n|Label created, no updates yet|The order has been processed/packaged, but not scanned at a shipping location yet|PENDING|\n|Wrong carrier|There is no tracking info available because the carrier is wrong|PENDING|\n|No recent updates|There have been no new tracking updates in the last 120 days|PENDING|\n|Unrecognized carrier|AfterShip can’t track this type of shipment as the carrier is unrecognized.|PENDING|\n|Expired|No tracking information of the shipment, from the last 30 days|EXPIRED|\n"},"trackingUrl":{"type":"string","description":"Official tracking URL of the carrier (if any)."},"redirectUrl":{"type":"string","description":"Delivery instructions (delivery date or address) can be modified by visiting the link if supported by the carrier."},"estimatedDeliveryDate":{"type":"string","description":"'The estimated delivery date provided by the carrier. It is in the format ```YYYY-MM-DDThh:mm:ssZ``` for the recipent's timezone.'","format":"date-time"},"lastUpdatedAt":{"type":"string","description":"The date and time the shipment was updated. It is in the format ```YYYY-MM-DDThh:mm:ssZ``` for the timezone GMT+0.","format":"date-time"},"deliveryDate":{"type":"string","description":"'The date and time the shipment was delivered. It is in the format ```YYYY-MM-DDThh:mm:ssZ``` for the recipent's timezone.'","format":"date-time"},"signedBy":{"type":"string","description":"Signed by information for delivered shipment."},"failedDeliveryAttempts":{"type":"string","description":"Number of failed attempts courier tried to deliver the card."},"lastCheckpoint":{"$ref":"#/components/schemas/lastCheckpoint"}}},"lastCheckpoint":{"type":"object","description":"The tracking information of the last checkpoint","properties":{"checkpointTime":{"type":"string","description":"The date and time of the checkpoint event, provided by the carrier. It is in the format ```YYYY-MM-DDThh:mm:ssZ``` for the timezone of the checkpoint.","format":"date-time"},"city":{"minLength":1,"type":"string","description":"The city info provided by carrier."},"countryName":{"type":"string","description":"The country/Region name of the checkpoint, may also contain other location information."},"message":{"type":"string","description":"The checkpoint message."}}},"services":{"required":["issuance","delivery"],"properties":{"cardProductId":{"$ref":"#/components/schemas/cardProductId"},"issuance":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[a-zA-Z0-9_-\\s]{1,64}$","description":"The type of issuance.\n<br/>  \n|Attribute|Description|\n|-------|-------|\n|CREATION|Issuance of a brand-new card to a user|\n|RENEWAL|An existing card reaches its expiration date and needs to be replaced with a new one for continued use|\n|REPLACEMENT|An existing card needs to be reissued due to loss, theft, or damage.|\n"},"priority":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[a-zA-Z0-9_-\\s]{1,64}$","description":"The level of priority agreed for the card production (defined during the onboarding of D1).\n"},"delivery":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[a-zA-Z0-9_-\\s]{1,64}$","description":"The shipment method (defined during the onboarding of D1).\n"},"packaging":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[a-zA-Z0-9_-\\s]{1,64}$","default":"NO_PACK","description":"Unique identifier of the packaging (defined during the onboarding of D1).\n"},"cardCarrier":{"type":"string","minLength":1,"maxLength":64,"default":"NO_CARRIER","pattern":"^[a-zA-Z0-9_-\\s]{1,64}$","description":"Unique identifier of the card carrier (defined during the onboarding of D1).\n"}}},"cardProductId":{"type":"string","description":"Unique identifier of the type of card ( defined during the onboarding of D1)","minLength":1,"maxLength":48,"pattern":"^[A-Za-z0-9_-]{1,48}$"},"cardPackageDetails":{"type":"object","properties":{"plastic":{"type":"string","description":"Reference of the plastic used for the card\n","minLength":2,"maxLength":40},"artworkId":{"type":"string","description":"Reference of the artwork printed on the card\n","minLength":2,"maxLength":40},"cardCarrier":{"type":"string","description":"Reference of the card carrier used for the card\n","minLength":2,"maxLength":100},"envelope":{"type":"string","description":"Reference of the envelope used for the card\n","minLength":2,"maxLength":100},"package":{"type":"string","minLength":2,"maxLength":100,"description":"Reference of the package used for the card\n"},"cardActivationLabel":{"type":"string","minLength":2,"maxLength":100,"description":"Reference of the activation label used for the card\n"},"inserts":{"type":"array","minItems":0,"maxItems":10,"items":{"type":"string"},"description":"List of inserts\n"}}},"addressInProduceNotification":{"type":"object","required":["line1","zipCode","city","countryCode"],"properties":{"companyName":{"type":"string","description":"The name of the company.","minLength":1,"maxLength":64,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,64}$"},"line1":{"type":"string","description":"The first line of the address.","minLength":1,"maxLength":64,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,64}$"},"line2":{"type":"string","description":"The second line of the address.","minLength":1,"maxLength":64,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,64}$"},"line3":{"type":"string","description":"The third line of the address.","minLength":1,"maxLength":64,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,64}$"},"city":{"type":"string","description":"The city name.","minLength":1,"maxLength":32,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,32}$"},"state":{"type":"string","description":"The state.","minLength":1,"maxLength":30,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,30}$"},"zipCode":{"type":"string","description":"The zip Code.","minLength":1,"maxLength":10,"pattern":"^[0-9A-Z- ]{1,10}$"},"countryCode":{"type":"string","description":"The country code, based on ISO 639-1 alpha-2 format","minLength":2,"maxLength":2,"pattern":"^[A-Z]{2}$"}}},"PasskeyEnrollmentDetails":{"type":"object","title":"PassKey Enrollment operation","description":"The passkey enrollment notifcation details","required":["bindingId"],"properties":{"bindingId":{"type":"string","description":"Unique identifier of the passkey binding."},"fido2":{"type":"object","description":"FIDO2 proof data extracted from the Visa trustchain surrogate proof.","properties":{"type":{"type":"string","description":"The FIDO2 attestation/assertion type."},"userHandle":{"type":"string","description":"The user handle (mapped from user_handle)."},"credentialsId":{"type":"string","description":"The credential identifier (mapped from credential_id)."},"clientData":{"type":"string","description":"Base64url-encoded client data JSON (mapped from client_data_json)."},"attestationObject":{"type":"string","description":"Base64url-encoded attestation object (mapped from attestation_object)."},"authenticatorData":{"type":"string","description":"Base64url-encoded authenticator data (mapped from authenticator_data)."},"assertionSignature":{"type":"string","description":"Base64url-encoded assertion signature (mapped from assertion_signature)."}}}}},"DigitizeDetails":{"title":"DIGITIZE operation","type":"object","description":"The card digitization details","required":["tbd"],"properties":{"deviceInformation":{"$ref":"#/components/schemas/deviceInformation"},"digitalCardsDetails":{"type":"array","minItems":1,"maxItems":2,"items":{"type":"object","required":["generalInformation","credentials"],"properties":{"isPrimary":{"description":"Flag indicating whether the digital card was create by the primary TSP or not.","type":"boolean","default":true},"generalInformation":{"type":"object","allOf":[{"$ref":"#/components/schemas/digitalCardInformation"},{"type":"object","properties":{"digitalCardRequestorInformation":{"$ref":"#/components/schemas/digitalCardRequestorInformation"}}}]},"credentials":{"type":"string","description":"The field is the json (cf http://www.json.org/ ) representation of the DIGITAL card.\nJWE encryption is used to secure the field (please refer to the [Encrypt sensitive data](../../../integrate-the-d1-api/encrypt-sensitive-data) for more details)\nDetails:\n\n{\n\n  \"pan\":\"...\",\n  \n  \"exp\":\"...\"\n  \n}\n\n\nThe PAN is Mandatory,  up to 19 digits.\n\nThe expiry date in the format MMYY. It is not provided for UPI scheme.","minLength":1,"maxLength":8196}}}},"eligibilityInformation":{"$ref":"#/components/schemas/eligibilityInformation"},"digitizationInformation":{"$ref":"#/components/schemas/digitizationInformation"}}},"deviceInformation":{"title":"deviceInformation","additionalProperties":false,"type":"object","description":"Provides details about the device that has been used for the card digitization.\nNote that this data is available only if the check eligbility has passed with success.\nData availability dependes on the requestor.","properties":{"deviceId":{"type":"string","minLength":1,"maxLength":128,"description":"Identifier of the token storage."},"digitalCardStorageType":{"type":"string","maxLength":32,"description":"Type of the token sorage location. Following values are possible:\n- HCE\n- SPAY_PHONE\n- SPAY_TABLET\n- SPAY_WATCH\n- SPAY_TV\n- IPHONE\n- IWATCH\n- IPAD\n- MAC_BOOK\n- ANDROID_PHONE\n- ANDROID_TABLET\n- ANDROID_WATCH\n- MOBILE_PHONE\n- TABLET\n- WATCH\n- MOBILE_PHONE_OR_TABLET\n- BRACELET\n- UNKNOWN"},"manufacturer":{"type":"string","minLength":1,"maxLength":32,"description":"Device manufacturer name"},"brand":{"type":"string","minLength":1,"maxLength":32,"description":"Device brand"},"model":{"type":"string","minLength":1,"maxLength":32,"description":"Device model"},"osVersion":{"type":"string","minLength":1,"maxLength":16,"description":"Device OS version"},"firmwareVersion":{"type":"string","description":"Device firmware version","minLength":1,"maxLength":32},"phoneNumber":{"type":"string","description":"Device phone number","minLength":1,"maxLength":20},"fourLastDigitPhoneNumber":{"type":"string","description":"","minLength":1,"maxLength":4},"deviceName":{"type":"string","maxLength":128,"description":"Device name set by the consumer"},"deviceParentId":{"type":"string","description":"ID of parent device. Applies to wearable","minLength":1,"maxLength":64},"language":{"type":"string","description":"Language set on the device in ISO 639-3","minLength":1,"maxLength":3},"serialNumber":{"type":"string","minLength":1,"maxLength":64,"description":"Device serial number"},"timeZone":{"type":"string","description":"Device time zone abbreviation. Example: PST, GMT, etc...","minLength":1,"maxLength":32},"timeZoneSetting":{"type":"string","maxLength":32,"description":"Who has set the timezone.\nPossible values:\n- NETWORK_SET\n- CONSUMER_SET"},"simSerialNumber":{"type":"string","description":"Secure Element serial number","minLength":1,"maxLength":24},"IMEI":{"type":"string","minLength":1,"maxLength":32},"networkOperator":{"type":"string","description":"Network operator name.","maxLength":32},"networkType":{"type":"string","description":"Network type. Can be:\n- CELLULAR\n- WIFI","maxLength":16}},"required":["deviceId"]},"digitalCardInformation":{"title":"digitalCardInformation","type":"object","description":"Provides information about the token. Note that this data is available only if the tokenization is successful or pending.","properties":{"digitalCardId":{"type":"string","minLength":1,"maxLength":64,"description":"Unique identifier of the token specified by the TSP"},"panSuffix":{"type":"string","minLength":4,"maxLength":4,"description":"Last four digits of the token. Available only in the status='SUCCESSFUL' Notification"},"state":{"$ref":"#/components/schemas/digitalCardState"},"type":{"$ref":"#/components/schemas/tokenType"},"provisioningTime":{"type":"string","maxLength":32,"description":"The provisioning time of the token. Format ISO 8601 YYYY-MM-DDThh:mm:ssTZD"}},"required":["digitalCardId","state"]},"digitalCardState":{"type":"string","description":"the state of the digital card (token)","enum":["ACTIVE","INACTIVE","DELETED","DEPLOYMENT_ONGOING","PENDING_ACTIVATION"],"title":"digitalCardState"},"tokenType":{"type":"string","maxLength":16,"description":"The type of the token. Following values are supported:\n- SE\n- HCE\n- COF\n- ECOM\n- QRC"},"digitalCardRequestorInformation":{"title":"digitalCardRequestorInformation","additionalProperties":false,"type":"object","description":"Provides details about the digital card requestor.","properties":{"id":{"type":"string","description":"Digital Card requestor identifier. This is provided by the TSP itself.","minLength":11,"maxLength":11},"walletId":{"type":"string","description":"MasterCard ONLY. Wallet Application identifier","maxLength":32},"name":{"type":"string","maxLength":256,"description":"Wallet or Merchant human readable name"},"tspId":{"type":"string","maxLength":11,"minLength":11,"description":"VISA only. Identifiers of the couple Token Requestor - Token Service Provider"},"originalDigitalCardRequestorId":{"type":"string","description":"Applies only to VISA in case of token for token provisioning","minLength":11,"maxLength":11}}},"eligibilityInformation":{"type":"object","description":"Provides details about the eligibility check operation","properties":{"cardBIN":{"type":"string","minLength":6,"maxLength":6},"eligible":{"type":"boolean"},"cardProduct":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":64},"name":{"type":"string","minLength":1,"maxLength":256}}}},"required":["cardBIN","eligible"]},"digitizationInformation":{"type":"object","description":"Provides details about the tokenization (digitization) operation whatever the result is (that is, successful, pending or cancelled)","title":"digitizationInformation","properties":{"digitizationChecks":{"type":"object","required":["issuerVerifications","decisionEngineVerifications","digitalCardRequestorAssessment"],"properties":{"issuerVerifications":{"$ref":"#/components/schemas/issuerVerifications"},"decisionEngineVerifications":{"$ref":"#/components/schemas/decisionEngineVerifications"},"digitalCardRequestorAssessment":{"$ref":"#/components/schemas/digitalCardRequestorAssessment"},"verificationCodes":{"type":"array","maxItems":100,"description":"D1 Verification codes generated by the decision engine during rule evaluation. Following values are possible:\n\t \n|value |description| \n|-----------|----------------------------------| \n|TR_RECOMMENDATION_NOT_AVAILABLE|wallet recommendation is missing|\n|TR_DEVICE_SCORE_NOT_AVAILABLE|device scoring is missing|\n|TR_ACCOUNT_SCORE_NOT_AVAILABLE|account scoring is missing|","items":{"type":"string"}},"matchedRule":{"type":"object","description":"Decision Engine rule triggerig the final decision.\r\n\r\nApplicable only to Decision Engine Version V2","required":["id"],"properties":{"id":{"type":"string","description":"Unique identifier of the matching rule."},"name":{"type":"string","description":"Name of the matching rule."},"scenario":{"type":"object","description":"The actual matching scenario ","required":["id"],"properties":{"id":{"type":"string","description":"Unique identifier of the matched scenario."},"name":{"type":"string","description":"Name of the matched scenario."}}}}}}},"digitizationResult":{"type":"object","required":["flow"],"properties":{"flow":{"type":"string","description":"Tokenization Decision Engine assessment result.\nFollowing values are possible:\n- RED (DECLINE)\n- GREEN (APPROVE)\n- YELLOW (STEP-UP)","minLength":1,"maxLength":64,"enum":["RED","YELLOW","GREEN"]},"score":{"type":"string","minLength":1,"maxLength":1,"pattern":"[1-5]{1,1}$","description":"This is the final score the decision engine has computed considering all the verifications and the scoring from the requestor and/or TSP.\nScore goes from 1 (low trust) to 5 (high trust)."},"idAndVMethods":{"$ref":"#/components/schemas/idAndVMethods"},"digitizationDecisionTimestamp":{"type":"string","minLength":1,"maxLength":64,"description":"The time when the digitization decision has been sent to the TSP.\nThis parameter can be used by the Issuer to manage the notifications to cardholder in case of PENDING status of digitize operation.\nFormat ISO 8601 YYYY-MM-DDThh:mm:ssTZD\n"}}}},"required":["digitizationChecks","digitizationResult"]},"issuerVerifications":{"title":"issuerVerifications","type":"object","properties":{"cardIsExpired":{"$ref":"#/components/schemas/result"},"cardIsLostOrStolen":{"$ref":"#/components/schemas/result"},"wrongCVV":{"$ref":"#/components/schemas/result"},"fraudSuspect":{"$ref":"#/components/schemas/result"},"cardIsInvalid":{"$ref":"#/components/schemas/result"}},"required":["cardIsExpired","cardIsLostOrStolen","wrongCVV","fraudSuspect","cardIsInvalid"]},"result":{"title":"result","type":"object","properties":{"result":{"type":"string","enum":["YES","NO","NOT_APPLICABLE"]}}},"decisionEngineVerifications":{"title":"decisionEngineVerifications","type":"object","properties":{"tooManyDigitizationRequests":{"$ref":"#/components/schemas/result"},"tooManyCVVVerificationFailed":{"$ref":"#/components/schemas/result"},"walletPhoneNumberNotMatchingConsumerPhoneNumber":{"$ref":"#/components/schemas/result"},"digitizationCountExceededOnSameFPAN":{"$ref":"#/components/schemas/result"},"digitizationCountExceededOnSameDevice":{"$ref":"#/components/schemas/result"},"cardIsExpired":{"$ref":"#/components/schemas/result"},"cardIsInvalid":{"$ref":"#/components/schemas/result"},"wrongCVV":{"$ref":"#/components/schemas/result"},"CVVNotProvided":{"$ref":"#/components/schemas/CVVNotProvided"}},"required":["tooManyDigitizationRequests","tooManyCVVVerificationFailed","walletPhoneNumberNotMatchingConsumerPhoneNumber","digitizationCountExceededOnSameFPAN","digitizationCountExceededOnSameDevice","cardIsExpired","cardIsInvalid","wrongCVV","CVVNotProvided"]},"CVVNotProvided":{"title":"CVVNotProvided","type":"object","description":"If CVV has not been provided by the digital card requestor, then D1 verifies if this is incompatible with either the card capture method used or the digital card type requested.","properties":{"incompatibleWithCaptureMethod":{"$ref":"#/components/schemas/captureMethodIncompatible"},"incompatibleWithDigitalCardType":{"$ref":"#/components/schemas/digitalCardTypeIncompatible"}},"required":["incompatibleWithCaptureMethod","incompatibleWithDigitalCardType"]},"captureMethodIncompatible":{"title":"captureMethodIncompatible","type":"object","properties":{"result":{"type":"string","enum":["YES","NO","NOT_APPLICABLE"]}},"description":"If the capture method of the card details is NOT one of the following:\n- BANK_APP (card details from the Banking App)\n- TOKEN (card details derived by the TSP from an existing digital card)\n- ON-FILE (card details from a card stored on file)\n\nthen the absence of CVV is unexpected, the result will be YES"},"digitalCardTypeIncompatible":{"title":"digitalCardTypeIncompatible","type":"object","properties":{"result":{"type":"string","enum":["YES","NO","NOT_APPLICABLE"]}},"description":"If the digital card type required is NOT one of the following:\n- COF (card on file)\n- ECOM (e-Commerce)\n\nthen the absence of CVV is unexpected, the result will be YES"},"digitalCardRequestorAssessment":{"title":"digitalCardRequestorAssessment","type":"object","required":["averageScore","deviceScore","accountScore","recommendation"],"properties":{"averageScore":{"type":"string","description":"Average scoring from the digital card requestor. Following values are possible:\n\nNOT_APPLICABLE (score is based on data from digital card requestor. If the data is not available, average can't be computed).\n1\n2\n3\n4\n5"},"deviceScore":{"type":"string","description":"Following values are possible:\n\nNOT_APPLICABLE (score is based on data from digital card requestor. If the data is not available, score can't be provided).\n1\n2\n3\n4\n5"},"accountScore":{"type":"string","description":"Wallet Provider account scoring, low values means high risk.\nFollowing values are possible:\n\nNOT_APPLICABLE (score is based on data from digital card requestor. If the data is not available, score can't be provided).\n\n1 2 3 4 5"},"recommendation":{"$ref":"#/components/schemas/walletRecommendation"},"reasonCodesRecommendationDescription":{"type":"array","description":"This field shall allow to list the received Wallet Reason Code Recommendation(s).Values are mapped to more user friendly descriptions. The full list of mapped codes is available here: https://docs.payments.thalescloud.io/implement-tokenization/card-tokenization-request/processing-the-decision/decision-engine/data-validation-codes/wallet-reason-codes","uniqueItems":true,"items":{"type":"object"}}}},"walletRecommendation":{"type":"string","description":"Wallet/Digital Card Requestor colour recommended during the card tokenization request\n\nPlease note that in certain situations a recommendation might be not provided by the wallet.","enum":["NOT_APPLICABLE","GREEN","YELLOW","ORANGE","RED"]},"idAndVMethods":{"additionalProperties":false,"type":"object","properties":{"supported":{"type":"array","items":{"type":"string"}},"selected":{"type":"string","minLength":1,"maxLength":64,"description":"The following values are possible:\n- OTP_BY_SMS\n- OTP_BY_EMAIL\n- BANK_APP\n- CUSTOMER_SERVICE"}}},"pullOperation":{"title":"UPDATE_ORDER operation","type":"object","description":"The update order status notification details","required":["pullType","status"],"properties":{"pullType":{"type":"string","description":"The type of change to apply on the card order","enum":["ACCELERATE","ACCELERATE_AND_REDIRECT","CANCEL","REDIRECT"]},"status":{"$ref":"#/components/schemas/updateOrderStatus"},"newDeliveryAddress":{"description":"The new delivery address","$ref":"#/components/schemas/addressInPullNotification"}}},"updateOrderStatus":{"type":"string","enum":["PULL_SUCCESSFUL","PULL_FAILED"],"description":"The status of pull request.\n\n|status code                | description                                                                                                       |\n|---------------------------|-------------------------------------------------------------------------------------------------------------------|\n|PULL_SUCCESSFUL        | The pull request was successfully processed.                                                                          |\n|PULL_FAILED            | The pull request processing failed.                                                                                   |\n| \n"},"addressInPullNotification":{"allOf":[{"$ref":"#/components/schemas/addressCommonFields"}]},"addressCommonFields":{"type":"object","required":["lastName","line1","zipCode","city","countryCode"],"properties":{"title":{"type":"string","description":"The title.","minLength":1,"maxLength":40,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,40}$"},"firstName":{"type":"string","description":"The first name.","minLength":1,"maxLength":40,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,40}$"},"lastName":{"type":"string","description":"The last name.","minLength":1,"maxLength":40,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,40}$"},"companyName":{"type":"string","description":"The name of the company.","minLength":1,"maxLength":64,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,64}$"},"line1":{"type":"string","description":"The first line of the address.","minLength":1,"maxLength":64,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,64}$"},"line2":{"type":"string","description":"The second line of the address.","minLength":1,"maxLength":64,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,64}$"},"line3":{"type":"string","description":"The third line of the address.","minLength":1,"maxLength":64,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,64}$"},"city":{"type":"string","description":"The city name.","minLength":1,"maxLength":32,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,32}$"},"state":{"type":"string","description":"The state.","minLength":1,"maxLength":30,"pattern":"^[\\p{L}\\p{N}\\p{M} ,.'_#;:\\/-]{1,30}$"},"zipCode":{"type":"string","description":"The zip Code.","minLength":1,"maxLength":10,"pattern":"^[0-9A-Z- ]{1,10}$"},"countryCode":{"type":"string","description":"The country code, based on ISO 639-1 alpha-2 format","minLength":2,"maxLength":2,"pattern":"^[A-Z]{2}$"},"email":{"type":"string","description":"The email, used for card shipment contact purpose.","minLength":1,"maxLength":255,"pattern":"^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,15}$"}}},"trackingOperation":{"type":"object","title":"STANDALONE_TRACKING","description":"The card tracking details","required":["status"],"properties":{"status":{"type":"string","enum":["CARD_SHIPPED","CARD_RETURNED"],"description":"The current status of card.\n\n- CARD_SHIPPED: The card has been picked up by the carrier.\n- CARD_RETURNED: The card has been returned back to sender and destroyed.\n"},"trackingType":{"type":"string","enum":["PRODUCTION","SHIPMENT","RETURN"],"description":"The current status of card.\n\n- PRODUCTION: Track Card Production.\n- SHIPMENT: Track Card Production and Shipment.\n- RETURN: Track Card return.\n"},"productionSite":{"maxLength":50,"minLength":0,"type":"string","description":"The factory where the card is produced."},"shipment":{"$ref":"#/components/schemas/shipment"}}},"errorGenericWithErrorCodeOutbound":{"additionalProperties":false,"type":"object","description":"Generic error returned by the APIs.","properties":{"errorCode":{"type":"string","description":"The type of the error"},"error":{"type":"string","description":"Provide more error details if possible.<br/>For example name of the field with invalid format."}}}},"responses":{"ServiceUnavailableError-outbound":{"description":"The service is temporarily unavailable. D1 will retry the request later."}}},"paths":{"/notifications/d1/v2/issuers/{issuerId}/cards":{"post":{"parameters":[{"schema":{"type":"string"},"in":"header","name":"Authorization","description":"Oauth Access token (optional)"}],"summary":"Notify Card Operations","operationId":"notifyCardOperations","description":"This request is used by D1 to notify the system of the bank about any card status update.<br>\nThere is a retry mechanism in case the notification has not been sent.\nThus the bank system can use this notification to synchronize card status with their card repository.<br>\nThe number max of card status update in the notification is defined at onboarding time according to bank's system capability.<br>\nEach update is linked to a given card id, and can contain a message dedicated for the final end-user.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"operations":{"type":"array","items":{"$ref":"#/components/schemas/CardStatus-operation-notification"}}}}}}},"responses":{"204":{"description":"Successful"},"400":{"description":"Bad Request, Invalid request URI, header, paramters.<br> \nD1 will not retry the request until the issue is considered as resolved.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGenericWithErrorCodeOutbound"}}}},"401":{"description":"Unauthorized request.<br>\nD1 will not retry the request until the issue is considered as resolved.            ","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGenericWithErrorCodeOutbound"}}}},"403":{"description":"Forbidden action<br>\nD1 will not retry the request until the issue is considered as resolved.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGenericWithErrorCodeOutbound"}}}},"404":{"description":"Ressource not found, Unknown issuerId<br>\nD1 will not retry the request until the issue is considered as resolved.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGenericWithErrorCodeOutbound"}}}},"500":{"description":"Internal Server Error. D1 will retry the request later.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errorGenericWithErrorCodeOutbound"}}}},"503":{"$ref":"#/components/responses/ServiceUnavailableError-outbound"}}}}}}
````


# Developer Platform

Welcome to your team’s developer platform

{% columns %}
{% column width="58.333333333333336%" valign="middle" %}

### Empowering card issuers and banks to <mark style="color:$primary;">revolutionize payments</mark>

At Thales, we empower banks and card issuers to accelerate their modern card programs, enabling delivery of trusted, convenient and state-of-the-art digital banking and payment services to billions

<a href="https://www.thalesgroup.com/en/solutions-catalogue/enterprise/financial-services/card-issuing-solution-payment-card-issuers-banks" class="button primary">Learn more</a>
{% endcolumn %}

{% column width="41.666666666666664%" %}

<figure><img src="/files/oEHiLYXobaZhp6dOjWWy" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

<h3 align="center">Why Thales for <mark style="color:$primary;">Card Issuers &#x26; Banks</mark>?</h3>

<figure><img src="/files/wKziRvQMB72ftD9H9tOx" alt=""><figcaption></figcaption></figure>

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th></tr></thead><tbody><tr><td><h4><mark style="color:$primary;">•</mark> Faster time to market</h4></td><td>Accelerate modern card issuing with a streamlined digital roadmap</td></tr><tr><td><h4><mark style="color:$primary;">•</mark> Seamless Issuance API</h4></td><td>One integration for both online and in-person issuance workflows</td></tr><tr><td><h4><mark style="color:$primary;">•</mark> Control costs</h4></td><td>Help issuers control engineering, maintenance and operating costs by optimising processes</td></tr><tr><td><h4><mark style="color:$primary;">•</mark> Simplified IT &#x26; compliance</h4></td><td>Reduce IT burden with modern card issuing, easing compliance and security challenges</td></tr></tbody></table>

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

<figure><img src="/files/5zb2WA9taIGu84uEC4Oc" alt="" width="375"><figcaption></figcaption></figure>
{% endcolumn %}

{% column valign="middle" %}

### Global <mark style="color:$primary;">scale & trust</mark>

Supporting over 3,000 institutions with multiple payment methods across digital and physical transactions
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

### Card Issuers and Banks <mark style="color:$primary;">products</mark>

#### **Tokenization**

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-type="content-ref"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Tokenization</strong></td><td>Replace sensitive card numbers with secure digital tokens to reduce fraud and enable safe mobile and online payments.</td><td><a href="/files/rP1UEkmTEKpaQfdstoGC">/files/rP1UEkmTEKpaQfdstoGC</a></td><td><a href="/spaces/W6dljaTEEzefPQILRFB7">/spaces/W6dljaTEEzefPQILRFB7</a></td><td><a href="/spaces/W6dljaTEEzefPQILRFB7">/spaces/W6dljaTEEzefPQILRFB7</a></td></tr><tr><td><strong>Push Provisioning</strong></td><td>Securely deliver cards directly into mobile wallets (Apple Pay, Google Pay, Samsung Pay…) from your app with minimal user friction.</td><td><a href="/files/dcpaZiSMwbuV55o2EqqI">/files/dcpaZiSMwbuV55o2EqqI</a></td><td><a href="/spaces/WDlYTPaq4dNHuiWtf8ux">/spaces/WDlYTPaq4dNHuiWtf8ux</a></td><td><a href="/spaces/WDlYTPaq4dNHuiWtf8ux">/spaces/WDlYTPaq4dNHuiWtf8ux</a></td></tr><tr><td><strong>NFC Payment</strong></td><td>Enable fast, secure tap-to-pay experiences using NFC for cards, smartphones, and wearables.</td><td><a href="/files/omh3pWO8fn6EEEWeP6bs">/files/omh3pWO8fn6EEEWeP6bs</a></td><td><a href="/spaces/ZgiyG6N9D1zZznYclcT7">/spaces/ZgiyG6N9D1zZznYclcT7</a></td><td><a href="/spaces/ZgiyG6N9D1zZznYclcT7">/spaces/ZgiyG6N9D1zZznYclcT7</a></td></tr><tr><td><strong>Click to Pay</strong></td><td>Offer a standardized EMVCo checkout that speeds up online payments and improves conversion.</td><td><a href="/files/eC3HGMMEV4FbXPHI5YPC">/files/eC3HGMMEV4FbXPHI5YPC</a></td><td><a href="/spaces/uKGiYHoxBTUoHkwRFlXH">/spaces/uKGiYHoxBTUoHkwRFlXH</a></td><td><a href="/spaces/uKGiYHoxBTUoHkwRFlXH">/spaces/uKGiYHoxBTUoHkwRFlXH</a></td></tr></tbody></table>

#### Transaction Control

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Transaction Control</strong></td><td>Allow cardholders to manage spending limits, and domain control in real time.</td><td><a href="/files/IFI2oRQuJgUKCZN0pxNi">/files/IFI2oRQuJgUKCZN0pxNi</a></td><td><a href="/spaces/HmPuatDdrQt7vDstf0NP">/spaces/HmPuatDdrQt7vDstf0NP</a></td></tr><tr><td><strong>Dynamic CVV</strong></td><td>Reduce online fraud with CVVs that update automatically at regular intervals.</td><td><a href="/files/UqkUxAhKj5o9pHxkRwLb">/files/UqkUxAhKj5o9pHxkRwLb</a></td><td><a href="/spaces/5VOT3Bv7Bs6VgM2Hf9li">/spaces/5VOT3Bv7Bs6VgM2Hf9li</a></td></tr><tr><td><strong>3D Secure</strong></td><td>Authenticate online transactions with strong customer verification, improving security and approval rates.</td><td><a href="/files/44YhCqBgzPd3uXPtG2JQ">/files/44YhCqBgzPd3uXPtG2JQ</a></td><td><a href="/spaces/ZbrxO27N21lFBogZ9mkF/pages/rwLRxtdALdUT5z5MuLau#protect-every-transaction-with-smarter-authentication">/spaces/ZbrxO27N21lFBogZ9mkF/pages/rwLRxtdALdUT5z5MuLau#protect-every-transaction-with-smarter-authentication</a></td></tr></tbody></table>

#### Digital Issuing

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Secure Card Display</strong></td><td>Offer physical cards with dynamic, real-time credentials for added fraud protection.</td><td><a href="/files/wVqGzGCTZuggCHqWyqU2">/files/wVqGzGCTZuggCHqWyqU2</a></td><td><a href="/spaces/dtyHvT2CJEJbb6gkHON7">/spaces/dtyHvT2CJEJbb6gkHON7</a></td></tr></tbody></table>

#### **Physical Card Issuance**&#x20;

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Central Issuance</strong></td><td>Manage secure production, personalization, and delivery of physical cards end-to-end.</td><td><a href="/files/I9as22FCKUhKI0JJHDgC">/files/I9as22FCKUhKI0JJHDgC</a></td><td><a href="/spaces/WhgSoXgpjZJxLx4cDHB1">/spaces/WhgSoXgpjZJxLx4cDHB1</a></td></tr><tr><td><strong>Instant Issuance</strong></td><td>Empower customers to receive fully personalised EMV cards within minutes</td><td><a href="/files/JbIfjDaQXoRV1l3keBmk">/files/JbIfjDaQXoRV1l3keBmk</a></td><td></td></tr><tr><td><strong>PIN Management</strong></td><td>Let users set, update, or recover their PIN directly through digital channels.</td><td><a href="/files/mPvEwwS5t1I1iXWOAjG1">/files/mPvEwwS5t1I1iXWOAjG1</a></td><td><a href="/spaces/Ezl7yJruGtpgrpgTXEjo">/spaces/Ezl7yJruGtpgrpgTXEjo</a></td></tr><tr><td><strong>Card Perso Services</strong></td><td>Create personalized and co‑branded payment cards at scale — designed by your customers or your partners, and issued seamlessly through any Thales or partner issuance channels</td><td><a href="/files/FTepeBGnE5KppX39a3ar">/files/FTepeBGnE5KppX39a3ar</a></td><td></td></tr></tbody></table>

<div align="left"><figure><img src="/files/aqTUWCxCSJtL7B3fdw7A" alt="" width="122"><figcaption></figcaption></figure></div>

{% columns %}
{% column width="91.66666666666666%" valign="middle" %}

### <mark style="color:$primary;">Start Building</mark> with Thales

Accelerate your payment solutions and deliver secure, scalable experiences today.

<a href="https://lp.thalesgroup.com/dev-portal" class="button primary">Contact Us</a>&#x20;

&#x20;
{% endcolumn %}

{% column width="8.333333333333343%" %}

{% endcolumn %}
{% endcolumns %}


# Developer Platform

Welcome to your team’s developer platform

{% columns %}
{% column width="58.333333333333336%" valign="middle" %}

### Enhancing Digital Wallets <mark style="color:$primary;">with Frictionless Payments</mark>

At Thales, we help digital wallet providers deliver trusted and seamless payment experiences with our scheme-certified SDK.

<a href="https://www.thalesgroup.com/en/solutions-catalogue/enterprise/financial-services/digital-wallet-solutions" class="button primary">Learn more</a>
{% endcolumn %}

{% column width="41.666666666666664%" %}

<figure><img src="/files/jkyrEYOQwHsWmE2Ms3QV" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

<h3 align="center">Why Thales for <mark style="color:$primary;">Digital Wallets</mark>?</h3>

<figure><img src="/files/BWR0zkod582pYyYoEXiF" alt=""><figcaption></figcaption></figure>

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th></tr></thead><tbody><tr><td><h4><mark style="color:$primary;">•</mark> Launch Faster and Expand Globally</h4></td><td>We support all payment schemes, both international and domestic. Our unique expertise helps you launch faster and positions you among the first in your market.</td></tr><tr><td><h4><mark style="color:$primary;">•</mark> Deliver Best-in-Class Contactless Payment Experience</h4></td><td>Whether integrating OEM Pays or launching your own wallet, our scheme-certified SDK enables frictionless NFC payments with smooth 1-tap and 2-tap flows on Android and iOS, fully compliant with global and domestic schemes.</td></tr></tbody></table>

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

<figure><img src="/files/hqaKpZUxMSguYbXTLgqW" alt=""><figcaption></figcaption></figure>
{% endcolumn %}

{% column valign="middle" %}

#### <mark style="color:$primary;">Secure and Scale</mark> with Confidence

Our hybrid cloud architecture delivers resilient, high-performance, high-volume operations with no compromise on security or scalability, backed by a 99.99% uptime SLA.

{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

### Digital Wallets <mark style="color:$primary;">products</mark>

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>NFC Wallet</strong></td><td>Enable your own branded wallet to support secure tap-to-pay using NFC.</td><td><a href="/files/clLdettFjtArug5FW0s0">/files/clLdettFjtArug5FW0s0</a></td><td><a href="/spaces/1qH2BUpGoh4ljBdsqlZq">/spaces/1qH2BUpGoh4ljBdsqlZq</a></td></tr></tbody></table>

<div align="left"><figure><img src="/files/O3QF4hUwzQ5X8YETEWy5" alt="" width="122"><figcaption></figcaption></figure></div>

{% columns %}
{% column width="91.66666666666666%" valign="middle" %}

### <mark style="color:$primary;">Start Building</mark> with Thales

Accelerate your payment solutions and deliver secure, scalable experiences today.

<a href="https://lp.thalesgroup.com/dev-portal" class="button primary">Contact Us</a>&#x20;

&#x20;
{% endcolumn %}

{% column width="8.333333333333343%" %}

{% endcolumn %}
{% endcolumns %}


# Page

{% columns %}
{% column width="58.333333333333336%" valign="middle" %}

### Enhance Your Domestic Payment Scheme with <mark style="color:$primary;">Secure, Modular Payment Solutions</mark>

Thales helps domestic payment schemes stay secure, innovative, and compliant while meeting local and global demands.

<a href="https://www.thalesgroup.com/en/solutions-catalogue/enterprise/financial-services/thales-domestic-payment-schemes" class="button primary">Learn more</a>
{% endcolumn %}

{% column width="41.666666666666664%" %}

<figure><img src="/files/NJqbSBrmLpAJTcPWgmkg" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

<h3 align="center">Why Thales for <mark style="color:$primary;">Domestic Payment Schemes</mark> ?</h3>

<figure><img src="/files/5DeWV7Q8owcm28dKwP0M" alt=""><figcaption></figcaption></figure>

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th></tr></thead><tbody><tr><td><h4><mark style="color:$primary;">•</mark> Stay Compliant &#x26; Secure</h4></td><td>Keep up with evolving regulations and security demands. Thales offers a range of solutions to ensure compliance, security, and market adaptability.</td></tr><tr><td><h4><mark style="color:$primary;">•</mark> Flexible &#x26; Scalable</h4></td><td>Scale your payment infrastructure with ease. Thales' modular solutions grow with your needs, offering flexibility across payment methods and technologies.</td></tr></tbody></table>

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

### Domestic Payment Schemes <mark style="color:$primary;">Services</mark>

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th><th data-hidden data-card-cover data-type="image">Cover image</th></tr></thead><tbody><tr><td><strong>xPay Enablement</strong></td><td>Activate cards across major mobile wallets and manage the full lifecycle of tokens securely and efficiently.</td><td><a href="/spaces/uVU9HE1S0V7GM7BaU9NB">/spaces/uVU9HE1S0V7GM7BaU9NB</a></td><td><a href="/files/WW9SMNI4nIMEs6oX5w5H">/files/WW9SMNI4nIMEs6oX5w5H</a></td></tr></tbody></table>

<div align="left"><figure><img src="/files/O3QF4hUwzQ5X8YETEWy5" alt="" width="122"><figcaption></figcaption></figure></div>

{% columns %}
{% column width="91.66666666666666%" valign="middle" %}

### <mark style="color:$primary;">Start Building</mark> with Thales

Accelerate your payment solutions and deliver secure, scalable experiences today.

<a href="https://lp.thalesgroup.com/dev-portal" class="button primary">Contact Us</a>&#x20;

&#x20;
{% endcolumn %}

{% column width="8.333333333333343%" %}

{% endcolumn %}
{% endcolumns %}


# Private Label Issuers

{% columns %}
{% column width="58.333333333333336%" valign="middle" %}

### Empowering Private Label Issuers to Innovate and <mark style="color:$primary;">Efficiently Issue Physical and Digital Cards</mark>.

At Thales, we help private label issuers streamline the issuance of physical, digital, and virtual EMV cards with our flexible, cloud-based D1 platform, supporting open-loop, closed-loop, and hybrid schemes.

<a href="https://www.thalesgroup.com/en/solutions-catalogue/enterprise/financial-services/d1-private-labels-issuers" class="button primary">Learn more</a>
{% endcolumn %}

{% column width="41.666666666666664%" %}

<figure><img src="/files/auBFvJLH7GUhJcxRmmk1" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

<h3 align="center">Why Thales for <mark style="color:$primary;">Private Label Issuers</mark>?</h3>

<figure><img src="/files/fzZzklecmFlWAGRjWyUG" alt=""><figcaption></figcaption></figure>

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th></tr></thead><tbody><tr><td><h4><mark style="color:$primary;">•</mark> Customer Reach &#x26; Market Expansion</h4></td><td>Thales enables private label issuers to maximize point-of-sale reach by supporting both closed-loop and open-loop cards, expanding their customer base locally and internationally.</td></tr><tr><td><h4><mark style="color:$primary;">•</mark> Acceptance Across Networks</h4></td><td>Thales’ solutions support multiple payment kernels, enabling private label issuers to ensure wide acceptance across their own and partner networks, expanding card reach and enhancing the customer experience.</td></tr></tbody></table>

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th></tr></thead><tbody><tr><td><h4><mark style="color:$primary;">•</mark> End-to-End Support &#x26; Guidance</h4></td><td>Thales provides end-to-end support from consultation to implementation, enabling private label issuers to rely on expert guidance for secure, efficient payment migration and tailored solutions.</td></tr><tr><td><h4><mark style="color:$primary;">•</mark> Modern Card Issuance</h4></td><td>With the D1 platform, issuers can issue physical and digital cards in multiple formats, including instant virtual cards, while enabling real-time tracking of physical card deliveries for a seamless experience.</td></tr></tbody></table>

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

### Private Label Issuers <mark style="color:$primary;">Products</mark>

#### Tokenization

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th><th data-hidden data-card-cover data-type="image">Cover image</th></tr></thead><tbody><tr><td><strong>Tokenization</strong></td><td>Replace sensitive card numbers with secure digital tokens to reduce fraud and enable safe mobile and online payments.</td><td><a href="/spaces/W6dljaTEEzefPQILRFB7">/spaces/W6dljaTEEzefPQILRFB7</a></td><td><a href="/files/TPxFAvITnoLk3QeFAt5H">/files/TPxFAvITnoLk3QeFAt5H</a></td></tr><tr><td><strong>Push Provisioning</strong></td><td>Securely deliver cards directly into mobile wallets (Apple Pay, Google Pay, Samsung Pay…) from your app with minimal user friction.</td><td><a href="/spaces/WDlYTPaq4dNHuiWtf8ux">/spaces/WDlYTPaq4dNHuiWtf8ux</a></td><td><a href="/files/zELvXdbFE81Twpkua8pC">/files/zELvXdbFE81Twpkua8pC</a></td></tr><tr><td><strong>xPay Enablement</strong></td><td>Activate cards across major mobile wallets and manage the full lifecycle of tokens securely and efficiently.</td><td><a href="/spaces/uVU9HE1S0V7GM7BaU9NB">/spaces/uVU9HE1S0V7GM7BaU9NB</a></td><td><a href="/files/CVaJR4VJKQezDQxInSDY">/files/CVaJR4VJKQezDQxInSDY</a></td></tr><tr><td><strong>NFC Payment</strong></td><td>Enable fast, secure tap-to-pay experiences using NFC for cards, smartphones, and wearables.</td><td><a href="/spaces/ZgiyG6N9D1zZznYclcT7">/spaces/ZgiyG6N9D1zZznYclcT7</a></td><td><a href="/files/cYvsBcrYzeG0DwdjNLKH">/files/cYvsBcrYzeG0DwdjNLKH</a></td></tr></tbody></table>

#### Transaction Control

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Transaction Control</strong></td><td>Allow cardholders to manage spending rules, usage limits, and restrictions in real time.</td><td><a href="/files/pK0DsxwxvohWg8Cf2FSp">/files/pK0DsxwxvohWg8Cf2FSp</a></td><td><a href="/spaces/HmPuatDdrQt7vDstf0NP">/spaces/HmPuatDdrQt7vDstf0NP</a></td></tr><tr><td><strong>Dynamic CVV</strong></td><td>Reduce online fraud with CVVs that update automatically at regular intervals.</td><td><a href="/files/McsuV3ZBUMsGFBi7rWn1">/files/McsuV3ZBUMsGFBi7rWn1</a></td><td><a href="/spaces/5VOT3Bv7Bs6VgM2Hf9li">/spaces/5VOT3Bv7Bs6VgM2Hf9li</a></td></tr><tr><td><strong>3D Secure</strong></td><td>Authenticate online transactions with strong customer verification, improving security and approval rates.</td><td><a href="/files/x73iFno4fzIw93xEyAl1">/files/x73iFno4fzIw93xEyAl1</a></td><td><a href="/spaces/ZbrxO27N21lFBogZ9mkF">/spaces/ZbrxO27N21lFBogZ9mkF</a></td></tr></tbody></table>

#### Digital Issuing

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Secure Card Display</strong></td><td>Offer physical cards with dynamic, real-time credentials for added fraud protection.</td><td><a href="/files/muw8P2w9XDqeom5tjumP">/files/muw8P2w9XDqeom5tjumP</a></td><td><a href="/spaces/dtyHvT2CJEJbb6gkHON7">/spaces/dtyHvT2CJEJbb6gkHON7</a></td></tr></tbody></table>

#### **Physical Card Issuance**&#x20;

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Central Issuance</strong></td><td>Manage secure production, personalization, and delivery of physical cards end-to-end.</td><td><a href="/files/I9as22FCKUhKI0JJHDgC">/files/I9as22FCKUhKI0JJHDgC</a></td><td><a href="/spaces/WhgSoXgpjZJxLx4cDHB1">/spaces/WhgSoXgpjZJxLx4cDHB1</a></td></tr><tr><td><strong>Instant Issuance</strong></td><td>Empower customers to receive fully personalised EMV cards within minutes</td><td><a href="/files/JbIfjDaQXoRV1l3keBmk">/files/JbIfjDaQXoRV1l3keBmk</a></td><td><a href="/spaces/1qJ8OQRIA2FuYOSRgnR2">/spaces/1qJ8OQRIA2FuYOSRgnR2</a></td></tr><tr><td><strong>PIN Management</strong></td><td>Let users set, update, or recover their PIN directly through digital channels.</td><td><a href="/files/mPvEwwS5t1I1iXWOAjG1">/files/mPvEwwS5t1I1iXWOAjG1</a></td><td><a href="/spaces/Ezl7yJruGtpgrpgTXEjo">/spaces/Ezl7yJruGtpgrpgTXEjo</a></td></tr><tr><td><strong>Perso Design Services</strong></td><td>Create personalized and co‑branded payment cards at scale — designed by your customers or your partners, and issued seamlessly through any Thales or partner issuance channels</td><td><a href="/files/FTepeBGnE5KppX39a3ar">/files/FTepeBGnE5KppX39a3ar</a></td><td><a href="/spaces/GXrAcxed6FAfqv2HHr1N">/spaces/GXrAcxed6FAfqv2HHr1N</a></td></tr></tbody></table>

<div align="left"><figure><img src="/files/O3QF4hUwzQ5X8YETEWy5" alt="" width="122"><figcaption></figcaption></figure></div>

{% columns %}
{% column width="91.66666666666666%" valign="middle" %}

### <mark style="color:$primary;">Start Building</mark> with Thales

Accelerate your payment solutions and deliver secure, scalable experiences today.

<a href="https://lp.thalesgroup.com/dev-portal" class="button primary">Contact Us</a>&#x20;

&#x20;
{% endcolumn %}

{% column width="8.333333333333343%" %}

{% endcolumn %}
{% endcolumns %}


# Transit

{% columns %}
{% column width="58.333333333333336%" valign="middle" %}

## <mark style="color:$primary;">Enhance the Traveller Journey</mark> with Thales Transit solutions   &#x20;

At Thales, we help transit agencies implement innovative solutions that enhance the traveller experience while reducing operating costs. Our D1 platform digitizes fare products across all major NFC wallets and apps, making fare payment simpler and more secure for passengers.

<a href="https://www.thalesgroup.com/en/solutions-catalogue/enterprise/financial-services/mass-transit-ticketing-solutions" class="button primary">Learn more</a>
{% endcolumn %}

{% column width="41.666666666666664%" %}

<figure><img src="/files/PDPjEks511H9NDxZ55jr" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

<h3 align="center">Why Thales for <mark style="color:$primary;">Transit</mark> ?</h3>

<figure><img src="/files/jFkUQBXNlYoTnVhlGJ8z" alt=""><figcaption></figcaption></figure>

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th></tr></thead><tbody><tr><td><h4><mark style="color:$primary;">•</mark> Improved User Experiences</h4></td><td>The Thales D1 platform enables travellers to instantly purchase tickets and manage fares via digital wallets, with real-time updates for a more convenient and efficient experience.</td></tr><tr><td><h4><mark style="color:$primary;">•</mark> Solutions for All</h4></td><td>D1 supports both account-based and card-based ticketing, integrates with leading NFC technologies (EMV, Calypso, MIFARE DESFire, FeliCa), and works seamlessly with major wallets including Apple Wallet, Google Wallet, and Samsung Pay.</td></tr><tr><td><h4><mark style="color:$primary;">•</mark> Operating Efficiency</h4></td><td>Leveraging the popularity of EMV bank cards, Thales D1 connects to open-loop systems to reduce operational costs, enabling transit agencies to benefit from open-loop infrastructure while remaining independent of financial institutions and regulatory constraints.</td></tr><tr><td><h4><mark style="color:$primary;">•</mark> Inclusive Ticketing</h4></td><td>Thales D1 supports passengers who prefer paying with bank cards digitized in wallets while ensuring inclusive access to convenient transport options for those unable or unwilling to use cards.</td></tr></tbody></table>

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

### Transit <mark style="color:$primary;">Products</mark>

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Transit Digitization</strong></td><td>Convert physical transport cards or tickets into secure digital versions usable on smartphones and wearables.</td><td><a href="/files/rzFzqkQXWJiDCjuTExEk">/files/rzFzqkQXWJiDCjuTExEk</a></td><td><a href="/spaces/ZoFRCpZeaDWwcHYhJY7B">/spaces/ZoFRCpZeaDWwcHYhJY7B</a></td></tr></tbody></table>

{% columns %}
{% column width="91.66666666666666%" valign="middle" %}

### <mark style="color:$primary;">Start Building</mark> with Thales

Accelerate your payment solutions and deliver secure, scalable experiences today.

<a href="https://lp.thalesgroup.com/dev-portal" class="button primary">Contact Us</a>&#x20;

&#x20;
{% endcolumn %}

{% column width="8.333333333333343%" %}

{% endcolumn %}
{% endcolumns %}


# Untitled

{% columns %}
{% column width="58.333333333333336%" valign="middle" %}

### Elevate Your Payments with the Future of <mark style="color:$primary;">Secure Digital Commerce</mark>

Discover the future of seamless payments with our Digital Commerce platform, uniting Network Tokenization (VISA, Mastercard, AMEX) — the cornerstone of modern e-commerce&#x20;

with innovative solutions like Click to Pay, Payment Passkey, and Biometric Payment authentication. Empower your merchants and delight customers with fast, secure, and frictionless transactions

<a href="https://www.thalesgroup.com/en/solutions-catalogue/enterprise/financial-services/card-issuing-solution-payment-card-issuers-banks" class="button primary">Learn more</a>
{% endcolumn %}

{% column width="41.666666666666664%" %}

<figure><img src="/files/ss2bO3ggzQChAl54kodY" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

<h3 align="center">Why Thales for <mark style="color:$primary;">Digital Commerce</mark> ?</h3>

<figure><img src="/files/9X1UJ3uHEmD6BJZXUNvi" alt=""><figcaption></figcaption></figure>

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th></tr></thead><tbody><tr><td><h4><mark style="color:$primary;">•</mark> Faster time to market</h4></td><td>One platform, all international payment schemes – seamless access for you</td></tr><tr><td><h4><mark style="color:$primary;">•</mark> Enhancing Digital Checkout</h4></td><td>From Merchant to PSP, Acquirer to Issuer, we deliver a one stop shop solution.</td></tr><tr><td><h4><mark style="color:$primary;">•</mark> Continuous Product Evolution</h4></td><td>We ensure you always have access to the latest security updates and new features from us, VISA, Mastercard, and other international payment schemes.</td></tr><tr><td><h4><mark style="color:$primary;">•</mark> Security &#x26; High availability</h4></td><td>Our platform is designed to ensure uninterrupted service, delivering a superior 99.99% uptime.</td></tr></tbody></table>

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

{% endcolumn %}

{% column %}

{% endcolumn %}
{% endcolumns %}

### Card Issuers and Banks <mark style="color:$primary;">products</mark>

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><em><strong>Merchant Tokenization</strong></em></td><td><em>Replace sensitive card numbers with secure digital tokens to reduce fraud and enable sage mobile and online payments</em></td><td><a href="/files/UDepOJLNlM9KHFhh5a8O">/files/UDepOJLNlM9KHFhh5a8O</a></td><td><a href="/spaces/9XBN1F9dv7Dl1ggilGWC">/spaces/9XBN1F9dv7Dl1ggilGWC</a></td></tr><tr><td><em><strong>Merchant Click to Pay</strong></em></td><td><em>Offer a standardized EMVCo checkout that speeds up online payments and improves conversion</em></td><td><a href="/files/4Harl3YwaXdaTIN3qES3">/files/4Harl3YwaXdaTIN3qES3</a></td><td><a href="/spaces/MvQajFqINagsokrwMXOu">/spaces/MvQajFqINagsokrwMXOu</a></td></tr><tr><td><strong>Merchant Payment Passkey</strong></td><td>Enable fast, secure tap-to-pay experiences using NFC for cards, smartphones, and wearables.</td><td><a href="/files/g2gKUSTO4WSrVCpQIaGc">/files/g2gKUSTO4WSrVCpQIaGc</a></td><td></td></tr></tbody></table>

{% columns %}
{% column width="91.66666666666666%" valign="middle" %}

### <mark style="color:$primary;">Start Building</mark> with Thales

Accelerate your payment solutions and deliver secure, scalable experiences today.

<a href="https://lp.thalesgroup.com/dev-portal" class="button primary">Contact Us</a>&#x20;

&#x20;
{% endcolumn %}

{% column width="8.333333333333343%" %}

{% endcolumn %}
{% endcolumns %}


# NFC Wallet SDK (Android)

## NFC Wallet SDK for Android

This documentation helps you integrate and maintain the **NFC Wallet SDK** in an Android **digital wallet application**.

<table data-view="cards"><thead><tr><th>Topic</th><th data-card-target data-type="content-ref">Link</th></tr></thead><tbody><tr><td>Understand what Thales delivers</td><td><a href="/pages/4vPvICp4CnramiCAgqIK">/pages/4vPvICp4CnramiCAgqIK</a></td></tr><tr><td>Integrate the SDK and configure your project</td><td><a href="/pages/NQBalcWhV0F4tYbKtmx4">/pages/NQBalcWhV0F4tYbKtmx4</a></td></tr></tbody></table>


# Release Notes


# General

Start here to understand what you receive from Thales for the NFC Wallet SDK. Also review platform support and certification status before integrating into your digital wallet application.

### In this section

* [Deliverables](/nfc-wallet-sdk-android/general/deliverables)\
  Review SDK package contents, documentation, and build recommendations.
* [Certifications](/nfc-wallet-sdk-ios/general/certifications)\
  Check certification status by payment network.
* [Mobile OS compatibility](/nfc-wallet-sdk-ios/general/mobile-os-compatibility)\
  Check latest Android compatibility status.

### Next step

Continue with [Get started](/nfc-wallet-sdk-ios/get-started).


# Deliverables

NFC Wallet SDK for Android includes libraries to integrate into your **digital wallet application**.

The delivery package also includes API documentation to support your integration.

### Library naming

Library files follow this naming convention:

`TSHPaySDK-<build type>-<version number>.<version qualifier>.aar`

`<version qualifier>` is optional and depends on the delivery (for example, `rc1`).

### Build types

`<build type>` is one of:

* `release`: Use for `Production` and certification builds.
* `dev`: Use for development and testing only. It is functionally equivalent to `release`, except it enables SDK logging, HTTP inspection, and debugging. Do not release a **digital wallet application** that includes the `dev` build.

{% hint style="warning" %}
Do not use the `dev` SDK build in `Production`.

* For `Production`, set your **digital wallet application** to non-debuggable:
  * Set `debuggable false` in `build.gradle`.
  * Set `android:debuggable="false"` in `AndroidManifest.xml`.
* If a `Production` build initializes with the `dev` library, initialization fails with `DEBUG_SDK_USED`.
  {% endhint %}


# Certifications

## Overview <a href="#overview" id="overview"></a>

Thales performs regular security and functional certifications for NFC Wallet SDK to meet payment network requirements. Contact **Thales Customer Support** if you need more details.

Before you deploy your digital wallet application to the **Production Environment** for all **End Users**, verify the certification status for each payment network you plan to support.

## Certification status by payment network <a href="#certification-status-by-payment-network" id="certification-status-by-payment-network"></a>

**Mastercard**

<table data-full-width="true"><thead><tr><th width="128.111083984375">SDK version</th><th width="153.00006103515625">Certification status</th><th>Certificate validity</th></tr></thead><tbody><tr><td>Android 6.15</td><td>Exempted by Mastercard</td><td>Refer to 6.13 certification status</td></tr><tr><td>Android 6.14</td><td>Exempted by Mastercard</td><td>Refer to 6.13 certification status</td></tr><tr><td>Android 6.13</td><td>Completed</td><td><p>Component Conformity Statement: 25th Nov 2026</p><p>Security Test Assessment Summary: 25th Nov 2026</p></td></tr></tbody></table>

**Visa**

<table><thead><tr><th width="129.888916015625">SDK version</th><th width="152.111083984375">Certification status</th><th>Certificate validity</th></tr></thead><tbody><tr><td>Android 6.15</td><td>Exempted by Visa</td><td>Refer to 6.14 certification status</td></tr><tr><td>Android 6.14</td><td>Completed</td><td>Valid until 7th November 2026.</td></tr><tr><td>Android 6.12</td><td>Exempted by Visa</td><td>Valid until 31st October 2026</td></tr></tbody></table>

{% hint style="info" %}
**Notes**

* You can integrate and test NFC Wallet SDK (previously **TSH Pay SDK**) before the certification process is completed.
* Thales renews certificates only for the **latest** NFC Wallet SDK release. Plan upgrades before certificate expiry.
  {% endhint %}


# Mobile OS compatibility

NFC Wallet SDK for Android supports a defined set of Android versions.

Thales validates each Android update against the latest NFC Wallet SDK release.

## Supported Android versions by SDK release

Each NFC Wallet SDK release defines the supported Android versions, including the minimum version.

For the requirements that apply to latest SDK version see [Supported configurations](https://gitlab.sre.ops.gcloud.thalescloud.io/bps/gitbook/nfc-wallet-gitbook-docs/-/blob/dev-sdk/NFC-Wallet-SDK-Android/get-started/configuration/1.-binary-integration#supported-configurations).

See release notes for other SDK release.

## Android versioning

{% hint style="info" %}
Android version numbering is defined by Google and may change.
{% endhint %}

Google publishes beta versions before the public release. Use them to validate your digital wallet application early:

* The number and cadence of betas depend on Google’s release plan.
* The public release date can change based on beta feedback.

## Android compatibility status

| Version                   | Release date | Status |
| ------------------------- | ------------ | ------ |
| Android 17 QPR1 Beta 5    | 2026-06-23   | OK     |
| Android 17 Public release | 2026-06-16   | OK     |

Last updated: July 2026


# Get started

This section helps you set up the NFC Wallet SDK in your Android **digital wallet application**.

### Before you begin

* Review what’s included in the SDK delivery package in [Deliverables](/nfc-wallet-sdk-android/general/deliverables).
* Check the supported Android versions in [Supported configurations](https://gitlab.sre.ops.gcloud.thalescloud.io/bps/gitbook/nfc-wallet-gitbook-docs/-/blob/dev-sdk/NFC-Wallet-SDK-Android/get-started/configuration/1.-binary-integration#supported-configurations).

### Set up the SDK

Use these guides to integrate the NFC Wallet SDK into your Android **digital wallet application**.

* Configure your project: [Configuration](/nfc-wallet-sdk-android/get-started/configuration).
* Use the Android **Sample App** as an end-to-end example: [Sample App](/nfc-wallet-sdk-android/get-started/sample-app).

### Next steps

Use these resources after you complete configuration and initialization.

* **Browse the API reference:** [Android API](/nfc-wallet-sdk-android/android-api)
* **Implement the core flow:** [Implement NFC Wallet](/nfc-wallet-sdk-android/implement-nfc-wallet)\
  Start with the contactless capability check. Then enroll the wallet and complete **Tokenization**, card management, and payment.
* **Prepare for release:** [Security guidance](/nfc-wallet-sdk-android/security-and-privacy/security-guidance)\
  Apply security requirements before production rollout. Review logging, data handling, and hardening recommendations.

### Additional features

Add optional capabilities after you implement the core flow.

* [Additional features](/nfc-wallet-sdk-android/additional-features)


# Configuration


# 1. Binary integration

## Integrate the NFC Wallet SDK for Android

Use this guide to add NFC Wallet SDK libraries to your Android **digital wallet application**.

### Supported configurations

Latest NFC Wallet SDK for Android supports the following configurations for this integration:

* **Android version:** 8.1 to 16.0
* **CPU architecture (ABI):** `armeabi-v7a`, `arm64-v8a`

{% hint style="info" %}
Supported Android versions are SDK-release specific. For the latest compatibility status, see [Mobile OS compatibility](/nfc-wallet-sdk-android/general/mobile-os-compatibility).
{% endhint %}

### Copy the AAR files

Get the SDK AAR files from [Deliverables](/nfc-wallet-sdk-android/general/deliverables).

Copy them into a dedicated folder in your project. For example:

```
./dependencies
 ├── TSHPaySDK-dev-[version].[qualifier].aar
 └── TSHPaySDK-release-[version].[qualifier].aar
```

{% hint style="info" %}
NFC Wallet SDK was previously named **TSH Pay SDK**.

Some deliveries still use `TSHPaySDK-...` as the AAR filename prefix.
{% endhint %}

### Configure repositories

Add the folder as a local Maven repository using `flatDir`.

{% tabs %}
{% tab title="Groovy (settings.gradle)" %}
{% code title="settings.gradle" %}

```groovy
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven { url 'https://developer.huawei.com/repo/' }
        flatDir { dirs "$rootDir/dependencies" }
    }
}
```

{% endcode %}
{% endtab %}

{% tab title="Groovy (root build.gradle)" %}
{% code title="build.gradle" %}

```groovy
allprojects {
    repositories {
        google()
        mavenCentral()
        maven { url 'https://developer.huawei.com/repo/' }
        flatDir { dirs "${rootProject.projectDir}/dependencies" }
    }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

### Enable ABI splits

Enable ABI splits to reduce APK size (one APK per ABI). See [Build multiple APKs](/nfc-wallet-sdk-android/get-started/configuration/1.-binary-integration/build-multiple-apks).

### Add dependencies

Declare in depencies:

* NFC Wallet AARs
* required external libraries dependencies:
  * JNA ([Java Native Access](https://github.com/java-native-access/jna/tree/5.17.0))

{% code title="app/build.gradle" expandable="true" %}

```groovy
def nfcWalletSdkVersion = "[version].[qualifier]"

dependencies {
    // NFC Wallet SDK (AAR filenames can still start with "TSHPaySDK")
    debugImplementation(name: "TSHPaySDK-dev-${nfcWalletSdkVersion}", ext: "aar")
    releaseImplementation(name: "TSHPaySDK-release-${nfcWalletSdkVersion}", ext: "aar")

    // SDK Dependency
    // JNA
    implementation(libs.jna) { artifact { type = 'aar' } }
    
    // FCM - Google push notifications
    implementation platform(libs.firebase.bom)
    implementation libs.firebase.messaging
    implementation libs.firebase.analytics

    // Multi-dex application to prevent any size issue.
    implementation libs.multidex
}
```

{% endcode %}

{% hint style="warning" %}
JNA 5.17.0 or later is required to support devices using 16 KB memory pages.
{% endhint %}

{% hint style="info" %}
If you use push notifications (FCM or HMS Push Kit), add the required dependencies. See [Configure push provider](/nfc-wallet-sdk-android/get-started/configuration/5.-push-notifications/configure-push-provider).
{% endhint %}

### Verify the build

The project should be now ready to be synced and compiled.

1. Sync Gradle.
2. Build the `dev` variant.

{% hint style="info" %}
You must comply with Google Play target API level requirements for new or updated digital wallet application releases. See [Meet Google Play's target API level requirement](https://developer.android.com/google/play/requirements/target-sdk).
{% endhint %}


# Build multiple APKs

## Overview

To reduce APK size, generate one APK per CPU architecture (ABI).

For background, see Android’s documentation on APK splits:\
<https://developer.android.com/build/configure-apk-splits>

NFC Wallet SDK supports these ABIs:

* `armeabi-v7a` (32-bit)
* `arm64-v8a` (64-bit)

When you enable ABI splits, Gradle generates one APK per ABI for your **digital wallet application**.

The following figure illustrates the building of APK for 32-bit and 64-bit architectures.

<figure><img src="/files/GzjjwcUNcQNCS1Xgv2J7" alt="Overview of splits for architecture"><figcaption><p>Overview of splits for architectures</p></figcaption></figure>

{% hint style="info" %}

### Size consideration <a href="#size-considerationbr" id="size-considerationbr"></a>

The SDK AAR contains native `.so` libraries for all supported ABIs.

* Universal AAR size = size(`armeabi-v7a` `.so`) + size(`arm64-v8a` `.so`)
* With ABI splits, each generated APK contains only one `.so`
* 32-bit APK size ≈ size(`armeabi-v7a` `.so`) + other application components
  {% endhint %}

## Configure your build for multiple APKs <a href="#configure-split" id="configure-split"></a>

In your app module build file:

* Enable ABI splits so Gradle generates one APK per ABI.
* Expect APK names like `appname-abi-buildType.apk` (for example, `mpa-arm64-v8a-debug.apk`).
* If you publish multiple APKs, assign a unique `versionCode` per APK before uploading to Google Play.\
  See: <https://developer.android.com/studio/build/configure-apk-splits#configure-APK-versions>

{% tabs %}
{% tab title="Groovy (build.gradle)" %}
{% code title="app/build.gradle" %}

```groovy
android {
    splits {
        // Generate one APK per ABI.
        abi {
            enable true
            reset()
            include "armeabi-v7a", "arm64-v8a"

            // Do not generate a universal APK containing all ABIs.
            universalApk false
        }
    }
}
```

{% endcode %}
{% endtab %}

{% tab title="Kotlin (build.gradle.kts)" %}
{% code title="app/build.gradle.kts" %}

```kotlin
android {
    splits {
        abi {
            isEnable = true
            reset()
            include("armeabi-v7a", "arm64-v8a")
            isUniversalApk = false
        }
    }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}


# 2. Onboarding

## Provide onboarding data

Before you start integrating the NFC Wallet SDK, exchange a set of application identifiers, keys, and endpoints with the **Thales delivery team**.

## Send required data to the Thales delivery team

Provide the following information for your **digital wallet application**.

<table><thead><tr><th width="199">Parameter</th><th width="141">Format</th><th>Description</th></tr></thead><tbody><tr><td><p>PreProd</p><p>FCM service account</p></td><td>JSON file</td><td>Enables sending push notifications to your digital wallet application in the <strong>PreProd</strong> environment.</td></tr><tr><td><p>Production</p><p>FCM service account</p></td><td>JSON file</td><td>Enables sending push notifications to your digital wallet application in the <strong>Production</strong> environment.</td></tr><tr><td><p>PreProd</p><p>HMS Push Kit configuration</p></td><td>See below</td><td><strong>Optional</strong><br>Enables sending push notifications to your digital wallet application running on Huawei devices in the <strong>PreProd</strong> environment.</td></tr><tr><td>Production<br>HMS Push Kit configuration</td><td>See below</td><td><strong>Optional</strong><br>Enables sending push notifications to your digital wallet application running on Huawei devices in the <strong>Production</strong> environment.</td></tr><tr><td>Application binding key</td><td>Hexadecimal string</td><td>Thales uses this key to bind wallet enrollment requests to your <strong>digital wallet application</strong>.</td></tr></tbody></table>

### Get your application data

#### Get FCM service account

For details on an FCM service account, see the [Firebase Console](https://console.firebase.google.com/).

Then contact the **Thales delivery team** to complete the push notification setup.

{% hint style="info" %}
FCM can deliver push notifications to the same digital wallet application from multiple senders.
{% endhint %}

#### Get HMS Push Kit configuration <a href="#fetching-hms-push-kit-configuration" id="fetching-hms-push-kit-configuration"></a>

For details on HMS Push Kit, see [HMS Push Kit](https://developer.huawei.com/consumer/en/doc/HMSCore-Guides/service-introduction-0000001050040060) and [HMS Authentication](https://developer.huawei.com/consumer/en/doc/HMSCore-Guides/open-platform-0000001053709196).

Then contact the **Thales delivery team** to complete the push notification setup.

The solution supports two authentication methods:

* OAuth 2.0 authentication
* API key authentication

#### Get application binding key <a href="#fetching-the-app-signer-public-key-sha-256-digest" id="fetching-the-app-signer-public-key-sha-256-digest"></a>

The application binding key is computed from the application signing certificate.

Thales uses this key to bind wallet enrollment requests to your **digital wallet application**.

Only registered digital wallet applications can enroll wallets. See [Enroll wallet](https://docs.payments.thalescloud.io/M18oJyCDXLd5bElIV1dz/nfc-wallet-sdk-ios-7.3/implement-nfc-wallet/enroll-wallet).

For details on how to compute the application binding key, see [Compute the application binding key](/nfc-wallet-sdk-android/help/knowledge-base/compute-the-application-binding-key).

{% hint style="info" %}
You can specify multiple values for different signing configurations used in your application's build and deployment process.
{% endhint %}

{% hint style="warning" %}

### Signing key rotation / Multiple signers <a href="#receive-this-from-the-thales-delivery-team" id="receive-this-from-the-thales-delivery-team"></a>

NFC Wallet supports **signing key rotation** and **mulipe signers**

To avoid any issue:

* Provide oldest signing key
* Ensure that the oldest signing key is provided as the first signer.

In **signing key rotation** oldest signing key provided in the proof-of-rotation struct is used as the first signer.
{% endhint %}

## Receive this from the Thales delivery team <a href="#receive-this-from-the-thales-delivery-team" id="receive-this-from-the-thales-delivery-team"></a>

Configure the following values in your **digital wallet application** and, if applicable, your **backend**.

| Parameter                                  | Description                                                                                                       | Format                                         |
| ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- |
| PreProd source IP addresses                | IP addresses to allowlist in FCM so the Thales backend can send push notifications to the PreProd environment.    | Comma-separated list of IPv4 or IPv6 addresses |
| Production source IP addresses             | IP addresses to allowlist in FCM so the Thales backend can send push notifications to the Production environment. | Comma-separated list of IPv4 or IPv6 addresses |
| PreProd URLs                               | Endpoints to connect to the Thales backend in the PreProd environment.                                            | String                                         |
| Production URLs                            | Endpoints to connect to the Thales backend in the Production environment.                                         | String                                         |
| PreProd card information encryption key    | Key to secure transmission of card information (PAN, CSC, and expiration date) in the PreProd environment.        | Hexadecimal string or PEM certificate          |
| Production card information encryption key | Key to secure transmission of card information (PAN, CSC, and expiration date) in the Production environment.     | Hexadecimal string or PEM certificate          |


# 3. Application manifest file

Configure `AndroidManifest.xml` so the NFC Wallet SDK can run correctly.

### Android permissions

Declare the following permissions in `AndroidManifest.xml`:

<table data-full-width="true"><thead><tr><th width="338.25">Android permission</th><th width="167.75">Requirement</th><th>Description</th></tr></thead><tbody><tr><td><code>android.permission.INTERNET</code></td><td>Required</td><td>Enable network calls (for example, enrollment and payment key replenishment).</td></tr><tr><td><code>android.permission.NFC</code></td><td>Required</td><td>Enable NFC access for contactless payment.</td></tr><tr><td><code>android.permission.USE_BIOMETRIC</code></td><td>Conditional</td><td>Enable biometric authentication as CDCVM.</td></tr><tr><td><code>android.permission.USE_FINGERPRINT</code></td><td>Conditional</td><td>Support Android 9 and earlier when using biometrics as CDCVM.</td></tr></tbody></table>

### Declare NFC features

For contactless payment, the device must support:

* `android.hardware.nfc`
* `android.hardware.nfc.hce`

#### Option A: Filter unsupported devices in Google Play

Declare both features as required:

```xml
<uses-feature android:name="android.hardware.nfc" android:required="true" />
<uses-feature android:name="android.hardware.nfc.hce" android:required="true" />
```

{% hint style="warning" %}
`uses-feature` declarations filter your application in Google Play to compatible devices only.
{% endhint %}

#### Option B: Allow install and check at runtime

If you cannot filter device compatibility in Google Play, check feature support using the Android APIs:

```java
public static boolean doesDeviceSupportHCE(@NonNull final Context context) {
    final PackageManager pm = context.getPackageManager();
    final boolean hasNfc = pm.hasSystemFeature(PackageManager.FEATURE_NFC);
    final boolean supportsHce = pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION);
    
    if (!hasNfc || !supportsHce) {
        // The device does not support NFC or HCE.
        return false;    
    }
    return true;
}
```

### Enable CPS communication service

Enable `CPSCommService` to process **CPS** message communication.

```xml
<!-- CPS communication service -->
<service
    android:name="com.gemalto.mfs.mwsdk.provisioning.push.CPSCommService"
    android:enabled="true"
    android:exported="false" />
```

### Disable backup and restore

Disable Android application backup and restore.

```xml
<application
    android:allowBackup="false">
```

### Example `AndroidManifest.xml`

This example shows the typical declarations you need. Adjust names and metadata to your digital wallet application.

```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.NFC" />
    <uses-permission android:name="android.permission.USE_BIOMETRIC" />
    <uses-permission android:name="android.permission.USE_FINGERPRINT" />

    <uses-feature android:name="android.hardware.nfc" android:required="true" />
    <uses-feature android:name="android.hardware.nfc.hce" android:required="true" />

    <application
        android:allowBackup="false">

        <service
            android:name="com.gemalto.mfs.mwsdk.provisioning.push.CPSCommService"
            android:enabled="true"
            android:exported="false" />

        <!-- Your HCE service (example) -->
        <service
            android:name=".payment.contactless.YourHostApduService"
            android:exported="true"
            android:permission="android.permission.BIND_NFC_SERVICE">
            <intent-filter>
                <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>

            <meta-data
                android:name="android.nfc.cardemulation.host_apdu_service"
                android:resource="@xml/apduservice" />
        </service>

    </application>
</manifest>
```

{% hint style="info" %}
Declaration of HCE service will be described in [Implement HCE service](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/1.-implement-hce-service)
{% endhint %}


# 4. Initialize the NFC Wallet SDK

## Initialize the NFC Wallet SDK

Initialize the NFC Wallet SDK before you call any other SDK API.

Recommended flow:

1. Add the required properties files.
2. Build a `CustomConfiguration`.
3. (Optional) Call `SDKInitializer.INSTANCE.configure(...)` during app startup.
4. Call `SDKInitializer.INSTANCE.initialize(...)` on a background thread.
5. Call `MobileGatewayManager.INSTANCE.configure(...)` to configure **Mobile Gateway (MG)**.

{% hint style="warning" %}

### Check Android version

Verify the Android version meets the minimum NFC Wallet Android SDK requirements before initializing the SDK.

Hide NFC Wallet features for unsupported Android versions.
{% endhint %}

### Add the required properties files

Create the following files in your Android **digital wallet application** `assets` folder:

* `mobilegateway.properties`
* `rages.properties`
* `gemcbp.properties`

Set the values provided by Thales (unless a value is explicitly marked as fixed below).

#### mobilegateway.properties

<details>

<summary>mobilegateway.properties description</summary>

<table><thead><tr><th width="353">Key</th><th>Description</th></tr></thead><tbody><tr><td>MG_CONNECTION_URL</td><td>[String] URL of the MG server (provided by Thales).</td></tr><tr><td>MG_TRANSACTION_HISTORY_CONNECTION_URL</td><td>[String] URL for retrieving transaction history (provided by Thales).</td></tr><tr><td>WALLET_PROVIDER_ID</td><td>[String] Wallet provider ID.</td></tr><tr><td>WALLET_APPLICATION_ID</td><td>[String] Wallet provider application ID (Optional). Required when the wallet provider supports multiple wallet applications.</td></tr><tr><td>MG_CONNECTION_TIMEOUT</td><td>[Integer] Connection timeout in milliseconds. Recommended: 30000.</td></tr><tr><td>MG_CONNECTION_READ_TIMEOUT</td><td>[Integer] Read timeout in milliseconds. Recommended: 30000.</td></tr><tr><td>MG_RETRY_COUNTER</td><td>[Integer] Number of retries. Recommended: 3.</td></tr><tr><td>MG_RETRY_INTERVAL</td><td>[Integer] Interval in milliseconds between retries. Recommended: 10000.</td></tr></tbody></table>

</details>

#### rages.properties

<details>

<summary>rages.properties description</summary>

<table><thead><tr><th width="353">Key</th><th>Description</th></tr></thead><tbody><tr><td>REALM</td><td>[String] Fixed value: <strong>CBP</strong>.</td></tr><tr><td>OAUTH_CONSUMER_KEY</td><td>[String] OAuth consumer key (provided by Thales).</td></tr><tr><td>RAGES_GATEWAY_URL</td><td>[String] RAGES gateway URL (provided by Thales).</td></tr><tr><td>RAGES_CONNECTION_TIMEOUT</td><td>[Integer] Connection timeout in milliseconds. Recommended: 30000.</td></tr><tr><td>CSR_DOMAIN</td><td>[String] Domain used in the certificate signing request (CSR) for HTTPS. Ask the Thales delivery team for the value.</td></tr><tr><td>CSR_EMAIL</td><td>[String] Company email address.</td></tr></tbody></table>

</details>

#### gemcbp.properties

<details>

<summary>gemcbp.properties description</summary>

<table><thead><tr><th width="353">Key</th><th>Description</th></tr></thead><tbody><tr><td>CPS_URL</td><td>[String] CPS URL (provided by Thales).</td></tr><tr><td>CPS_CONNECTION_TIMEOUT</td><td>[Integer] Connection timeout in milliseconds. Recommended: 30000.</td></tr><tr><td>CPS_READ_TIMEOUT</td><td>[Integer] Read timeout in milliseconds. Recommended: 30000.</td></tr></tbody></table>

</details>

### Configure payment behavior

`CustomConfiguration` defines payment behavior:

* `keyValidityPeriod`: Time (in seconds) between end user authentication and the tap on the POS terminal. Range: 0–300. Default: 45.
* `domesticCurrencyCode`: [ISO 4217 numeric currency code](https://en.wikipedia.org/wiki/ISO_4217) used for CDCVM during LVT (Low Value Transaction) payments. Default: 978 (EUR).

{% hint style="info" %}
`CustomConfiguration` supports additional risk management and CDCVM parameters. See [Define risk management](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/7.-configure-cdcvm-experiences/define-risk-management).

We recommend reviewing these parameters when implementing contactless payment.
{% endhint %}

The SDK uses `CustomConfiguration` during initialization.

```java
/* Initialize SDK with different values than default */
CustomConfiguration customConfig = new CustomConfiguration.Builder()
                .domesticCurrencyCode(978)
                .keyValidityPeriod(60)
                .build();
```

{% hint style="warning" %}
Do not change `keyValidityPeriod` and `domesticCurrencyCode` after the first initialization.

Changes can introduce delays and intermittent issues between authentication and the final tap at the POS terminal.
{% endhint %}

### Run SDK quick configuration (optional)

Use `SDKInitializer.INSTANCE.configure(...)` to preload the Android `Context`, `CustomConfiguration`, and native libraries.

After `configure(...)` completes, you can call APIs that only read local SDK storage.

See [SDK API requirements](/nfc-wallet-sdk-android/help/sdk-api-requirements) for details.

{% hint style="info" %}
`configure()` does not run SDK migration. If migration is required, it runs during `initialize()`.
{% endhint %}

{% code title="MyApp.java" expandable="true" %}

```java
public class MyApp extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        try {
            // 1. Build your CustomConfiguration (see above).
            ...

            // 2. Run quick configuration to ensure the SDK has an Android Context.
            SDKInitializer.INSTANCE.configure(this, customConfig);
        } catch (InternalComponentException e) {
            // You can log and continue with initialize().
        } catch (Exception e) {
            // Safeguard against crashes during Application startup.
            // You can log and continue with initialize().
        } catch (Throwable e) {
            // This is unlikely.
            // If it happens, do not call initialize().
            return;
        }

        // 3. Initialize the SDK asynchronously so Application startup is not blocked.
        // See "Initialize the SDK (payment)" below.
    }
}
```

{% endcode %}

### Initialize the SDK (payment)

Check the SDK state using `SDKController.getInstance().getSDKServiceState()` and only initialize when needed.

Use `SDKInitializer.INSTANCE.initialize(...)` to initialize the payment components:

* Provide `CustomConfiguration` as an input parameter.
* This API is synchronous. Call it from a background thread.

{% code title="Initialize the NFC Wallet SDK (Java)" %}

```java
final Context appContext = getApplicationContext();

if (SDKController.getInstance().getSDKServiceState() != SDKServiceState.STATE_INITIALIZED) {
    Thread sdkInit = new Thread(new Runnable() {
        @Override
        public void run() {
            SDKInitializer.INSTANCE.initialize(appContext, customConfig);
        }
    });
    sdkInit.start();
}
```

{% endcode %}

{% hint style="info" %}
The initialization APIs are idempotent. You can call them multiple times safely.
{% endhint %}

### Configure Mobile Gateway (MG)

After SDK initialization completes, call `MobileGatewayManager.INSTANCE.configure(...)` to enable Tokenization, digital card LCM, and transaction history.

Use `MobileGatewayManager.INSTANCE.getConfigurationState()` to check configuration state.

{% code title="Configure Mobile Gateway (Java)" %}

```java
protected void initMgSdk(@NonNull final Context context) {
    final MobileGatewayManager mgManager = MobileGatewayManager.INSTANCE;

    try {
        // Avoid multiple initialization.
        if (mgManager.getConfigurationState() == MGSDKConfigurationState.NOT_CONFIGURED) {
            mgManager.configure(context);
        }
    } catch (final MGConfigurationException exception) {
        // Log error.
    }
}
```

{% endcode %}

### Retrieve the wallet ID

Use `getWalletId()` from `MGCardEnrollmentService` to retrieve the wallet identifier.

{% code title="Retrieve the wallet ID (Java)" lineNumbers="true" %}

```java
MGCardEnrollmentService enrollService = MobileGatewayManager.INSTANCE.getCardEnrollmentService();
String walletId = enrollService.getWalletId();
```

{% endcode %}

`MGSDKException` is thrown if an error occurs while retrieving the wallet ID.

{% hint style="info" %}
Use the wallet ID for troubleshooting and support.
{% endhint %}

The SDK generates the wallet ID the first time you initialize the SDK:

* The wallet ID remains stable across application restarts.
* If you reset the SDK, the wallet ID is regenerated.


# 5. Push notifications

NFC Wallet uses push notifications for **LCM** events, payment key replenishment, and transaction notifications.

On Android, implement push delivery using **Firebase Cloud Messaging (FCM)**.

{% hint style="info" %}
On Huawei devices without Google Play services, use **HMS Push Kit**.
{% endhint %}

### What you need to implement

Your **digital wallet application** must:

* Configure FCM or HMS Push Kit.
* During enrollment, retrieve the push token and pass it to the NFC Wallet SDK.
* Route inbound push payloads from the NFC Wallet backend to the NFC Wallet SDK.
* Handle push token refresh and update the NFC Wallet SDK.

### In this section

* [Configure push provider](/nfc-wallet-sdk-android/get-started/configuration/5.-push-notifications/configure-push-provider)

  Set up FCM or HMS Push Kit.
* [Handle push tokens](/nfc-wallet-sdk-android/get-started/configuration/5.-push-notifications/handle-push-tokens)

  Keep the push token in sync with the NFC Wallet SDK.
* [Handle push notifications](/nfc-wallet-sdk-android/get-started/configuration/5.-push-notifications/handle-push-notifications)

  Route and process inbound NFC Wallet push notifications.


# Configure push provider

## Set up FCM

Follow Google’s guide: [Setting up a FCM client app on Android](https://firebase.google.com/docs/cloud-messaging/android/client).

At a high level:

1. Create a Firebase project and register your Android application.
2. Add Firebase to your Android project.
3. Implement a service extending `FirebaseMessagingService`:
   1. Override `onNewToken` to support the push token update
   2. Override `onMessageReceived` to handle push notification from NFC Wallet backend.
4. Declare the service in your application manifest.

{% code title="FcmService.java" expandable="true" %}

```java
public class FcmService extends FirebaseMessagingService {

    @Override
    public void onNewToken(@NonNull final String token) {
        super.onNewToken(token);

        // Notify the NFC Wallet SDK about the new token.
        updateToken(this, token);
    }

    @Override
    public void onMessageReceived(@NonNull final RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);

        // Route the push payload to your common handler.
        processIncomingMessage(this, remoteMessage.getData());
    }
}
```

{% endcode %}

## Set up HMS Push Kit

For Huawei devices without Google Play services, configure HMS Push Kit.

Follow Huawei’s guide: [HMS Push Kit (Android) Codelabs](https://developer.huawei.com/consumer/en/codelab/HMSPushKit).

{% hint style="warning" %}
To route messages correctly, prefix HMS tokens with `HMS:`.
{% endhint %}

At a high level:

1. Enable Push Kit for your application in [AppGallery Connect](https://developer.huawei.com/consumer/en/service/josp/agc/index.html).
2. Integrate HMS Core SDK into your **digital wallet application**.
3. Implement a service extending `HmsMessageService`:
   1. Override `onNewToken` to support the push token update
   2. Override `onMessageReceived` to handle push notification from NFC Wallet backend..
4. Declare the service in your application manifest.

{% code title="HmsService.java" expandable="true" %}

```java
public class HmsService extends HmsMessageService {

    // Use "HMS:" prefix for HMS Push Kit token
    private static final String HMS_TOKEN_PREFIX = "HMS:";

    @Override
    public void onNewToken(final @NonNull String token) {
        super.onNewToken(token);

        // Notify the NFC Wallet SDK about the new token.
        updateToken(this, HMS_TOKEN_PREFIX + token);
    }

    @Override
    public void onMessageReceived(@NonNull final RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);

        // Route the push payload to your common handler.
        processIncomingMessage(this, remoteMessage.getDataOfMap());
    }
}
```

{% endcode %}


# Handle push tokens

## Update the push token

The push provider may rotate the push token (token refresh).

When the token changes, notify the NFC Wallet SDK using API `ProvisioningBusinessService.updatePushToken`.

{% code expandable="true" %}

```java
void updateToken(@NonNull final Context context,
                 @Nullable final String token) {
    final ProvisioningBusinessService provisioningService = 
                 ProvisioningServiceManager.getProvisioningBusinessService();
    provisioningService.updatePushToken(token, new PushServiceListener() {
    
        @Override
        public void onComplete() {
            // Success
        }
    
        @Override
        public void onError(final ProvisioningServiceError provisioningServiceError) {
            // Handle error.
        }

        @Override
        public void onUnsupportedPushContent(final Bundle bundle) {
            // Not relevant for push token updates.
        }

        @Override
        public void onServerMessage(final String message, final ProvisioningServiceMessage provisioningServiceMessage) {
            // Not relevant for push token updates.
        }
     });
}
```

{% endcode %}


# Handle push notifications

NFC Wallet uses push notifications to notify your **digital wallet application**. Notifications are sent by the NFC Wallet backend.

{% hint style="info" %}
Handling NFC Wallet push notifications is required to support **LCM**, transaction notifications, and card enrollment flows where the digital card is activated directly by the issuer.
{% endhint %}

### Route notifications using `sender`

Read `sender` key from message payload `data` and route the notification to the right handler:

* `CPS`: digital card operations (**LCM**)
* `TNS`: transaction notifications
* `MG`: payment key replenishment triggered by the **TSP**

<pre class="language-java" data-expandable="true"><code class="lang-java">private static final String KEY_SENDER = "sender";

public void processIncomingMessage(@NonNull final Context context,
                                   @NonNull final Map&#x3C;String, String> data) {
     
    String sender = "";
    if (!data.isEmpty()) {
        for (String key : data.keySet()) {
            if (KEY_SENDER.equalsIgnoreCase( key )) {
                sender = data.get(key);
            }
        }
    }
     
    switch (sender) {
    case "CPS":
        // Digital card operations (LCM).
        // See `ProvisioningBusinessService.processIncomingMessage`
        break;
  
    case "TNS":
<strong>         // Transaction notifications.
</strong>         // Refresh transaction history. See `MGTransactionHistoryService` in the API reference.
         break;
                  
    case "MG":
         // Key replenishment triggered by the TSP.
         // Trigger replenishment. See `ReplenishmentService` in the API reference.
        break;

    default:
        // Non-SDK notifications
<strong>        break;
</strong>    }     
}
</code></pre>

### Process CPS notifications (digital card operations) <a href="#process-cps-notifications-digital-card-operations" id="process-cps-notifications-digital-card-operations"></a>

Forward **CPS** notifications using `ProvisioningBusinessService`.`processIncomingMessage()`.

<pre class="language-java" data-expandable="true"><code class="lang-java">public void processIncomingMessage(@NonNull final Context context,
                                   @NonNull final Map&#x3C;String, String> data) {
    // ...
    // CPS sender processing
<strong>    // 1 - Build bundle from push payload data
</strong><strong>    final Bundle bundle = new Bundle();
</strong>    if (!data.isEmpty()) {
        for (String key : data.keySet()) {
            if (null != data.get(key)) {
                 bundle.putString(key, data.get(key));    
            }
        }
    }

<strong>    // 2 - Process CPS sender push
</strong><strong>    My_PushServiceListener pushListener = new My_PushServiceListener();
</strong>    final ProvisioningBusinessService provService 
                = ProvisioningServiceManager.getProvisioningBusinessService();                
    provService.processIncomingMessage( bundle, pushListener );
</code></pre>

The NFC Wallet SDK processes the push and interacts with the NFC Wallet backend.

#### Implement `PushServiceListener`

Implement `PushServiceListener` to handle callback to track the digital card operation.

Supported callbacks:

* `onUnsupportedPushContent`: Triggered when the push payload is not supported by the SDK.
* `onComplete`: Triggered when processing completes successfully (for example, after provisioning a card profile and payment keys).
* `serverMessage`: Triggered when the backend returns a server message The SDK provides a `ProvisioningServiceMessage` object and a `tokenizedCardId`.

When you receive `ProvisioningServiceMessage`, call `getMsgCode` to determine which operation the backend is executing:

* `REQUEST_INSTALL_CARD`: message indicates request for card to be to installed.
* `REQUEST_REPLENISH_KEYS`: message indicates request for a replenishment.
* `REQUEST_RESUME_CARD`: message indicates request to move a card from suspended to active.
* `REQUEST_SUSPEND_CARD`: message indicates request to move a card from active to suspended.
* `REQUEST_DELETE_CARD`: message indicates request to delete a card.
* `REQUEST_RENEW_CARD`: message indicates request to renew a card

{% code expandable="true" %}

```java
public class My_PushServiceListener implements PushServiceListener {

  @Override
  public void onServerMessage(String tokenizedCardId, ProvisioningServiceMessage message) {
    /*
    It is triggered during the provisioning flow steps, during an life cycle managment operation, during the keys replenishment.

    To understand which action has been performed, parse the ProvisioningServiceMessage object.
    **/

      //Example
    	String messageCode = provisioningServiceMessage.getMsgCode();

      switch (messageCode) {
          case KnownMessageCode.REQUEST_INSTALL_CARD:
              // 1st push notification for installing card
          case KnownMessageCode.REQUEST_REPLENISH_KEYS:
              // 2nd push notification for installing payment keys and subsequent replenishments
          case KnownMessageCode.REQUEST_RESUME_CARD:
              // card to be resumed
          case KnownMessageCode.REQUEST_SUSPEND_CARD:
              // card to be suspended
          case KnownMessageCode.REQUEST_RENEW_CARD:
              //token to be renewed (profile update)
          case KnownMessageCode.REQUEST_DELETE_CARD:
              //card to be deleted.
              LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(ACTION_RELOAD_CARDS));
              break;
          default:
      }
  }

  @Override
  public void onUnsupportedPushContent(Bundle pushMessageBundle) {
    /*
    It is triggered if the message passed has not been understood or it is not supported
    **/
  }

  @Override
  public void onComplete() {
    /*
    It is triggered once the provisioning session has been completed with success. The card is ready for payment.
    **/
  }

  @Override
  public void onError(ProvisioningServiceError error) {
    /*
    It is triggered once an error occurs. Developer has to parse the error and take appropriate actions.
    **/
  }
}
```

{% endcode %}

### Process TNS notifications (transactions)

Transaction notifications provide details about completed payment transactions. Use `MGTransactionHistoryService` to retrieve transaction records.

Through the push notification, the **digital wallet application** obtains the following information via the message payload `data` :

* Key `sender`: `TNS`.
* Key `action`: `TNS:PaymentTransactionNotification`.
* Key `digitalCardId`: Digital card identifier. Use it with `MGTransactionHistoryService.refreshHistory()` to fetch the transaction
* Key `transactionRecordType`: Present only for co-badged cards. Pass it to `MGTransactionHistoryService.refreshHistory()` to fetch only the relevant records (primary or auxiliary).

{% code expandable="true" %}

```java
private static final String KEY_SENDER = "sender";
private static final String KEY_ACTION = "action";
private static final String KEY_DIGITALIZED_CARD_ID = "digitalCardID";
private static final String KEY_TRANSACTION_RECORD_TYPE = "transactionRecordType";

public void processIncomingMessage(@NonNull final Context context,
                                   @NonNull final Map<String, String> data) {
    
    String action = "";
    String digitalCardID = "";
    String transactionRecordType = "";
    
    // ...
    // TNS sender processing
    // 1 -Extract values for TNS sender notification
    final Bundle bundle = new Bundle();
    if (!data.isEmpty()) {
        for (String key : data.keySet()) {
            if (KEY_DIGITALIZED_CARD_ID.equalsIgnoreCase( key )) {
                 digitalCardID = data.get(key);
            }
            else if (KEY_ACTION.equalsIgnoreCase( key )) {
                 action = data.get(key);
            }
            else if (KEY_TRANSACTION_RECORD_TYPE .equalsIgnoreCase( key )) {
                 transactionRecordType = data.get(key);
            }
        }
    }
    
    // 2 - check parameters
    if( ! "TNS:PaymentTransactionNotification".equals( action ) || digitalCardID == null ) {
         // log error
    }
    else {
         // 3 - Call MG Transaction history service         
         final MGTransactionHistoryService tnsService 
                = MobileGatewayManager.INSTANCE.getTransactionHistoryService();
                
         // 3a - you should prior get an access token
         final ProvisioningBusinessService provService 
                = ProvisioningServiceManager.getProvisioningBusinessService();
         provService.getAccessToken(digitalCardID, 
              GetAccessTokenMode.REFRESH, new AccessTokenListener() {
                 @Override
                 public void onSuccess(String digitalCardId, String accessToken) {
                      // 3b - using access token you can get transaction
                      tnsService.refreshHistory(accessToken, 
                                               digitalCardID, null, transactionRecordType , new TransactionHistoryListener() {
                              
                              @Override
                              public void onSuccess(List<MGTransactionRecord> list, String digitalCardId, String timeStamp) {
                                  // Success
                                  // you can parse the list of transaction record
                              }

                              @Override
                              public void onError(String s, MobileGatewayError mobileGatewayError) {
                                  // Log an error
                              }
                      });              
                 }
                 
                 @Override
                 public void onError(String digitalCardId, ProvisioningServiceError provisioningServiceError) {
                       // Failed to get access token
                       // Log an error
                  }
             });
      } 
}


```

{% endcode %}

### Process MG notifications (replenishment)

The **TSP** can request payment key replenishment. Use `ProvisioningServiceManager.sendRequestForReplenishment` to replenish keys.

Through the push notification, the **digital wallet application** obtains the following information via the message payload `data`

* `sender`: `MG`.
* `action`: `MG:ReplenishmentNeededNotification`.
* `"digitalCardId`: Digital card identifier. Use it with `ReplenishmentService.replenish(digitalCardID:isForced:)`.

<pre class="language-java" data-expandable="true"><code class="lang-java">private static final String KEY_SENDER = "sender";
private static final String KEY_ACTION = "action";
private static final String KEY_DIGITALIZED_CARD_ID = "digitalCardID";

public void processIncomingMessage(@NonNull final Context context,
                                   @NonNull final Map&#x3C;String, String> data) {
    
    String action = "";
    String digitalCardID = "";
    String transactionRecordType = "";
    
    // ...
    // MG sender processing
    // 1 -Extract values for TNS sender notification
    final Bundle bundle = new Bundle();
    if (!data.isEmpty()) {
        for (String key : data.keySet()) {
            if (KEY_DIGITALIZED_CARD_ID.equalsIgnoreCase( key )) {
                 digitalCardID = data.get(key);
            }
            else if (KEY_ACTION.equalsIgnoreCase( key )) {
                 action = data.get(key);
            }
        }
    }
    
    // 2 - check parameters
    if( ! "MG:ReplenishmentNeededNotification".equals( action ) || digitalCardID == null ) {
         // log error
    }
    else {
         // 3 - Call Provisioning business service
         final ProvisioningBusinessService provService 
                = ProvisioningServiceManager.getProvisioningBusinessService();
         provService.sendRequestForReplenishment( digitalCardID, new ReplenishmentListener(), true);                             
    }
}

/**
 * By using this listener as we will observe only the result
 * of calling the ProvisioningBusinessService#sendRequestForReplenishment() API which uses
 * same PushServiceListener API, but there is no push message processing involved.
 */
private static class ReplenishmentListener implements PushServiceListener {

        public ReplenishmentListener(){
        }


        @Override
        public void onError(final ProvisioningServiceError provisioningServiceError) {
            // Log error
        }

        @Override
        public void onUnsupportedPushContent(final Bundle bundle) {
            // This should never ever happen in the replenishment use case as we are not passing
            // Log error
        }

        @Override
        public void onServerMessage(final String tokenizedCardId,
                                    final ProvisioningServiceMessage provisioningServiceMessage) {
            //  This should never ever happen in the replenishment
            // Log error
<strong>         }
</strong>
        @Override
        public void onComplete() {

            // For Mastercard and PURE (white label EMV) card it only means that we sent out the replenishment request and we need to wait
            // a push message to come once the SUKs are prepared to be fetched from the backend.
 
            // For Visa card this means we are done and the card is ready with new LUK
            // Thus we'll check if it is a Visa card and if so we'll reuse the push message handling code to notify the user
        }
    }



</code></pre>


# Sample App

## Use the Sample App <a href="#use-the-sample-app" id="use-the-sample-app"></a>

To accelerate your integration with the **NFC Wallet SDK**, use the Android Sample App provided by Thales.

Use it to:

* See an end-to-end integration of the **NFC Wallet SDK** in an Android **digital wallet application**.
* Reuse proven implementation patterns in your own **digital wallet application**.

#### Get the Sample App <a href="#get-the-sample-app" id="get-the-sample-app"></a>

The Sample App is available on GitHub:

* [dp-hce-sample-android](https://github.com/ThalesGroup/dp-hce-sample-android)

Follow the repository README to build and run the project.

{% hint style="info" %}
The Sample App is intended as an integration guide and starter project. If you reuse code, review and adapt it to your security, UX, and release requirements.
{% endhint %}


# Android API


# Implement NFC Wallet

## Overview

Use these guides to implement NFC Wallet in your Android **digital wallet application**.

Start with [Get started](/nfc-wallet-sdk-android/get-started) for onboarding and SDK initialization.

## Implementation guides

Follow these guides in order. Each guide depends on the previous one.

1. [Handle CDCVM](/nfc-wallet-sdk-android/implement-nfc-wallet/handle-cdcvm)\
   Check device support for **CDCVM** and prompt the end user when required.
2. [Enroll wallet](/nfc-wallet-sdk-ios/implement-nfc-wallet/enroll-wallet)\
   Enroll the wallet after you have initialized SDK and before **Tokenization**.
3. [Tokenize a card](/nfc-wallet-sdk-ios/implement-nfc-wallet/tokenize-a-card)\
   Perform **Tokenization** to create a digital card.
4. [Manage digital cards](/nfc-wallet-sdk-ios/implement-nfc-wallet/manage-digital-cards)\
   Let the end user view and manage digital cards, including **LCM**.
5. [Make payments](/nfc-wallet-sdk-ios/implement-nfc-wallet/make-payments)\
   Enable payments with the digital card after **Tokenization**.


# Handle CDCVM

## Overview

NFC Wallet SDK supports multiple CVM (Cardholder Verification Method) to authenticate the end user during payment, such as CDCCVM, online PIN and signature.

CDCVM (Consumer Device Cardholder Verification Method) is a CVM relying on device to verify the **end user** before an NFC payment.

Most NFC Wallet programs use **CDCVM**. CDCVM relies on the device’s user authentication.

In this section, we explain that NFC Wallet SDK is relying on Android secure device unlock method as CDCVM.

### CDCVM Android (device unlock)

NFC Wallet SDK for Android uses the Android secure lock screen for CDCVM. It supports:

* **Biometric**: strong biometric credentials, such as fingerprint or face.
* **Device credentials (keyguard)**: PIN, pattern, or password.

{% hint style="info" %}
NFC Wallet uses Android Keystore user authentication. See [Android Keystore user authentication](https://developer.android.com/privacy-and-security/keystore#UserAuthentication).
{% endhint %}

### Recommendations

Handle CDCVM early in your integration:

* Check device CDCVM capabilities before before you start wallet enrollment or Tokenization.
* Prompt the end user to enable a secure lock screen when required.

{% hint style="warning" %}

### NFC device capability check

Check your device supports HCE as stated in [Declare NFC features](/nfc-wallet-sdk-android/get-started/configuration/3.-application-manifest-file#declare-nfc-features). You can perform check at application installation (Google Play device filtering) or at runtime.

If you use a runtime check, hide NFC Wallet features for unsupported devices.
{% endhint %}

## SDK integration

### Check device CDCVM capabilities

Use `DeviceCVMEligibilityChecker.checkDeviceEligibility` to check device capabilities.

It returns a `DeviceCVMEligibilityResult`. Use it to evaluate biometric and keyguard support.

Run this check after you [initialize the NFC Wallet SDK](/nfc-wallet-sdk-android/get-started/configuration/4.-initialize-the-nfc-wallet-sdk), and before you start wallet enrollment or Tokenization.

#### Check biometric support

Call `DeviceCVMEligibilityResult.getBiometricsSupport`.

It returns `BiometricSupport.SUPPORTED` when biometric CDCVM is available. Check the possible error in case biometric is not supported in table below.

<details>

<summary>Biometric eligibility error</summary>

| Result                           | Description                                                                 |
| -------------------------------- | --------------------------------------------------------------------------- |
| ANDROID\_VERSION\_NOT\_SUPPORTED | Returned when the device runs Android earlier than 6.0 (API level 23).      |
| NO\_FINGERPRINT\_SENSOR          | Returned when no biometric sensor is available on the device.               |
| NO\_FINGERPRINT\_ENROLLED        | Returned when the end user has not enrolled biometrics on the device.       |
| PERMISSION\_NOT\_GRANTED         | Returned when the required biometric permission is missing in the manifest. |
| SECURE\_LOCK\_NOT\_PRESENTED     | Returned when no secure lock screen is enabled on the device.               |

</details>

#### Check device keyguard support

Call `DeviceCVMEligibilityResult.getDeviceKeyguardSupport`.

It returns `DeviceKeyguardSupport.SUPPORTED` when device keyguard CDCVM is available. Check the possible error in case keygard is not supported in table below.

<details>

<summary>Device keyguard eligibility error</summary>

| Result                           | Description                                                            |
| -------------------------------- | ---------------------------------------------------------------------- |
| ANDROID\_VERSION\_NOT\_SUPPORTED | Returned when the device runs Android earlier than 6.0 (API level 23). |
| SECURE\_LOCK\_NOT\_PRESENTED     | Returned when no PIN, pattern, or password is enabled on the device.   |

</details>

### Implementation example

```java
// Check Device's Eligibility for Choosing CDCVM
DeviceCVMEligibilityResult result =
        DeviceCVMEligibilityChecker.checkDeviceEligibility(getApplicationContext());

if(result.getBiometricsSupport() == BiometricsSupport.SUPPORTED) {
    // Biometric is supported
    // ...
}
else if(result.getDeviceKeyguardSupport() == DeviceKeyguardSupport.SUPPORTED){
    // If Biometrics are not supported, Device KeyGuard should be used.
    // Device keyguard is supported
    // ...
}
else {
    // Log Error, Device is not supported
    // or end user does not enable secure lock screen
    // We recommend to prompt the end user to enable a secure lock screen
    // ...
}
```


# Enroll wallet

## Overview

Enroll the digital wallet application after **NFC Wallet SDK** initialization and before you start **Tokenization**.

Wallet enrollment provisions the digital wallet application with the security assets required to use **NFC Wallet** services:

* Run this once per wallet instance.
* Run this only if the digital wallet application uses **NFC Wallet** services.
* Run this only on eligible devices.

{% hint style="warning" %}
Enroll only digital wallet applications that use **NFC Wallet** services.

This avoids unnecessary network traffic from the digital wallet application and unnecessary load on **NFC Wallet**.
{% endhint %}

## Sequence diagram

High-level flow to enroll your wallet application.

<figure><img src="/files/YVC4N2vRqMvRjR5xBmzm" alt=""><figcaption><p>Wallet enrollment high-level flow.</p></figcaption></figure>

{% hint style="info" %}
This flow is technically called **wallet secure enrollment** in **NFC Wallet**.
{% endhint %}

## SDK Integration

### Prerequisites

Before you start, verify the following:

* Your digital wallet application is onboarded in the NFC Wallet backend.
* You initialized the **NFC Wallet SDK**.
* The wallet is not enrolled (see below).

### Perform wallet enrollment

Wallet enrollment is a one-time action in the digital wallet application lifecycle.

Run it after SDK initialization, and only if the wallet is not enrolled.

1. Get a `WalletSecureEnrollmentBusinessService` instance.
2. Check `getState()` returns `WSE_REQUIRED`.
3. If needed, call `startWalletSecureEnrollment()` to start wallet enrollment.
4. Implement `WalletSecureEnrollmentListener` to track progress.

These are the possible callbacks:

* `onProgressUpdate` with state `WSE_STARTED`: The process starts.
* `onProgressUpdate` with state `WSE_COMPLETED`: The process completes successfully.
* `onError`: The process fails with an error.

After wallet enrollment completes successfully, continue with [Tokenize a card](/nfc-wallet-sdk-android/implement-nfc-wallet/tokenize-a-card).

```java
public void performWseIfNeeded() {
    // First check current status. Whether we need WSE at all.
    final WalletSecureEnrollmentBusinessService wseService 
                = ProvisioningServiceManager.getWalletSecureEnrollmentBusinessService();
    final WalletSecureEnrollmentState state = wseService.getState();

    switch (state) {
        case WSE_COMPLETED:
        case WSE_NOT_REQUIRED:
            // WSE was already done in current or some previous instance.
            break;
        case WSE_STARTED:
            // WSE was triggered during this instance. Simple wait for the first one to finish.
            return;
        case WSE_REQUIRED:
            // Trigger WS enrollment.
            wseService.startWalletSecureEnrollment(new WalletSecureEnrollmentListener() {
                @Override
                public void onProgressUpdate(final WalletSecureEnrollmentState wseState) {
                    if (wseState == WalletSecureEnrollmentState.WSE_COMPLETED) {
                        // Success
                    }
                    else if (wseState == WalletSecureEnrollmentState.WSE_STARTED) {
                        // Started
                    }
                }

                @Override
                public void onError(final WalletSecureEnrollmentError wbDynamicKeyRenewalServiceError) {
                    // Log error
                }
            });
            break;
        default:
            // Log error as it should not happen
            break;
    }
}   
```

### Error code details

When `WalletSecureEnrollmentListener.onError(...)` is triggered, the SDK provides a `WalletSecureEnrollmentError`.

It includes an error code and a message, plus additional fields depending on the failure type.

#### Parse `WalletSecureEnrollmentError`

The structure of the `WalletSecureEnrollmentError` object is as follows:

* SDK error code: The error type for this operation.
* CPS error code: The numeric error code returned by the CPS module (server-side).
* HTTP status code: The HTTP status code returned for communication errors.
* Message: A human-readable error description.

The error needs to be parsed as follows:

1. Read `getSdkErrorCode()` to get a `WalletSecureEnrollmentErrorCodes` value.
2. If the SDK error code indicates a communication error (`COMM_ERROR`), read `getHttpStatusCode()`.
3. If the SDK error code indicates a server-side error (`SERVER_ERROR`), read `getCpsErrorCode()`.
4. Read `getErrorMessage()` for log-friendly description.
5. If the SDK error code is `DEVICE_SUSPICIOUS`, read `getStatusAdditionalInfo()` and log it for troubleshooting.

Refer to `WalletSecureEnrollmentErrorCodes` in the [Android API](/nfc-wallet-sdk-android/android-api) reference for the full list of codes.

#### `WalletSecureEnrollmentErrorCodes`

Use the following recommendations to decide whether to retry, stop, or reset the SDK.

{% hint style="info" %}
Call `SDKDataController.wipeAll()` when the recommendation is to reset the SDK.
{% endhint %}

<details>

<summary>Error code tables</summary>

<table data-full-width="true"><thead><tr><th width="240">Error code</th><th>When it happens</th><th>Recommended action</th></tr></thead><tbody><tr><td><code>WSE_INTERNAL_ERROR</code></td><td>An internal SDK error occurs.</td><td><p>Retry wallet enrollment.</p><p>If the issue persists, reset the SDK.</p></td></tr><tr><td><code>COMMON_NO_INTERNET</code></td><td>The device has no network connectivity.</td><td>Ask the end user to connect to a network, then retry wallet enrollment.</td></tr><tr><td><code>COMMON_COMM_ERROR</code></td><td>A communication error occurs while retrieving security assets.</td><td>Retry wallet enrollment.</td></tr><tr><td><code>COMMON_SERVER_ERROR</code></td><td>A server-side error occurs while retrieving security assets.</td><td><p>Retry wallet enrollment.</p><p>If the issue persists, contact the Thales delivery team to validate the environment setup.</p></td></tr><tr><td><code>RE_ENROLLMENT_REQUIRED</code></td><td>Re-enrollment is required for security reasons.</td><td>Reset the SDK, then run wallet enrollment again.</td></tr><tr><td><code>WSE_STORAGE_ACCESS_ERROR</code></td><td>The SDK exceeds its internal retry limit when accessing secure storage.</td><td>Reset the SDK, then retry wallet enrollment.</td></tr><tr><td><code>JSON_PARSING_ERROR</code></td><td>The response data cannot be parsed.</td><td><p>Retry wallet enrollment.</p><p>If the issue persists, reset the SDK.</p></td></tr><tr><td><code>WSE_REQUEST_ERROR</code></td><td>The enrollment request fails.</td><td>Retry wallet enrollment.</td></tr><tr><td><code>WSE_DOWNLOAD_ERROR</code></td><td>The security asset download fails.</td><td>Verify network connectivity, then retry wallet enrollment.</td></tr><tr><td><code>WSE_ERROR_INIT_SESSION</code></td><td>WSE session initialization fails (typically authentication-related).</td><td>Retry wallet enrollment.</td></tr><tr><td><code>WSE_ERROR_COMPUTE_AUTH_VALUE_FAILED_PACKAGE_NOT_FOUND</code></td><td>The SDK cannot compute the authentication value because the package name cannot be resolved.</td><td>Verify the application package name used in your onboarding configuration, then retry wallet enrollment.</td></tr><tr><td><code>WSE_ERROR_COMPUTE_AUTH_VALUE_FAILED_CERT_EXCEPTION</code></td><td>The SDK cannot compute the authentication value due to an application signing or public key issue.</td><td>Verify the application signing certificate used in your onboarding configuration, then retry wallet enrollment.</td></tr><tr><td><code>WSE_CPS_COMPONENT_NOT_INITIALIZED</code></td><td>Wallet enrollment starts before the CPS component is initialized.</td><td>Initialize the SDK, then retry wallet enrollment.</td></tr><tr><td><code>WSE_MG_COMPONENT_NOT_INITIALIZED</code></td><td>Wallet enrollment starts before the MobileGateway component is initialized.</td><td>Initialize the SDK, then retry wallet enrollment.</td></tr><tr><td><code>DEVICE_SUSPICIOUS</code></td><td>The SDK detects a device security threat.</td><td><p>Stop the flow and inform the end user that the device cannot be used.</p><p>Capture and share <code>getStatusAdditionalInfo()</code> when contacting Thales support.</p></td></tr><tr><td><code>WSE_KCV_ERROR</code></td><td>The SDK fails to validate downloaded security assets (KCV check fails).</td><td>Retry wallet enrollment.</td></tr></tbody></table>

</details>

## Application binding key (notes)

As described in [onboarding](/nfc-wallet-sdk-android/get-started/configuration/2.-onboarding) you must provide the **application binding key.**

If the application binding key is not provided or incorrect, enroll wallet will failed.

Please check warning and note below.

{% hint style="warning" %}

### Signing key rotation / Multiple signers <a href="#receive-this-from-the-thales-delivery-team" id="receive-this-from-the-thales-delivery-team"></a>

If the oldest signing key is not provided as the first signer value in the proof-of-rotation struct, then enroll wallet will fail
{% endhint %}

{% hint style="info" %}
**Downgrading to earlier versions of NFC Wallet SDK**

To downgrade to an earlier version of NFC Wallet SDK, the application has to ensure that the oldest signing key is provided as the first signer in the proof-of-rotation struct.
{% endhint %}


# Tokenize a card

## Overview

**Tokenization** creates a digital card from a funding card (FPAN) and provisions it in your **digital wallet application**.

During Tokenization, you typically:

* Capture card credentials.
* Check card eligibility.
* Present the terms and conditions (T\&C) and record the end user’s acceptance.
* Digitize the card to create a digital card.
* Start secure provisioning to provision the digital card.
* Set the CDCVM method (when the digital card profile supports CDCVM).

{% hint style="info" %}
Depending on your program, the terms and conditions (T\&C) might not be required.
{% endhint %}

## Capture card credentials

Card credentials can be provided by:

* **Issuer backend**. For example, when the digital wallet application is an issuer application.
* **End user**, via manual entry or camera scan. For example, when your digital wallet application is an open wallet (supporting cards from multiple issuers).

{% hint style="warning" %}
Treat FPAN, expiry date, and CSC as sensitive data. Never log them. Only send them in encrypted form.
{% endhint %}

## Issuer Tokenization decision

During digitization, the issuer approves or declines **Tokenization**.

The issuer Tokenization decision can be:

* **Green:** Approve Tokenization without step-up authentication.
* **Yellow:** Approve Tokenization with step-up authentication (**ID\&V**).
* **Red:** Decline Tokenization.

{% hint style="info" %}
When the end user enters card details manually, the issuer Tokenization decision is typically **Yellow** and requires step-up authentication (**ID\&V**).
{% endhint %}

## User experiences

### Green flow

Typical flow:

1. End user selects a card to digitize.
2. End user accepts the terms and conditions (optional).
3. Issuer backend approves Tokenization with no conditions.
4. The digital wallet application shows the digital card, ready to pay.

<figure><img src="/files/T047dXgeUGH7iAQ9Og9L" alt="" width="563"><figcaption><p>Green flow user experience.</p></figcaption></figure>

### Yellow flow

Typical flow:

1. The end user enters card information (manual entry or camera scan).
2. The end user accepts the terms and conditions.
3. The issuer backend approves Tokenization with conditions (step-up authentication required).
4. The digital wallet application displays the available ID\&V methods.
5. The end user selects an ID\&V method and completes ID\&V.
6. After successful ID\&V, the digital wallet application displays the digital card, ready to pay.

<figure><img src="/files/XSrE6haz8mhOIRbh9WFC" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/8f0X6fOs6zt863kdnetC" alt=""><figcaption></figcaption></figure>

## Implementation guides

### Before you start

Make sure you have:

* Initialized the **NFC Wallet SDK**. See [Initialize the NFC Wallet SDK](/nfc-wallet-sdk-android/get-started/configuration/4.-initialize-the-nfc-wallet-sdk).
* Configured push notifications and retrieved a push token. See [Push notifications](https://gitlab.sre.ops.gcloud.thalescloud.io/bps/gitbook/nfc-wallet-gitbook-docs/-/blob/dev-sdk/NFC-Wallet-SDK-Android/get-started/configuration/5.-push-notifications).
* Enrolled your wallet instance when required. See [Enroll wallet](/nfc-wallet-sdk-android/implement-nfc-wallet/enroll-wallet).
* Validated device support for **CDCVM** (recommended). See [Handle CDCVM](/nfc-wallet-sdk-android/implement-nfc-wallet/handle-cdcvm).

### Implement Tokenization

Implement these steps in order:

1. [Check card eligibility](/nfc-wallet-sdk-android/implement-nfc-wallet/tokenize-a-card/check-card-eligibility)\
   Check whether the card is eligible and retrieve the applicable T\&C.
2. [Digitize a card](/nfc-wallet-sdk-android/implement-nfc-wallet/tokenize-a-card/digitize-a-card)\
   Digitize the card to create a digital card (support green flow, yellow flow, or both).
3. [Trigger provisioning](/nfc-wallet-sdk-android/implement-nfc-wallet/tokenize-a-card/trigger-provisioning)\
   Start a provisioning session to provision the digital card in the application.
4. [Set CDCVM method](/nfc-wallet-sdk-android/implement-nfc-wallet/tokenize-a-card/set-cdcvm-method)\
   Set the CDCVM method for the wallet instance when required by the digital card profile.


# Check card eligibility

## Overview

Card eligibility is the first step in **Tokenization**. It confirms whether a card can be tokenized in the **digital wallet application**.

The NFC Wallet SDK checks eligibility with the Token Service Provider (TSP).

If the card is eligible, the SDK returns the terms and conditions (T\&C) from the TSP. Show the T\&C to the **end user** and collect acceptance before digitization.

{% hint style="info" %}
Depending on your program, **T\&C** might not be required.
{% endhint %}

After eligibility and (when required) T\&C acceptance, continue with [Digitize a card](/nfc-wallet-sdk-android/implement-nfc-wallet/tokenize-a-card/digitize-a-card).

## SDK integration

Call `MGCardEnrollmentService.checkEligibility()` to confirm **Tokenization** eligibility.

Provide:

* `EligibilityData`
* One of:
  * `InstrumentData`
  * `pushSessionId`

`EligibilityData` includes:

* `language`: Preferred language (for example, `en`).
* `inputMethod`: How card details were collected (for example, **issuer application** or manual entry).

`InstrumentData` can be built from:

* `encryptedCardData`
* `issuerPushReceipt`

In the push card enrollment use case, the NFC Wallet backend returns `pushSessionId` to the **issuer backend**.

### Check eligibility with card credentials

In most cases, check eligibility using card credentials. Provide PAN and expiry date. Optionally provide card security code (CSC).

```java
// Get the handler of the Enrollment Service
MGCardEnrollmentService enrollmentService =
        MobileGatewayManager.INSTANCE.getCardEnrollmentService();

// Build the instrument data from encrypted card data and public key
InstrumentData instrumentData =
        new InstrumentData.EncryptedCardDataBuilder(encryptedCardInfo)
                .publicKeyIdentifier(pubKey)
                .build();

// Build the eligibility data
EligibilityData eligibilityData =
        new EligibilityData.Builder(InputMethod.BANK_APP, "en").build();

// Invoke eligibility with listener CardEligibilityListener
enrollmentService.checkEligibility(eligibilityData, instrumentData, new CardEligibilityListener() {
    @Override
    public void onSuccess(TermsAndConditions termsAndConditions, IssuerData issuerData) {
        // If the card is eligible, get the T&C
        String tncContent = termsAndConditions.getContent();
        ContentType tncContentType = termsAndConditions.getContentType();

        // Persist and display the T&C.
        // Collect acceptance before calling digitizeCard(...).
    }

    @Override
    public void onError(MobileGatewayError error) {
        // Card is not eligible, or the request failed.
        // Check error reason and decide whether to retry or stop the flow.
    }
});
```

### Check eligibility with an issuer push receipt

The issuer can initiate enrollment from the **issuer application**. In this flow, the issuer application sends an issuer push receipt. The **digital wallet application** uses it to build `InstrumentData`.

{% hint style="info" %}
Enrollment using an **issuer push receipt** is only supported for Mastercard. NFC Wallet supports the MDES Token Connect specification.
{% endhint %}

Build `InstrumentData` using the issuer push receipt. Then call `checkEligibility(...)` as in the card credentials flow.

```java
final String type = "pushAccountReceipt"; // Constant
final String scheme = "MASTERCARD"; // Only supported by Mastercard / MDES
String payload = "..."; // Payload received from issuer app

// Build the instrument data from issuer push receipt
InstrumentData instrumentData =
        new InstrumentData.IssuerPushReceiptBuilder(scheme, type, payload).build();
```

### Check eligibility with a push card enrollment session ID

To avoid handling encrypted card details in the application, the **issuer backend** can push card details directly to the NFC Wallet backend. The NFC Wallet backend returns an ephemeral push card enrollment session ID (`pushSessionId`).

```java
// Get the pushSessionId generated by the NFC Wallet backend
String pushSessionId = "....";

// Get the handler of the Enrollment Service
MGCardEnrollmentService enrollmentService =
        MobileGatewayManager.INSTANCE.getCardEnrollmentService();

// Invoke the card eligibility
enrollmentService.checkEligibility(eligibilityData, pushSessionId, new CardEligibilityListener() {
    @Override
    public void onSuccess(TermsAndConditions termsAndConditions, IssuerData issuerData) {
        // If the card is eligible, get the T&C
        String tncContent = termsAndConditions.getContent();
        ContentType tncContentType = termsAndConditions.getContentType();

        // Persist and display the T&C.
        // Collect acceptance before calling digitizeCard(...).
    }

    @Override
    public void onError(MobileGatewayError error) {
        // Card is not eligible, or the request failed.
    }
});
```

### T\&C acceptance

After a successful eligibility check, present the terms and conditions (T\&C) to the **end user** when required.

Then, after the end user accepts, create a `TermsAndConditionSession` and pass it to `digitizeCard(...)`. See [Digitize a card](/nfc-wallet-sdk-android/implement-nfc-wallet/tokenize-a-card/digitize-a-card).

```java
// From eligibility: retrieve TermsAndConditions.
// Render termsAndConditions.getContent() based on termsAndConditions.getContentType().
// Then, after end user acceptance:
TermsAndConditionSession tncSession = termsAndConditions.accept();
```

{% hint style="info" %}
The **digital wallet application** is responsible for displaying the T\&C and collecting acceptance (when required by your program).

If your program allows implicit acceptance, you can call `termsAndConditions.accept()` without end user interaction.
{% endhint %}


# Digitize a card

## Overview

After the card passes eligibility checks, and the end user accepts the terms and conditions (T\&C) when required, start digitization.

During the digitization:

* The issuer backend returns the **Tokenization** decision (green flow, yellow flow, or red flow) to the digital wallet application via NFC Wallet.
* If the issuer backend approves (green flow or yellow flow):
  * The Token Service Provider (TSP) creates the digital card and its assets (profile and payment keys).
  * NFC Wallet securely provisions the digital card profile and payment keys in the digital wallet application.

In the yellow flow, the digital wallet application performs ID\&V (step-up authentication) before the card can be provisioned.

In the red flow, digitization is declined and the SDK returns an error callback.

Implement the green flow, the yellow flow, or both, based on your program.

{% hint style="info" %}
Depending on your program, **T\&C** might not be required. If so, the digital wallet application can accept the T\&C without end user interaction.
{% endhint %}

## SDK integration

Start **card digitization** by calling `MGCardEnrollmentService.digitizeCard(...)`.

You shall first implement `MGDigitizationListener` to track the digitization progress by handling callbacks according to the enrollment color flow:

* In the **Green flow (approved, no step-up)** the SDK calls these callbacks:

  * `onCPSActivationCodeAcquired`
  * `onComplete`

  For details, see [Green flow digitization](/nfc-wallet-sdk-android/implement-nfc-wallet/tokenize-a-card/digitize-a-card/green-flow-digitization).
* In the **yellow flow (approved with step-up)** the SDK also calls:

  * `onSelectIDVMethod`
  * `onActivationRequired`

  For details, see [Yellow flow digitization](/nfc-wallet-sdk-android/implement-nfc-wallet/tokenize-a-card/digitize-a-card/yellow-flow-digitization).

In case of digization error, NFC Wallet SDK emits the callback:

* `onError`: Digitization failed. Use `error.getCode()` to decide whether to retry, ask the end user to take action, or route to support.

### `MGDigitizationListener` implementation example

See code snipet below to implement `MGDigitizationListener`

{% code expandable="true" %}

```java
// build your Digitization listener
public class MyDigitizationListener implements MGDigitizationListener {

    @Override
    public void onCPSActivationCodeAcquired(String digitalCardId, byte[] activationCode) {
        // Receive activationCode to start provisioning for this digitalCardId.
        // See "Trigger a provisioning session".
    }

    @Override
    public void onSelectIDVMethod(IDVMethodSelector idvMethodSelector) {
        // Yellow flow only - Receive the list of ID&V methods
        // See "Yellow flow digization"
    }

    @Override
    public void onActivationRequired(PendingCardActivation pendingCardActivation) {
        // Yellow flow only - selected ID&V method requiring activation
        // See "Yellow flow digization"
   }

    @Override
    public void onComplete(String digitalCardId) {
        // Digitization completed successfully.
    }

    @Override
    public void onError(String digitalCardId, MobileGatewayError error) {
        // Digitization failed.
        // Parse error.getCode() and apply the right retry / recovery logic.
    }
});
```

{% endcode %}

### Digitize card example

In the example below you can find the code to start digitization.

* In case of green flow, you have to provide an **authentication token**.

{% code expandable="true" %}

```java
// reference to your Card Digitization listener
// - to track digitization progress using callback
MyDigitizationListener digitizationListener = new MyDigitizationListener();

// Get the enrollment service.
MGCardEnrollmentService enrollmentService =
        MobileGatewayManager.INSTANCE.getCardEnrollmentService();

// From eligibility: retrieve TermsAndConditions.
// See "Check card eligibility".
TermsAndConditionSession tncSession = termsAndConditions.accept();

// Provide the authentication in case of green flow
byte[] authenticationToken = null;

enrollmentService.digitizeCard(tncSession, authenticationToken, digitizationListener);
```

{% endcode %}


# Green flow digitization

## Overview

Green flow is a Tokenization flow where the issuer backend approves Tokenization without step-up authentication.

This flow is common when the NFC Wallet SDK is integrated in the issuer application and the end user is already authenticated in-app.

## User experience

See Green [flow user experience](/nfc-wallet-sdk-android/implement-nfc-wallet/tokenize-a-card#green-flow).

## Sequence diagram

<figure><img src="/files/OKivmeylr83mgX30soLK" alt=""><figcaption></figcaption></figure>

## Integrate SDK

After you [Check card eligibility](/nfc-wallet-sdk-android/implement-nfc-wallet/tokenize-a-card/check-card-eligibility). Implement `MGDigitizationListener` to track digitization progress and then:

1. Call `MGCardEnrollmentService.digitizeCard(...)`

   Include an `authenticationToken` generated by your digital wallet backend.

   You should provide a reference of your `MGDigitizationListener`
2. If Tokenization is approved with no conditions (green flow), the SDK emits theses callbacks:
   1. `onCPSActivationCodeAcquired`

      You receive the `activationCode` to start the secure provisioning.

      See [Trigger provisioning](/nfc-wallet-sdk-android/implement-nfc-wallet/tokenize-a-card/trigger-provisioning).
   2. `onComplete`

      Digitization steps is completed successfully.
3. The **Tokenization** is completed when the provisioning session is completed

   Check callback `EnrollingServiceListener.onComplete(`) as described in [Trigger provisioning](/nfc-wallet-sdk-android/implement-nfc-wallet/tokenize-a-card/trigger-provisioning)


# Yellow flow digitization

## Overview

Yellow flow is a **Tokenization** flow where the **issuer backend** approves Tokenization with step-up authentication (**ID\&V**).

This flow is common when the NFC Wallet SDK is integrated into a **digital wallet application** that supports cards from multiple issuers.

In this flow, the **end user** completes ID\&V before Tokenization can complete.

## User experience

See [Yellow flow user experience](/nfc-wallet-sdk-android/implement-nfc-wallet/tokenize-a-card#yellow-flow).

## Sequence diagram

<figure><img src="/files/EH8oJD3StrEArBgGng1F" alt=""><figcaption><p>Yellow flow digitization sequence.</p></figcaption></figure>

## Integrate SDK

After you [Check card eligibility](/nfc-wallet-sdk-android/implement-nfc-wallet/tokenize-a-card/check-card-eligibility), implement `MGDigitizationListener` to track digitization progress. Then:

1. Call `MGCardEnrollmentService.digitizeCard(...)`.

   Provide a reference to your `MGDigitizationListener`.
2. If the issuer backend approves Tokenization with step-up authentication (yellow flow), the SDK triggers these callbacks:
   1. `onCPSActivationCodeAcquired`

      You receive the `activationCode` to start the secure provisioning.

      See [Trigger provisioning](/nfc-wallet-sdk-android/implement-nfc-wallet/tokenize-a-card/trigger-provisioning).
   2. `onSelectIDVMethod`: Receive the ID\&V methods to display to the end user. See [List and select an ID\&V method](#list-and-select-an-id-and-v-method).
   3. `onActivationRequired`: Triggered only if the selected ID\&V method requires activation (for example, OTP).
   4. `onComplete`: Digitization steps is completed successfully.

      if ID\&V methods are:

      1. **cell\_phone**, **email** or **app\_to\_app with cryptogram**: Tokenization is completed
      2. **website**, **customer\_service**, or **app\_to\_app without cryptogram**: Tokenization is completed after your [process CPS notifications](/nfc-wallet-sdk-android/get-started/configuration/5.-push-notifications/handle-push-notifications#process-cps-notifications-digital-card-operations).

{% hint style="info" %}
For the **website**, **customer\_service**, or **app\_to\_app without cryptogram** ID\&V methods, the issuer activates the token using the TSP issuer API.

In this case, provisioning completes only after you [process CPS notifications](/nfc-wallet-sdk-android/get-started/configuration/5.-push-notifications/handle-push-notifications#process-cps-notifications-digital-card-operations).
{% endhint %}

### List and select an ID\&V method

In `MGDigitizationListener.onSelectIDVMethod`, use `IDVMethodSelector` to list the available ID\&V methods.

`IDVMethodSelector.getIdvMethodList()` returns an array of `IDVMethod` with these fields:

* `id`: Use this value when selecting the method.
* `type`: The ID\&V type (for example, OTP by SMS, OTP by email, or verification by **issuer application**).
* `value`: The display value. The content depends on `type`.
* `isOTPRequired`: Indicates whether the SDK will trigger `onActivationRequired`.

NFC Wallet supports these ID\&V `type` values:

* **cell\_phone**

  ID\&V using an OTP sent by SMS.

  Use `value` to display the masked phone number where the OTP will be sent.
* **email**

  ID\&V using an OTP sent by email.

  Use `value` to display the masked email address where the OTP will be sent.
* **customer\_service**

  ID\&V using a call to issuer customer care.

  Use `value` to display the phone number the end user must call.
* **website**

  The end user completes ID\&V on the issuer website.

  Use `value` to get the website URL.
* **app\_to\_app**

  The **digital wallet application** redirects the end user to the **issuer application**.

  Use `value` to display the issuer application name.

When the end user selects a method, capture its `id` and call `IDVMethodSelector.select(...)` to notify the NFC Wallet backend.

<pre class="language-java" data-expandable="true"><code class="lang-java">// Reference of the idvMethodSelector
IDVMethodSelector idvMethodSelector = null;

<strong>// Methods from interface MGDigitizationListener 
</strong><strong>@Override
</strong>public void onSelectIDVMethod(final IDVMethodSelector idvMethodSelector) {
    if (idvMethodSelector.getIdvMethodList().length == 0) {
        // Log error
    }
    
    this.idvMethodSelector = idvMethodSelector;
    
    displayIdvMethods();
}

// Method to build Dialog UI to display possible ID&#x26;V...
<strong>public void displayIdvMethods() {
</strong>    // ... so list of possible ID&#x26;V using idvMethodSelector
    for (int i = 0; i &#x3C; idvMethodSelector.getIdvMethodList().length; i++) {
        IDVMethod idvMethod = idvMethodSelector.getIdvMethodList()[i];
        String id = idvMethod.getId();
        String type = idvMethod.getType();
        String value = idvMethod.getValue();
        boolean isOtpRequired = idvMethod.isOtpRequired();
        ...
    }
    ...
}

// Method to be called from UI, when the ID&#x26;V method is selected by end user
// Provide the id of the selected idvMethod
public void selectIdvMethod( int idvSelectedMethodId) {
    idvMethodSelector.select( idvSelectedMethodId );
}
</code></pre>

### ID\&V with OTP

If the end user selects **cell\_phone** or **email**, the TSP generates an OTP. Then the TSP requests the issuer to send the OTP by SMS or email.

The NFC Wallet SDK triggers `MGDigitizationListener.onActivationRequired` with `PendingCardActivation.getState()` set to `OTP_NEEDED`.

Your **digital wallet application** must display an OTP entry UI.

After the end user enters the OTP, call `PendingCardActivation.activate(...)` and provide the OTP.

If the OTP is valid, the SDK triggers `MGDigitizationListener.onComplete` callback.

{% hint style="info" %}
**Implement the OTP entry UI**

The NFC Wallet SDK does not provide an OTP entry UI. Implement and customize the UI in your **digital wallet application**.
{% endhint %}

<pre class="language-java" data-expandable="true"><code class="lang-java">// reference to your Card Digitization listener
MyDigitizationListener digitizationListener = new MyDigitizationListener();

// Reference of the pending card activation
PendingCardActivation pendingCardActivation = null;

<strong>// Methods from interface MGDigitizationListener 
</strong><strong>@Override
</strong>public void onActivationRequired (PendingCardActivation pendingCardActivation) {
    this.pendingCardActivation = pendingCardActivation;
    
    PendingCardActivation activationState = pendingCardActivation.getState();
    switch( activationState ) {
        case OTP_NEEDED:
            // display a UI to enter an OTP
            ...
    }
    ...
}

// Method to be called from UI, when the OTP has been provided by end user
public void idvActivationWithOtp( String otp) {
    pendingCardActivation.activate( otp.getBytes(), digitizationListener );
}
</code></pre>

### Customer service or web service ID\&V

If the end user selects **customer\_service** or **website**, the issuer manages ID\&V directly (for example, via an issuer web portal or issuer customer care).

Use `value` to get the web portal URL or the issuer customer care phone number.

After the issuer successfully authenticates the end user, the issuer activates the token using the TSP issuer API.

Then the NFC Wallet backend sends a `CPS` push notification to the digital wallet application.

Process the push as described in [Process CPS notifications](/nfc-wallet-sdk-android/get-started/configuration/5.-push-notifications/handle-push-notifications#process-cps-notifications-digital-card-operations).

### App-to-app ID\&V

In this ID\&V method, the digital wallet application redirects the end user to the issuer application.

The NFC Wallet SDK triggers `MGDigitizationListener.onActivationRequired` with `PendingCardActivation.getState()` set to `APP2APP_NEEDED`.

Use `PendingCardActivation.getAppToAppData()` to retrieve an `AppToAppData` object.

Use `AppToAppData.getPayLoad()`, `AppToAppData.getScheme()`, and `AppToAppData.getSource()` to redirect the end user to the issuer application.

```java
MGCardEnrollmentService enrollmentService = MobileGatewayManager.INSTANCE.getCardEnrollmentService();
PendingCardActivation pendingCardActivation = enrollmentService.getPendingCardActivation(digitalCardId);
PendingCardActivationState state = pendingCardActivation.getState();
if (PendingCardActivationState.APP2APP_NEEDED == state) {
  AppToAppData appToAppData = pendingCardActivation.getAppToAppData();
  if(appToAppData != null) {
    String scheme = appToAppData.getScheme();
    String source = appToAppData.getSource();
    String payload = appToAppData.getPayload();
  // use source to get packageId and intent action to launch issuer application
  }
}
```

After the issuer application completes authentication, it redirects the end user back to the digital wallet application.

There are two variants:

* `AppToApp with cryptogram`: The issuer application generates an issuer cryptogram.
* `AppToApp without cryptogram`: The issuer activates the token using the TSP issuer API.

For `AppToApp with cryptogram`,

* call `PendingCardActivation.resumeAppToAppActivation(...)` and provide the issuer cryptogram.
* If the cryptogram is valid,
  * The NFC Wallet SDK provisions the digital card profile in the background.
  * and the SDK triggers `MGDigitizationListener.onComplete` callback.

For `AppToApp without cryptogram`,

* call `PendingCardActivation.resumeAppToAppActivation()`.
* Process the push as described in [Process CPS notifications](/nfc-wallet-sdk-android/get-started/configuration/5.-push-notifications/handle-push-notifications#process-cps-notifications-digital-card-operations).


# Trigger provisioning

## Overview

After you digitize a card, start a provisioning session to provision the digital card.

During the provisioning session, the **NFC Wallet** provisions securly the digital card profile and payment keys in your **digital wallet application**.

Start the provisioning session right after you receive the `activationCode` from `MGDigitizationListener.onCPSActivationCodeAcquired`. See [Digitize a card](/nfc-wallet-sdk-android/implement-nfc-wallet/tokenize-a-card/digitize-a-card#sdk-integration).

This callback also returns `digitalCardId`. Store it for later operations (for example, access tokens, transaction history, and LCM). You do not need it to start secure provisioning.

{% hint style="info" %}
This step also sets up the secure channel between the **NFC Wallet SDK** and the **NFC Wallet backend**.

This setup is called **device enrollment** (also known as **CPS enrollment**).
{% endhint %}

## Sequence diagram

<figure><img src="/files/73f2CdCI46tIeD1g7h9H" alt=""><figcaption><p>Secure provisioning flow (device enrollment and provisioning session).</p></figcaption></figure>

## SDK integration

Secure provisioning requires **device enrollment**.

Device enrollment is typically required once per wallet instance on a device. When enrollment is required, the enrollment flow triggers the provisioning session automatically.

If device enrollment is already complete, start the provisioning session by calling `ProvisioningBusinessService.sendActivationCode(...)`.

The SDK requests the `activationCode` through `EnrollingServiceListener.onCodeRequired(...)`. Provide the value at that time.

### Prerequisites

Before you start, make sure you have:

* Initialized the **NFC Wallet SDK**. See [Initialize the NFC Wallet SDK](/nfc-wallet-sdk-android/get-started/configuration/4.-initialize-the-nfc-wallet-sdk).
* Configured push notifications and retrieved a push token. See [Push notifications](https://gitlab.sre.ops.gcloud.thalescloud.io/bps/gitbook/nfc-wallet-gitbook-docs/-/blob/dev-sdk/NFC-Wallet-SDK-Android/get-started/configuration/5.-push-notifications).
* Received the `activationCode` from digitization. See [Digitize a card](/nfc-wallet-sdk-android/implement-nfc-wallet/tokenize-a-card/digitize-a-card#sdk-integration).

### Device enrollment

Device enrollment requires these inputs:

* `activationCode` (`byte[]`): Returned by digitization.
* `walletId`: Retrieve using `MGCardEnrollmentService.getWalletId()`. Pass this value as the `userId` parameter to `EnrollingBusinessService.enroll(...)`. See [Retrieve the wallet ID](/nfc-wallet-sdk-android/get-started/configuration/4.-initialize-the-nfc-wallet-sdk#retrieving-the-wallet-id).
* `pushToken`: The push token for **FCM** or **HMS Push Kit**.

{% hint style="warning" %}
Prefix **HMS Push Kit** tokens with `HMS:` (for example, `HMS:<token>`).
{% endhint %}

### Check device enrollment status

Check the device enrollment status using `EnrollingBusinessService.isEnrolled()`.

This status indicates whether the secure channel is already established for the current wallet instance on this device.

It returns an `EnrollmentStatus`:

* `ENROLLMENT_NEEDED`: Call `EnrollingBusinessService.enroll(...)`.
* `ENROLLMENT_IN_PROGRESS`: Call `EnrollingBusinessService.continueEnrollment(...)`.
* `ENROLLMENT_COMPLETE`: Call `ProvisioningBusinessService.sendActivationCode(...)`.

### Implement `EnrollingServiceListener`

Implement `EnrollingServiceListener` to drive the enrollment flow:

* `onCodeRequired`: Provide the `activationCode`.
* `onComplete`: Device enrollment completes successfully.
* `onError`: Handle errors using `ProvisioningServiceError`.

<pre class="language-java" data-title="MyEnrollingServiceListener.java"><code class="lang-java"><strong>public class MyEnrollingServiceListener implements EnrollingServiceListener {
</strong>
    // Receive from MGDigitizationListener.onCPSActivationCodeAcquired(...)
    private final byte[] activationCode;

    public MyEnrollingServiceListener(final byte[] activationCode) {
        this.activationCode = activationCode;
    }

    @Override
    public void onStarted() {
        // Called when the enrollment flow starts.
    }

    @Override
    public void onCodeRequired(final CHCodeVerifier chCodeVerifier) {
        // Called when the activation code is required to continue the flow.
        final SecureCodeInputer inputer = chCodeVerifier.getSecureCodeInputer();
        for (final byte b : activationCode) {
            inputer.input(b);
        }
        inputer.finish();
    }

    @Override
    public void onComplete() {
        // Called once the device enrollment completes successfully.
        // In a Green flow, this usually means provisioning is complete.
    }

    @Override
    public void onError(final ProvisioningServiceError error) {
        // Called when device enrollment fails.
        // Parse error.getCode() and apply the right retry / recovery logic.
    }
}
</code></pre>

### Device enrollment code implementation

```java
byte[] activationCode = ...; // from MGDigitizationListener.onCPSActivationCodeAcquired(...)
String pushToken = "..."; // from FCM or HMS Push Kit
String language = "en"; // Use your app locale when possible.

// Wallet ID is the user identifier for device enrollment.
String walletId = MobileGatewayManager.INSTANCE.getCardEnrollmentService().getWalletId();

EnrollingServiceListener enrollingListener = new MyEnrollingServiceListener(activationCode);

final EnrollingBusinessService enrollingService = ProvisioningServiceManager.getEnrollingBusinessService();
final ProvisioningBusinessService provisioningBusinessService = ProvisioningServiceManager.getProvisioningBusinessService();

// Check enrollment status.
final EnrollmentStatus status = enrollingService.isEnrolled();
switch (status) {
    case ENROLLMENT_NEEDED:
        // First device enrollment attempt on this wallet instance.
        enrollingService.enroll(walletId, pushToken, language, enrollingListener);
        break;
    
    case ENROLLMENT_IN_PROGRESS:
        // Enrollment was started earlier and must be resumed.
        enrollingService.continueEnrollment(language, enrollingListener);
        break;
    
    case ENROLLMENT_COMPLETE:
        // Device enrollment is already completed.
        // Trigger provisioning for this card.
        // The SDK requests the activation code via enrollingListener.onCodeRequired(...).
        provisioningBusinessService.sendActivationCode(enrollingListener);
        break;
    
    default:
        // Log error (unknown status).
 }

```


# Set CDCVM method

## Overview

The digital card profile defines whether it supports CDCVM.

For a given wallet instance, the **first provisioned card that supports CDCVM** defines the **CDCVM method** used by the **digital wallet application**.

NFC Wallet SDK does not allow cards with different CDCVM methods to co-exist in the same wallet instance.

As described in [Handle CDCVM](/nfc-wallet-sdk-android/implement-nfc-wallet/handle-cdcvm), most NFC Wallet programs use CDCVM.

In this section, you set the CDCVM method based on device capabilities during **Tokenization** of the first card that supports CDCVM.

{% hint style="danger" %}
**Setting the CDCVM method is Required**

If the profile supports CDCVM and you do not set the CDCVM method:

* Retrieving the card list fails with `DigitalizedCardErrorCodes.CD_CVM_REQUIRED`.
* NFC payments fail until you set the CDCVM method.
  {% endhint %}

## SDK integration

### Check whether CDCVM is supported and set

Use `CHVerificationManager` to check whether CDCVM is supported and already configured for the current wallet instance:

* `CHVerificationManager.isFCDCVMSupported()` checks whether CDCVM is supported.
* `CHVerificationManager.isFCdCvmSet()` checks whether the CDCVM method is already set.
* `CHVerificationManager.getDefaultFCdCvm()` returns the CDCVM method used by the digital wallet application.

If CDCVM is supported and not set, initialize it as described in [Set the CDCVM method](#set-the-cdcvm-method).

### Handle `CD_CVM_REQUIRED` when listing cards

If you do not set the CDCVM method and you retrieve the card list using `DigitalizedCardManager.getAllCards()`, the SDK can return `DigitalizedCardErrorCodes.CD_CVM_REQUIRED`. In such case initialize CDCVM method it as described in [Set the CDCVM method](#set-the-cdcvm-method).

```java
DigitalizedCardManager.getAllCards( new AbstractAsyncHandler<String[]> () {
    
    @Override
    public void onComplete(final AsyncResult<String[]> asyncResult) {
        if (asyncResult.isSuccessful()) {
            // Card list retrieved successfully
        }
        else {
            // Card list retrieval failed
            final int errorCode = asyncResult.getErrorCode();
            if (errorCode == DigitalizedCardErrorCodes.CD_CVM_REQUIRED) {
                // Set the CDCVM method here (see next section)
                // ....
            }
        }
    }
    
});
```

### Set the CDCVM method

Use `DeviceCVMManager.initialize(...)` to set the CDCVM method according to device capabilities:

* **Biometric**: `CHVerificationMethod.BIOMETRICS`
* **Device credentials (keyguard)**: `CHVerificationMethod.DEVICE_KEYGUARD`

{% hint style="info" %}
After you set the CDCVM method, consider scenarios where the end user changes the device unlock method. See [Device unlock method update scenario](/nfc-wallet-sdk-android/implement-nfc-wallet/tokenize-a-card/set-cdcvm-method/device-unlock-method-update-scenarios).
{% endhint %}

#### Implementation example

```java
// Check device eligibility for CDCVM
DeviceCVMEligibilityResult result =
        DeviceCVMEligibilityChecker.checkDeviceEligibility(getApplicationContext());

if (result.getBiometricsSupport() == BiometricsSupport.SUPPORTED) {
    // Biometric is supported
    try {
        DeviceCVMManager.INSTANCE.initialize(CHVerificationMethod.BIOMETRICS);
    } catch (DeviceCVMException e) {
        // Handle error
    }
}
else if (result.getDeviceKeyguardSupport() == DeviceKeyguardSupport.SUPPORTED) {
    // If biometrics are not supported, use device keyguard.
    try {
        DeviceCVMManager.INSTANCE.initialize(CHVerificationMethod.DEVICE_KEYGUARD);
    } catch (DeviceCVMException e) {
        // Handle error
    }
}
else {
    // Device does not support CDCVM, or the end user did not enable a secure lock screen.
    // Prompt the end user to enable biometrics or device credentials.
}
```


# Device unlock method update scenarios

## Overview

If the end user enables a secure lock screen and the issuer application sets **biometric** or **device credentials (keyguard)** as the CDCVM method, handle device unlock changes carefully.

Some changes invalidate the key material stored in Android Keystore. NFC Wallet SDK detects this only when it accesses the keystore. During payment, the issuer application may then fail to retrieve cards and receive a `CARD_NOT_EXISTING` exception.

The following scenarios summarize the expected behavior.

## Scenarios

<table data-full-width="true"><thead><tr><th>Scenario</th><th>OS</th><th>SDK</th><th>Digital wallet application</th></tr></thead><tbody><tr><td>End user disables the secure lock screen</td><td>Invalidates the key material in Android Keystore. Android does not notify the digital wallet application when this happens.</td><td>Detects the invalid key material only when it accesses the keystore.</td><td>During payment, does not find any cards and receives a <code>CARD_NOT_EXISTING</code> exception.</td></tr><tr><td>End user changes the secure lock screen type, for example from fingerprint to passcode, or from passcode to PIN</td><td>No action.</td><td>No action.</td><td>Optionally detect this change at startup or in a background check, based on your issuer application logic.</td></tr><tr><td>End user disables the secure lock screen, then enables it again</td><td>Invalidates the key material as soon as the secure lock screen is disabled.</td><td>Detects the invalid key material only when it accesses the keystore.</td><td>During payment, does not find any cards and receives a <code>CARD_NOT_EXISTING</code> exception.</td></tr><tr><td>End user adds a new fingerprint</td><td>No action.</td><td>No action.</td><td>No action.</td></tr><tr><td>End user removes all fingerprints</td><td>Invalidates the key material in Android Keystore if the digital wallet application uses <strong>biometric</strong> as the CDCVM method.</td><td>If <strong>biometric</strong> is used as the CDCVM method, detects the invalid key material only when it accesses the keystore.</td><td>If <strong>biometric</strong> is used as the CDCVM method, during payment does not find any cards and receives a <code>CARD_NOT_EXISTING</code> exception.</td></tr></tbody></table>


# Manage digital cards

## Overview

After **Tokenization**, your **digital wallet application** should let the **end user** view and manage their digital cards.

If you have not integrated Tokenization yet, start with [Tokenize a card](/nfc-wallet-sdk-ios/implement-nfc-wallet/tokenize-a-card).

## Implementation guides

* [Display digital cards](/nfc-wallet-sdk-android/implement-nfc-wallet/manage-digital-cards/display-digital-cards)

  Retrieve the digital card list and card details.
* [Set default payment card](/nfc-wallet-sdk-android/implement-nfc-wallet/manage-digital-cards/set-the-default-payment-card)

  Set the default digital card used for payments.
* [Manage digital card LCM](/nfc-wallet-sdk-android/implement-nfc-wallet/manage-digital-cards)

  And Perform **LCM** actions on a digital card (as delete card).


# Display digital cards

## Overview

After **Tokenization**, your **digital wallet application** should show the **end user** their digital cards.

Provide a list view and a details view.

Use card status, card art, and metadata to drive the UI.

## SDK integration

### Use `DigitalizedCardManager` <a href="#digitalizedcardmanager" id="digitalizedcardmanager"></a>

After **Tokenization** completes, use `DigitalizedCardManager` to access the **NFC Wallet SDK** persistent data and retrieve digital cards.

`DigitalizedCardManager` supports asynchronous and blocking calls:

* `AsyncHandler`: Receive results via callbacks.
* `AsyncToken`: Block the calling thread until the operation completes.

{% hint style="warning" %}
`AsyncToken` blocks the calling thread. Avoid it on the UI thread.
{% endhint %}

### Retrieve card list

After **Tokenization** completes, use `DigitalizedCardManager.getAllCards()` to retrieve all **tokenized card IDs**.

For the difference between identifiers, see [Tokenized card ID versus digital card ID](#tokenized-card-id-versus-digital-card-id).

The examples below show how to retrieve tokenized card IDs with `AsyncHandler` and `AsyncToken`.

{% tabs %}
{% tab title="AsyncHandler" %}
{% code title="Retrieve tokenized card IDs using AsyncHandler" %}

```kotlin
// Instantiate a HandlerThread to avoid work on the UI thread.
val cardDisplayThread = HandlerThread("getAllCards")
cardDisplayThread.start()

val looper = cardDisplayThread.looper

val handler = object : AbstractAsyncHandler<Array<String>>(looper) {
    override fun onComplete(result: AsyncResult<Array<String>>) {
        if (result.isSuccessful) {
            val tokenizedCardIds = result.result
            // TODO: display the cards
        } else {
            // TODO: handle error
        }
    }
}

DigitalizedCardManager.getAllCards(handler)
```

{% endcode %}
{% endtab %}

{% tab title="AsyncToken" %}
{% code title="Retrieve tokenized card IDs using AsyncToken" %}

```kotlin
val token = DigitalizedCardManager.getAllCards(null)
val result = token.waitToComplete()

if (result.isSuccessful) {
    val tokenizedCardIds = result.result
    // Display the cards in your UI
} else {
    // Handle error
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

### Tokenized card ID versus digital card ID <a href="#tokenized-card-id-versus-digital-card-id" id="tokenized-card-id-versus-digital-card-id"></a>

`DigitalizedCardManager` lists and retrieves cards using a **tokenized card ID**.

`DigitalizedCard.getTokenizedCardID()` returns the **tokenized card ID.**

This identifier is not the same as the **digital card ID**.

{% hint style="warning" %}
The **NFC Wallet SDK** uses two identifiers for the same card:

* **Tokenized card ID**: Generated during secure provisioning. Also known as a CPS token ID. See [Trigger provisioning](/nfc-wallet-sdk-android/implement-nfc-wallet/tokenize-a-card/trigger-provisioning).
* **Digital card ID**: Generated during digitization. Also known as an MG card ID. See [Digitize a card](/nfc-wallet-sdk-android/implement-nfc-wallet/tokenize-a-card/digitize-a-card).
  {% endhint %}

Use these helper methods to convert identifiers:

* `DigitalizedCardManager.getDigitalCardId()`: Get the digital card ID from a tokenized card ID.
* `DigitalizedCardManager.getTokenizedCardId()`: Get the tokenized card ID from a digital card ID.

{% hint style="info" %}
A TSP also provides its own digital card identifier.

Retrieve it in [Card metadata](#card-metadata).

Use it when troubleshooting with the TSP (VTS/MDES).

This identifier is different from the tokenized card ID and the digital card ID.
{% endhint %}

### Retrieve digital card information

#### Use `DigitalizedCard`

`DigitalizedCard` represents a digitized card and exposes card data, such as:

* `DigitalizedCardStatus`
  * Card state: `ACTIVE`, `SUSPENDED`
  * Payment keys status: Use it to detect replenishment needs.
* `DigitalizedCardDetails`
  * `getLastFourDigits()` : Last four digits of FPAN.
  * `getLastFourDigitsOfDPAN()` : Last four digits of DPAN.
  * `getPANExpiry()` : FPAN expiry date.
  * `getScheme()`: Payment network (Visa, Mastercard, and PURE).
* `DigitalizedCard.getPaymentAccountReference()`
  * Payment Account Reference (PAR) for the primary contactless card.

Retrieve a `DigitalizedCard` from `DigitalizedCardManager` using the **tokenized card ID**.

```kotlin
// Get the DigitalizedCard instance
val digitalizedCard = DigitalizedCardManager.getDigitalizedCard(tokenizedCardId)

// Get card state
val statusToken = digitalizedCard.getCardState(null)
val statusResult = statusToken.waitToComplete()

if (statusResult.isSuccessful) {
    val status = statusResult.result
    
    // Card states include ACTIVE and SUSPENDED
    // ACTIVE: Card can be used for payment
    // SUSPENDED: Card requires activation before payment
    val state = status.state
    
    // Payment key information
    val numberOfPaymentsLeft = status.numberOfPaymentsLeft
    val needsReplenishment = status.needsReplenishment()
    val expiryDate = status.expiryDate // LUK expiry date (null for SUK)
}

// Get card details
val detailsToken = digitalizedCard.getCardDetails(null)
val detailsResult = detailsToken.waitToComplete()

if (detailsResult.isSuccessful) {
    val details = detailsResult.result
    
    // Card metadata
    val lastFourDigits = details.lastFourDigits // Last four digits of FPAN
    val lastFourDigitsOfDPAN = details.lastFourDigitsOfDPAN // Last four digits of DPAN
    val panExpiry = details.panExpiry // FPAN expiry date
    val scheme = details.scheme // Payment network: Visa, Mastercard, PURE
}

// Get the PAR for the primary card
try {
    val paymentAccountReference = digitalizedCard.paymentAccountReference
    // Returns null if contactless data is unavailable or PAR is not present
} catch (e: InternalComponentException) {
    // Handle error
}
```

### Retrieve auxiliary card information

If the card is co-badged, you can retrieve additional properties from `DigitalizedCard`:

* `DigitalizedCard.hasAuxiliaryScheme()`: Returns `true` if the card has an auxiliary scheme.
* `DigitalizedCardDetails`
  * `getAuxiliaryLastFourDigitsOfDPAN()` : Last four digits of the auxiliary DPAN.
  * `getAuxiliaryScheme()` : Payment network for the auxiliary card.
* `DigitalizedCard.getAuxiliaryPaymentAccountReference()`: Payment Account Reference (PAR) for the auxiliary contactless card.

If the card is not co-badged, these properties return `null`.

```kotlin
// Check if the card has an auxiliary scheme
val hasAuxiliaryScheme = digitalizedCard.hasAuxiliaryScheme()

if (hasAuxiliaryScheme) {
    // Get auxiliary card details
    val detailsToken = digitalizedCard.getCardDetails(null)
    val detailsResult = detailsToken.waitToComplete()
    
    if (detailsResult.isSuccessful) {
        val details = detailsResult.result
        
        // Auxiliary scheme information
        val auxiliaryScheme = details.auxiliaryScheme // Auxiliary payment network
        val auxiliaryLastFourDigitsOfDPAN = details.auxiliaryLastFourDigitsOfDPAN // Last four digits of the auxiliary DPAN
    }
    
    // Get auxiliary payment key information
    val statusToken = digitalizedCard.getCardState(null)
    val statusResult = statusToken.waitToComplete()
    
    if (statusResult.isSuccessful) {
        val status = statusResult.result
        
        // Remaining payments for the auxiliary card
        val auxiliaryNumberOfPaymentsLeft = status.auxiliaryNumberOfPaymentsLeft
    }
    
    // Get the PAR for the auxiliary card
    try {
        val auxiliaryPaymentAccountReference = digitalizedCard.auxiliaryPaymentAccountReference
        // Returns null if:
        // - The card does not have an auxiliary scheme
        // - Contactless data is unavailable
        // - PAR is unavailable in contactless data
    } catch (e: InternalComponentException) {
        // Handle error
    }
}

// Note: If the card is not co-badged, auxiliary properties return null
```

#### Card metadata

Use `MGCardEnrollmentService.getCardMetaData()` and the **digital card ID** to retrieve card metadata, such as:

* TSP issuer name
* TSP ID (VTS, MDES, or another identifier)
* PAR (payment account reference)
* TSP digital card ID (`tokenId`)

For full field coverage, see the SDK API reference.

{% hint style="info" %}
TSP digital card ID (`tokenId`) maps to:

* Mastercard (MDES): `tokenUniqueReference`
* Visa (VTS): `tokenReferenceID`
  {% endhint %}

#### Card art

Use `MobileGatewayManager.getCardArt()` and the **digital card ID** to retrieve `CardArt`.

Use `CardArt.getBitmap()` to retrieve these images:

* `BANK_LOGO`: Issuer logo
* `CARD_BACKGROUND`: Card background
* `CARD_BACKGROUND_COMBINED`: Card background combined with the payment network
* `CARD_ICON`: Card icon

{% hint style="warning" %}
Card art retrieval triggers network requests; cache images within the digital wallet application to improve performance.
{% endhint %}

The sample application demonstrates a simple local caching approach:

{% code title="Cache card art locally" %}

```kotlin
fun getCardArt(context: Context, digitalCardId: String) {
    // First check if we already have the image locally
    val imageBytes = readFromFile(context, digitalCardId)
    if (imageBytes.isNotEmpty()) {
        val image = BitmapDrawable(
            context.resources,
            BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size)
        )
        // Use the cached image in your UI
        return
    }

    // Download card art data from the backend
    val gatewayManager = MobileGatewayManager.INSTANCE
    try {
        val cardArt = gatewayManager.getCardArt(digitalCardId)
        cardArt.getBitmap(
            CardArtType.CARD_BACKGROUND_COMBINED,
            object : MGAbstractAsyncHandler<CardBitmap>() {
                override fun onComplete(result: MGAsyncResult<CardBitmap>) {
                    if (result.isSuccessful) {
                        val value = result.result
                        // Store data for future use
                        writeToFile(context, digitalCardId, value.resource)
                        val image = BitmapDrawable(
                            context.resources,
                            BitmapFactory.decodeByteArray(
                                value.resource,
                                0,
                                value.resource.size
                            )
                        )
                        // Use the downloaded image in your UI
                    }
                }
            }
        )
    } catch (exception: NoSuchCardException) {
        // Handle error - card not found
    }
}
```

{% endcode %}


# Set the default payment card

## Overview

The default digital card is the card your **digital wallet application** selects automatically for contactless payments.

The **end user** can keep the default digital card or switch cards in your UI before confirming the payment.

See [Implement contactless payments](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments).

## SDK integration

### Set the default payment card

Call `DigitalizedCard.setDefault()` on the `DigitalizedCard` you want to set as the default.

{% hint style="warning" %}
Before you set a digital card as the default, confirm it is active and has at least one payment remaining (payment key). Use the card status and payment key status fields in [Display digital cards](/nfc-wallet-sdk-android/implement-nfc-wallet/manage-digital-cards/display-digital-cards#retrieve-digital-card-information) to validate both.

* Call `DigitalizedCardStatus.getState()` to verify the card state.
* Call `DigitalizedCardStatus.getNumberOfPaymentsLeft()` to check remaining payments.
  {% endhint %}

The example below sets the default digital card for contactless payments.

{% code title="SetDefaultCard.java" %}

```java
public void setDefault(final DigitalizedCard digitalizedCard) {
    digitalizedCard.setDefault(
        PaymentType.CONTACTLESS,
        new AsyncHandlerVoid(new AsyncHandlerVoid.Delegate() {
            @Override
            public void onSuccess() {
                // Default card successfully set.
            }

            @Override
            public void onError(final String error) {
                // TODO: handle error
            }
        })
    );
}
```

{% endcode %}

### `DigitalizedCardManager` for default card management

`DigitalizedCardManager` provides additional APIs for default card management:

* `DigitalizedCardManager.getDefault()`: Retrieve the **tokenized card ID** for the default card.
* `DigitalizedCardManager.unsetDefaultCard()`: Unset the current default card. After that, no card is selected by default.


# Get an access token

## Overview

During **Tokenization**, the NFC Wallet SDK sets up a secure channel with the **NFC Wallet backend** when you [Trigger provisioning](/nfc-wallet-sdk-android/implement-nfc-wallet/tokenize-a-card/trigger-provisioning).

The SDK uses this secure channel to issue an **access token** for:

* digital card **LCM**
* transaction notifications

Access tokens expire. Refresh them when needed.

## SDK integration

Use `ProvisioningBusinessService` and the **digital card ID** to retrieve an access token.

Implement `AccessTokenListener` to receive the token in `onSuccess(...)`.

{% hint style="warning" %}
Treat access tokens as sensitive data.

Do not log them or persist them to disk.
{% endhint %}

{% code title="GetAccessToken.java" %}

```java
public void getAccessToken(final String digitalCardId) {
    final ProvisioningBusinessService provisioningService =
            ProvisioningServiceManager.getProvisioningBusinessService();

    provisioningService.getAccessToken(
            digitalCardId,
            GetAccessTokenMode.REFRESH,
            new AccessTokenListener() {
                @Override
                public void onSuccess(final String digitalCardId, final String accessToken) {
                    // Token successfully retrieved.
                    // Use it to call LCM services and retrieve transaction notifications.
                }

                @Override
                public void onError(final String digitalCardId, final ProvisioningServiceError error) {
                    // Handle errors (for example, no data connection).
                }
            }
    );
}
```

{% endcode %}


# Manage digital card LCM

## Overview

Use the NFC Wallet SDK in your digital wallet application to manage a digital card lifecycle (LCM).

Primary use case:

* Delete a digital card from the digital wallet application

Before you start you should get an access token as described in [Get an access token](/nfc-wallet-sdk-android/implement-nfc-wallet/manage-digital-cards/get-an-access-token).

{% hint style="info" %}
In this section, we describe LCM actions initiated from the digital wallet application. The issuer backend can also initiate digital card LCM directly with the TSP.
{% endhint %}

## SDK integration

Use `MGCardLifeCycleManager` and the digital card ID to trigger LCM actions.

Implement `MGCardLifecycleEventListener` to handle `onSuccess` and `onError` callbacks.

Supported actions:

* `deleteCard`
* `suspendCard`
* `resumeCard`

`onSuccess` confirms that the NFC Wallet SDK accepted the request. The digital wallet application updates after it receives a push notification.

{% hint style="info" %}
Changes from the **NFC Wallet backend** don't appear immediately in the digital wallet application.

**NFC Wallet backend** sends a push notification to synchronize the digital card state.

See [Handle push notifications](/nfc-wallet-sdk-android/get-started/configuration/5.-push-notifications/handle-push-notifications).
{% endhint %}

### Delete a digital card

Delete a digital card using `MGCardLifeCycleManager.deleteCard(...)`.

Deleting a card permanently removes it from the digital wallet application.

{% code title="DeleteCard.java" %}

```java
// get the access token
String accessToken = "....";

// Get the card life cycle manager.
MGCardLifeCycleManager cardLifeCycleManager = MGClient.getCardLifeCycleManager();

// Delete a card using its digital card ID.
cardLifeCycleManager.deleteCard(
    digitalCardId,
    new MGCardLifecycleEventListener() {
        @Override
        public void onSuccess(String digitalCardId) {
            /*
             * Request accepted by the NFC Wallet SDK.
             * The NFC Wallet backend sends a push notification to complete the operation.
             *
             * If the card is already deleted server-side, the SDK removes local card data.
             */
        }

        @Override
        public void onError(String digitalCardId, MobileGatewayError error) {
            /*
             * Request failed.
             * Inspect MobileGatewayError to determine the cause.
             */
        }
    },
    null,
    null,
    accessToken );
```

{% endcode %}

{% hint style="info" %}
After the **issuer backend** or **digital wallet application** initiates a delete request, the digital card can temporarily appear as `RETIRED`state.

During this time, `DigitalizedCardManager#getAllCards()` can still return the card.

The card disappears from the list after the SDK removes it from local storage.
{% endhint %}

### Suspend a digital card

Suspend a digital card using `MGCardLifeCycleManager.suspendCard(...)`.

### Resume a digital card

Resume a digital card using `MGCardLifeCycleManager.resumeCard(...)`.


# Make payment

## Overview

Use the NFC Wallet SDK to make contactless payments on NFC-enabled POS terminals.

Supported payment networks:

* Visa
* Mastercard
* PURE (Thales white-label EMV payment network)

This guide shows how to add payment support to your digital wallet application.

Before you implement payments, complete **Tokenization** and **Manage digital cards**:

* [Tokenize a card](/nfc-wallet-sdk-android/implement-nfc-wallet/tokenize-a-card)
* [Manage digital cards](/nfc-wallet-sdk-android/implement-nfc-wallet/manage-digital-cards)

## Implementation guides

### Contactless payments (NFC)

* [Implement contactless payments](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments)

  Implement Android HCE and handle contactless payment callbacks.

### After the payment

* [Get transaction history](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/get-transaction-history)

  Retrieve transaction records and handle transaction notifications.
* [Replenish payment keys](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/replenish-payment-keys)

  Replenish payment keys when required.
* [Renew ODA certificates](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/renew-oda-certificates)

  Renew Visa ODA certificate when required (Visa only).

### Recommended reading order

1. [Implement contactless payments](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments)
2. [Replenish payment keys](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/replenish-payment-keys)
3. [Get transaction history](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/get-transaction-history)

{% hint style="info" %}

#### Other payment methods

For non-NFC payment flows (for example, QR code payment or DSRP remote payment), see [Other payment methods](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/other-payment-methods).
{% endhint %}


# Implement contactless payments

## Overview

The NFC Wallet SDK supports multiple contactless payment payment experience on Android:

* **Single-tap**: Only one tap is required to handle the transaction with point-of-sale (POS) terminal with or without end user authentication.
* **Two-tap** End users needs 2 taps with POS to handle transaction, the first tap to open the digital wallet application to required end user authentication.
* **Manual mode**: The end user opens your digital wallet application and starts a payment from the in-app UI.

Choose the experience that matches your digital wallet application UX.

### Android settings

Android settings can affect the payment experience. Check these settings before you start:

* Check that your digital wallet application is the default payment application. This is required for **single-tap** and **two-tap** payments.

  See [Default payment application](/nfc-wallet-sdk-android/help/knowledge-base/control-nfc-payments-on-android#default-payment-application).
* Check whether Android allows the foreground application to override the default payment application. This can affect **manual mode** payment experience.

  See [Pay with foreground app](/nfc-wallet-sdk-android/help/knowledge-base/control-nfc-payments-on-android#pay-with-foreground-app).

## User experience

### Single-tap

With **single-tap** experience end user brings the device close to a POS terminal only one time to perform the contacless transaction with or without a pre-authentication.

#### **With authentication**

<figure><img src="/files/mtgZwPD5UY6nobDlek0K" alt="" width="563"><figcaption></figcaption></figure>

In this experience end user needs to unlock the device using a CDCVM method (**biometric** or **keyguard**) before the tap.

{% hint style="warning" %}
The tap must be performed within a configured validity period after authentication to unlock device.

See `keyValidityPeriod` in [Configure payment behavior](/nfc-wallet-sdk-android/get-started/configuration/4.-initialize-the-nfc-wallet-sdk#configure-payment-behavior).
{% endhint %}

{% hint style="info" %}
See [Activate pre-entry](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/3.-consider-application-start#activate-pre-entry) to support this payment experience.
{% endhint %}

#### Without authentication

End users doesn't need to authenticate to perform the single-tap transaction in the following case:

* **Low value transaction (LVT)**

  Transaction below a amount and for a dedicated currency.
* **Transit transaction**

  Transaction without authentication to allow a frictionless payment experience at transit gate.

See [Configure CDCVM experiences](https://gitlab.sre.ops.gcloud.thalescloud.io/bps/gitbook/nfc-wallet-gitbook-docs/-/blob/dev-sdk/NFC-Wallet-SDK-Android/implement-nfc-wallet/make-payment/implement-contactless-payments/7.-configure-cdcvm-experiences) for more details.

### Two-tap

<figure><img src="/files/dx57ETbc0un58TNlpckn" alt=""><figcaption></figcaption></figure>

With **two-tap** experience end user brings the device close to a POS terminal, the OS launches the default digital wallet application to request end user authentication. Once authenticated the end-user could be perform the transaction by executing the 2nd tap.

{% hint style="warning" %}
The 2nd tap must be performed within a configured validity period after authentication.

See `keyValidityPeriod` in [Configure payment behavior](/nfc-wallet-sdk-android/get-started/configuration/4.-initialize-the-nfc-wallet-sdk#configure-payment-behavior).
{% endhint %}

{% hint style="info" %}
As an option end user could select the card to pay before the 2nd tap.
{% endhint %}

### Manual mode

<figure><img src="/files/dPlnhc9OTCTHNJuFHZ36" alt=""><figcaption></figcaption></figure>

In this experience, the end user starts the payment from within your digital wallet application. You implement the UI and the action that triggers the payment flow.

## Implementation guides

After you choose the contactless payment experience for your digital wallet application, implement contactless payment in this order:

1. [Implement HCE service](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/1.-implement-hce-service)\
   Implement the Android HCE service used for contactless payments.
2. [Implement contactless payment callbacks](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/2.-implement-contactless-payment-callbacks)\
   Handle NFC Wallet SDK callbacks during a contactless payment.
3. [Consider application start](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/3.-consider-application-start)\
   Ensure your digital wallet application is ready when a payment starts.
4. [Support manual mode](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/4.-support-manual-mode)\
   Add app-side support for manual mode payments.
5. [Perform CDCVM verification](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/5.-perform-cdcvm-verification)\
   Verify **CDCVM** and handle fallback when required.
6. [Display transaction context](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/6.-display-transaction-context)\
   Show transaction details to the end user.
7. [Configure CDCVM experiences](https://gitlab.sre.ops.gcloud.thalescloud.io/bps/gitbook/nfc-wallet-gitbook-docs/-/blob/dev-sdk/NFC-Wallet-SDK-Android/implement-nfc-wallet/make-payment/implement-contactless-payments/7.-configure-cdcvm-experiences)\
   Enable **single-tap** without authentication for LVT and/or transit transaction.


# 1. Implement HCE service

## Overview

NFC Wallet SDK supports Android Host Card Emulation (HCE). It allows NFC card emulation and exchange APDUs with a POS terminal over NFC.

For details, see Android documentation: [Host-based card emulation overview](https://developer.android.com/develop/connectivity/nfc/hce).

To continue, first implement an HCE service as described in this section.

After you register the service, verify it appears under **Tap and Pay** in Android settings.

## SDK integration

### Extend `AsyncHCEService`

To handle contactless payments, enable APDU processing by extending `AsyncHCEService`.

You do not need to override any methods.

Use overrides only if you want to log or customize APDU handling.

```java
public class MyHCEService extends AsyncHCEService {

    // Overriding 'processCommandApdu' is optional
    // Digital wallet application can capture APDU processing time.
    @Override
    public byte[] processCommandApdu(byte[] inputApdu, Bundle bundle) {
        // Return the SDK value (always 'null').
        // APDU processing is asynchronous.
        // The SDK automatically sends response APDU to the POS terminal.
        return super.processCommandApdu(inputApdu, bundle);
    }

    // Overriding 'onApduResponse' is optional
    // Digital wallet application can inspect or override the response APDU.
    @Override
    public boolean onApduResponse(final byte[] inputApdu, final Bundle extras, final byte[] responseApdu){
        // Digital wallet application can log responseApdu.

        // If you want to override the response and reply to the POS terminal:
        // 1. modify the responseAPDU
        // 2. sendResponseApdu(modifiedResponseApdu);
        // 3. return true; it tells the SDK the response is already sent.

        // Otherwise, return false and let the SDK send responseApdu.
        return false;
    }
}
```

{% hint style="info" %}
NFC Wallet SDK suspends APDU processing when authentication is required.

APDU processing resumes after authentication succeeds, is aborted, or the HCE service is deactivated.
{% endhint %}

{% hint style="danger" %}
Some devices block background launches of an `Activity` for the step-up authentication prompt. This can block contactless payments until you call `deactivate()`.

Your digital wallet application can implement a timeout and call `deactivate()` to unblock the contactless payment flow.
{% endhint %}

### Register the service in `AndroidManifest.xml`

Register your HCE service (the class that extends `AsyncHCEService`) as `HOST_APDU_SERVICE` in your manifest.

```xml
<!-- The service name must match your package structure. -->
<service android:name="com.mycompany.myapplication.myservices.MyHCEService"
  android:exported="true"
  android:label="@string/app_name"
  android:permission="android.permission.BIND_NFC_SERVICE">
  <intent-filter>
    <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE" />
  </intent-filter>
  <meta-data
    android:name="android.nfc.cardemulation.host_apdu_service"
    android:resource="@xml/apduservice"/>
</service>
```

{% hint style="info" %}
Create `apduservice.xml` in `res/xml` to declare the supported AIDs.
{% endhint %}

### Declare supported AIDs

Create `apduservice.xml` in `res/xml`.

Declare the PPSE AID and the payment network AIDs you support.

```xml
 <?xml version="1.0" encoding="utf-8"?>
<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
  android:description="@string/hce_service_description"
  android:requireDeviceUnlock="false"
  android:apduServiceBanner="@drawable/hce_banner">
  <aid-group
    android:description="@string/aid_description"
    android:category="payment">
    <!-- required PPSE AID -->
    <aid-filter android:name="325041592E5359532E4444463031"/>
    <!-- Mastercard AIDs -->
    <aid-filter android:name="A0000000041010"/>
    <aid-filter android:name="A0000000043060"/>
    <aid-filter android:name="A0000000042010"/>
    <!-- Visa AIDs -->
    <aid-filter android:name="A0000000031010"/>
    <aid-filter android:name="A0000000980840"/>
    <aid-filter android:name="A0000000032020"/>
    <aid-filter android:name="A0000000032010"/>
    
  </aid-group>
</host-apdu-service>
```

In the example above:

* The required PPSE AID is:
  * `325041592E5359532E4444463031`
* The Mastercard AIDs are:
  * `A0000000041010`
  * `A0000000043060`
  * `A0000000042010`
* The Visa AIDs are:
  * `A0000000031010`
  * `A0000000980840`
  * `A0000000032020`
  * `A0000000032010`

{% hint style="info" %}
The AID list depends on your NFC Wallet program. Confirm the list with your payment network representative.
{% endhint %}

### Verify Tap and Pay settings

After you register the HCE service in `AndroidManifest.xml`, it appears under **Tap and Pay** in Android settings.

To verify:

1. Open **Settings** on the device.
2. Go to **Tap and Pay**.
3. Confirm your application appears in the list.

<figure><img src="/files/uEJDvmp9fVjCEqMJAXFL" alt="" width="375"><figcaption><p>Android settings showing the application listed under Tap and Pay.</p></figcaption></figure>


# 2. Implement contactless payment callbacks

## Overview

During APDU processing, NFC Wallet SDK calls your application with payment lifecycle events.

Implement `ContactlessPaymentServiceListener` in your digital wallet application to:

* Detect when a contactless transaction starts and completes.
* Trigger step-up authentication when CDCVM is required.
* Handle errors and recover for the next transaction.

## SDK integration

### Implement `ContactlessPaymentServiceListener`

Create a listener instance and implement the callbacks you need.

```java
// Instantiate a listener for the HCE service.
PaymentServiceListener myPaymentListener = new ContactlessPaymentServiceListener() {

    @Override
    public void onTransactionStarted() {
        /*
         * Triggered when the first APDU is exchanged with the POS terminal.
         */
    }

    @Override
    public void onAuthenticationRequired(
            PaymentService activatedPaymentService,
            CHVerificationMethod chVerificationMethod,
            long cvmResetTimeout) {
        /*
         * Triggered when the end user must authenticate (CDCVM).
         *
         * Use chVerificationMethod to determine the required method.
         * cvmResetTimeout applies only to some methods (for example, wallet PIN).
         * Use it to tell the end user how long the verification stays valid.
         */
    }

    @Override
    public void onReadyToTap(PaymentService paymentService) {
        /*
         * Triggered after successful authentication.
         * Prompt the end user to tap again before cvmResetTimeout expires.
         */
    }

    @Override
    public void onTransactionCompleted(TransactionContext transactionContext) {
        /*
         * Triggered when the transaction completes successfully.
         * Use TransactionContext to display details (amount, date, and more).
         */
    }

    @Override
    public void onTransactionInterrupted() {
        /*
         * Triggered when the NFC link to the POS terminal is interrupted.
         * Prompt the end user to tap again.
         * Optional callback
         */
    }

    @Override
    public void onError(
            TransactionContext transactionContext,
            PaymentServiceErrorCode paymentServiceErrorCode,
            String message) {
        /*
         * Triggered when the transaction cannot complete successfully.
         */
    }

    @Override
    public void onFirstTapCompleted() {
        /*
         * Indicates the first-tap APDU processing completed.
         * Supported only for PFP-based transactions.
         */
    }

    @Override
    public void onNextTransactionReady(
            DeactivationStatus deactivationStatus,
            DigitalizedCardStatus digitalizedCardStatus,
            DigitalizedCard digitalizedCard) {
        /*
         * Triggered after a transaction completes.
         * Use it to verify the card state and prepare for the next payment.
         */
    }
};
```

### Return the listener from your HCE service

In your class extending `AsyncHCEService`, return the listener from `setupListener()`.

```java
public class MyHCEService extends AsyncHCEService {

    @Override
    public PaymentServiceListener setupListener() {
        return myPaymentListener;
    }
}
```

## Callback flow (typical)

Callbacks are usually triggered in this order.

`onTransactionInterrupted()` can occur any time after `onTransactionStarted()`.

1. `onTransactionStarted()` after the first APDU exchange with the POS terminal.
2. `onAuthenticationRequired()` when the end user must complete CDCVM.
3. `onReadyToTap()` after successful authentication, to request a second tap.
4. `onTransactionCompleted()` when the transaction completes successfully.
5. `onTransactionInterrupted()` (optional) when the NFC link to the POS terminal drops. See [Handle POS terminal disconnects](#handle-pos-terminal-disconnects-optional).
6. `onNextTransactionReady()` when the SDK is ready for the next transaction.

If an error occurs, the SDK triggers `onError()` instead of completing the flow.

## Handle POS terminal disconnects (optional)

The SDK can notify you when the NFC link to the POS terminal is interrupted.

Use `onTransactionInterrupted()` to prompt the end user to tap again.

Configure the retry behavior before starting contactless payments:

* `PaymentSetting.setRetryLimit(int)`

  Sets how many POS terminal disconnects are tolerated before failing the transaction.

  Default is `0`.

  With `0`, the SDK triggers `onError()` on the first disconnect.
* `PaymentSetting.setTransactionRetryTimeout(long)`

  Sets how long the POS terminal can retry after a disconnect.

  If no APDU is received during this interval, the SDK triggers `onError()`.

  Range is `500` to `10000` milliseconds.

  Default is `2000` milliseconds.


# 3. Consider application start

## Overview

When your application starts, initialize the NFC Wallet SDK.

Also set the payment experience your digital wallet application supports:

* Support **single-tap** payments.
* Or require **two-tap** payments.

Even if you enable **single-tap**, some transactions can fall back to **two-tap**. See [Single-tap can fall back to two-tap](#single-tap-can-fall-back-to-two-tap).

### Payment application in background

When the digital wallet application is the default payment application (see [Default payment app](/nfc-wallet-sdk-android/help/knowledge-base/control-nfc-payments-on-android#default-payment-application)), Android may keep it in the background. This lets it respond quickly to contactless payment APDUs from the POS terminal without recreating the `Application`.

Some devices terminate the default payment application while it is in the background. On these devices, contactless payments can trigger an application cold start. See [Optimize cold starts](#optimize-cold-starts).

## SDK integration

### Update application startup

In `Application.onCreate()`, your application must:

1. Run SDK quick configuration.
2. Set the expected payment experience:
   * `ONE_TAP_ENABLED` to support **single-tap** transactions
   * `TWO_TAP_ALWAYS` to always require authentication after the first tap (always **two-tap** payments)
3. Initialize the SDK in a separate thread.
4. Optional: after initialization succeeds, activate pre-entry. See [Activate pre-entry](#activate-pre-entry).

For steps 1 and 2, see [Initialize the NFC Wallet SDK](/nfc-wallet-sdk-android/get-started/configuration/4.-initialize-the-nfc-wallet-sdk).

{% code title="MyApp.java" expandable="true" %}

```java
public class MyApp extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        
        // Build custom config with no value change (same config since the first SDK init)
        CustomConfiguration customConfig = new CustomConfiguration.Builder()
                .domesticCurrencyCode(978)
                .keyValidityPeriod(60)
                .build();
        
        // 1 - Run quick configuration
        // ... to make sure SDK has the 'Context'
        try {
            SDKInitializer.INSTANCE.configure(this,  customConfig);
        } catch (InternalComponentException e){
            // SDK internal component exception
            // App can ignore this, 
            // and proceed with the actual SDK initialization API and perform the error handling there if Exception is raised
        } catch (Exception e) {
            // Generic exception, this is a safeguard as to prevent any event 
            // that could lead to a crash durign Application startup. 
            // App can ignore this, and proceed with the actual SDK initialization API and perform the error handling there if Exception is raised
        } catch (Throwable e) {
            // this is unlikely to happen, however because this piece of code resides in Application class,
            // in oder to minimized the impact of any error that could implact on the whole application, 
            // we recommend to catch this error. 
            // In case of this error, app shall NOT call SDKInitializer.INSTANCE.initialize()
        }
    
        // 2 - Set the payment experience.
        PaymentExperienceSettings.setPaymentExperience(this, PaymentExperience.ONE_TAP_ENABLED);
        
        // 3 - Initialize the SDK (in separate thread)
        Thread sdkInit = new Thread(new Runnable() {
            @Override
            public void run() {
                SDKInitializer.INSTANCE.initialize(this, customConfig);
            }
        });
        sdkInit.start();
        
        // 4 - Activate pre-entry (optional).
        activatePreEntry();
    }
    
    // Activate pre-entry.
    private void activatePreEntry() {
        final DeviceCVMPreEntryReceiver receiver = new DeviceCVMPreEntryReceiver();
        receiver.init();
        final IntentFilter filter = new IntentFilter(Intent.ACTION_USER_PRESENT);
        registerReceiver(receiver, filter);
    }
    
    

}
```

{% endcode %}

{% hint style="warning" %}

### Single-tap can fall back to two-tap

If you enable `ONE_TAP_ENABLED`, not every transaction is performed as **single-tap**.

Treat **single-tap** as the best-case flow. If the required conditions are not met, NFC Wallet SDK falls back to **two-tap**.

Examples:

* The end user does not tap within the configured validity period after unlocking the device. See `keyValidityPeriod` in [Initialize the NFC Wallet SDK](/nfc-wallet-sdk-android/get-started/configuration/4.-initialize-the-nfc-wallet-sdk).
* An LVT transaction without authentication reaches a configured risk threshold. In that case, NFC Wallet SDK requires authentication. See [Define risk management](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/7.-configure-cdcvm-experiences/define-risk-management).
  {% endhint %}

### Reduce cold start time

Some devices terminate the default payment application while it is in the background. On these devices, a contactless payment can trigger an application **cold start**.

APDU processing starts immediately after the **cold start**.

The cold start process includes:

* Service binding (around 100–200 milliseconds)
* Completion of `Application.onCreate()`

Minimize work in `Application.onCreate()`. Limit it to NFC Wallet SDK configuration and initialization.

Avoid other operations in the first 0.5 seconds after `Application.onCreate()` starts. Parallel work can delay APDU handling when Android sends APDU commands to the POS terminal.

If needed, delay non-payment work by at least 0.5 seconds after SDK initialization completes.

### Activate pre-entry

Use pre-entry to support **single-tap** payments.

Pre-entry lets the end user authenticate before the payment flow starts.

Authentication happens when the end user unlocks the device with biometrics or device keyguard (PIN, pattern, or password). This enables a payment without an additional verification step.

{% hint style="info" %}
Only one payment is allowed per device unlock when this mode is enabled.
{% endhint %}

```java
private void activatePreEntry() {
    DeviceCVMPreEntryReceiver receiver = new DeviceCVMPreEntryReceiver();
    receiver.init();
    IntentFilter filter = new IntentFilter(Intent.ACTION_USER_PRESENT);
    registerReceiver(receiver, filter);
}
```

{% hint style="warning" %}
Do not add additional intent filters with `DeviceCVMPreEntryReceiver`. This class is designed to act only on the `ACTION_USER_PRESENT` intent.
{% endhint %}


# 4. Support manual mode

## Overview

Complete this step if you plan to support the **manual mode** payment experience.

If you do not support manual mode, skip to [Perform CDCVM verification](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/5.-perform-cdcvm-verification).

## Sequence flow

In this payment experience:

1. The end user unlocks the device.
2. The end user opens your digital wallet application.
3. The end user selects the card to pay.
4. The application prompts the end user to authenticate.
5. The end user performs a tap within the `keyValidityPeriod`.
6. The transaction is performed with the selected payment card.
7. After the payment completes, or the `keyValidityPeriod` expires, NFC Wallet SDK reverts to the default payment card for the next payment.

## SDK integration

Call `PaymentBusinessService.startAuthentication(...)` to start a manual mode transaction.

This call activates the NFC Wallet payment service. NFC Wallet SDK handles the transaction using the standard contactless payment callback flow.

The following callbacks from `ContactlessPaymentServiceListener` will be called in this order:

1. `onTransactionStarted`
2. `onAuthenticationRequired`
3. `onReadyToTap`
4. `onTransactionCompleted`

```java
// 01 - Temporarily change the default card to the selected card, if necessary.
DigitalizedCard originalDefault = null;

// Get card selected by the end user.
DigitalizedCard selectedCard = getSelectedCard();

// If selected card is not the default card, take note of the original default card,
// then set the selected card as the default, before proceeding with payment.
if (!isDefault(selectedCard)) {
    originalDefault = getDefaultCard();  // Save the original default card.
    setDefaultCard(selectedCard);        // Set the selected card as the new default.
}

// 02 - Define the listener to handle the contactless payment flow events.
private PaymentServiceListener paymentServiceListener = new ContactlessPaymentServiceListener() {
    @Override
    public void onAuthenticationRequired(PaymentService paymentService,
                                          CHVerificationMethod cvm, long cvmResetTimer) {
        // 04 - Trigger the authentication according to the CDCVM method.
        startInputCvmActivity(cvm);
    }

    @Override
    public void onTransactionCompleted(TransactionContext ctx) {
        // 05a - After successful transaction, revert to the original default card, if necessary.
        setDefaultCard(originalDefault);
    }

    @Override
    public void onError(TransactionContext transactionContext,
                        PaymentServiceErrorCode errorCode, String msg) {
        // 05b - After failed transaction, revert to the original default card, if necessary.
        setDefaultCard(originalDefault);
    }

    @Override
    public void onTransactionStarted() {
    }

    @Override
    public void onReadyToTap(PaymentService service) {
    }
};


// 03 - Trigger authentication prior to payment.
final PaymentBusinessService paymentBusinessService = PaymentBusinessManager.getPaymentBusinessService();
paymentBusinessService.startAuthentication(paymentServiceListener, PaymentType.CONTACTLESS);

```


# 5. Perform CDCVM verification

## Overview

During a contactless transaction, NFC Wallet SDK can require the **end user** to authenticate to complete CDCVM verification.

Your **digital wallet application** must perform this authentication using the CDCVM method you configured earlier. See [Set CDCVM method](/nfc-wallet-sdk-android/implement-nfc-wallet/tokenize-a-card/set-cdcvm-method).

## SDK integration

Handle authentication in `ContactlessPaymentServiceListener.onAuthenticationRequired()`. See [Implement contactless payment callbacks](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/2.-implement-contactless-payment-callbacks).

To authenticate the end user, use the `CHVerificationMethod` provided by the SDK. Use it to obtain a `DeviceCVMVerifier` instance, then start authentication and listen for the result using `DeviceCVMVerifyListener`.

`cvmResetTimeout` tells you how long the verification stays valid. Use it to guide the end user for the second tap.

### CDCVM verification with device keyguard

When the device keyguard is used as the CDCVM method:

```java
//From a ContactlessPaymentServiceListener() implementation
//...

@Override
public void onAuthenticationRequired(
  PaymentService activatedPaymentService,
  CHVerificationMethod cvm,
  long cvmResetTimeout) {

    // check the CDCVM type
    if(cvm == CHVerificationMethod.DEVICE_KEYGUARD) {
        // Launch the Activity implemented to manage the Keyguard authentication screen
        // In this example the activity is called 'KeyguardActivity'
        Intent intent = new Intent(getApplicationContext(), KeyguardActivity.class);
        intent.putExtra(Tags.CVM, cvm);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }
}

//...
```

Implement `KeyguardActivity` in your digital wallet application. It must extend `DeviceCVMKeyguardActivity`. This enables CDCVM verification using device credentials.

The following example shows the implementation of the `KeyguardActivity` class:

{% code expandable="true" %}

```java
public class KeyguardActivity extends DeviceCVMKeyguardActivity{

     private static String TAG = KeyguardActivity.class.getName();
     private PaymentBusinessService paymentBusinessService;
     private DeviceCVMVerifier chDeviceCVMVerifier;
     private TextView message;
     private boolean keyguardVerificationStart = false;
     private CharSequence title;
     private CharSequence message1;

     @Override
     protected void onCreate(Bundle savedInstanceState) {

      Log.d(TAG, "KeyguardActivity:onCreate");
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_device_keyguard);
      Log.d(TAG, "KeyguardActivity:unlockAndWake : start");
      unlockAndWake();
      Log.d(TAG, "KeyguardActivity:unlockAndWake : end");

      title=getString(R.string.keyguard_title);
      message1=getString(R.string.keyguard_message);

      Bundle extras = getIntent().getExtras();

      // get the cvm object from the bundle passed
      CHVerificationMethod cvm = (CHVerificationMethod) extras.getSerializable(Tags.CVM);

      message = (TextView) findViewById(R.id.message);

      paymentBusinessService = PaymentBusinessManager.getPaymentBusinessService();

      PaymentService paymentService = paymentBusinessService.getActivatedPaymentService();

      // thanks to the cvm object, get an instance of the corresponding DeviceCVMVerifier object
      chDeviceCVMVerifier = (DeviceCVMVerifier) paymentService.getCHVerifier(cvm);

      // set then the corresponding listener to the DeviceCVMVerifier object
      chDeviceCVMVerifier.setDeviceCVMVerifyListener(new DeviceCVMVerifyListener() {

      @Override
      public void onVerifySuccess() {
         // Verification was OK!
         message.setText("");
         KeyguardActivity.this.finish();
     }


      @Override
      public void onVerifyError(int errorCode, CharSequence charSequence) {
          //Not expected to be called
      }

      @Override
      public void onVerifyFailed() {
        // Verification is Not OK! User shall be asked to retry
        message.setText("Unable to autheticate. Please try again.");
      }


      @Override
      public void onVerifyHelp(int i, CharSequence charSequence) {
          //Not expected to be called
      }

      });

      cbDeviceCVMVerifier.setKeyguardActivity(this);

      //Start Authentication when the screen is ON and Unlock
      if (DeviceUtil.isDeviceScreenOn(getApplicationContext())) {

             Log.d(TAG, "Starting device keyguard authentication");
             keyguardVerificationStart = true;
             DeviceCVMVerifierInput input = new  DeviceCVMVerifierInput(title,message1);
             chDeviceCVMVerifier.startAuthentication(input);
       } else {
             Log.d(TAG, "Screen is disactivate, skiping keyguard authentication");
       }

     }

}
```

{% endcode %}

### CDCVM verification with biometrics (fingerprint example)

Use this method when the device supports biometric authentication (fingerprint is shown in the example).

The following example shows how this mechanism can be implemented:

```java
//From a ContactlessPaymentServiceListener() implementation
//...

@Override
public void onAuthenticationRequired(
  PaymentService activatedPaymentService,
  CHVerificationMethod cvm,
  long cvmResetTimeout) {

    // check the CDCVM type
    if(cvm == CHVerificationMethod.FINGERPRINT) {
        // Launch the  activity that manages the Fingerprint authentication screen
        // In this case this activity is called 'BioFingerprintActivity'
        Intent intent = new Intent(getApplicationContext(),
        BioFingerprintActivity.class);
        intent.putExtra(Tags.CVM, cvm);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }
}

//...
```

Implement a dedicated `Activity` that extends `DeviceCVMKeyguardActivity`. This enables fallback to device keyguard when biometric verification fails.

{% code expandable="true" %}

```java
public class BioFingerprintActivity extends DeviceCVMKeyguardActivity {

    private static String TAG = BioFingerprintActivity.class.getName();
    private PaymentBusinessService paymentBusinessService;
    private DeviceCVMVerifier deviceCVMVerifier;
    private CancellationSignal cancellationSignal;
    private TextView message;
    private boolean isBioFPVerificationStarted = false;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_bio_fingerprint_2);
      unlockAndWake();
      Bundle extras = getIntent().getExtras();

      // get the cvm object passed through the bundle
      CHVerificationMethod cvm = (CHVerificationMethod) extras.getSerializable(Tags.CVM);

      message = (TextView) findViewById(R.id.message);
      paymentBusinessService = PaymentBusinessManager.getPaymentBusinessService();
      PaymentService paymentService = paymentBusinessService.getActivatedPaymentService();

      // thanks to the cvm object get an intance to the 'DeviceCVMVerifier'
      deviceCVMVerifier = (DeviceCVMVerifier) paymentService.getCHVerifier(cvm);

			// set the corresponding listener
      deviceCVMVerifier.setDeviceCVMVerifyListener(new DeviceCVMVerifyListener() {

            @Override
            public void onVerifySuccess() {
              // Verification is OK!
              message.setText("");
              BioFingerprintActivity.this.finish();
            }

            @Override
            public void onVerifyError(int errorCode, CharSequence charSequence) {

              Log.d(TAG, "BioFingerprintActivity:error :" + errorCode);

              // Special case when triggered in lock screen mode
              // FINGERPRINT_ERROR_CANCELED error is raised
              if (errorCode == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
                  Log.d(TAG, "restart Fp");
                  if (cancellationSignal != null)
                      cancellationSignal.cancel();

              isBioFPVerificationStarted=true;
              cancellationSignal = new CancellationSignal();
              DeviceCVMVerifierInput input = new DeviceCVMVerifierInput(cancellationSignal);
              deviceCVMVerifier.startAuthentication(input);
              }
              // usual handling of error code
              else {
                        message.setText(charSequence + ". Please try again...");
                        if(errorCode == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT) {
                            confirmCredential("Verify by Keyguard", "Too many attempts. Please verify  using your PIN / Pattern / Password");
                  }
              }
            }

            @Override
            public void onVerifyFailed() {
                message.setText("Unable to recognize the fingerprint. Please try again.");
            }


            @Override
            public void onVerifyHelp(int i, CharSequence charSequence) {
                message.setText(charSequence + ". Please try again.");
            }

        });

        deviceCVMVerifier.setKeyguardActivity(this);
        cancellationSignal = new CancellationSignal();

        //Start Authentication when the screen is ON and Unlock
        if (DeviceUtil.isDeviceScreenOn(getApplicationContext())) {
            Log.d(TAG, "Starting Fingerprint authentication");
            DeviceCVMVerifierInput input = new DeviceCVMVerifierInput(cancellationSignal);
            deviceCVMVerifier.startAuthentication(input);
        } else {
            Log.d(TAG, "Screen is de-activated, skipping Fingerprint authentication");
        }
    }

  	/* In case of fingerprint verification failure, implementing the following callback is possible
    to fallback on the Keyguard verification.
    **/
    public void onKeyguardFallback(View v) {

      Log.d(TAG, "onKeyguardFallback");
      // call deviceCVMVerifier.startAuthentication(input)


    }

  	@Override
  	public void onCancel(View v) {
      Log.d(TAG, "Cancel authentication");
      cancelTransaction("The transaction has been cancelled.");
    }

    @Override
    public void onBackPressed() {
        Log.d(TAG, "onBackPressed()");
        cancelTransaction("The transaction has been cancelled.");
    }


    /*
    After cancelling the fingerprint biometric authentication, the Payment service shall be deactivated
    **/
  	private void cancelTransaction(String message) {
          if (cancellationSignal != null) {
              cancellationSignal.cancel();
          }
          PaymentBusinessManager.getPaymentBusinessService().deactivate();
    }

}
```

{% endcode %}

If the digital wallet application goes to the background, stop listening for fingerprint authentication.

This can be accomplished using the following code snippet:

```java
@Override
public void onResume() {
       super.onResume();
       cancellationSignal=new CancellationSignal();
       deviceCVMVerifier.startAuthentication(cancellationSignal);
   }

@Override
public void onPause() {
     if(cancellationSignal != null)
             cancellationSignal.cancel();
}
```

### Support lock screen scenarios (optional)

If you need to support authentication prompts when the device is locked, verify the following:

* Activities shown during payment are declared with `showOnLockScreen=true`.
* A wake lock is acquired and window flags are set to show the UI on the lock screen.
* Release the `wakeLock` when the payment completes to reduce battery usage.

Configure the following settings in the manifest, and implement the sample code as needed:

```xml
<activity
        android:name=".BioFingerprintActivity"
        android:showOnLockScreen="true"
        android:screenOrientation="portrait" />
```

```java
@Override
public void onCreate() {
        //…
        unlockAndWake();
        //…
}

private void unlockAndWake() {

    PowerManager.WakeLock mWl;
    PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
    if (!pm.isScreenOn()) {
        mWl = pm.newWakeLock(
                PowerManager.SCREEN_BRIGHT_WAKE_LOCK | 
                PowerManager.FULL_WAKE_LOCK | 
                PowerManager.ACQUIRE_CAUSES_WAKEUP, "");
        mWl.acquire();
    }

    getWindow().addFlags(
            WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | 
            WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON   | 
            WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON   | 
            WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
}

@Override
public void onDestroy() {

  try{
      if(null!=mW1){
          mWl.release();
      }
  }
 	catch(Exception e){ }
}
```

### Delegated authentication

Delegated authentication lets your digital wallet application prompt the end user for authentication and then inform the SDK that the payment can proceed.

The authentication can use device keyguard or biometrics to unlock the underlying keystore protected by user authentication.

This flow applies when the SDK requests authentication during payment. Your digital wallet application can either:

* Prompt the end user for authentication, then call `DeviceCVMVerifier.onDelegatedAuthPerformed(timeOfAuth)`.
* Reuse a recent successful authentication (within the configured key validity period) and call `DeviceCVMVerifier.onDelegatedAuthPerformed(timeOfAuth)` immediately.

If the end user aborts the transaction, call `DeviceCVMVerifier.onDelegatedAuthCancelled()`.

```java
@Override
public void onAuthenticationRequired(final PaymentService service, CHVerificationMethod cvm, long cvmResetTimeout) {
                            
  // only applicable for Biometric or KeyGuard method
   if(cvm == CHVerificationMethod.BIOMETRICS || cvm == CHVerificationMethod.DEVICE_KEYGUARD){
      // obtain the verifier
      final DeviceCVMVerifier verifier = (DeviceCVMVerifier)service.getCHVerifier(cvm);
                                
      // MPA perform authentication, providing the time-stamp of the authentication
      ...

      // time stamp is used by SDK to compare against current time, to make sure that it is still within the Key-Validity-Duration

      // MPA could configure CVM Type as FINGERPRINT if verification method is biometrics
      verifier.setCVMType(CVMType.FINGERPRINT);

      // it is also recommended that MPA performs a check and ensure that there are enough time left for the end user to perform the 2nd tap of a transaction.
      verifier.onDelegatedAuthPerformed(timeOfAuth);
                                
      // if user does not wish to perform the authentication MPA shall cancel the transaction
      verifier.onDelegatedAuthCancelled();
  }
}
```


# 6. Display transaction context

## Overview

After each transaction, your **digital wallet application** can display transaction details.

NFC Wallet SDK provides a `TransactionContext` in these callbacks:

* `ContactlessPaymentServiceListener.onTransactionCompleted()`
* `ContactlessPaymentServiceListener.onError()`

{% hint style="warning" %}
Treat `TransactionContext` as sensitive data.

Call `TransactionContext.wipe()` after you finish using it.
{% endhint %}

## SDK integration

### Read and format transaction details

Read the values you need from the context, then format them for display.

{% code title="MyPaymentListener.java" expandable="true" %}

```java
@Override
public void onTransactionCompleted(TransactionContext ctx) {
    try {
        TransactionData data = TransactionData.from(ctx);
        // Display data in your UI.
    } finally {
        ctx.wipe();
    }
}

@Override
public void onError(
        TransactionContext ctx,
        PaymentServiceErrorCode errorCode,
        String message) {

    if (ctx == null) {
        // Handle the error when no transaction context is available.
        return;
    }

    try {
        TransactionData data = TransactionData.from(ctx);
        // Display data and error details in your UI.
    } finally {
        ctx.wipe();
    }
}

/**
 * Convenience data class for transaction display.
 */
public class TransactionData {

    private final String currencyCode;
    private final double amount;
    private final String transactionDate;
    private final String transactionType;
    private final String transactionId;

    private TransactionData(
            String currencyCode,
            double amount,
            String transactionDate,
            String transactionType,
            String transactionId) {
        this.currencyCode = currencyCode;
        this.amount = amount;
        this.transactionDate = transactionDate;
        this.transactionType = transactionType;
        this.transactionId = transactionId;
    }

    public static TransactionData from(TransactionContext ctx) {
        String currencyCode = TransactionDisplayUtils.bcdToString(ctx.getCurrencyCode());
        String transactionDate = TransactionDisplayUtils.bcdToString(ctx.getTrxDate());
        String transactionType = TransactionDisplayUtils.getTransactionType(ctx.getTrxType());

        return new TransactionData(
                currencyCode,
                ctx.getAmount(),
                transactionDate,
                transactionType,
                ctx.getTrxId());
    }

    public String getCurrencyCode() {
        return currencyCode;
    }

    public double getAmount() {
        return amount;
    }

    public String getTransactionDate() {
        return transactionDate;
    }

    public String getTransactionType() {
        return transactionType;
    }

    public String getTransactionId() {
        return transactionId;
    }
}
```

{% endcode %}

### Convert BCD values for display (utility)

The following utility converts BCD-encoded values to strings.

Adjust the formatting to match your UI and your payment network requirements.

{% code title="TransactionDisplayUtils.java" expandable="true" %}

```java
public final class TransactionDisplayUtils {

    private TransactionDisplayUtils() {
        // Utility class.
    }

    public static String bcdToString(byte[] bcd) {
        if (bcd == null) {
            return "";
        }

        StringBuilder sb = new StringBuilder();
        for (byte b : bcd) {
            sb.append(bcdToString(b));
        }
        return sb.toString();
    }

    public static String bcdToString(byte bcd) {
        int high = (bcd & 0xF0) >>> 4;
        int low = (bcd & 0x0F);
        return String.valueOf(high) + low;
    }

    public static String getTransactionType(byte trxType) {
        switch (trxType) {
            case 0:
                return "PAY";
            case 32:
                return "REFUND";
            default:
                return "TRANSACTION";
        }
    }
}
```

{% endcode %}


# 7. Configure CDCVM experiences

## Overview

This page summarizes the supported transaction types and explains when you must configure risk management to support a **single-tap** experience without authentication for:

* **low-value transaction** (**LVT**)
* **transit transaction**

You may also review CDCVM for Mastercard, Visa, and PURE dedidcated sections. Indeede event if NFC Wallet SDK provides payment-network-agnostic CDCVM behavior, payment-network-specific details still apply.

## Transaction types

### High-value transaction (HVT)

Every HVT requires end user authentication.

NFC Wallet SDK prompts the end user to authenticate before payment.

Each authentication covers one payment only.

### Low-value transaction (LVT)

LVT does not always require end user authentication.

Based on LVT accumulators, NFC Wallet SDK may require end user authentication.

See [Define risk management](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/7.-configure-cdcvm-experiences/define-risk-management) for more details.

### Transit transaction

A transit transaction occurs at a transit gate. To improve the end user experience, a transit transaction can be performed without end user authentication.

The digital wallet application can allow transit transactions without authentication.

See [Define risk management](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/7.-configure-cdcvm-experiences/define-risk-management) for more details.

## Product-specific CDCVM behavior

NFC Wallet SDK provides a transparent CDCVM behavior across payment networks.

But product-specific details still apply for each digital card product. For more details, see:

* [Mastercard CDCVM](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/7.-configure-cdcvm-experiences/mastercard-cdcvm)
* [Visa CDCVM](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/7.-configure-cdcvm-experiences/visa-cdcvm)
* [PURE CDCVM](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/7.-configure-cdcvm-experiences/pure-cdcvm)


# Mastercard CDCVM

### Overview

This page describes CDCVM behavior for a Mastercard digital card.

### Supported CDCVM variants

Mastercard supports two CDCVM variants in the `MCBPv2` digital card profile:

* `FLEXIBLE_CDCVM` supports LVT without authentication and transit payments without authentication.
* `CDCVM_ALWAYS` requires **end user** authentication for every transaction.

### Low-value transaction (LVT)

For Mastercard, the terminal determines whether a transaction is an LVT.

It uses data in the `Generate AC` APDU command, including the CVM result and terminal capabilities.

To support LVT without authentication:

* The Mastercard digital card profile must be `FLEXIBLE_CDCVM`.
* You must enable the LVT payment experience as described in [Define risk management](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/7.-configure-cdcvm-experiences/define-risk-management).

### Transit payment without authentication

For Mastercard, NFC Wallet SDK treats a transaction as a transit transaction when both conditions are true:

* The transaction amount is `0`.
* The transaction `MCC` identifies a transit merchant.

To support transit payments at a transit gate without authentication:

* The Mastercard digital card profile must be `FLEXIBLE_CDCVM`.
* You must enable transit payment without authentiction as described in [Define risk management](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/7.-configure-cdcvm-experiences/define-risk-management).

#### MCC for transit

<details>

<summary>MCC for transit</summary>

<table><thead><tr><th width="114.22222900390625">MCC</th><th>Description</th></tr></thead><tbody><tr><td>4111</td><td>Transportation - suburban and local commuter passenger, including ferries</td></tr><tr><td>4131</td><td>Bus lines</td></tr><tr><td>4784</td><td>Bridge and road fees, tolls</td></tr><tr><td>7523</td><td>Automobile parking lots and garages</td></tr></tbody></table>

</details>


# Visa CDCVM

### Overview

This page describes CDCVM behavior for a Visa digital card.

{% hint style="info" %}
See [Configure Visa CVM priority](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/7.-configure-cdcvm-experiences/visa-cdcvm/visa-cvm-priority) for details about CVM selection between the digital wallet application and the POS terminal. It also explains how to prioritize Online PIN.
{% endhint %}

### Low-value transaction (LVT)

For Visa, the terminal determines whether a transaction is an LVT.

It uses the `TTQ` (Terminal Transaction Qualifier) in the `Get Processing Options` (`GPO`) APDU command.

To support LVT without authentication:

* You must enable the LVT payment experience as described in [Define risk management](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/7.-configure-cdcvm-experiences/define-risk-management).

### Transit payment without authentication

NFC Wallet SDK treats a transaction with a Visa digital card as a transit transaction when both conditions are true:

* The transaction amount is `0`.
* The terminal indicates support for `ODA for Online Authorizations` (`TTQ` byte 1 bit 1 is set).

To support transit payments at a transit gate without authentication:

* You must enable transit payment without authentication as described in [Define risk management](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/7.-configure-cdcvm-experiences/define-risk-management).


# Visa CVM priority

Prioritize Online PIN or CDCVM for Visa contactless payments.

## Overview

Visa CVM selection is a negotiation between the **digital wallet application** and the POS terminal.

It determines the Cardholder Verification Method (CVM) used to authenticate the **end user**.

Set the CVM priority during SDK initialization in [Initialize the NFC Wallet SDK](/nfc-wallet-sdk-android/get-started/configuration/4.-initialize-the-nfc-wallet-sdk#configure-payment-behavior) using `CustomConfiguration`.

Use `CustomConfiguration.Builder.selectCvmOnlinePINPriority(...)` to prioritize:

* Online PIN

If you do not set a priority, NFC Wallet SDK uses **CDCVM priority**.

Based on the selected priority, NFC Wallet SDK chooses the best CVM supported by both:

* the card profile (CAP)
* the terminal capabilities (TTQ)

### Inputs used for CVM selection

#### CAP (card capabilities)

The supported CVMs per AID for a Visa contactless profile are defined by Card Additional Processes (CAP).

| Bit mapping  | Description                                                 |
| ------------ | ----------------------------------------------------------- |
| Byte 3 bit 8 | 1b: Online PIN is supported for domestic transactions.      |
| Byte 3 bit 7 | 1b: Online PIN is supported for international transactions. |
| Byte 3 bit 5 | 1b: Signature is supported.                                 |
| Byte 3 bit 4 | 1b: CDCVM is supported.                                     |

#### TTQ (terminal capabilities)

The POS terminal uses Terminal Transaction Qualifier (TTQ) to indicate supported capabilities.

| Bit mapping  | Description                                   |
| ------------ | --------------------------------------------- |
| Byte 1 bit 3 | 1b: Online PIN is supported.                  |
| Byte 1 bit 2 | 1b: Signature is supported.                   |
| Byte 3 bit 7 | 1b: CDCVM is supported.                       |
| Byte 2 bit 7 | 1b: CVM is required (high-value transaction). |

#### “Commonly supported” CVM

A CVM is *commonly supported* when it is supported by both the card profile (CAP) and the terminal (TTQ).

{% hint style="info" %}
Visa documentation often refers to CDCVM as **Device CVM**.
{% endhint %}

### Online PIN priority <a href="#online_pin-priority" id="online_pin-priority"></a>

1. Check whether CVM is required (`TTQ Byte 2 bit 7 == 1b`).
   * If false, proceed as a low-value transaction.
   * If true, continue with step 2.
2. Check if `ONLINE_PIN` is commonly supported.
   * If true, continue payment processing using Online PIN.
   * If false, continue with step 3.
3. Check if `Device CVM` is commonly supported.
   * If true, continue payment processing using CDCVM.
   * If false, continue with step 4.
4. Check if `SIGNATURE` is commonly supported.
   * If true, continue payment processing using signature.
   * If false, no commonly supported CVM exists. The terminal may require POS verification or reject the transaction.

### CDCVM priority <a href="#cdcvm-priority" id="cdcvm-priority"></a>

1. Check if `Device CVM` is commonly supported.
   * If true, continue with step 2.
   * If false, continue with step 3.
2. Check if CAP supports CDCVM and if CVM is required (`TTQ Byte 2 bit 7 == 1b`).
   * If true, proceed to authenticate the high-value transaction.
   * If CAP supports CDCVM but CVM is not required (`TTQ Byte 2 bit 7 == 0b`), proceed with the low-value transaction.
   * If CAP does not support CDCVM, continue payment processing using `CARD_LIKE`.
3. Check whether CVM is required (`TTQ Byte 2 bit 7 == 1b`).
   * If false, proceed as a low-value transaction.
   * If true, continue with step 4.
4. Check if `ONLINE_PIN` is commonly supported.
   * If true, continue payment processing using Online PIN.
   * If false, continue with step 5.
5. Check whether `SIGNATURE` is commonly supported.
   * If true, continue payment processing using signature.
   * If false, no commonly supported CVM exists. The terminal may require POS verification or reject the transaction.


# PURE CDCVM

### Overview

This page describes CDCVM behavior for a PURE (Thales white-label EMV payment network )digital card.

{% hint style="info" %}
See [PURE CVM priority](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/7.-configure-cdcvm-experiences/pure-cdcvm/pure-cvm-priority) for details about CVM selection between the digital wallet application and the POS terminal.
{% endhint %}

### Low-value transaction (LVT)

Using PURE, a transaction is determined LVT by the terminal together with `CIAC-CVM` value from digital card profile.

PURE profiles can be classified into `TTPI` (Terminal Transaction Processing Information) profile and non-`TTPI` profile:

* `TTPI` profile
  * supports CVM processing during `Get Processing Options` (`GPO`) APDU command and may ask for authentication after `GPO` command.
  * `TTPI` Byte 2 Bit 7 indicates if the transaction requries authentication (HVT) by terminal.
* non `TTPI` profile
  * processes CVM during `Generate Application Cryptogram` (`GenAC`) APDU command.
  * `CVM Results` in `GenAC` command indicates if the transaction requries authentication (HVT) by terminal..

To support LVT without authentication:

* You must enable the LVT payment experience as described in [Define risk management](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/7.-configure-cdcvm-experiences/define-risk-management).

{% hint style="info" %}
PURE Digital card profile is providing with some risk parameters for LVT without authentication as described in [Pure risk management](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/7.-configure-cdcvm-experiences/define-risk-management#pure-risk-management)
{% endhint %}


# PURE CVM priority

## Overview

PURE CVM selection is a negotiation between the **digital wallet application** and the terminal.

It determines the Cardholder Verification Method (CVM) used to authenticate the **end user**.

This page describes the CVM selection process based on the supported CVM options and the configured CVM priority.

## CVM selection process

A PURE profile defines the supported CVMs and the CVM priority.

It uses the `PURE application control` field, byte 1 or byte 3:

* Byte 1 defines the CVM options associated with CIAC-CVM1.
* Byte 3 defines the CVM options associated with CIAC-CVM2.

{% hint style="info" %}
NFC Wallet SDK requires the same CVM options for CIAC-CVM1 and CIAC-CVM2.
{% endhint %}

When a transaction requires CVM, the selection process chooses the first CVM supported by both the digital wallet application and the terminal.

The following parameters are used for CVM selection.

### `PURE application control` details

The `PURE application control` field is a PURE profile value.

<table><thead><tr><th width="166.22216796875">Bit mapping</th><th>Description</th></tr></thead><tbody><tr><td>Byte 1 bit 6</td><td>1b: Local CDCVM is supported.</td></tr><tr><td>Byte 1 bit 4</td><td>1b: Signature is supported.</td></tr><tr><td>Byte 1 bit 3</td><td>1b: Online PIN is supported.</td></tr><tr><td>Byte 1 bit 1</td><td><ul><li>1b: Online PIN is preferred over CDCVM.</li><li>0b: CDCVM is preferred over online PIN.</li></ul></td></tr></tbody></table>

### `TTPI` details

If the PURE profile supports `TTPI` (Terminal Transaction Processing Information), the terminal advertises its supported CVM capabilities through this field.

<table><thead><tr><th width="162.88885498046875">Bit mapping</th><th>Description</th></tr></thead><tbody><tr><td>Byte 1 bit 3</td><td><p>Terminal capability: Support of Online PIN.</p><ul><li>1 = Online PIN is supported.</li><li>0 = Online PIN is not supported.</li></ul></td></tr><tr><td>Byte 1 bit 2</td><td><p>Terminal capability: Support of Signature.</p><ul><li>1 = Signature is supported.</li><li>0 = Signature is not supported.</li></ul></td></tr><tr><td>Byte 2 bit 7</td><td><p>Terminal request related to cardholder verification.</p><ul><li>1 = CVM is required.</li><li>0 = CVM is not required.</li></ul></td></tr><tr><td>Byte 3 bit 7</td><td><p>Terminal capability: Supports Consumer Device CVM as a possible CVM method when terminal requests for the cardholder verification in byte 2 bit 7.</p><ul><li>1 = The terminal supports CDCVM as a possible CVM.</li><li>0 = Terminal does not consider CDCVM as a possible CVM.</li></ul></td></tr></tbody></table>


# Define risk management

## Overview

To support low-value transactions (LVT) without authentication and transit payments, the **digital wallet application** must define risk management settings.

These settings:

* Apply only to digital cards that support **CDCVM** and allow LVT without authentication.
* Define the thresholds used by the LVT accumulators.

### LVT accumulators

NFC Wallet SDK tracks LVT accumulators, including:

* cumulative transaction amount without authentication
* number of consecutive LVT payments without authentication

When an accumulator reaches its configured limit, NFC Wallet SDK prompts the **end user** to authenticate.

{% hint style="info" %}
After a successful authentication (during an HVT or LVT), NFC Wallet SDK resets the accumulators.
{% endhint %}

## SDK integration

### Risk management parameters

Define risk management using `CustomConfiguration` during NFC Wallet SDK initialization. See [Initialize the NFC Wallet SDK](/nfc-wallet-sdk-android/get-started/configuration/4.-initialize-the-nfc-wallet-sdk#configure-payment-behavior).

The following parameters are available:

<table data-full-width="true"><thead><tr><th width="313.800048828125">Configuration parameter</th><th>Description</th></tr></thead><tbody><tr><td><code>maxConsecutivePaymentsForLVT</code></td><td>Set the maximum number of consecutive LVT payments allowed without authentication.<br>When the limit is reached, the next LVT requires authentication.<br>Default: <code>0</code> (require authentication for every LVT).<br>Maximum: <code>50</code>.<br>Note: This counter increments regardless of transaction currency.</td></tr><tr><td><code>singleTransactionAmountLimitForLVT</code></td><td>Set the maximum amount allowed per LVT without authentication.<br>Any LVT above this limit requires authentication.<br>Default: <code>0</code> (require authentication for every LVT).<br>Applies only when the transaction currency code matches <code>domesticCurrencyCode</code>.</td></tr><tr><td><code>maxCumulativeAmountForLVT</code></td><td>Set the maximum cumulative amount of LVT payments allowed without authentication.<br>When the limit is reached, the next LVT requires authentication.<br>Default: <code>0</code> (require authentication for every LVT).<br>Applies only when the transaction currency code matches <code>domesticCurrencyCode</code>.</td></tr><tr><td><code>domesticCurrencyCode</code></td><td>Set the ISO 4217 numeric currency code used for LVT accumulators.<br>Used with:<br><code>singleTransactionAmountLimitForLVT</code><br><code>maxCumulativeAmountForLVT</code><br>Accumulators update only when the transaction currency matches this value.<br>Default: <code>978</code> (Euro).</td></tr><tr><td><code>suppportTransitWithoutCDCVM</code></td><td>Enable transit payments without CDCVM.<br>Transit transactions do not update LVT accumulators (amount or count).<br>When enabled, transit payments do not require authentication.<br>Default: <code>false</code>.</td></tr></tbody></table>

The following examples show how currency minor units affect accumulator thresholds:

```java
// South Korean Won: Currency with 0 decimal
.domesticCurrencyCode(410) //KRW
.maxCumulativeAmountForLVT(10) // 10 KRW
.maxCumulativeAmountForLVT(100) // 100 KRW
.maxCumulativeAmountForLVT(1000) // 1000 KRW
.maxCumulativeAmountForLVT(10000) // 10000 KRW

// Euro: Currency with 2 decimal
.domesticCurrencyCode(978) //EUR
.maxCumulativeAmountForLVT(1) // 0.01 EUR
.maxCumulativeAmountForLVT(10) // 0.10 EUR
.maxCumulativeAmountForLVT(100) // 1.00 EUR
.maxCumulativeAmountForLVT(1000) // 10.00 EUR
.maxCumulativeAmountForLVT(10000) // 100.00 EUR

// Jordanian dinar: Currency with 3 decimal
.domesticCurrencyCode(400) //JOD
.maxCumulativeAmountForLVT(1) // 0.001 JOD
.maxCumulativeAmountForLVT(10) // 0.010 JOD
.maxCumulativeAmountForLVT(100) // 0.100 JOD
.maxCumulativeAmountForLVT(1000) // 1.000 JOD
.maxCumulativeAmountForLVT(10000) // 10.000 JOD
```

### PURE risk management

PURE (Thales white-label EMV payment network) can also provide risk configuration in the digital card profile.

When processing a transaction, NFC Wallet SDK applies PURE risk management in addition to `CustomConfiguration`.

The following table shows how PURE risk parameters interact with the risk management parameters you set in `CustomConfiguration`.

<table data-full-width="true"><thead><tr><th width="289.4444580078125">PURE risk parameter</th><th>SDK behavior</th></tr></thead><tbody><tr><td><code>maxTransactionNoCVM</code></td><td>Compare with <code>maxConsecutivePaymentsForLVT</code> and use the most restrictive (lowest) value.</td></tr><tr><td><code>muta</code></td><td>Reject the transaction when the amount exceeds this value and the transaction currency code equals <code>crmCurrencyCode</code> (from the PURE profile).</td></tr><tr><td><code>issuerCVMLimit</code></td><td><p>If the transaction currency code equals <code>domesticCurrencyCode</code>, compare with <code>singleTransactionAmountLimitForLVT</code> and use the most restrictive (lowest) value.</p><p>Otherwise, use <code>issuerCVMLimit</code>.</p></td></tr><tr><td><code>maxTransactionAmountNoCVM</code></td><td><p>If the transaction currency code equals <code>domesticCurrencyCode</code>, compare with <code>maxCumulativeAmountForLVT</code> and use the most restrictive (lowest) value.</p><p>Otherwise, use <code>maxTransactionAmountNoCVM</code>.</p></td></tr></tbody></table>


# Other payment methods


# 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).

## 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).
* `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.


# Implement DSRP remote payment

## Overview

Use Mastercard Digital Secure Remote Payment (DSRP) to generate payment data for remote acceptance, such as e-commerce.

In this flow, your **digital wallet application** generates payment data. You pass that data to your merchant system or payment gateway for authorization.

Before you start, complete **Tokenization**. See [Tokenize a card](/nfc-wallet-sdk-android/implement-nfc-wallet/tokenize-a-card).

{% hint style="warning" %}
The NFC Wallet SDK supports DSRP remote payment for **Mastercard** digital cards with the **MCBP 2.x profile** only.

If you need DSRP remote payment for a different profile or payment network, contact your Thales delivery team.
{% endhint %}

## SDK Integration

### Check prerequisites

Confirm the digital card supports DSRP remote payment using `DigitalizedCardDetails.paymentTypeSupported()`. This API returns a list of supported payment types. Verify that `PaymentType.DSRP` is present.

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

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

### Create the DSRP payment input data

Create `PaymentInputData`. It contains the transaction parameters used to generate the DSRP remote payment payload.

Use `PaymentInputData.PaymentInputBuilder` with:

* `withRemotePaymentParameters` to provide `amount` and `currencyCode`
* `withMCRemotePaymentParameters` to provide `countryCode`, `transactionType`, `cryptogramDataType`, and `unpredictableNumber`

Use the following sample values as placeholders.

```java
long amount = 11900; // minor units. Example: 119.00
char currencyCode = 702; // SGD (ISO 4217 numeric)
char countryCode = 702; // Singapore (ISO 3166-1 numeric)
TransactionType transactionType = TransactionType.PURCHASE;
long unpredictableNumber = 12345;
PaymentInputData paymentInputData = new PaymentInputData.PaymentInputBuilder(PaymentType.DSRP)
                .withRemotePaymentParameters(amount, currencyCode)
                .withMCRemotePaymentParameters(countryCode, transactionType, CryptogramDataType.DE55, unpredictableNumber)
                .build();
```

`PaymentInputData` for DSRP payment has the following fields:

| Field                 | Type             | Format                                                 | Requirement | Description                                                                                       |
| --------------------- | ---------------- | ------------------------------------------------------ | ----------- | ------------------------------------------------------------------------------------------------- |
| `amount`              | `long`           | Numeric, minor units                                   | Required    | Set the transaction amount in minor units (no decimal separator). Example: 119.00 USD is `11900`. |
| `currencyCode`        | `char` (integer) | 3-digit ISO 4217 numeric                               | Required    | Set the transaction currency code. Example: USD is `840`.                                         |
| `countryCode`         | `char` (integer) | 3-digit ISO 3166-1 numeric                             | Required    | Set the merchant country code. Example: United States is `840`.                                   |
| `transactionType`     | Enum             | `TransactionType.PURCHASE`                             | Required    | Set the financial transaction type. For DSRP remote payments, use `TransactionType.PURCHASE`.     |
| `cryptogramDataType`  | Enum             | `CryptogramDataType.UCAF` or `CryptogramDataType.DE55` | Required    | Set the cryptogram format returned by the SDK.                                                    |
| `unpredictableNumber` | `long`           | Numeric                                                | Required    | Provide a random number generated by the merchant or payment gateway.                             |

### Generate a remote payment cryptogram

In your digital wallet application, call `PaymentBusinessService.generateApplicationCryptogram()` with `PaymentType.DSRP` to generate payment data for remote acceptance (for example, e-commerce).

You must implement a `RemotePaymentServiceListener`.

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

### Implement `RemotePaymentServiceListener`

The remote payment listener handles events during DSRP cryptogram generation.

The listener has three 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).
* `onDataReadyForPayment`

  Remote payment output data is ready. Retrieve it using `PaymentService.getRemotePaymentData()`.

  Deactivate the payment service after you retrieve the data. If you skip deactivation, the next generation can fail with `REMOTE_PAYMENT_WRONG_STATE`.
* `onError`

  The SDK encountered a failure during remote payment generation.

  Deactivate the payment service to reset the state before retrying.

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

{% code expandable="true" %}

```java
public class MyRemotePaymentPaymentServiceListener implements RemotePaymentServiceListener{
    /**********************************************************/
    /*                Payment Service listener                */
    /**********************************************************/
    @Override
    public void onAuthenticationRequired(PaymentService paymentService, CHVerificationMethod chVerificationMethod, long cvmResetTimeout) {
        toggleProgress(false);
        if (chVerificationMethod == CHVerificationMethod.BIOMETRICS
                || chVerificationMethod == CHVerificationMethod.DEVICE_KEYGUARD) {
            Intent intent = new Intent(this, DeviceCVMActivity.class);
            intent.putExtra(DeviceCVMActivity.EXTRA_CVM, chVerificationMethod);
            overridePendingTransition(0, 0);
            startActivityForResult(intent, REQ_CODE_FINGERPRINT);
        } else {
            // NOTE: Not supported any other verification
            AppLogger.e(TAG, "Verification method " + chVerificationMethod + " not currently supported!");
            deactivatePaymentService();
        }
    }

    @Override
    public void onDataReadyForPayment(PaymentService paymentService, TransactionContext transactionContext) {
        toggleProgress(false);
        RemotePaymentOutputData remotePaymentData = paymentService.getRemotePaymentData();
        Toast.makeText(this, " DSRP payment data is " +remotePaymentData.getCryptogramData(), Toast.LENGTH_LONG).show();
        deactivatePaymentService();
    }

    @Override
    public void onError(SDKError<PaymentServiceErrorCode> sdkPaymentServiceErrorCode) {
        AppLogger.e(TAG, "Failed to generate DSRP payment data with error code " + sdkPaymentServiceErrorCode.getErrorCode());
        Toast.makeText(this, "Failed to generate DSRP payment data with error code " + sdkPaymentServiceErrorCode.getErrorCode(), Toast.LENGTH_SHORT).show();
        deactivatePaymentService();
    }
}
```

{% endcode %}

Pass your listener instance when you call `generateApplicationCryptogram(...)`.

### Get DSRP payment data

Get `RemotePaymentOutputData` when `RemotePaymentServiceListener.onDataReadyForPayment()` is triggered.

`RemotePaymentOutputData` contains the following fields.

| Field                  | Description                                                                                                       |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `cryptogramData`       | Byte array containing the formatted response. This is either UCAF or TLV data for the merchant to populate DE-55. |
| `dpan`                 | DPAN with any `F` padding removed (if present).                                                                   |
| `dpanSequenceNumber`   | DPAN sequence number (PSN) of the card used.                                                                      |
| `track2EquivalentData` | Track 2 equivalent data, according to ISO/IEC 7813, excluding start sentinel, end sentinel, and LRC.              |
| `PAR`                  | Payment account reference (PAR), if provided by the payment network.                                              |
| `dPanexpirationDate`   | DPAN expiration date.                                                                                             |
| `cryptogramDataType`   | Cryptogram format returned (`UCAF` or `DE55`).                                                                    |

`track2EquivalentData` includes:

* Primary Account Number
* Field separator (hex `D`)
* Expiration date (`YYMM`)
* Service code
* Discretionary data (defined by the payment network)
* Optional padding with hex `F` to align to a whole byte

### Handle errors

When `RemotePaymentServiceListener.onError(...)` is triggered, the SDK provides a `PaymentServiceErrorCode`.

Always call `PaymentBusinessService.deactivate()` in `onError(...)` to reset the payment service state before you retry.

`PaymentBusinessService.generateApplicationCryptogram(...)` throws `IllegalArgumentException` if `paymentInputData` is `null` or if the listener is `null`.

| Payment service error code       | Description                                                                       | Recommended action                                                                                                         |
| -------------------------------- | --------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| REMOTE\_PAYMENT\_WRONG\_STATE    | The payment service is already activated when trying to perform a remote payment. | Call `PaymentBusinessService.deactivate()` after each generation. Call it when the end user cancels CDCVM.                 |
| REMOTE\_PAYMENT\_OUTPUT\_INVALID | Output data cannot be parsed and is not available.                                | Retry the transaction.                                                                                                     |
| REMOTE\_PAYMENT\_NOT\_SUPPORTED  | The default card does not support remote payment.                                 | Check `DigitalizedCardDetails.paymentTypeSupported()` before payment. Use a digital card that supports `PaymentType.DSRP`. |
| REMOTE\_PAYMENT\_INPUT\_INVALID  | The input data exists but some fields are not valid.                              | Rebuild `PaymentInputData` with valid values. Ensure all required fields are set.                                          |
| NO\_DEFAULT\_CARD                | There is no default card.                                                         | Set a default card before generating a cryptogram.                                                                         |
| CARD\_OUT\_OF\_PAYMENT\_KEYS     | No payment credentials are available.                                             | Replenish payment credentials before retrying.                                                                             |


# Get transaction history

## Overview

Transaction history lets your **digital wallet application** support:

* Transaction notifications
* Refreshing transaction history

{% hint style="warning" %}
During onboarding, confirm that transaction history is enabled in your program configuration.
{% endhint %}

## SDK integration

### Transaction notifications

To support transaction notifications, process **TNS notifications (transactions)** as described in [Handle push notifications](/nfc-wallet-sdk-android/get-started/configuration/5.-push-notifications/handle-push-notifications).

### Retrieve transaction history

`MGTransactionHistoryService.refreshHistory(...)` retrieves transaction records from the NFC Wallet backend.

If you support co-badged cards, use the overload that accepts `transactionRecordType` to retrieve primary or auxiliary records.

The transaction record contains the following information:

* Transaction ID
* Transaction date
* Transaction type
* Transaction status
* Currency code
* Amount and display amount
* Merchant name
* Merchant type
* Merchant postal code
* Terminal ID
* Merchant ID
* Primary or auxiliary card indicator (for co-badged cards)

Transaction history limits depend on the payment network:

* Time window (for example, transactions from the last 30 days).
* Maximum count (for example, the last 10 transactions).

#### Implementation

To retrieve transaction history for a digital card:

1. Get the corresponding **digital card ID**.

   See [Display digital cards](/nfc-wallet-sdk-android/implement-nfc-wallet/manage-digital-cards/display-digital-cards#tokenized-card-id-versus-digital-card-id).
2. Get an access token.

   See [Get an access token](/nfc-wallet-sdk-android/implement-nfc-wallet/manage-digital-cards/get-an-access-token).
3. (Optional) Provide the `transactionRecordType` :

   `PRIMARY` or `AUXILIARY` use in co-badged and provided on [Handle push notifications](/nfc-wallet-sdk-android/get-started/configuration/5.-push-notifications/handle-push-notifications).
4. Call `MGTransactionHistoryService.refreshHistory(...)` and implement `TransactionHistoryListener`:
   1. `onSuccess`

      Triggered when the SDK successfully retrieves transactions. The callback provides a `List<MGTransactionRecord>`.

      Each `MGTransactionRecord` represents a transaction record.
   2. `onError`

      Triggered when the SDK cannot retrieve transaction history. Use `MobileGatewayError` for error details.

The following code snippet demonstrates how to retrieve the transaction records:

{% code title="GetTransactionHistory.java" %}

```java
// Values previously initialized.
String digitalCardId = "...";
String accessToken = "...";

// Get the transaction history service.
MobileGatewayManager mgClient = MobileGatewayManager.INSTANCE;
MGTransactionHistoryService transactionHistoryService = mgClient.getTransactionHistoryService();

// Fetch the transaction history.
transactionHistoryService.refreshHistory(
        accessToken,
        digitalCardId,
        null,
        new TransactionHistoryListener() {

            @Override
            public void onSuccess(
                    List<MGTransactionRecord> records,
                    String digitalCardId,
                    String timeStamp) {
                // Success.
                // Each MGTransactionRecord holds details for one transaction.
                // See the API reference for field-level details.
            }

            @Override
            public void onError(String digitalCardId, MobileGatewayError error) {
                // Handle the error.
            }
        }
);
```

{% endcode %}


# Replenish payment keys

## Overview

Payment keys (SUK or LUK) are required to compute EMV cryptograms for contactless payments.

In a Host Card Emulation (HCE) model, payment keys are temporary. Replenish them before they run out. This prevents payment interruptions.

This guide covers when to replenish and how to trigger it.

{% hint style="info" %}
The NFC Wallet SDK supports these payment key types:

* **SUK (Single Use Key)**: Use one key per transaction. Used for Mastercard and PURE (white label EMV).
* **LUK (Limited Use Key)**: Use one key for multiple transactions. Used for Visa.
  {% endhint %}

## Prerequisites

### Configure replenishment thresholds (onboarding)

Configure replenishment thresholds during onboarding with the **Thales delivery team**.

{% hint style="info" %}
When you define thresholds, consider:

* **SUK**: Remaining SUK count that triggers replenishment.
* **LUK**: Remaining transaction count and LUK expiration time.
  {% endhint %}

## SDK integration

### Detect when replenishment is required

Use one (or both) of these signals:

* **Proactive check**: Read the digital card status.
* **Reactive push (TSP-triggered)**: Process `MG:ReplenishmentNeededNotification` from the **TSP**.

For push delivery and routing, see [Handle push notifications](/nfc-wallet-sdk-android/get-started/configuration/5.-push-notifications/handle-push-notifications).

#### Proactive check

Run this check for each digital card. Run it at app startup or after a payment.

1. Get `DigitalizedCardStatus` from `DigitalizedCard`.
2. Call `DigitalizedCardStatus.needsReplenishment()`.

See [Display digital cards](/nfc-wallet-sdk-android/implement-nfc-wallet/manage-digital-cards/display-digital-cards).

{% code title="Check whether a digital card needs replenishment" %}

```java
public static boolean needsReplenishment(final DigitalizedCard card) {
    AsyncResult<DigitalizedCardStatus> result =
            card.getCardState(null).waitToComplete();

    if (!result.isSuccessful()) {
        // TODO: handle error
        return false;
    }

    DigitalizedCardStatus status = result.getResult();
    return status != null && status.needsReplenishment();
}
```

{% endcode %}

Perform this proactive check:

* At regular application startup
  * Do not perform the check if application is stated for a payment - see warning below
* After a payment
  * On event `onNextTransactionReady` - see [implement contactless payment callbacks](/nfc-wallet-sdk-android/implement-nfc-wallet/make-payment/implement-contactless-payments/2.-implement-contactless-payment-callbacks).
* When the card is set as default.
* After connectivity returns (offline → online).

{% hint style="warning" %}
Run this check at application startup, after **NFC Wallet SDK** initialization.

Do not run this check when the end user launches the application to make a contactless payment. It can delay payment execution.
{% endhint %}

### Trigger replenishment

Call `ProvisioningBusinessService.sendRequestForReplenishment(...)` to request new payment keys.

1. Get the card identifier.

   Use the **tokenized card ID** - see [Display digital card](/nfc-wallet-sdk-android/implement-nfc-wallet/manage-digital-cards/display-digital-cards#tokenized-card-id-versus-digital-card-id).
2. Send the replenishment request.

   Call `sendRequestForReplenishment(...)` and implement `PushServiceListener`:

   * `onComplete`: The request is accepted.
   * `onError`: The SDK cannot send the request. Inspect `ProvisioningServiceError`.

   <pre class="language-java" data-title="Send a replenishment request"><code class="lang-java">public void replenish(final String tokenizedCardId, final boolean forced) {
       ProvisioningBusinessService service =
               ProvisioningServiceManager.getProvisioningBusinessService();

       service.sendRequestForReplenishment(
               tokenizedCardId,
               new ReplenishmentListener(),
               forced
       );
   }

   private static class ReplenishmentListener implements PushServiceListener {
       @Override
       public void onComplete() {
           // TODO: log success
       }

       @Override
       public void onError(final ProvisioningServiceError error) {
           // TODO: log error
       }

       @Override
       public void onUnsupportedPushContent(final Bundle bundle) {
           // Not used for this call.
       }

       @Override
       public void onServerMessage(final String tokenizedCardId,
                                   final ProvisioningServiceMessage message) {
           // Not used for this call.
       }
   }
   </code></pre>
3. Process the replenishment push.

   After you submit the request, the NFC Wallet backend sends a push notification. Your **digital wallet application** must process it. The SDK then retrieves the new payment keys.

{% hint style="info" %}
Avoid terminating the **digital wallet application** while replenishment is in progress.
{% endhint %}

{% hint style="info" %}
**TSP-triggered replenishment**

When you receive `MG:ReplenishmentNeededNotification`, trigger replenishment with `forced = true`.

See [Process MG notifications (replenishment)](/nfc-wallet-sdk-android/get-started/configuration/5.-push-notifications/handle-push-notifications#process-mg-notifications-replenishment).
{% endhint %}


# Renew ODA certificates

### Overview

Visa contactless payments can use Offline Data Authentication (ODA).

Each Visa digital card includes an ODA certificate with an expiry date. Renew the certificate before it expires to avoid payment interruptions.

{% hint style="info" %}
The NFC Wallet SDK supports ODA certificate renewal for Visa only.
{% endhint %}

### SDK integration

#### Check whether Visa ODA renewal is needed

To check whether a digital card supports Visa ODA and whether its certificate has expired, retrieve `DigitalizedCardDetails` and call:

* `DigitalizedCardDetails.isVisaODASupported()`
* `DigitalizedCardDetails.isVisaODACertificateExpired()`

Use the **tokenized card ID** as the card identifier. See [Display digital cards](/nfc-wallet-sdk-android/implement-nfc-wallet/manage-digital-cards/display-digital-cards#tokenized-card-id-versus-digital-card-id).

```java
String tokenizedCardId = "...";

DigitalizedCard card =
        DigitalizedCardManager.getDigitalizedCard(tokenizedCardId);

card.getCardDetails(new AbstractAsyncHandler<DigitalizedCardDetails>() {
    
    @Override
    public void onComplete(AsyncResult<DigitalizedCardDetails> result) {
        if (!result.isSuccessful()) {
            // Handle error.
            return;
        }

        DigitalizedCardDetails details = result.getResult();

        // Check the payment scheme.
        if (!"VISA".equalsIgnoreCase(details.getScheme())) {
            return;
        }

        // Request renewal only when needed.
        if (details.isVisaODASupported() && details.isVisaODACertificateExpired()) {
            // Request the ODA certificate renewal.
        }
    }
});
```

Perform this check:

* After **NFC Wallet SDK** initialization.
* After a payment.
* After the card is set as default.
* After connectivity returns (offline -> online).

#### Renew the ODA certificate

Call `ProvisioningBusinessService.sendRequestForODACertificateRenewal(...)` to request renewal of a Visa digital card ODA certificate.

1. Get the card identifier.

   Use the **tokenized card ID**. See [Display digital cards](/nfc-wallet-sdk-android/implement-nfc-wallet/manage-digital-cards/display-digital-cards#tokenized-card-id-versus-digital-card-id).
2. Send the ODA certificate renewal request.

   Call `sendRequestForODACertificateRenewal(...)` and implement `PushServiceListener`:

   * `onComplete`: The SDK sends the request successfully.
   * `onError`: The SDK cannot send the request. Inspect `ProvisioningServiceError`.

```java
String tokenizedCardId = "...";

ProvisioningBusinessService provisioningService =
        ProvisioningServiceManager.getProvisioningBusinessService();

provisioningService.sendRequestForODACertificateRenewal(
        tokenizedCardId,
        new PushServiceListener() {

            @Override
            public void onComplete() {
                // The request was sent successfully.
                // Expect a push notification from the NFC Wallet backend.
            }

            @Override
            public void onUnsupportedPushContent(Bundle bundle) {
                // Not used for Visa ODA certificate renewal.
            }

            @Override
            public void onServerMessage(String tokenizedCardId,
                                        ProvisioningServiceMessage message) {
                // Optional: handle status messages from the NFC Wallet backend.
            }

            @Override
            public void onError(ProvisioningServiceError error) {
                // Handle the error.
            }
        }
);
```

To improve the end user experience, trigger renewal at predictable moments:

* After the default card is set.
* After a payment completes.


# Security and privacy


# Security guidance

## Overview

Use this security guidance when building and releasing an Android **digital wallet application** that integrates the NFC Wallet SDK.

This guidance is a set of security guidelines you must apply before release.

## General security guidelines

### Use the latest NFC Wallet SDK release

Use the latest NFC Wallet SDK release. It includes the latest security updates and fixes.

### Use the Release build of the NFC Wallet SDK

Before publishing to Google Play Store configure the digital wallet application to use the `Release` build.

{% hint style="warning" %}
The `Dev` SDK variant is not allowed in Production Environment.
{% endhint %}

### Strip debug symbols

Do not release with debug symbols. This practice increases the complexity of reverse engineering efforts and prevents the easy identification of sensitive variables, structures, and logic.

### Prevent sensitive data leaks

Clear sensitive data from the UI before the application enters the background.

Encrypt or wipe data until the application returns to the foreground.

Avoid logging sensitive information.

### Use code obfuscation

Use obfuscation to increase the cost of reverse engineering.

### Secure network communication

Use HTTPS for all network calls to the digital wallet backend.

Avoid self-signed certificates.

If you implement certificate pinning, follow these guidelines:

* Match the hostname against the leaf certificate.
* Validate the full certificate chain against the system trust store.
* Reject expired certificates.
* Pin the SHA-256 hash of the root CA or leaf certificate.

If you send confidential data containing personally identifiable information (PII), add application-level encryption and authentication when needed.

### Add RASP protection

Use a commercial Runtime Application Self Protection ([RASP](https://en.wikipedia.org/wiki/Runtime_application_self-protection)) solution.

Detect and respond to:

* Root or jailbreak.
* Debugging.
* Hooking.
* App tampering.
* Emulator execution.

### Logging

Avoid writing sensitive data to device logs.

Use build flags to exclude debug logs from Production Environment builds.

On Android, logs are a shared resource that are accessible with the `READ_LOGS` permission, and inappropriate logging of user sensitive information can lead to unintended data leaks to other application.

### Adopt secure coding practices

Apply secure coding practices throughout development. For exemple you should:

* perform input validation.
* proper management of memory.
* use secure C functions.
* avoide usage of immutable containers for storing sensitive data.

For a baseline checklist, see OWASP [Secure Coding Practices](https://owasp.org/www-project-secure-coding-practices-quick-reference-guide).

These practices can be enforced using static code analysis tools such as PMD or HP Fortify.

### Perform audits and penetration testing

Perform architecture and code audits, plus penetration testing, to identify vulnerabilities and assessing the overall security posture of the application.

### Evaluate the resilience of application security

Check the OWASP MASVS (Mobile Application Security Verification Standard) on [OWASP MASVS](https://github.com/OWASP/owasp-masvs). This is the security requirements baseline for mobile application.

It is highly recommended to use the OWASP MSTG [checklist](https://github.com/OWASP/owasp-mastg/releases/latest) to evaluate the security stature of your application.

## Android developer security guidelines

Use Android security guidance for detailed, defense-in-depth recommendations before release.

Review these topics:

* [Application-level protection](#application-level-protection)
* [Data protection](#data-protection)
* [Authentication](#authentication)
* [Cryptography guidelines](#cryptography-guidelines)
* [Application hardening](#application-hardening)
* [Secure coding](#secure-coding)

{% hint style="info" %}
Use Android’s baseline security checklist as an additional reference to this guidance: [Android security checklist](https://developer.android.com/training/articles/security-tips).
{% endhint %}

### Application-level protection

#### Verify the installer of your application

Verify your digital wallet application's installer package name at runtime.

Only trust installs from Google Play, which uses `com.android.vending`.

To prevent side-channel distribution or unauthorized installations from third-party sources.

#### Enforce security updates (force application update)

Ensure a forced application update in case of security fixes.

* Block access to the service when the installed version is below the minimum allowed version.

#### Store resources in internal storage

Keep your **digital wallet application** and its resources in internal storage. This reduces the risk of a man-in-the-disk (MITD) attack. In MITD attacks, an attacker may modify or manipulate files stored on external storage.

Application should not allow itself to be moved to external storage using the `android:installLocation` manifest attribute.

#### Support SDK-supported OS versions

Run your **digital wallet application** only on OS versions supported by the NFC Wallet SDK. This reduces functional issues and security gaps on older devices. It also improves the **end user** experience.

#### Require a device lock screen

Require the device to have a screen lock. Use a PIN, pattern, or password. Block sensitive flows if no screen lock is set.

```java
KeyguardManager keyguardManager =
        (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);

boolean isDeviceSecure = keyguardManager != null && keyguardManager.isDeviceSecure();

if (!isDeviceSecure) {
    // Block the flow.
    // Prompt the end user to enable a screen lock in Android Settings.
}
```

#### Prevent excessive permissions

Declare only the Android permissions required for your **digital wallet application**.

Unneeded permissions expand the attack surface and can expose privileged data.

#### Restrict exported components

Android applications are built from components:

* Activities
* Services
* Broadcast receivers
* Content providers

Consider:

* Inter-application communication as risky.
* Every exported component as a public entry point into your **digital wallet application,** thereby increasing its exposure to risks and attacks.

We recommend to design your application

* with only a main activity made publicly accessible.
* All other components should explicitly have the attribute `export=false`.

For components to be public, consider protecting them with custom permissions.

#### Disable debugging in release builds

Ensure the `release` build of your **digital wallet application** is not debuggable.

You must:

* Set `android:debuggable="false"` on the `<application>` element in `AndroidManifest.xml`.
* And ensure your final APK is not debuggable.

To verify your final APK:

1. Run:

   ```bash
   aapt dump xmltree <myApplication.apk> AndroidManifest.xml
   ```
2. In the output, locate the `<application>` element. Confirm `android:debuggable` is set to `0x0`.

Automate this verification as part of your CI pipeline.

#### Evaluate app links and deep links

Deep links and app links can increase the attack surface of the application. They can introduce risks such as link hijacking and unintended exposure of sensitive functionality. Behavior varies by Android version:

* Before Android 12 (API level 31), if the application includes any non-verifiable links, the system may not verify all Android App Links for that application.
* Starting from Android 12 (API level 31), the application benefits from a reduced attack surface. Unless the target application is approved for the specific domain in the web intent, the web intent resolves to the end user’s default browser application.

Enumerate all deep links. Verify correct website association.

Test every operation exposed through deep links and app links.

Always validate all input data. Treat all inputs as untrustworthy. Validation ensures the application processes only the data it expects.

#### Prevent screenshots and app previews

Set `FLAG_SECURE` on any activity that displays sensitive data. This prevents sensitive data leak through screenshots in the foreground.

Add the flag in `Activity.onCreate()` before rendering the UI:

```java
@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
}
```

Also clear sensitive information in your activities in `onPause()` method.

#### Proper app signing

Sign your release APK with:

* APK Signature Scheme v1 and v2 for broad Android compatibility.
* APK Signature Scheme v3 when targeting Android 9 (API level 28) and later.

{% hint style="info" %}
Keep the APK signing key under your control. Do not share it.
{% endhint %}

Verify signatures with `apksigner` from Android SDK Build Tools:

```bash
$ apksigner verify --verbose Desktop/example.apk
Verified using v1 scheme (JAR signing): true
Verified using v2 scheme (APK Signature Scheme v2): true Verified using v3 scheme (APK Signature Scheme v3): true Number of signers: 1
```

#### Prevent backup of application data

Disable Android backup and restore for your **digital wallet application**.

Set `android:allowBackup="false"` on the `<application>` element in `AndroidManifest.xml`.

```xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application
        android:allowBackup="false">
    </application>
</manifest>
```

By default, `android:allowBackup` is `true`. This allows the OS to back up and restore application data. This can have security implications.

The backup feature can also let an end user copy application data when USB debugging is enabled.

Once exported, the data can be inspected outside the app sandbox.

#### Limit accessibility on sensitive screens

Android accessibility services can read UI content and trigger actions. This is essential for users with disabilities. It can also be abused by malware to capture sensitive data.

Decide, per screen, whether accessibility services should access sensitive content. Use the techniques below to reduce data leakage through accessibility events.

{% hint style="warning" %}
Blocking accessibility can prevent some **end users** from using your **digital wallet application**. Apply these controls only to truly sensitive screens.
{% endhint %}

**Detect enabled accessibility services**

Check whether any accessibility service is enabled. If needed, limit specific flows when services are enabled.

**Allowlist accessibility services**

Use the Android APIs to list enabled services. Maintain an allowlist or blocklist based on your risk policy. If a disallowed service is enabled, warn the **end user** or block the operation.

**Block accessibility for a view**

You can disable accessibility for a view subtree. This prevents accessibility events from the view and its children.

```java
private void disableAccessibilityEvents(View view) {
    ViewCompat.setImportantForAccessibility(
        view,
        ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
    );
}
```

**Prevent sensitive text from being exposed in accessibility events**

By default, Android may briefly show the last typed character before masking it. This can expose partial input (for example, `***1`) to accessibility services. If this is unacceptable for your threat model, mask characters immediately.

{% code expandable="true" %}

```java
private fun hideLastDigit() {
    transformationMethod = SecureTransformationMethod()
}

class SecureTransformationMethod : PasswordTransformationMethod() {
    override fun getTransformation(source: CharSequence?, view: View?): CharSequence {
        if (source == null) return SecureCharSequence("")
        return SecureCharSequence(source)
    }

    class SecureCharSequence(private val charSequence: CharSequence) : CharSequence {
        override val length: Int
            get() = charSequence.length

        override fun get(index: Int): Char {
            return 'x'
        }

        override fun subSequence(startIndex: Int, endIndex: Int): CharSequence {
            return SecureCharSequence(charSequence.subSequence(startIndex, endIndex))
        }
    }
}
```

{% endcode %}

#### Prevent overlay attacks

Android overlays let one application render UI on top of another. This can enable phishing and data theft. It is a common technique in overlay attacks.

Example phishing scenario: An attacker draws a full-screen overlay on top of your **digital wallet application**. The overlay impersonates a login or PIN screen. This increases the chance of stealing end user credentials.

Protect sensitive screens and inputs. Examples include login, PIN entry, and provisioning.

**Android 12 (API level 31) and later**

Call `setHideOverlayWindows(true)` on sensitive views. This blocks non-system overlays for those views.

**Android 2.3 (API level 9) to Android 11 (API level 30)**

Use touch filtering on sensitive views. This helps detect touches obscured by overlays.

Use one or more of these options:

* Enable `setFilterTouchesWhenObscured(true)` on sensitive views.
* Override `onFilterTouchEventForSecurity()` to reject obscured touch events.
* Check touch events in `onTouch()` and reject obscured events.

{% hint style="warning" %}
Touch filtering does not cover every overlay technique. Some overlays can avoid forwarding touch events. Treat this as defense-in-depth, not a complete solution.
{% endhint %}

For more details, see [Protecting against Android Overlay Attacks](https://www.guardsquare.com/blog/protecting-against-android-overlay-attacks-guardsquare).

#### Use a proprietary keyboard

Avoid third-party keyboards for sensitive inputs. Third-party keyboards can capture what an **end user** types.

Use a proprietary keyboard that is available only in your **digital wallet application**. Use it for PINs, passcodes, passwords, and personally identifiable information (PII).

If you cannot implement a proprietary keyboard, use a dedicated PIN pad for passcode entry. Randomize the key layout per session. This reduces shoulder surfing risk. It can also reduce the impact of some accessibility malware.

### Data protection

#### Protect data in transit

Use TLS 1.2 or TLS 1.3 for all network traffic between your **digital wallet application** and your **issuer backend**.

Configure your **issuer backend** to use strong cipher suites.

In addition:

* Implement **certificate pinning** in your **digital wallet application**.

  On Android 7.0 (API level 24) and later, use [Network security configuration](https://developer.android.com/training/articles/security-config) to pin the domains your application calls.
* Add **application-level encryption and authentication** on top of TLS to protect sensitive payloads (for example, personally identifiable information (PII)) between your **digital wallet application** and your **issuer backend**.

#### Protect stored data

Protect sensitive data stored on the device, even inside the application sandbox.

Assume a compromised device can expose local storage to malware.

It's recommended to encrypt and integrity-protect sensitive data at rest, using device-bound keys, and must require end-user authentication before access.

To encrypt all sensitive data at rest, application can use

* AndroidX Security Crypto `EncryptedSharedPreferences` for key-value data.
* AndroidX Security Crypto `EncryptedFile` for files.

For details, see Android guidance on [data storage](https://developer.android.com/topic/security/data).

### Authentication

#### Support biometric authentication

The **digital wallet application** must support biometric authentication for end-user authentication.

Provide a device credentials (keyguard) fallback when biometrics are unavailable.

Use Android Keystore with `BiometricPrompt` crypto objects when possible.

This binds keys to the device and detects biometric enrollment changes.

#### Enforce multi-factor authentication

Enforce multi-factor authentication (MFA) for sensitive operations in your **digital wallet application**.

MFA adds protection by requiring more than one authentication factor before access.

This reduces the risk of unauthorized access if one factor is compromised.

### Cryptography guidelines

#### Keep Google Play security provider up to date

Use the [Google Play services security provider](https://developer.android.com/training/articles/security-gms-provider) to receive cryptography and TLS fixes on devices that do not receive timely OS updates.

The NFC Wallet SDK does not install, update, or prompt for this provider. Your **digital wallet application** is responsible for ensuring the Google Play services security provider is installed and up to date on the **end user’s** device.

#### Use secure random

Use `java.security.SecureRandom` for all security-sensitive randomness (generate any sensitive cryptographic keys or for any random data generation).

On Android 10 (API level 29) and later, prefer `SecureRandom.getInstanceStrong()` when you require the strongest available source of randomness.

### Application hardening

#### Detect rooted devices

Detect a compromised device environment (for example, rooting frameworks and `su` binaries) before you initialize the NFC Wallet SDK and before you perform any sensitive operation.

See OWASP MSTG guidance on [Android Anti-Reversing Defenses](https://github.com/OWASP/mastg/blob/master/Document/0x05j-Testing-Resiliency-Against-Reverse-Engineering.md).

#### Detect hooking attempts

Hooking injects code into your **digital wallet application** at runtime. Attackers use it to intercept sensitive data (for example, cryptographic keys or PII), bypass security controls, or change application logic.

See OWASP MASVS: [Android Anti-Reversing Defenses](https://mas.owasp.org/MASTG/0x05j-Testing-Resiliency-Against-Reverse-Engineering/) / *Runtime Integrity Verification***.**

#### Detect debugger attachment

On compromised devices, an attacker can attach a debugger to a `Release` build of your **digital wallet application**. This enables step-by-step inspection of Java/Kotlin code and native libraries, and can expose sensitive logic and data.

Detect debugger attachment in both Java/Kotlin and native code, especially before you run sensitive flows. For more information.

See OWASP MASVS: [Android Anti-Reversing Defenses](https://mas.owasp.org/MASTG/0x05j-Testing-Resiliency-Against-Reverse-Engineering/) / *Anti-Debugging*.

#### Detect emulator

Emulators are a non-trusted execution environment. They make dynamic analysis and instrumentation easier for attackers.

Detect emulator execution as early as possible. Do it at application startup, and before you initialize the NFC Wallet SDK.

See OWASP MASVS: [Android Anti-Reversing Defenses](https://mas.owasp.org/MASTG/0x05j-Testing-Resiliency-Against-Reverse-Engineering/) / *Emulator Detection.*

#### Detect application tampering

Detect tampering by verifying the **digital wallet application** signing certificate hash at runtime.

This check helps detect repackaging attacks where an attacker modifies the binary or resources, then re-signs the APK. Attackers cannot reproduce your signing certificate.

Obfuscate the expected certificate hash to make it harder to locate and patch.

For background, see [Implement Anti-tamper Techniques](https://github.com/nowsecure/secure-mobile-development/blob/master/en/coding-practices/anti-tamper-techniques.md).

Optionally, send the signing certificate hash to your **backend**. Verify it server-side before honoring requests from the **digital wallet application**.

#### Obfuscate application

Obfuscate your **digital wallet application** and its components. This increases the cost of reverse engineering. It also makes it harder to locate sensitive logic and data.

Even if the NFC Wallet SDK is already obfuscated with DexGuard, you must obfuscate the Thales NFC Wallet SDK public APIs:

* Ensure the ProGuard/R8 rules provided with the SDK packages are applied.

  See [NFC Wallet SDK obfuscation](/nfc-wallet-sdk-android/security-and-privacy/nfc-wallet-sdk-obfuscation)
* Pay special attention to the package flattening rule:

  ```bash
  -flattenpackagehierarchy util
  ```

Use the package name `util` to keep obfuscation output consistent with the SDK rules.

Commercial obfuscation tools are available. On Android, we recommend *DexGuard*.

See OWASP MASVS: [Android Anti-Reversing Defenses](https://mas.owasp.org/MASTG/0x05j-Testing-Resiliency-Against-Reverse-Engineering/) / *Obfuscation*.

### Secure coding

#### **Wipe sensitive data from memory**

Store sensitive data (for example, cryptographic keys and personally identifiable information (PII)) in byte arrays.

In Java, you cannot reliably wipe immutable objects such as `String` and `StringBuilder`. You also cannot control how many copies are created in memory or how long they remain reachable.

Wipe sensitive data explicitly. Do not rely on the garbage collector.

Use a `finally` block to wipe sensitive buffers, even when you do not have a `catch` block. This reduces the risk of leaks if an exception occurs.

{% code expandable="true" %}

```java
byte[] password = this.getUserPassword();
try {
  // Use the password to login
  this.logUserIn(password);
} finally {
  	// Even if there is no exception catch here, there can be a
  	//RuntimeException that should still trigger this finally block
  	// to execute
  MemoryHelper.clearData(password);
}

//One way to implement a byte array wiping method is to rewrite every element in the arrays in the MemoryHelper
class public static void clearData(byte[] baBuffer) {
  if (baBuffer == null)
    return;
  for(i = 0;  i < baBuffer.length; i++) {
    baBuffer[i] = (byte)0;
  }
}

```

{% endcode %}

#### Follow secure coding standards

Follow secure coding standards from trusted sources such as Apple, Google, and OWASP (Open Web Application Security Project).

If you need Thales internal guidance, contact the Thales Handset Security Community to request access.

Enforce these standards with static code analysis tools such as PMD or Fortify. Add them to your CI pipeline to prevent regressions.

#### Run Android lint checks

Run Android Lint during development and before each release. Fix findings early to reduce security and quality risk.

Android Lint is a static analysis tool. It checks your project for correctness, security, performance, usability, accessibility, and internationalization issues.

Run lint locally and in your CI pipeline:

```bash
./gradlew lint
```

For details, see Android developer website: [Improve your code with lint checks](https://developer.android.com/studio/write/lint).

## Protect assets

This section outlines best practices in app development to protect assets.

### **Activation code**

Use in card tokenization with a limited time life cycle:

* Treat as a short-lived secret. Do not log or store

### FCM registration token

If the digital wallet application manages FCM at the app level:

* Avoid persisting the FCM registration token longer than necessary.

### **Funding card information**

If the digital wallet application collects payment card data:

* Disable risky `EditField` options, such as auto-complete, copy, paste, and so on.
* Use a secure keypad.
* Validate inputs before use.
* Do not store payment card data persistently.
* Before showing the input screen, enforce runtime checks (rooting, hooking, debugging, and tampering detection).
* Ensure confidentiality and integrity of this asset.

Apply the same controls to any other sensitive input sourced outside the app.

### App signing certificate and TLS certificate

* Control access to the app signing certificate.
* Do not disclose it to non-trusted parties.
* Ensure confidentiality and integrity of this asset.

### **QR / DSRP inputs data (Amount)**

When the digital wallet application collects the amount:

* Disable risky `EditField` options, such as auto-complete, copy, paste, and so on.
* Use a secure keypad.

Apply the same controls to any other sensitive input sourced outside the app.

### QR Code (2D barcode)

The app must be implemented to detect and to prevent the capturing of QR code in screenshots or from being viewed on non-secure displays.

### Other sensitive assets

* Obfuscate code and protect sensitive strings shipped in the binary.
* Reassess assets on every release (new features could add new sensitive data).
  * Assess the value and criticality of each asset and apply the required protection.
* Do not persist transient data. Clear sensitive data from memory when no longer needed.
* Always consider the device untrusted. Use RASP to help protect the application binary and third-party libraries at runtime.


# Security countermeasures

The NFC Wallet SDK includes countermeasures for common mobile threats.

This page lists the runtime security countermeasures built into the NFC Wallet SDK.

## Coverage by flow <a href="#security-countermeasures" id="security-countermeasures"></a>

### SDK initialization and provisioning

Provisioning includes wallet secure enrollment and Tokenization.

During SDK initialization and provisioning, the NFC Wallet SDK protects against:

* **Debugger attached**
* **Man-in-the-middle (MITM) attack**
* **Digital wallet application data backup**
* **Rooted mobile device**
* **SDK Bind**
* **Use of emulator**
* **Non-designated application signing certificate**

### Payment

During payment, the NFC Wallet SDK protects against:

* **Debugger attached**
* **Digital wallet application data backup**
* **SDK Bind**
* **Non-designated application signing certificate**

## Countermeasures

Countermeasures applied for each threat are listed below.

<details>

<summary><strong>Debugger attached</strong></summary>

* **Threat**: An attacker attempts to reverse engineer the digital wallet application by attaching a debugger at runtime.
* **Applies to**: SDK initialization, provisioning, payment
* **Build type**: `release`
* **SDK behavior**: Return an error when a debugger is detected during the flow.

</details>

<details>

<summary><strong>Man-in-the-middle (MITM) attack</strong></summary>

* **Threat**: An attacker attempts to intercept or modify the communication channel between the digital wallet application and the NFC Wallet backend.
* **Applies to**: SDK initialization, provisioning
* **Build type**: `release`
* **SDK behavior**: When using the `release` build with a misconfigured TLS (SSL) certificate, the following errors may occur:
  * HttpStatusCode: -2
  * ErrorMessage: Unable to communicate with gateway.
  * SdkErrorCode: COMMON\_COMM\_ERROR

</details>

<details>

<summary><strong>Digital wallet application data backup</strong></summary>

* **Threat**: Data stored in the **digital wallet application** is backed up and restored to a different device.
* **Applies to**: SDK initialization, provisioning, payment
* **Build type**: `release`, `dev`
* **SDK behavior**: Wipe local digital wallet application data.

</details>

<details>

<summary><strong>Rooted mobile device</strong></summary>

* **Threat**: Running the digital wallet application on an Android rooted device.
* **Applies to**: SDK initialization, provisioning
* **Build type**: `release`, `dev`
* **SDK behavior**: Return an error during SDK initialization and provisioning when the device is detected as rooted. After enrollment, a change in device root state triggers the server to prompt the end user to re-enroll on the next SDK call to the server (via the `ProvisioningServiceListener.onError()` callback).

</details>

<details>

<summary><strong>SDK Bind</strong></summary>

* **Threat**: The SDK bundle (`.aar`) contains two main artifacts (`.jar` and `.so`). These artifacts are bound and must be used together. Always use the same build type for both artifacts.
* **Applies to**: SDK initialization, provisioning, payment
* **Build type**: `release`, `dev`
* **SDK behavior**: Return an error when the `.jar` and `.so` artifacts do not match.

</details>

<details>

<summary><strong>Use of emulator</strong></summary>

* **Threat**: Using an emulator to make NFC transactions.
* **Applies to**: SDK initialization, provisioning
* **Build type**: `release`, `dev`
* **SDK behavior**: The SDK cannot be initialized in an emulator. An error will be returned when an emulator is detected.

</details>

<details>

<summary><strong>Non-designated application signing certificate</strong></summary>

* **Threat**: The digital wallet application must be signed with a designated certificate. The SDK uses the signing certificate hash to verify application authenticity. See [Fetching application binding key](/nfc-wallet-sdk-android/get-started/configuration/2.-onboarding) for more information.
* **Applies to**: SDK initialization, provisioning, payment
* **Build type**: `release`, `dev`
* **SDK behavior**: Return an error when the application signing certificate does not match the designated certificate.

</details>


# NFC Wallet SDK obfuscation

## Overview

NFC Wallet SDK is obfuscated with DexGuard.

In this section we are presenting the recommended minimum R8/ProGuard rules for properly obfuscating TSH SDK packages and classes. Theses rules do not affect the application packages.

Please refer to [Enable the R8 app optimizer](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization).

## R8/ProGuard rules

{% hint style="info" %}
The below consumer rules are bundled with the distributed .aar libraries and are applied automatically when code obfuscation is enabled in your app.
{% endhint %}

```bash
#NFC Wallet SDK
-dontwarn util.**
-dontwarn com.gemalto.mfs.mwsdk.**
-dontnote com.gemalto.mfs.mwsdk.utils.async.AbstractAsyncHandler
-keep class util.h.xz.** { *; }
-keepclasseswithmembernames class * {
native <methods>;
}
# Global JNA Rules
-keep,allowobfuscation interface com.sun.jna.Library
-keep,allowobfuscation interface com.sun.jna.Callback
-keep,allowobfuscation interface com.sun.jna.Function
-keep,allowobfuscation interface * implements com.sun.jna.Library
-keep,allowobfuscation interface * implements com.sun.jna.Callback
-keepclassmembers interface * implements com.sun.jna.Library {
<methods>;
}
-keepclassmembers interface * implements com.sun.jna.Callback {
<methods>;
}
-keep class com.sun.jna.CallbackReference {
void dispose();
com.sun.jna.Callback getCallback(java.lang.Class,com.sun.jna.Pointer,boolean);
com.sun.jna.Pointer getFunctionPointer(com.sun.jna.Callback,boolean);
com.sun.jna.Pointer getNativeString(java.lang.Object,boolean);
java.lang.ThreadGroup initializeThread(com.sun.jna.Callback,com.sun.jna.CallbackReference$AttachOptions);
}
-keep,includedescriptorclasses class com.sun.jna.Native {
com.sun.jna.Callback$UncaughtExceptionHandler callbackExceptionHandler;
void dispose();
java.lang.Object fromNative(com.sun.jna.FromNativeConverter,java.lang.Object,java.lang.reflect.Method);
com.sun.jna.NativeMapped fromNative(java.lang.Class,java.lang.Object);
com.sun.jna.NativeMapped fromNative(java.lang.reflect.Method,java.lang.Object);
java.lang.Class nativeType(java.lang.Class);
java.lang.Object toNative(com.sun.jna.ToNativeConverter,java.lang.Object);
int getNativeSize(java.lang.Class);
}
-keep class com.sun.jna.FromNativeConverter {
public java.lang.Class nativeType();
public java.lang.Object fromNative(java.lang.Object, com.sun.jna.FromNativeContext);
}
-keep class com.sun.jna.Native$ffi_callback {
void invoke(long,long,long);
}
-keep class com.sun.jna.Structure {
long typeInfo;
com.sun.jna.Pointer memory;
<init>(int);
void autoRead();
void autoWrite();
com.sun.jna.Pointer getTypeInfo();
com.sun.jna.Structure newInstance(java.lang.Class,long);
}
-keep class com.sun.jna.Structure$FFIType$FFITypes {
<fields>;
}
-keep class com.sun.jna.Structure$ByValue {
}
-keep class com.sun.jna.CallbackReference$AttachOptions {
<fields>;
}
-keep class com.sun.jna.Callback$UncaughtExceptionHandler {
void uncaughtException(com.sun.jna.Callback,java.lang.Throwable);
}
-keep class com.sun.jna.ToNativeConverter {
java.lang.Class nativeType();
}
-keep class com.sun.jna.NativeMapped {
java.lang.Object toNative();
}
-keep class com.sun.jna.IntegerType {
long value;
}
-keep class com.sun.jna.PointerType {
com.sun.jna.Pointer pointer;
}
-keep class com.sun.jna.LastErrorException {
<init>(int);
<init>(java.lang.String);
}
-keep class com.sun.jna.Pointer {
long peer;
<init>(long);
}
-keep class com.sun.jna.WString {
<init>(java.lang.String);
}
-keep class com.sun.jna.JNIEnv { *; }
Note

```


# RASP compatibility notes

## Overview

NFC Wallet SDK includes a RASP (runtime application self-protection) component.

Some third-party security libraries can conflict with it. These conflicts can cause SDK errors, crashes, or payment flow hangs.

## Known incompatibilities

### Child process tracing the parent process

If a module or library spawns a child process, and that child process traces the parent process, NFC Wallet SDK can detect a conflict and return `DEVICE_SUSPICIOUS`.

Known examples:

* OneSpan
* DexGuard (DebugBlocker)
* AppDome
* Promon

### SIGTRAP handler overrides

If a module or library registers or overrides the SIGTRAP handler after NFC Wallet SDK initialization, your **digital wallet application** can crash or hang during payment flows.

## Recommendations

1. Avoid combining NFC Wallet SDK with third-party RASP providers when possible.
2. If you must use a library that registers SIGTRAP handlers, initialize it **before** initializing NFC Wallet SDK.


# Additional features

Use these optional features to extend your NFC Wallet SDK integration.

### Summary

* [Reset the NFC Wallet SDK](/nfc-wallet-sdk-android/additional-features/reset-the-nfc-wallet-sdk)

  Delete all NFC Wallet SDK data stored on the device. Reset is local only.
* [Add wallet transaction data](/nfc-wallet-sdk-android/additional-features/add-wallet-transaction-data)

  Attach 14-byte wallet transaction data to a Mastercard contactless payment.
* [Handle Visa multiple AIDs](/nfc-wallet-sdk-android/additional-features/handle-visa-multiple-aids)

  Read available AIDs and update their priority and lock status for Visa cards.
* [Collect logs with LogService](/nfc-wallet-sdk-android/additional-features/collect-logs-with-secure-logger)

  Collect NFC Wallet SDK logs in the application sandbox for troubleshooting.
* [Correlation ID](/nfc-wallet-sdk-android/additional-features/use-correlationid)

  Understand how correlation IDs are used in digitization flows.


# Reset the NFC Wallet SDK

## Overview

Resetting the NFC Wallet SDK deletes all data stored by the SDK on the device.

This includes items managed by the SDK, such as digital cards and payment credentials.

{% hint style="warning" %}
Reset is local only. It does not call any server APIs. Any tokens that already exist on the server side are not deleted.

After you reinitialize the SDK, the wallet ID changes. Tokens created before the reset can become orphan tokens on the server side. They may be deleted when you run Tokenization for a new card (in process called **tokens cleanup**).
{% endhint %}

After a reset, the SDK assigns a new wallet ID at the next initialization. See [Retrieve the wallet ID](/nfc-wallet-sdk-android/get-started/configuration/4.-initialize-the-nfc-wallet-sdk#retrieving-the-wallet-id).

{% hint style="info" %}
After you reset the NFC Wallet SDK, run [Enroll wallet](/nfc-wallet-sdk-android/implement-nfc-wallet/enroll-wallet) before any new Tokenization.
{% endhint %}

## SDK integration

Call `SDKDataController.INSTANCE.wipeAll(appCcontext)` to delete all data stored by the NFC Wallet SDK.

```java
SDKDataController.INSTANCE.wipeAll(appContext);
```


# Add wallet transaction data

Attach wallet transaction data to Mastercard and PURE contactless payments.

## Overview

You can attach wallet transaction data to a contactless payment. The processing host can use this data during authorization processing.

Wallet transaction data is defined for each digital card. You can provide it in two ways:

* **Persistent:** The SDK stores the data in secure storage. It remains available after the digital wallet application restarts.
* **Ephemeral:** The digital wallet application provides the data for one transaction only.

The digital wallet application decides whether to include this data in each payment.

This feature is supported for Mastercard (MCBP 2.3) and PURE contactless payment profiles.

Before a transaction, the wallet transaction data mode must be set to specify whether to use stored persistent data or ephemeral custom data.

The wallet transaction data mode resets after each transaction and must be re-established if the card changes during a transaction.

{% hint style="warning" %}
The following APIs are deprecated as of `6.14.0`:

* `DigitalizedCard.setWalletTransactionData(WalletTransactionData walletTransactionData)`
* `DigitalizedCard.getWalletTransactionData()`
* `PaymentBusinessService.setWalletTransactionData(WalletTransactionData walletTransactionData)`

Use the APIs introduced in `6.14.0` for new integrations.
{% endhint %}

### Supported profiles

#### Mastercard (MCBP 2.3)

NFC Wallet SDK supports Mastercard specification **MCBP 2.3**.

If wallet transaction data is available before a contactless transaction, the SDK updates the `IAD` (EMV tag `9F10`, Issuer Application Data):

* Start offset: byte 19
* Max IAD length: 32 bytes
* Maximum wallet transaction data length: 14 bytes

In MCBP 2.3, this feature is called **wallet proprietary information**.

#### PURE contactless

If wallet transaction data is available before a contactless transaction, the SDK updates the `IAD` (EMV tag `9F10`, Issuer Application Data):

* Start offset: byte 18
* Max IAD length: 32 bytes
* Maximum wallet transaction data length: 15 bytes

## SDK integration

### Set wallet transaction data mode

Set the wallet transaction data mode before the transaction starts.

Use `PaymentBusinessService.setWalletTransactionDataMode(WalletTransactionDataMode)` to select how the SDK supplies wallet transaction data for the next payment.

Available modes:

* **Storage mode:** Use the default wallet transaction data stored for the digital card.
* **Ephemeral mode:** Set a wallet transaction data for the next transaction only. This data will not be stored.

{% hint style="warning" %}
Wallet transaction data mode is reset:

* on card change during a transaction. See [Handle a card change during a transaction](#handle-a-card-change-during-a-transaction).
* after the transaction, regardless of status (success, failure, or cancellation)
  {% endhint %}

#### Use storage mode

In the code snipet below the digital wallet application notifies the NFC Wallet SDK to use the persistent wallet transaction data for the next transaction.

{% code lineNumbers="true" %}

```java
// Set default wallet transaction data for a payment transaction.
PaymentBusinessManager.getPaymentBusinessService().
setWalletTransactionDataMode(WalletTransactionDataMode.storage());
```

{% endcode %}

{% hint style="info" %}
See [Manage persistent wallet transaction data](#manage-persistent-wallet-transaction-data) for details on setting persistent wallet transaction data for each digital card.
{% endhint %}

#### Use ephemeral mode

In the code snipet below the digital wallet application is providing to the NFC Wallet SDK the ephemeral wallet transaction data for the next transaction.

For Mastercard, the payload can contain up to 14 bytes. For PURE, it can contain up to 15 bytes.

{% code overflow="wrap" lineNumbers="true" %}

```java
// Set custom wallet transaction data for a payment transaction.
byte[] walletTransactionData = new byte[]{(byte) 0x0a, (byte) 0x0c, (byte) 0x0f, (byte) 0x0d, (byte) 0xae, (byte) 0xdd, (byte) 0xee, (byte) 0xaa};

PaymentBusinessManager.getPaymentBusinessService().
setWalletTransactionDataMode(WalletTransactionDataMode.ephemeral(walletTransactionData));
```

{% endcode %}

{% hint style="info" %}
NFC Wallet SDK pads PURE wallet transaction data with `00` bytes when needed to reach 15 bytes.\
NFC Wallet SDK does not pad Mastercard wallet transaction data.
{% endhint %}

### Manage persistent wallet transaction data

Stored wallet transaction data is associated with a digital card. The SDK uses this value if you select the **storage mode**.

#### Set persistent wallet transaction data

Use `DigitalizedCard.setWalletTransactionData(byte[] walletTransactionData)` to set persistent wallet transaction data.

* Pass up to 14-byte `byte[]` for Mastercard 2.3.
* Pass up to 15-byte `byte[]` for PURE.

{% code lineNumbers="true" expandable="true" %}

```java
String tokenId = "tokenId";
DigitalizedCard digitalizedCard = DigitalizedCardManager.getDigitalizedCard(tokenId);

// Wallet transaction data to set (14 bytes as per Mastercard)
byte[] walletTransactionDataToSet = new byte[]{
    (byte) 0xaa, (byte) 0xba, (byte) 0xca, (byte) 0xda,
    (byte) 0xea, (byte) 0xfa, (byte) 0xff, (byte) 0xaa,
    (byte) 0xba, (byte) 0xca, (byte) 0xda, (byte) 0xea,
    (byte) 0xfa, (byte) 0xff
};

try {
    // Set the wallet transaction data on the card
    digitalizedCard.setWalletTransactionData(walletTransactionDataToSet);
    
    // ... App logic here .

} catch (InternalComponentException e) {
    // Handle issues such as unsupported scheme, initialization error, or data length problem
}
```

{% endcode %}

{% hint style="info" %}
NFC Wallet SDK pads PURE wallet transaction data with `00` bytes when needed to reach 15 bytes.\
NFC Wallet SDK does not pad Mastercard wallet transaction data.
{% endhint %}

#### Clear persistent wallet transaction data

Use `DigitalizedCard.setWalletTransactionData(byte[] walletTransactionData)` and pass `null` to clear the stored value for the digital card

{% code lineNumbers="true" expandable="true" %}

```java
String tokenId = "tokenId";
DigitalizedCard digitalizedCard = DigitalizedCardManager.getDigitalizedCard(tokenId);

try {
    // Clear the persistent wallet transaction data
    digitalizedCard.setWalletTransactionData(null);

} catch (InternalComponentException e) {
    // Handle issues such as unsupported scheme, initialization error, or data length problem
}
```

{% endcode %}

#### Retrieve persistent wallet transaction data

Use `DigitalizedCard.retrieveWalletTransactionData()` to retrieve the wallet transaction data associated with the digital card.

{% code lineNumbers="true" expandable="true" %}

```java
String tokenId = "tokenId";
DigitalizedCard digitalizedCard = DigitalizedCardManager.getDigitalizedCard(tokenId);

try {
    // Retrieve the wallet transaction data from the card
    byte[] retrievedWalletTransactionData = digitalizedCard.retrieveWalletTransactionData();
    if (retrievedWalletTransactionData != null) {
        // Process the retrieved data here
    } else {
        // No wallet transaction data found 
    }

} catch (InternalComponentException e) {
    // Handle issues such as unsupported scheme, initialization error, or data length problem
}
```

{% endcode %}

### Handle a card change during a transaction

If the card changes during the transaction, the **digital wallet application** must set the wallet transaction data mode again after a successful card activation callback.

{% code lineNumbers="true" %}

```java
final PaymentBusinessService paymentBusinessService = PaymentBusinessManager.getPaymentBusinessService();
CardActivationListener activationListener = new CardActivationListener() {
  @Override
  public void onCardActivated(PaymentServiceErrorCode code) {
    if (code == PaymentServiceErrorCode.SUCCESS) {
      try {
        PaymentBusinessManager.getPaymentBusinessService()
            .setWalletTransactionDataMode(WalletTransactionDataMode.storage());
      } catch (InternalComponentException e) {
        // Handle exceptions.
      }
    }
  }
};

// Start a payment with a different card.
paymentBusinessService.activateNonDefaultCard(
    cardBTokenId,
    PaymentType.CONTACTLESS,
    keepAsDefault,
    paymentServiceListener,
    activationListener
);
```

{% endcode %}


# Customize PPSE

## Overview

As defined in EMV Book B, the PPSE (Proximity Payment System Environment) is the entry point for contactless payments. Each digital card has its own PPSE, defined in the token profile. It contains the list of supported application identifiers (AIDs), with the corresponding application labels and priorities.

NFC Wallet SDK provides **PPSE Management API.** It allows your digital wallet application to:

* Get the **PPSE** (default PPSE defined in the digital card profile).
* Get the **auxiliary PPSE** (PPSE define in the auxiliary digital card profile for co-badged cards).
* Customize a new PPSE (**custom PPSE**).
* Get or reset the **custom PPSE**.

NFC Wallet SDK uses the **custom PPSE** when it is defined for a contactless transaction.

{% hint style="info" %}
Use **PPSE Management API** to apply your policy in a co-badged digital wallet program.

**NFC Wallet SDK** uses only the **PPSE** or the **custom PPSE**. It does not use the **auxiliary PPSE**.
{% endhint %}

## SDK integration

The **PPSE Management API** includes the `PpseFciTemplate` class and these `DigitalizedCard` operations:

* `DigitalizedCard.getPpse()`: Gets the default PPSE defined in the token profile.
* `DigitalizedCard.getAuxiliaryPpse()`: Gets the PPSE defined in the auxiliary digital card profile (co-badged cards).
* `DigitalizedCard.getCustomPpse()`: Gets the custom PPSE. Returns `null` if it is not defined.
* `DigitalizedCard.setCustomPpse()`: Sets a custom PPSE. Pass `null` to clear it.

{% hint style="warning" %}
The SDK automatically validates the PPSE template when you call `DigitalCard.setCustomPPSE`.

See [Validation rules](#validation-rules).
{% endhint %}

### Building custom PPSE

Build a custom PPSE with `PpseFciTemplate` in one of these ways:

* Use an existing PPSE template.
* Use raw PPSE bytes.
* Build it from scratch.

#### Method 1: Build PPSE from an existing template

Use this approach when you want to start with the digital card PPSE and make targeted modifications.

**When to use:**

* You want to customize specific fields in the existing PPSE, such as priority or tags.
* You want to preserve the default PPSE structure while making selective changes.
* You need a base template for customization.

{% code title="Set a custom PPSE template" %}

```kotlin
try {
    // Fetch the primary PPSE template.
    val ppse = card.getPpse()

    // Extract the directory entries.
    val directoryEntryList =
        ppse.proprietaryTemplate.issuerDiscretionaryData.directoryEntryList
    val targetAid = byteArrayOf(
        0xA0.toByte(),
        0x00.toByte(),
        0x00.toByte(),
        0x00.toByte(),
        0x03.toByte(),
        0x10.toByte(),
        0x10.toByte()
    )

    directoryEntryList.forEach { entry ->
        if (entry.applicationIdentifier.contentEquals(targetAid)) {
            entry.priority = byteArrayOf(0x02.toByte())
        }
    }

    // Save the updated template.
    card.setCustomPpse(ppse)
} catch (e: InternalComponentException) {
    Log.d("PPSE", "Error code: ${e.getmErrorCode()} Error message: ${e.message}")
}
```

{% endcode %}

#### Method 2: Build PPSE from raw bytes

Use this approach when you have the complete PPSE response data already available in BER-TLV format.

**When to use:**

* You already have the full PPSE response data as raw bytes.

{% code title="Build from Raw Bytes" %}

```kotlin
// Complete PPSE response data in BER-TLV format
// Note: .toByte() is used for values > 0x7F to handle Kotlin's signed byte type
val fciData = byteArrayOf(
    0x6F, 0x50, 0x84.toByte(), 0x0E, 0x32, 0x50, 0x41, 0x59, 0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46,
    0x30, 0x31, 0xA5.toByte(), 0x3E, 0xBF.toByte(), 0x0C, 0x3B, 0x61, 0x2F, 0x4F, 0x07, 0xA0.toByte(), 0x00, 0x00, 0x00, 0x03,
    0x10, 0x10, 0x50, 0x0B, 0x56, 0x69, 0x73, 0x61, 0x20, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x87.toByte(),
    0x01, 0x01, 0x9F.toByte(), 0x2A, 0x01, 0x03, 0x9F.toByte(), 0x0A, 0x04, 0x00, 0x01, 0x01, 0x02, 0xDF.toByte(),
    0x02, 0x03, 0x03, 0x04, 0x05, 0xDF.toByte(), 0x01, 0x02, 0x03, 0x04, 0x9F.toByte(), 0x02, 0x02, 0x01, 0x03,
    0x9F.toByte(), 0x01, 0x02, 0x01, 0x02
)

// Construct PpseFciTemplate from raw bytes
val template = PpseFciTemplate(fciData)

// Save the custom PPSE
try {
    digitalCard.setCustomPpse(template)
} catch (e: InternalComponentException) {
    Log.d("PPSE", "Error code: ${e.getmErrorCode()} Error message: ${e.message}")
}
```

{% endcode %}

#### Method 3: Build PPSE from scratch

Use this approach when you need to construct a PPSE structure programmatically by defining each component individually.

**When to use:**

* You are building PPSE data without existing byte data.
* You need to define directory entries, AIDs, labels, and other PPSE components programmatically.
* You want type-safe construction with compile-time validation.
* You prefer structured objects over raw bytes.

`DigitalizedCard` exposes the PPSE response as `PpseFciTemplate`. You can build your own `PpseFciTemplate`. The following example shows how to build it.

{% code title="Build from Scratch Using PpseFciTemplate" %}

```kotlin
val dfName = byteArrayOf(
    0x32, 0x50, 0x41, 0x59, 0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46, 0x30, 0x31
)

// Create directory entry
val aid = byteArrayOf(0xA0.toByte(), 0x00, 0x00, 0x00, 0x03, 0x10, 0x10)
val label = byteArrayOf(0x56, 0x69, 0x73, 0x61, 0x20, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74)
val kernelId = byteArrayOf(0x03)
val asrpd = byteArrayOf(0x00, 0x01, 0x01, 0x02)
val priority = byteArrayOf(0x01)
val entry = DirectoryEntry(aid, label, kernelId, asrpd, priority, null, HashMap())

val entries = arrayListOf(entry)

val issuerData = FciIssuerDiscretionaryData(entries, HashMap())
val proprietaryTemplate = FciProprietaryTemplate(issuerData)

// Create template with explicit parameters
val template = PpseFciTemplate(dfName, proprietaryTemplate)

// Save the custom PPSE
try {
    digitalCard.setCustomPpse(template)
} catch (e: InternalComponentException) {
    Log.d("PPSE", "Error code: ${e.getmErrorCode()} Error message: ${e.message}")
}
```

{% endcode %}

### Clear a custom PPSE

Pass `null` to remove the custom PPSE and restore the default PPSE response.

{% code title="Clear a custom PPSE template" %}

```kotlin
try {
    card.setCustomPpse(null)
} catch (e: InternalComponentException) {
    Log.d("PPSE", "Error code: ${e.getmErrorCode()} Error message: ${e.message}")
}
```

{% endcode %}

### Validation rules

NFC Wallet SDK validates the custom PPSE when you call `DigitalizedCard.setCustomPpse()`. It ensures that the custom PPSE follows EMV requirements and BER-TLV encoding.

#### Size limits

* The serialized BER-TLV payload must be 256 bytes or less.
* Custom tag keys inside `BF0C` or `61` must not exceed 2 bytes.

#### Required tags

Your `PpseFciTemplate` must include:

1. DF Name — Tag `84`
2. At least one Directory Entry — Tag `61` inside `BF0C`
3. An Application Identifier in each Directory Entry — Tag `4F`

If validation fails, the SDK throws `InternalComponentException` with error code `ERROR_CODE_INVALID_PPSE_DATA`.

#### AID Lock Restrictions

Locking an AID with `LockStatus.LOCKED` is supported only for mono-badged Visa cards.

If you set `LockStatus.LOCKED` for an unsupported card, the SDK throws `InternalComponentException`.


# Handle Visa multiple AIDs

## Overview

Use the NFC Wallet SDK to manage multiple Visa AIDs on a digital card.

You can:

* Detect whether a digital card exposes multiple AIDs.
* Read the AID list (sorted by priority).
* Update AID priority.
* Lock or unlock an AID.

## SDK integration

### Detect multiple AIDs

Use `DigitalizedCard.isMultiAids()`.

### Read AIDs

Use `DigitalizedCard.getAllAids()` to return a list of `Aid` objects.

The list is sorted by priority (highest priority first).

Each `Aid` includes:

* `Aid.getAid()`: Returns the AID as a `String`.
* `Aid.getLabel()`: Returns the label as a `String`.
* `Aid.getLockStatus()`: Returns `true` when the AID is locked.
* `Aid.setLockStatus(boolean locked)`: Locks or unlocks the AID.

{% hint style="info" %}
A terminal returns status word `6A81` when it sends **SELECT** to a locked AID.
{% endhint %}

### Update priority and lock status

To update priority (and optionally lock status), rebuild a list containing **all AIDs** in the desired priority order. Then call `DigitalizedCard.updateAidList(...)`.

```java
// Get a reference to a digital card using its tokenId.
DigitalizedCard digitalizedCard = DigitalizedCardManager.getDigitalizedCard(tokenId);

// Check whether this digital card exposes multiple AIDs.
if (digitalizedCard.isMultiAids()) {

    // Read all AIDs. The list is sorted by priority (highest first).
    List<Aid> aids = digitalizedCard.getAllAids();

    // Lock the highest-priority AID.
    aids.get(0).setLockStatus(true);

    // Rebuild the list in the desired priority order.
    // IMPORTANT: The updated list must contain all AIDs.
    List<Aid> updatedAids = new ArrayList<>();
    updatedAids.add(aids.get(1));
    updatedAids.add(aids.get(0));
    // Add remaining AIDs in the required order.

    // Apply both the new priority and lock status changes.
    digitalizedCard.updateAidList(updatedAids);
}
```




---

[Next Page](/llms-full.txt/1)

