添加和删除回调
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
本指南介绍了如何通过 Google Wallet API 使用回调。当
创建或删除卡券时,Google 可以执行对 HTTPS 的回调
端点
此回调是特定于类的,并且包含数据
关于事件的信息,例如类、对象和事件类型。
这可用于
跟踪用户添加和删除操作的次数。对于
例如,回调可以配置为向 Analytics 发送事件
应用程序,用于在宣传活动期间跟踪客户参与度。
前提条件
在开始之前,请先查看以下前提条件:
-
建立一个处理 POST 请求的 HTTPS 端点。此端点需要
以供公开访问
-
以编程方式更新每个类的回调端点。请参阅
callbackOptions
属性。
- 推荐:使用 Tink 库来验证签名。
实现回调
对于用户在
一个对象
,Google 会通过在
每个课程
网址。商家需要先使用公钥来验证
消息内容。回调验证消息后,可以使用回调
处理下游操作
验证签名
我们建议您使用 Tink 库来验证消息签名
。通过
Tink 库
提供了 PaymentMethodTokenRecipient
,这是一个实用程序,
自动验证签名,并在收到邮件后返回实际邮件
验证成功。
以下示例展示了如何使用 Tink 库来实现
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
}
}
消息格式为 JSON,该 JSON 会序列化为字符串,其中包含以下
属性:
标识符 |
说明 |
classId |
完全限定的类 ID。请使用以下格式:
<issuer_id.class_id>
|
objectId |
完全限定对象 ID。请使用以下格式:
<issuer_id.object_id>
|
expTimeMillis |
到期时间(以毫秒为单位,从 EPOCH 开始)。在该到期时间过后
必须视为无效。
|
eventType |
可以是 del 或 save ,表示
DELETE 和SAVE 。
|
nonce |
用于跟踪任何重复递送的 Nonce。 |
处理来自 Google 服务器的请求
下面列出了请求标头中的关键字段
发送到回调端点:
- 用户代理:
Googlebot
- 内容类型:
application/json
配置服务器,使其不拒绝请求。为此,您可以
在 robots.txt
中设置以下内容:
User-agent: Googlebot
Disallow:
重试
系统会尽最大努力进行回调。Google 将使用常见的重试策略
在回调端点无响应或
间歇性服务中断,并能从容撤回尝试。
重复递送
在某些情况下,可能会有重复的递送。我们建议您使用
nonce
可对它们进行去重处理。
如未另行说明,那么本页面中的内容已根据知识共享署名 4.0 许可获得了许可,并且代码示例已根据 Apache 2.0 许可获得了许可。有关详情,请参阅 Google 开发者网站政策。Java 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):2025-08-29。
[null,null,["最后更新时间 (UTC):2025-08-29。"],[[["\u003cp\u003eGoogle Wallet can send callbacks to your HTTPS endpoint when a pass is created or deleted, allowing you to track user engagement.\u003c/p\u003e\n"],["\u003cp\u003eBefore implementing callbacks, ensure you have a publicly available HTTPS endpoint, update the callback endpoint for each class, and consider using the Tink library for signature verification.\u003c/p\u003e\n"],["\u003cp\u003eGoogle uses the \u003ccode\u003eclassId\u003c/code\u003e, \u003ccode\u003eobjectId\u003c/code\u003e, \u003ccode\u003eexpTimeMillis\u003c/code\u003e, \u003ccode\u003eeventType\u003c/code\u003e, and \u003ccode\u003enonce\u003c/code\u003e in the JSON message to provide details about the event.\u003c/p\u003e\n"],["\u003cp\u003eConfigure your server to accept requests from Googlebot by adjusting your \u003ccode\u003erobots.txt\u003c/code\u003e and be aware of potential retries and duplicate deliveries.\u003c/p\u003e\n"],["\u003cp\u003eUse the provided code example and expected message format to implement the callback functionality in your application.\u003c/p\u003e\n"]]],["Google Wallet API callbacks notify merchants via HTTPS endpoints when a pass is added or deleted. Merchants must set up a public HTTPS endpoint and programmatically update each class's `callbackOptions`. Google sends per-class event data, including `classId`, `objectId`, `eventType` (`save` or `del`), `expTimeMillis`, and a `nonce`. The Tink library is recommended to verify the message's signature, ensuring authenticity. Merchants should use `nonce` to prevent processing duplicates and configure servers to accept `Googlebot` requests.\n"],null,["# Add and delete callbacks\n\nThis guide explains how to use callbacks with the Google Wallet API. When a\npass is created or deleted, Google can perform a callback to an HTTPS\nendpoint of your choosing.\n\nThis callback is class-specific, and includes data\nabout the event such as the class, object, and event type.\n\nThis can be used to\nkeep track of the number of user adds and deletions that occur. For\nexample, callbacks can be configured to send events to an analytics\napplication to track customer engagement during promotional events.\n\nPrerequisites\n-------------\n\nBefore you start, review the following prerequisites:\n\n- Stand up an HTTPS endpoint that handles POST requests. This endpoint needs to be publicly available.\n- Programmatically update the callback endpoint for each class. See the [`callbackOptions`](/wallet/retail/offers/rest/v1/CallbackOptions) property by class in the REST API.\n- Recommended: Use the [Tink](https://developers.google.com/tink) library to verify the signatures.\n\nImplement callbacks\n-------------------\n\n\nFor every add or delete performed by the user on an\n\nan object\n\n, Google makes callbacks to the merchants with details about the add or delete on a\n\nper-class\n\nURL. Merchants need to first use the Public Keys to verify the authenticity of\nthe message. After the callbacks verify the message, the callbacks can be used\nfor downstream operations.\n\nVerify the signature\n--------------------\n\n\nWe recommend that you use the Tink library to verify the message signature\nwhen you implement your HTTPS endpoint. The\n[Tink library](https://github.com/google/tink)\nprovides `PaymentMethodTokenRecipient`, a utility that\nautomatically verifies the signature and returns the actual message upon\nsuccessful verification.\n\n\nThe following example shows how to use the Tink library to implement\n`PaymentMethodTokenRecipient`: \n\n```python\nimport java.io.IOException;\nimport javax.servlet.http.*;\nimport com.google.common.io.CharStreams;\nimport com.google.crypto.tink.apps.paymentmethodtoken.*;\n\n// Replace ISSUER_ID with your issuer id\nprivate static final String RECIPIENT_ID = \"\u003cvar translate=\"no\"\u003eISSUER_ID\u003c/var\u003e\";\n\nprivate static final String PUBLIC_KEY_URL = \"https://pay.google.com/gp/m/issuer/keys\";\nprivate static final String SENDER_ID = \"GooglePayPasses\";\nprivate static final String PROTOCOL = \"ECv2SigningOnly\";\n\nprivate static final GooglePaymentsPublicKeysManager keysManager = new GooglePaymentsPublicKeysManager.Builder()\n .setKeysUrl(PUBLIC_KEY_URL)\n .build();\n\npublic void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {\n try {\n // Extract signed message with signature from POST request body.\n String signedMessage = CharStreams.toString(request.getReader());\n PaymentMethodTokenRecipient recipient =\n new PaymentMethodTokenRecipient.Builder()\n .protocolVersion(PROTOCOL)\n .fetchSenderVerifyingKeysWith(keysManager)\n .senderId(SENDER_ID)\n .recipientId(RECIPIENT_ID)\n .build();\n\n String serializedJsonMessage = recipient.unseal(signedMessage);\n\n // Use serializedJsonMessage to extract the details\n } catch (Exception e) {\n // Handle the error\n }\n}\n```\n\nExpected message format\n-----------------------\n\n\nThe message format is JSON that's serialized into a string with the following\nproperties:\n\n| Identifier | Description |\n|-----------------|-----------------------------------------------------------------------------------------------------------------|\n| `classId` | Fully qualified class ID. Uses the following format: ``` \u003cissuer_id.class_id\u003e ``` |\n| `objectId` | Fully qualified object ID. Uses the following format: ``` \u003cissuer_id.object_id\u003e ``` |\n| `expTimeMillis` | Expiration time in milliseconds since EPOCH. After the expiration time, the message needs to be deemed invalid. |\n| `eventType` | Can be either `del` or `save` for `DELETE` and `SAVE`. |\n| `nonce` | Nonce to track any duplicate deliveries. |\n\n### Handle the request from a Google server\n\n\nThe following is a list of the key fields in the header of the request that's\nsent to your callback endpoint:\n\n- User-Agent: `Googlebot`\n- Content-Type: `application/json`\n\n\nConfigure your server so that it doesn't reject the request. To do so, you can\nset the following in `robots.txt`: \n\n```\nUser-agent: Googlebot\nDisallow:\n```\n\n### Retries\n\n\nCallbacks are on a best-effort basis. Google will use common retry strategies\nto be resilient in cases where the callback endpoint is not responding or has an\nintermittent outage and will gracefully back off attempts.\n\n### Duplicate deliveries\n\n\nThere might be duplicate deliveries in some cases. We recommend that you use\n`nonce` to dedupe them."]]