支付专用 Webhooks(之前称为“实时更新”)是应用中的订单通过 Facebook 支付发生更改后,系统向您发送更改相关通知的基本方法。 |
Webhooks 是 Facebook 及您服务器之间的订阅制系统。订阅之后,您的应用会通过指定 HTTPS 端点从 Facebook 接收更新。如果在您应用中提交的订单有所更新,我们将向该端点发送 HTTPS POST
请求,以便向您的服务器通知该更新。
如发生以下 3 种主要情景,我们会向您的开发者服务器发送更新:
如要订阅支付 Webhooks,请先创建公开端点网址,用于接收 HTTPS GET
及 POST
。前者用于验证订阅,而后者则用于请求更改数据。下文将对这两种请求类型的结构进行说明。创建网址后,订阅应用的 payment
对象。如要执行此操作,可以采用以下 2 种方式:
无论采用哪种方式,您的端点都会以相同方式收到同样的数据。请查看回调服务器部分,进一步了解您的服务器将收到哪些数据。
如要为应用设置接收 Webhooks 更新,最简单的方法就是使用应用面板的“支付”窗口。在应用面板中找到您的应用,然后点击 Payments
选项卡。“Webhooks”部分将正好显示在您公司的“设置”部分下方。
然后,此屏幕将列出应用的订阅状态,无论是通过应用面板还是通过图谱 API 订阅,均是如此。您可以在这里更改订阅回调网址并对其进行测试。
在“回调”字段中,您必须提供有效且可公开访问的服务器端点。我们将使用订阅回调网址验证订阅及发送更新,而该网址需要按照回调服务器部分中所说明的方式作出响应。
最后,提供“验证口令”。该口令只会在注册阶段发送,以验证相关订阅的来源是安全位置,而不会在常规 Webhooks 更新中发送。
在保存订阅前,您应该测试回调设置。此操作会向您的端点发送验证 GET 请求,其中包含 hub.mode
、hub.challenge
及 hub.verify_token
参数,并确保您对这些参数的处理方法得当。例如,您必须确保端点会向 Facebook 回显 hub.challenge
:
输入订阅详情后,请务必点击页面底部的“保存更改”按钮。编辑订阅相当简单,只需修改字段内容、重新测试,然后再次保存表单即可。
您也可以通过图谱 API,以编程方式设置订阅并列出订阅清单。您需要应用的 access token
,而该口令可通过访问口令工具或图谱 API 的 /oauth
端点获取
您可以在 https://graph.facebook.com/[APP_ID]/subscriptions
端点中获取订阅 API
您可以通过此 API 执行 3 种任务:
POST
请求)GET
请求)如要设置订阅,请发送包含以下参数的 POST
。请注意,这些参数对应上文所述表单中的字段:
object
— 如上所述,此为您想接收相关更新的对象的类型。指定为 payments
。fields
— 使用逗号分隔的清单,其中包含您想接收相关更改更新通知的对象类型的属性。指定为“actions”及“disputes”。callback_url
— 有效并且可公开访问的服务器端点。verify_token
— 验证订阅时,向您的端点发送的任意字符串。收到此请求后,与上面的表单配置一样,我们将向您的回调执行 GET
,以确保您的回调有效并且已准备好接收更新。您尤其需要注意的是,务必确保端点向 Facebook 回显 hub.challenge
。
请注意,对于每种对象类型,应用只能有一个订阅,因此如果已存在对该对象类型的订阅,则新发布的数据将取代任何已有数据。
如果向订阅 API 发送 HTTP GET
,系统将会返回经过 JSON 编码的内容,并在其中列出您的订阅。例如:
[ { "object": "payments", "callback_url": "https://www.friendsmash.com/rtu.php", "fields": ["actions", "disputes"], "active": true } ]
您的回调服务器必须处理 2 种类型的请求。请务必确保回调服务器位于公开网址,只有这样我们才能成功发出这些请求。
首先,在您尝试添加或修改订阅时,Facebook 服务器将向您的回调网址发出单独的 HTTPS GET
。您的回调网址会附加包含以下参数的查询字符串:
参数 | 描述 |
---|---|
| 在此参数中传递“ |
| 随机字符串 |
| 创建订阅时指定的 |
端点应首先验证 hub.verify_token
。这样做可以确保您的服务器知道该请求是由 Facebook 发出,并且与您刚才配置的订阅相关。
然后,服务器应该回显 hub.challenge
值,以向 Facebook 确认此服务器将配置用于接收回调,并避免出现拒绝服务 (DDoS) 漏洞。
PHP 开发者注意事项:在 PHP 中,查询参数名称中的圆点和空格将自动转换为下划线。因此,如果您在 PHP 中编写回调端点,应该使用 $_GET['hub_mode']
、$_GET['hub_challenge']
和 $_GET['hub_verify_token']
访问这些参数。请参阅 PHP 语言手册中的这项说明,了解更多信息。
订阅成功后,当您所选择的字段或连接有更改,我们将向您的服务器端点发送 HTTPS POST
。您必须使用 HTTP 代码 200
对此请求作出响应。
备注:我们会将除 200
外的任何 HTTP 响应视为错误。在这种情况下,我们将继续尝试重新发送 Webhooks 更新。因此,如果您未能以正确方式作出响应,则可能会多次收到相同更新。
此请求的内容类型为 application/json
,其正文将由经过 JSON 编码的字符串组成,其中包含一或多项更改。
PHP 开发者注意事项:在 PHP 中,如要获取经过编码的数据,需要使用以下代码:
$data = file_get_contents("php://input"); $json = json_decode($data);`
请注意,确认订阅之后,系统不会再次发送 hub.mode
、hub.challenge
及 hub.verify_token
参数。
以下为向 payments
对象订阅发送的回调典型示例:
{ "object": "payments", "entry": [ { "id": "296989303750203", "time": 1347996346, "changed_fields": [ "actions" ] } ] }
请务必注意,Webhooks 更新只会通知您特定支付(由 id
字段标识)已发生更改。收到更新后,您接下来需要查询图谱 API 以了解交易详情,从而恰当地处理更改。
备注:虽然其他对象类型的 Webhooks 可以采用批量处理的方法,但是支付更新无法进行批量处理。
我们可确保每次交易有所更新时,无论该更新是由用户操作还是开发者操作所致,您都将收到新的更新。
如果向服务器发送的更新失败,我们将立即尝试重新发送,并在随后的 24 小时内以递减的频率再进行多次尝试。
在每个请求中,我们都会发送 X-Hub-Signature-256
HTTP 标头,其中包含请求负载的 SHA256 签名,这类签名将应用密钥用作密钥,并以 sha256=
为前缀。回调端点可以验证此签名,从而验证负载的完整性及来源。
服务器收到更新后,您应该使用 id
字段查询图谱 API,以了解交易新状态的详情。接下来,您应该根据状态采取行动。
以下部分列出了会导致系统发送更新的所有状态更改。这些更改大致可分为两类:
每个 payment
对象包含一个以 actions
为标题的数组,其中包含各交易阶段的一系列状态更改。actions
数组中的每个条目都有一个名为 type
的属性,用于描述所发生操作的类型。type
可以为以下值:charge
、refund
、chargeback
、chargeback_reversal
及 decline
(点击此处了解详细说明)。
以下示例为图谱 API 对支付对象的响应,其中包含相关操作:
{ "id": "3603105474213890", "user": { "name": "Marco Alvarez", "id": "500535225" }, "application": { "name": "Friend Smash", "namespace": "friendsmashsample", "id": "241431489326925" }, "actions": [ { "type": "charge", "status": "completed", "currency": "USD", "amount": "0.99", "time_created": "2013-03-22T21:18:54+0000", "time_updated": "2013-03-22T21:18:55+0000" }, { "type": "refund", "status": "completed", "currency": "USD", "amount": "0.99", "time_created": "2013-03-23T21:18:54+0000", "time_updated": "2013-03-23T21:18:55+0000" } ], "refundable_amount": { "currency": "USD", "amount": "0.00" }, "items": [ { "type": "IN_APP_PURCHASE", "product": "https://www.friendsmash.com/og/friend_smash_bomb.html", "quantity": 1 } ], "country": "US", "created_time": "2013-03-22T21:18:54+0000", "payout_foreign_exchange_rate": 1,}`
如果您注册 Webhooks 时订阅 actions 字段,当数组发生如下更改,我们会发送更新:
所有订单刚开始都包含一个带有 "status": "initiated"
的收费条目。“已发起的支付”表示支付仅仅只是被发起,但是尚未完成。我们不会就处于已发起状态的支付发送更新。
成功完成支付后,"status": "initiated"
将更改为 "status": "completed"
,我们将为此发送更新。看见此更改后,您应该查看支付记录,确认这是笔新交易还是已有交易,并按照以下方式作出响应:
initiated
状态,则您可以继续履行订单,向消费者发送相关虚拟商品或货币。之后,可以放心地将该支付标记为完成。您还会收到带有 "status": "failed"
的支付的更新。您不应该履行这类订单。
只要通过图谱 API 发起退款,就会收到更新。与 "type": "charge"
一样,退款也有各种状态,因此您必须加以注意。最需要注意的一点就是,退款有可能失败,而这通常是因为处理或连接出错。如果是因为这些原因,您应该重新尝试发起退款。
与退款一样,如果有人发起了拒付、拒付撤销或拒绝,您也会收到通知。在支付的图谱 API 响应数据操作数组中,会加入拒付、拒付撤销或拒绝对象。
消费者发起异议后,我们将通过发送更新来通知您。在这种情况下,您将看到 payment
对象中出现新的 "disputes"
数组。此数组将包含异议的发起时间、消费者发起相关操作的理由以及消费者的邮箱,以便您使用该邮箱直接联系消费者解决异议。
以下示例为图谱 API 对有异议的交易的完整响应:
{ "id": "990361254213890", "user": { "name": "Marco Alvarez", "id": "500535225" }, "application": { "name": "Friend Smash", "namespace": "friendsmashsample", "id": "241431489326925" }, "actions": [ { "type": "charge", "status": "completed", "currency": "USD", "amount": "0.99", "time_created": "2013-03-22T21:18:54+0000", "time_updated": "2013-03-22T21:18:55+0000" } ], "refundable_amount": { "currency": "USD", "amount": "0.99" }, "items": [ { "type": "IN_APP_PURCHASE", "product": "https://www.friendsmash.com/og/friend_smash_bomb.html", "quantity": 1 } ], "country": "US", "created_time": "2013-03-22T21:18:54+0000", "payout_foreign_exchange_rate": 1, "disputes": [ { "user_comment": "I didn't receive my item! I want a refund, please!", "time_created": "2013-03-24T18:21:02+0000", "user_email": "email\u0040domain.com", "status": "resolved", "reason": "refunded_in_cash" } ] }
如需进一步了解如何响应异议及发起退款,请参阅支付操作说明:处理异议和退款。