## Overview

Future token Lifecycle Management (LCM) notifications are sent from the Google Pay Online API to the `tokenUpdateUrl`
provided at the time of the original transaction. They are sent if a token is deactivated or deleted. They are also sent on a best-effort basis
with retries for failed deliveries. Here's an example of LCM flow when a card is removed from Google Wallet by a user:
<iframe src="https://developers.devsite.google/frame/pay/api/android/guides/resources/token-lifecycle-management_5e28c0bef6e4601f4645ed74291031c28ac7d3bc839a23b302b87ad5f5e4f587.frame" class="framebox inherit-locale " allow="clipboard-write https://developers.devsite.google" allowfullscreen is-upgraded></iframe>

## MerchantTokenUpdateNotificationRequest

An HTTP POST message from the Google Pay Online API, carries a JSON body encapsulating an encrypted
payload. The payload is encrypted with your shared public encryption key, and signed by Google's
private key. You can decrypt with your private encryption key, and verify with
[Google's root signing key](https://developers.google.com/pay/api/web/guides/resources/payment-data-cryptography.md.txt#root-signing-keys).
This encrypted payload wrapper format is identical to what you might receive as the
`PaymentMethodToken`. You can use the same library to decrypt this LCM notification.
Within the encrypted payload, there's a `MerchantTokenUpdateNotificationRequest` object
as detailed here.

| Property | Type | Necessity | Description |
|---|---|---|---|
| `messageId` | string | Required | Unique ID of this notification to deduplicate the messages and for debugging purposes. If this notification isn't successfully delivered, it remains the same for future retries. |
| `targetNotificationUrl` | string | Required | The intended URL for this notification. You must confirm that this URL is your intended endpoint to receive token LCM notifications from Google Pay. > [!NOTE] > **Note:** If the URL isn't owned by you or is incorrect, you must respond with a HTTP 400. |
| `timestamp` | string | Required | Timestamp of when this notification was originally created. It remains the same for future retries. If you receive multiple notifications for the same token ID, only the notification with the latest timestamp is considered accurate. |
| `apiVersion` | int | Required | API major version. |
| `apiVersionMinor` | int | Required | API minor version. |
| `merchantTokenId` | String | Required | The merchant token ID with an update. This is the ID returned originally when the user completed the Google Pay flow for the MIT. This is a field within the encrypted payload, sent in the [`Card`](https://developers.google.com/pay/api/web/guides/resources/payment-data-cryptography.md.txt#card) object. |
| `cardUpdateInfo` | [CardUpdateInfo](https://developers.google.com/pay/api/android/guides/resources/token-lifecycle-management.md.txt#CardUpdateInfo) | Required | Contains updates for the token. |

### CardUpdateInfo

| Property | Type | Necessity | Description |
|---|---|---|---|
| `fpanSuffix` | string | Conditional | A description to help users to identify the underlying Funding Primary Account Number (FPAN). It's a four digit string that contains the last four characters of the FPAN. When it's present, the token state can be presumed to be active. It's not present if there's no change. |
| `tokenState` | string(enum) | Conditional | The new state of the token, if changed since the initial transaction or previous notification. It's not present if there's no change. Valid value is `DISABLED`. |

## MerchantTokenUpdateNotificationResponse

### HTTP response codes

| HTTP response code | Usage |
|---|---|
| 200 | The notification is successfully received. Additional status information can be provided in the response body as a JSON object as described in the next table. |
| 401 | The `targetNotificationUrl` in the [`MerchantTokenUpdateNotificationRequest`](https://developers.google.com/pay/api/android/guides/resources/token-lifecycle-management.md.txt#MerchantTokenUpdateNotificationRequest) is invalid. All future notifications for this token can be disabled. |
| 5xx | Temporary server error. The notification should be sent again at a later time. |
| Other | Nonretriable error. The notification shouldn't be sent again at a later time. |

| Property | Type | Necessity | Description |
|---|---|---|---|
| `requestMessageId` | string | Required | The message ID generated from the request. It must match the message ID from the request, else the response can be ignored and future notifications for this token are stopped. |
| `status` | string(enum) | Required | The merchant or Payment Service Provider (PSP) can return a status which reflects their ingestion of the notification and their usage of the token. Valid values are: - `SUCCESS` - `TOKEN_NOT_IN_USE` - `TOKEN_NOT_FOUND` |

## Example

### Lifecycle notification

#### Notification request

This is the HTTP POST request which contains the token LCM notification, sent from Google Pay to
your endpoint. The body is an encrypted payload.

#### HTTP request

```javascript
  HTTP POST /token/notification/123
  Host: api.merchant.com
  Content-Type: application/json

  {
    "protocolVersion":"ECv2",
    "signature":"MEQCIH6Q4OwQ0jAceFEkGF0JID6sJNXxOEi4r+mA7biRxqBQAiAondqoUpU/bdsrAOpZIsrHQS9nwiiNwOrr24RyPeHA0Q\u003d\u003d",
    "intermediateSigningKey":{
      "signedKey": "{\"keyExpiration\":\"1542323393147\",\"keyValue\":\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/1+3HBVSbdv+j7NaArdgMyoSAM43yRydzqdg1TxodSzA96Dj4Mc1EiKroxxunavVIvdxGnJeFViTzFvzFRxyCw\\u003d\\u003d\"}",
      "signatures": ["MEYCIQCO2EIi48s8VTH+ilMEpoXLFfkxAwHjfPSCVED/QDSHmQIhALLJmrUlNAY8hDQRV/y1iKZGsWpeNmIP+z+tCQHQxP0v"]
    },
    "signedMessage":"{\"tag\":\"jpGz1F1Bcoi/fCNxI9n7Qrsw7i7KHrGtTf3NrRclt+U\\u003d\",\"ephemeralPublicKey\":\"BJatyFvFPPD21l8/uLP46Ta1hsKHndf8Z+tAgk+DEPQgYTkhHy19cF3h/bXs0tWTmZtnNm+vlVrKbRU9K8+7cZs\\u003d\",\"encryptedMessage\":\"mKOoXwi8OavZ\"}"
  }
```

#### Decrypted MerchantTokenUpdateNotificationRequest

```javascript
  {  // MerchantTokenUpdateNotificationRequest
    "messageId": "ZlxoWhLC3su",
    "targetNotificationUrl":
      "https://api.merchant.com/token/notification/123",
    "timestamp": "2025-03-28T07:53:12.39Z",
    "apiVersion": 1,
    "apiVersionMinor": 0,
    "merchantTokenId": "123",
    "cardUpdateInfo": {
      "tokenState": "DISABLED"
    }
  }
```

### Notification response

```javascript
  HTTP 200 OK
  Content-Type: application/json

  {  // MerchantTokenUpdateNotificationResponse
    "requestMessageId": "ZlxoWhLC3su",
    "status": "SUCCESS",
  }
```

## Test with your tokenUpdateUrl endpoint

In TEST mode, Google Pay sends a token LCM notification to your `tokenUpdateUrl`.
To trigger this, follow these steps:

- Complete a test transaction by calling `loadPaymentData` with a `*TransactionInfo` object, populating the `tokenUpdateUrl` field with your endpoint URL.

  > [!NOTE]
  > **Note:** To complete the transaction and trigger the notification in TEST mode, you must click the **Continue** or **Pay** button in the paysheet.

- Google's service will send a token LCM notification to your endpoint.
- Verify you can decrypt the notification using your private key. Note that, in TEST mode, this notification will always change the last 4 digits of the card number to "1234" and contain `"tokenState": "DISABLED"`, regardless of the token in the request.