付款專用 Webhooks

交易相關的即時更新。

我們會透過「付款專用 Webhooks」(前身為「即時更新」)這種基本方式,告知您應用程式內透過「Facebook 付款」所下訂單的任何變更。

總覽

Webhooks 是一種 Facebook 和伺服器之間的訂閱型系統。透過指定的 HTTPS 端點,應用程式會進行訂閱,以便從 Facebook 接收更新。當應用程式內所下訂單有所更新時,我們會向該端點發出 HTTPS POST 要求,通知伺服器所發生的變更。

在 3 種主要情況下,更新會傳送至開發人員伺服器:

訂閱 Webhooks

若要訂閱「付款 Webhooks」,請先建立公開端點網址,以同時接收用於訂閱驗證的 HTTPS GET 以及用於變更資料要求的 POST。以下會說明這兩種類型要求的結構。接著,設定對應用程式 payment 物件的訂閱。有 2 種作法可供您選擇:

不管是哪一種作法,端點都會以相同方式接收到相同資料。如需深入瞭解伺服器會接收到的資料,請參閱回呼伺服器

透過應用程式主控板訂閱

若要設定應用程式來接收 Webhooks 更新,最簡單的方式是使用應用程式主控板的「付款」面板。在主控板中找到應用程式,然後點擊 Payments 頁籤。「Webhooks」區塊位於公司「設定」區塊的正下方。

付款專用 Webhooks

不論訂閱是透過這個面板或 API 所新增,這個畫面都會列出應用程式的訂閱狀態。您可從這個畫面變更訂閱回呼網址並加以測試。

您必須在「回呼」欄位中提供有效、可公開存取的伺服器端點。我們會使用這個位址來驗證訂閱與傳送更新,且這個位址必須如回呼伺服器中所述進行回應。

最後,提供「驗證權杖」。系統只有在註冊階段才會傳送這個權杖,以驗證訂閱是否來自安全的位置。一般 Webhook 更新不會傳送這個權杖。

測試設定

儲存訂閱前,請務必測試回呼設定。這會向端點發出驗證 GET 要求,其中包含 hub.modehub.challengehub.verify_token 參數,並確保您可正確處理這些參數。例如,您必須確保端點會將 hub.challenge 回送至 Facebook:

測試設定

輸入訂閱詳細資料後,請務必點擊頁面底部的「儲存變更」按鈕。若要編輯訂閱,只需更改欄位內容、重新測試,然後再次儲存表單。

透過圖形 API 訂閱

您也可透過圖形 API,以程式設計的方式設定並列出訂閱。您需要應用程式的 access token,這可從存取權杖工具或利用圖形 API 的 /oauth 端點取得

https://graph.facebook.com/[APP_ID]/subscriptions 端點可提供訂閱 API

您可以透過此 API 執行 3 項工作:

  • 新增或修改訂閱(透過傳送 HTTPS POST 要求)
  • 列出每個現有訂閱(透過傳送 HTTPS GET 要求)

新增與修改訂閱

若要設定訂閱,請傳送包含下列參數的 POST。請注意,這些參數對應上述表單中的欄位:

  • object - 同上,為您想要收到更新的物件類型。指定 payments
  • fields - 為您想要收到變更相關更新的物件類型的屬性清單(以逗號分隔)。指定「actions」和「disputes」。
  • callback_url - 有效、可公開存取的伺服器端點。
  • verify_token - 驗證訂閱時傳送至端點的任意字串。

我們收到這個要求時,與上述的表單設定相同,會向回呼執行 GET,以確定訂閱是否有效並準備好接收更新。特別的是,您必須確保端點會將 hub.challenge 回送至 Facebook。

請注意,因為應用程式對每個物件類型只能有一項訂閱,如果已經存在對這個物件類型的訂閱,則新發佈的資料會取代所有現有資料。

列出訂閱

向訂閱 API 發出 HTTP GET 會傳回以 JSON 編碼的內容,其中會列出您的訂閱。例如:

[
  {
    "object": "payments",
    "callback_url": "https://www.friendsmash.com/rtu.php",
    "fields": ["actions", "disputes"],
    "active": true
  }
]

