Add and delete callbacks

This guide explains how to use callbacks with the Google Wallet API. For every valuable, whether it's added or deleted, Google performs a callback to the partners on a pre-configured class-level HTTPS endpoint. This callback includes data about the user's save or delete action, along with a signature. This lets your system stay in sync with the number of user adds and deletions that occur in the Wallet.

Prerequisites

Before you start, review the following prerequisites:

  • Stand up an HTTPS endpoint that handles POST requests. This endpoint needs to be publicly available.
  • Programmatically update the callback endpoint for each class. See the callbackOptions property by class in the REST API.
  • Recommended: Use the Tink library to verify the signatures.

Implement callbacks

For every add or delete performed by the user on an object, Google makes callbacks to the merchants with details about the add or delete on a per-class URL. Merchants need to first use the Public Keys to verify the authenticity of the message. After the callbacks verify the message, the callbacks can be used for downstream operations.

Verify the signature

We recommend that you use the Tink library to verify the message signature when you implement your HTTPS endpoint. The Tink library provides PaymentMethodTokenRecipient, a utility that automatically verifies the signature and returns the actual message upon successful verification.

The following example shows how to use the Tink library to implement PaymentMethodTokenRecipient:

private static final String PUBLIC_KEY_URL = "https://wallet.google.com/gp/m/issuer/keys". // Public key URL provided by Google.
private static final String SENDER_ID = "GoogleWalletPasses". // Constant.

private static final String RECIPIENT_ID = "ISSUER_ID". // Replace ISSUER_ID with your issuer id.

private static final String PROTOCOL = "ECv2SigningOnly".
Private static final GooglePaymentsPublicKeysManager keysManager = new
                       GooglePaymentsPublicKeysManager.Builder()
                      .setKeysUrl(PUBLIC_KEY_URL)
                      .build();

public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
    try {
      // Extract signed message with signature from POST request body.
      String signedMessage = CharStreams.toString(request.getReader());
      recipient =
          new PaymentMethodTokenRecipient.Builder()
              .protocolVersion(PROTOCOL)
              .fetchSenderVerifyingKeysWith(keysManager)
              .senderId(SENDER_ID)
              .recipientId(RECIPIENT_ID)
              .build();

      String serializedJsonMessage = recipient.unseal(signedMessage);
      // Use serializedJsonMessage to extract the details.
    } catch (Exception e) {
       // …
    }
}

Expected message format

The message format is JSON that's serialized into a string with the following properties:

Identifier Description
classId

Fully qualified class ID. Uses the following format:

<issuer_id.class_id>
objectId

Fully qualified object ID. Uses the following format:

<issuer_id.object_id>
expTimeMillis Expiration time in milliseconds since EPOCH. After the expiration time, the message needs to be deemed invalid.
eventType Can be either del or save for DELETE and SAVE.
nonce Nonce to track any duplicate deliveries.

Handle the request from a Google server

The following is a list of the key fields in the header of the request that's sent to your callback endpoint:

  • User-Agent: Google-Valuables
  • Content-Type: application/json

Configure your server so that it doesn’t reject the request. To do so, you can set the following in robots.txt:

User-agent: Google-Valuables
Disallow:

Retries

Callbacks are on a best-effort basis. Google tries to deliver the message for three days, in case of transient failures. After three days, Google deletes the message and doesn't try to resend it again.

Duplicate deliveries

There might be duplicate deliveries in some cases. We recommend that you use nonce to dedupe them.