Use callbacks

This guide explains how to use callbacks with Google Pay API for Passes. For every valuable saved and deleted, Google would callback the partners on a pre-configured class-level HTTPs endpoint with data about the user save/delete along with a signature.

Prerequisites

Before you get started, 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 per class. See the callbackOptions property by class in REST API.
  • (Recommended) Use the Tink library to verify the signatures.

Implement callbacks

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

Verify the signature

We recommend you use the Tink library to verify the message signature when implementing 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 implement PaymentMethodTokenRecipient using the Tink library:

private static final String PUBLIC_KEY_URL = "https://pay.google.com/gp/m/issuer/keys". // Public key URL provided by Google.
private static final String SENDER_ID = "GooglePayPasses". // 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 serialized into a string and contains 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 should 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

Below 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 appropriately so it doesn’t reject the request. For example, you may have to 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, the message is discarded and would not be retried in the future.

Duplicate deliveries

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