您可以使用圖形測試工具直接嘗試使用此 API,但切記使用應用程式的存取權杖

回呼伺服器

回呼伺服器必須處理 2 種類型的要求。請務必將回呼伺服器置於公開網址,我們才能成功發出這些要求。

訂閱驗證

當您嘗試新增或修改訂閱時,Facebook 伺服器首先會向回呼網址發出單一 HTTPS GET。系統會將查詢字串與下列參數一起附加至回呼網址:

參數 說明

hub.mode

此參數會傳遞「subscribe」字串

hub.challenge

隨機字串

hub.verify_token

建立訂閱時指定的 verify_token

端點應該首先驗證 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.modehub.challengehub.verify_token 參數。

以下是針對 payments 物件訂閱所發出回呼的典型範例:

{
  "object": "payments",
  "entry": [
    {
      "id": "296989303750203",
      "time": 1347996346,
      "changed_fields": [
        "actions"
      ]
    }
  ]
}

特別要注意的是,Webhook 更新只會在特定付款(id 欄位識別)有所變更時,向您發出通知。收到更新後,您必須查詢圖形 API 取得交易詳細資料,才能適當地處理變更。

注意 - 雖然系統可批次處理其他物件類型的 Webhooks,但絕不會批次處理付款更新。

每次交易更新時(不論是由用戶動作或開發人員動作所造成),保證您一定會收到新的更新。

如果傳送至伺服器的更新失敗,我們將立即再次重試,然後在接下來的 24 小時內,以遞減的頻率再重試幾次。

每次要求中,我們都會傳送 X-Hub-Signature-256 HTTP 標頭,其中包含要求承載的 SHA256 簽章,所使用的密鑰為應用程式密鑰,開頭則是 sha256=。您的回呼端點可以驗證此簽章,以驗證承載的完整性和來源。

回應更新

伺服器接收到更新後,您應該使用 id 欄位來查詢圖形 API,以取得新交易狀態的詳細資料。然後,您應該根據狀態來採取動作。

以下章節列舉所有會觸發更新傳送的可能狀態變更。大致上分為:

  • actions 陣列的變更,這會發生在付款非同步完成、(由您或 Facebook)發放退款或刷退時。
  • disputes 陣列的變更,這會發生在消費者提出訂單異議時。

動作

每個 payment 物件都會包含名為 actions 的陣列,內含交易進行中狀態變更的集合。actions 陣列中的每個項目都有名為 type 的屬性,用於說明所發生的動作類型。type 可為下列值:chargerefundchargebackchargeback_reversaldecline此處提供完整說明

以下是針對有相關動作的付款物件,圖形 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",我們也會發出更新。看到此變更時,您應該檢查付款記錄,確認是否為新交易或現有交易並做出回應,如下所示:

  • 若為已知訂單,且已由 JavaScript 回呼履行(建議首選),則可放心忽視更新,或作為額外確認。
  • 若為已知訂單,但處於 initiated 狀態,則可繼續履行訂單,將相關虛擬商品或虛擬貨幣發給消費者。然後這項付款就可放心地標示為完成。
  • 如為未知訂單,這表示用戶端流程並未完成,很有可能是因為連線問題,或消費者在結帳中途關閉瀏覽器。您仍可放心履行並完成這筆訂單,因為 Facebook 依舊是用戶帳單的最終真實來源。

您也會收到狀態為 "status": "failed" 的付款更新。您不應該履行這些訂單。

退款

每次透過圖形 API 發還退款,您都會收到更新。如同 "type": "charge",退款也可能有您必須知道的不同狀態。特別的是,退款也可能失敗,通常是因為處理或連線錯誤。在此情況下,您應該重試發放退款。

刷退、退款撤銷及刷卡遭拒

如同退款,發生刷退、退款撤銷或刷卡遭拒時,您也會收到通知。刷退、退款撤銷或刷卡遭拒物件會加入至付款之圖形 API 傳回資料的 actions 陣列中。

異議

有異議提出時,我們會發出更新來通知您。在此情況下,您會在 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"
      }
   ]
}

如需深入瞭解如何回應異議並發放退款,請參閱付款使用說明:處理異議和退款