Add and delete callbacks

This guide explains how to use callbacks with the Google Wallet API. When a valuable is created or deleted, Google can perform a callback to an HTTPS endpoint of your choosing. This callback is class-specific, and includes data about the event such as the class, object, and event type. This can be used to stay in sync with the number of user adds and deletions that occur. For example, callbacks can be configured to send events to an analytics application to track customer engagement during promotional events.

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:

import java.io.IOException;
import javax.servlet.http.*;
import com.google.common.io.CharStreams;
import com.google.crypto.tink.apps.paymentmethodtoken.*;

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

private static final String PUBLIC_KEY_URL = "https://pay.google.com/gp/m/issuer/keys";
private static final String SENDER_ID = "GooglePayPasses";
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());
    PaymentMethodTokenRecipient 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) {
    // Handle the error
  }
}

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: Googlebot
  • 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: Googlebot
Disallow:

Retries

Callbacks are on a best-effort basis. Google attempts twice to account for transient failures. After attempting twice, 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.