支払いのWebhooks (旧「リアルタイムアップデート」)は、アプリ内のFacebook決済で行われた注文に関する変更の知らせを受け取るのに不可欠な手段です。 |
Webhooksとは、Facebookと開発者のサーバーとの間のサブスクリプションベースのシステムです。アプリはサブスクリプション登録することで、指定されたHTTPSエンドポイントを経由して、Facebookからアップデートを受け取ります。アプリ内で行われた注文が変更されると、FacebookからそのエンドポイントにHTTPS POST
リクエストが発行されて、サーバーにその変更が通知されます。
開発者サーバーにアップデートが送信されるシナリオとして、主に以下の3つがあります。
支払いWebhooksにサブスクリプション登録するには、まず、サブスクリプション認証用のHTTPS GET
と変更データリクエスト用のPOST
の両方を受け取る公開エンドポイントのURLを作成します。これら両方のリクエストタイプの構造については、後述します。次に、アプリのpayment
オブジェクトをサブスクリプション登録します。次の2とおりの設定方法があります。
いずれの方法でも、エンドポイントは同じデータを同じ方法で受け取ります。サーバーが受け取る内容について詳しくは、コールバックサーバーをご覧ください。
Webhooksのアップデートを受信するようにアプリを設定する場合、アプリダッシュボードの[支払い]パネルを使う方法が最も簡単です。ダッシュボードで当該アプリを見つけたら、Payments
タブをクリックします。[Webhooks]セクションは、自社の[設定]セクションのすぐ下にあります。
アプリのサブスクリプションがこのパネルから追加された場合であっても、APIから追加された場合であっても、この画面にはアプリのサブスクリプションステータスが表示されます。ここから、サブスクリプションコールバックURLを変更してテストすることができます。
[コールバック]フィールドには、公開アクセスできる有効なサーバーエンドポイントを指定する必要があります。コールバックサーバーで説明したように、これはサブスクリプションの認証とアップデートの送信の両方に使用されるアドレスであり、応答する必要があります。
最後に、[認証トークン]を指定します。このトークンは、サブスクリプションが安全な場所から行われていることを検証するために、登録フェーズの間だけ送信されます。通常のWebhooksのアップデートでは送信されません。
サブスクリプションを保存する前に、コールバック設定をテストします。テストでは、hub.mode
、hub.challenge
、およびhub.verify_token
パラメーターを指定した認証GETリクエストがエンドポイントに発行され、これらが正しく処理されていることが確認されます。例えば次のように、エンドポイントからFacebookにhub.challenge
がエコーバックされることを確認します。
サブスクリプションの詳細を入力したら、必ずページ下部にある[変更を保存]ボタンをクリックしてください。サブスクリプションの編集は、フィールドの内容を変更し、再度テストし、もう一度フォームを保存するというシンプルな操作です。
グラフAPIを使って、サブスクリプションをプログラムで設定し、リストすることも可能です。その際には、アプリのaccess token
が必要になります。これは、アクセストークンツールから入手することも、グラフAPIの/oauth
エンドポイントを使って入手することもできます。
サブスクリプションAPIは、https://graph.facebook.com/[APP_ID]/subscriptions
エンドポイントで利用できます。
これを使って実行できるタスクは3つあります。
POST
リクエストを送信して)サブスクリプションを追加または変更するGET
リクエストを送信して)既存の各サブスクリプションのリストを取得するサブスクリプションを設定するには、次のパラメーターを指定してPOST
を送信します。これらのパラメーターは、上述のフォーム内のフィールドと対応しています。
object
- 上述のとおり、アップデートを受信するオブジェクトのタイプ。payments
を指定します。fields
- 変更に関する最新情報を希望するオブジェクトタイプのプロパティのコンマ区切りリスト。「actions」と「disputes」を指定します。callback_url
- 公開アクセスできる有効なサーバーのエンドポイント。verify_token
- サブスクリプションが認証されるときにエンドポイントに送信される、任意の文字列。Facebookは、上記のフォーム構成でこのリクエストを受け取ると、コールバックに対してGET
を実行し、有効であることとアップデートの受信準備が整っていることを確認します。特に、エンドポイントからFacebookに確実にhub.challenge
がエコーバックされるようにしなければなりません。
1つのアプリでサブスクリプション登録できるのは、1オブジェクトタイプにつき1つだけです。そのため、このオブジェクトタイプに既存のサブスクリプションがある場合、新たにPOSTされたデータで既存のデータが置き換えられるので注意してください。
サブスクリプションAPIにHTTP GET
を発行すると、サブスクリプションをリストした、JSONエンコードのコンテンツが返されます。以下はその例です。
[ { "object": "payments", "callback_url": "https://www.friendsmash.com/rtu.php", "fields": ["actions", "disputes"], "active": true } ]
グラフエクスプローラを利用して、直接このAPIを試すこともできます。その際には、必ず自分のアプリのアクセストークンを使ってください。
コールバックサーバーは、2種類のリクエストを処理する必要があります。これらのリクエストを成功させるため、必ず公開URLのサーバーにしてください。
サブスクリプションの追加や変更が試みられると、まず、FacebookサーバーからコールバックURLに単独のHTTPS GET
が実行されます。コールバックURLには、次のパラメーターを指定したクエリ文字列が追加されます。
パラメーター | 説明 |
---|---|
| このパラメーターの文字列「 |
| ランダム文字列 |
| サブスクリプションを作成したときに指定した |
エンドポイントはまずhub.verify_token
を認証します。これにより、サーバーはFacebookからリクエストが行われていることを確認し、設定したばかりのサブスクリプションに関連付けることができます。
次にサーバーからhub.challenge
値のみがエコーバックされます。これにより、Facebookはこのサーバーがコールバックを受け入れるように構成されていることを確認できるので、サービス拒否(DDoS)の脆弱性を防ぐことができます。
PHP開発者向けの注記: PHPでは、クエリパラメーター名にあるドットやスペースは自動的に下線に変換されます。そのため、PHPでコールバックエンドポイントを作成している場合は、$_GET['hub_mode']
、$_GET['hub_challenge']
、$_GET['hub_verify_token']
を使ってこれらのパラメーターにアクセスしてください。詳しくは、PHP言語マニュアルのこちらの注記をご覧ください。
サブスクリプション登録が完了したら、(対象のフィールドや接続に)変更があるたびに、FacebookからサーバーエンドポイントにHTTPS POST
が発行されます。このリクエストには、HTTPコード200
で応答する必要があります。
注 - 200
以外のHTTP応答はエラーと見なされます。その場合も、Webhooksアップデートの送信は引き続き再試行されます。そのため、正しく応答しないと、同じアップデートを複数回受信することがあります。
リクエストのコンテンツタイプはapplication/json
であり、本文はJSONエンコードの文字列で構成されており、そこに1件以上の変更が含まれています。
PHP開発者向けの注記: JSONエンコードのデータを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" ] } ] }
Webhookアップデートは、id
フィールドで特定される特定の支払いが変更されたことだけを通知します。アップデートの受信後に、グラフAPIをクエリして取引の詳細を確認し、変更に適宜対応する必要があります。
注 - 他のオブジェクトタイプのWebhooksはバッチ処理ができますが、paymentのアップデートについてはバッチ処理できません。
ユーザー側と開発者側のいずれのアクションによるものであっても、取引が更新されるたびに新しいアップデートを受け取ることが保証されます。
サーバーへのアップデート送信が失敗すると、直ちに再試行されます。その後24時間、頻度を落としながら数回にわたって試行が繰り返されます。
毎回のリクエストで、X-Hub-Signature-256
HTTPヘッダーが送信されます。これには、リクエストペイロードのSHA256署名があり、app secretがキーとして使用され、sha256=
のプレフィックスが付いています。コールバックエンドポイントは、この署名を認証して、ペイロードが改ざんされていないことと、ペイロードの発生元を確認できます。
サーバーがアップデートを受信したら、id
フィールドを使用してグラフAPIをクエリし、取引の新しいステータスに関して詳細を確認する必要があります。その後、そのステータスに応じて対応します。
以降のセクションでは、アップデート送信をトリガーする可能性があるすべての状態変更を列挙しています。これらは大きく次のように分類されます。
各payment
オブジェクトにはactions
というタイトルの配列があります。これに、取引の進行に伴う状態変更のコレクションが含まれています。actions
配列内の各項目には、実行されたアクションのタイプを記述するtype
という名前のプロパティがあります。type
の可能な値には、charge
、refund
、chargeback
、chargeback_reversal
、decline
があります。これらの値については、こちらで詳しく説明しています。
paymentオブジェクトと関連するactionsが含まれる、グラフ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"
になっています。initiatedステータスの支払いは、開始されただけで、まだ完了していません。initiated状態の支払いではアップデートは送信されません。
支払いが正常に完了すると、"status": "initiated"
が"status": "completed"
に変わり、アップデートが発行されます。この変更を受け取ったら、決済記録を確認して、新規取引であるか既存の取引であるかを確かめ、以下のように対応します。
initiated
状態である場合は、注文履行に進み、関連付けられている仮想アイテムまたは通貨を消費者に発行することができます。その後、この支払いを安全に完了とすることができます。"status": "failed"
の支払いのアップデートも受け取ります。これらの注文は履行しないでください。
グラフAPIを使って返金を発行すると、必ずアップデートを受け取ります。"type": "charge"
同様に、返金にも留意すべき各種のステータスがあります。主に処理エラーや接続エラーによって返金が失敗すると、返金の発行を再試行しなければならないので注意が必要です。
返金と同様に、チャージバック、チャージバックの取り消し、却下が発行されたときにも通知が届きます。チャージバック、チャージバックの取り消し、却下のオブジェクトが、当該支払いのグラフAPIの戻りデータのactions配列に追加されます。
申し立てが開始されると、Facebookからアップデートを発行して通知します。すると、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" } ] }
申し立てへの対応方法と返金の発行方法については、支払いの方法: 申し立てと返金に対応するをご覧ください。