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.