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.