> For the complete documentation index, see [llms.txt](https://docs.payments.thalescloud.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.payments.thalescloud.io/nfc-wallet-sdk-android/get-started/configuration/5.-push-notifications/handle-push-notifications.md).

# 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`&#x20;

* `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>


---

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

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

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

```
GET https://docs.payments.thalescloud.io/nfc-wallet-sdk-android/get-started/configuration/5.-push-notifications/handle-push-notifications.md?ask=<question>&goal=<endgoal>
```

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

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

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