コンテンツへスキップ

ウェブフック (1.0)

概要

ウェブフックは、システムで発生するイベントに関する通知です。特定のイベントが発生すると、エクソーラはHTTPリクエストを送信し、イベントデータがアプリケーション に送信されます。通常、これはJSON形式のPOSTリクエストです。

イベントの例:

  • アイテムカタログとのユーザーインタラクション
  • 注文の決済またはキャンセル

設定されたイベントが発生すると、エクソーラはウェブフック経由でシステムにそれを通知します。その結果、次のようなアクションを実行できます:

  • ユーザーの残高を補充する
  • 支払いを返金する
  • ユーザーアカウントから新しいアイテムをクレジットまたはデビットする
  • サブスクリプションの提供を開始する
  • 詐欺の疑いがある場合にユーザーをブロックする

支払い処理ウェブフックのワークフローの例:

支払い処理ウェブフック

注意

使用されるソリューションとその統合のタイプに応じて、ウェブフックのセットとインタラクションのシーケンスは、提供された例とは異なる場合があります。

エクソーラウェブフック統合のビデオガイド:

エクソーラ製品およびソリューションを使用する場合のウェブフック設定:

製品/ソリューション必須/任意ウェブフックは何に使用されますか
決済ソリューション必須
  • ユーザー検証。
  • 支払いが成功した場合や支払いが返金された場合に、トランザクションの詳細情報を受け取ります。
  • ユーザーに購入したアイテムを付与し、注文がキャンセルされた場合にアイテムを差し引きます。
ストア必須
  • ユーザー検証。
  • 支払いが成功した場合や支払いが返金された場合に、トランザクションの詳細情報を受け取ります。
  • ユーザーに購入したアイテムを付与し、注文がキャンセルされた場合にアイテムを差し引きます。
ゲーム販売任意ゲームキーの販売では、ユーザーの検証やアイテムの付与は必要ありません。支払いや注文キャンセルなどのイベントに関する情報を受け取りたい場合は、ウェブフックを接続することができます。
ウェブフックを接続する場合は、すべての受信した必要なウェブフックを処理することが重要です。
サブスクリプション任意サブスクリプションの作成、更新、またはキャンセルに関する情報を受け取ります。または、API経由で情報をリクエストすることもできます。
ウェブショップ必須
  • ユーザー検証。
  • 支払いが成功した場合や支払いが返金された場合に、トランザクションの詳細情報を受け取ります。
  • ユーザーに購入したアイテムを付与し、注文がキャンセルされた場合にアイテムを差し引きます。
  • ユーザー認証、ユーザーIDによる認証を使用する場合。または、エクソーラログイン経由でユーザー認証を使用することもできます。
デジタル配信ソリューション必須
  • ユーザー検証。
  • エクソーラ側のトランザクションIDをシステムのトランザクションIDにリンクします。
  • 注文に追加のトランザクションパラメータを転送します。
  • ユーザーに購入したアイテムを付与し、注文がキャンセルされた場合にアイテムを差し引きます。

ウェブフックの設定に関する詳細情報は、デジタル配信ソリューションのドキュメントを参照してください。

ログイン任意

イベント情報の受信:

  • ユーザー登録/認証
  • ユーザーメールアドレスの確認
  • ユーザーのソーシャルメディアアカウントをリンクする

ウェブフックの設定の詳細については、ログインに関するドキュメントを参照してください。

必須なウェブフックのリスト

ウェブフックの操作が必要な製品やソリューションを使用している場合、パブリッシャーアカウントでウェブフックを有効化してテストし、その処理をセットアップします。特定のイベントが発生する時、ウェブフックが順次送信されます。したがって、1つのウェブフックを処理しない 場合、その後のウェブフックは送信されません。必要なウェブフックのリストは以下の通りです。

ストアと決済ソリューション

エクソーラ側では、サイトでアイテムを購入して返品する際に2 つのウェブフック送信オプションが設定されています。支払いと取引データ、および購入したアイテムに関する情報は、個別に提供することも、1つのウェブフックにまとめるこ ともできます。

まとめたウェブフックで情報を受け取ります:

2025年1月22日以降にパブリッシャーアカウントに登録した場合は、注文支払い完了order_paid)と注文キャンセルorder_canceled)ウェブフックですべての情報を受け取ります。この場合、支払いpayment)と返金refund)ウェブフックを処理する必要はありません。

個別のウェブフックで情報を受け取ります:

2025年1月22日以前にパブリッシャーアカウントに登録した場合は、以下のウェブフックを受け取ります:

すべての受信ウェブフックを処理する必要があります。まとめたウェブフックを受信する新しいオプションに切り替えるには、カスタマーサクセスマネージャーにご連絡いただく か、csm@xsolla.comまで電子メールをお送りください。

インゲームストアと決済管理の完全な運用のためには、主要なウェブフックの処理を実装する必要があります。

まとめたウェブフックを受信する場合

ウェブフック名とタイプ説明
ユーザー検証 >ユーザー検証user_validationユーザーがゲームに登録されていることを確認するために、支払いプロセスのさまざまな段階で送信されます。
ゲームサービス > まとめたウェブフック >注文支払い完了order_paid支払いデータ、取引の詳細、購入されたアイテムに関する情報が含まれます。ウェブフックからのデータを使用して、ユーザーにアイテムを追加します。
ゲームサービス > まとめたウェブフック >注文キャンセルorder_canceledキャンセルされた支払のデータ、取引の詳細、および購入したアイテムに関する情報が含まれています。ウェブフックからのデータを使用して、購入されたアイテムを削除します。

個別のウェブフックを受信する場合

ウェブフック名とタイプ説明
ユーザー検証 >ユーザー検証user_validationユーザーがゲームに登録されていることを確認するために、支払いプロセスのさまざまな段階で送信されます。
決済ソリューション >支払いpayment支払いデータと取引の詳細が含まれています。
ゲームサービス> 個別のウェブフック>注文支払い完了order_paid購入したアイテムに関する情報が含まれています。ウェブフックからのデータを使用して、ユーザーにアイテムを追加します。
決済ソリューション >返金refund支払いデータと取引の詳細が含まれています。
ゲームサービス > 個別のウェブフック >注文キャンセルorder_canceled購入したアイテムとキャンセルされたトランザクションのIDに関する情報が含まれます。ウェブフックのデータを使用して、購入したアイテムを削除します。

アイテムカタログの個人用設定がアプリケーション側で実装されている場合は、パートナー側でのカタログ個人用設定ウェブフックの処理を設定します。

注意

実際の支払いを受け取るには、ライセンス契約に署名し、以下のウェブフック処理を実装するだけです:

サブスクリプション

サブスクリプションプランを自動的に管理するには、主要なウェブフックの処理を実装する必要があります:

  • ユーザーの検証user_validation) — 決済プロセスのさまざまな段階で送信され、ユーザーがゲームに登録されていることを確認します。
  • 決済payment) — 注文が支払われたときに送信され、決済データとトランザクションの詳細が含まれます。
  • 作成されたサブスクリプションcreate_subscription) — 決済ウェブフックが正常に処理されたとき、またはユーザーが試用期間付きのサブスクリプ ションを購入したときに送信されます。これは購入したサブスクリプションの詳細とユーザーデータを含んでいます。ウェブフックデータを使用して、ユーザーにサブスクリプシ ョンを追加します。
  • 更新されたサブスクリプションupdate_subscription) — サブスクリプションが更新または変更されたとき、決済ウェブフックが正常に 処理されたときに送信されます。購入したサブスクリプションの詳細とユーザーデータが含まれます。ウェブフックデータを使用して、ユーザーのサブスクリプションを延長する か、サブスクリプションパラメータを変更します。
  • 返金refund) — 注文がキャンセルされたときに送信され、キャンセルされた決済データとトランザクションの詳細が含まれます。
  • キャンセルされたサブスクリプションcancel_subscription) — 返金ウェブフックが正常に処理されたとき、またはサブスクリプションが別の理由でキャンセ ルされたときに送信されます。サブスクリプションとユーザーデータに関する情報を含んでいます。ウェブフックデータを使用して、ユーザーから購入したサブスクリプションを 差し引きます。

パブリッシャーアカウントでウェブフックをセットアップする

一般設定

ウェブフックの受信を有効にするには:

  1. パブリッシャーアカウントのプロジェクトで、プロジェクト設定>ウェブフ ックセクションに移動します。
  2. ウェブフックサーバーフィールドには、ウェブフックを受信したいサーバーのURLを https://example.com 形式で指定します。ウェブフックをテストするツールで見つけたURLを指定することもできます。

注意。

データ転送にはHTTPSプロトコルが使用されます。HTTPプロトコルはサポートされていません。

  1. 秘密鍵を生成します:
    1. 秘密鍵セクションで、「キーを追加」クリックします。
    2. 開いたモーダルウィンドウに、一般リストからこの項目を識別するためのキー名を入力してください。。
    3. キーを作成」クリックします。
    4. シークレットをコピー」をクリックし、作成されたキーをユーザー側で保存してください。
    5. 完了」クリックします。
    6. キーが保存されたことを確認し、「OK、閉じる」をクリックします。

Add key

注意

キーに関する推奨事項:

  • 生成されたシークレットキーは手元に保存してください。キーは作成時に一度だけパブリッシャーアカウントで確認できます。
  • 秘密鍵は決して他人に教えないでください。
  • 秘密鍵はサーバー上に保存する必要があり、バイナリファイルやフロントエンドには決して保存してはいけません。

  1. ウェブフックを有効にする」をクリックします。

注意

ウェブフックをテストするには、webhook.siteのような専用のウェブサイトか、ngrokのようなプラットフォームを選択できます。

注意

異なるURLに同時にウェブフックを送信することはできません。パブリッシャーアカウントでは、まずテスト用のURLを指定し、それを実際のURLに置き換えることができます。

ウェブフックの受信を無効にするには:

  1. パブリッシャーアカウントのプロジェクトで、プロジェクト設定>ウェブフ ックセクションに移動します。
  2. ウェブフックを無効にする」をクリックします。

秘密鍵のローテーション

秘密鍵を定期的に更新することで、統合のセキュリティを向上させることができます。プロジェクトでは最大5つの秘密鍵を作成し、ローテーションを有効にすることができます 。これを行うには:

  1. プロジェクト設定> ウェブフックセクションで、「キーを追加」をクリックします。

Add key

  1. 開いたモーダルウィンドウに、一般リストからこの項目を識別するためのキー名を入力してください。。
  2. キーを作成」をクリックします。
  3. シークレットをコピー」をクリックし、作成されたキーをユーザー側で保存してください。
  4. 完了」をクリックします。
  5. キーが保存されたことを確認し、「OK、閉じる」をクリックします。

注意

キーに関する推奨事項:

  • 生成されたシークレットキーは手元に保存してください。キーは作成時に一度だけパブリッシャーアカウントで確認できます。
  • 秘密鍵は決して他人に教えないでください。
  • 秘密鍵はサーバー上に保存する必要があり、バイナリファイルやフロントエンドには決して保存してはいけません。

プロジェクトごとに有効な秘密鍵は1つだけです。変更したい場合は、別のキーの行にある「有効にする」をクリックして操作を確定してください。新しいキーへの移行 が正常に完了した後は、無効化されたキーを削除することをお勧めします。

Change active 
key

詳細設定

ウェブフックについては決済ソリューションとストアセクションでは、詳細設定が利用できます。「ウェブフックを取得」ボタンをクリックする と、自動的に一般設定ブロックの下に表示されます。

注意

詳細設定が表示されない場合は、一般設定でウェブフック受信が接続されていることを確認し、テスト > 決済ソリューションとストアタブにいることを確認してください。

このセクションでは、ウェブフックでの追加情報の受信を設定できます。これを行うには、対応するスイッチをアクティブポジションに設定します。各権限の行は、設定の変更に よって影響を受けるウェブフックを示します。

トグル説明
保存された決済アカウントに関する情報を表示します(2025年1月22日以前にパブリッシャーアカウントに登録し、個別のウェブフックを受信している場合にのみ表示されます)。保存された決済方法に関する情報は、payment_accountカスタムオブジェクト。
保存された決済方法によるトランザクションに関する情報を表示します。

情報は、ウェブフックの以下のカスタムパラメータに渡されます:

  • saved_payment_method:
    • 0 — 保存された決済方法は使用されませんでした
    • 1 — 決済方法は現在の支払い時に保存されました
    • 2 — 保存された決済方法は使用されませんでした
  • payment_type:
    • 1 — 一回払い
    • 2 — 定期支払い
ウェブフックにorderオブジェクトを追加します(2025年1月22日以前にパブリッシャーアカウントに登録し、個別のウェブフックを受信している場合にのみ表示されます)。注文に関する情報は、決済ウェブフックのorderオブジェクトに渡されます。
機密データを含めず、必須のユーザーパラメータのみを送信します。

ウェブフックでは、ユーザーに関する次の情報のみが渡されます:

  • ID
カスタムパラメータを送信します。カスタムトークンパラメータに関する情報は、ウェブフックで渡されます。
カードのBINおよびサフィックスを表示します。

ウェブフックには、銀行カード番号に関する以下の情報が渡されます:

  • card_binパラメータの最初の6桁
  • card_suffixパラメータの最後の4桁
カードブランドを表示します。決済に使用したカードのブランド。例えば、MastercardやVisaなど。
返金理由に関する情報を表示します。返金理由に関する詳細情報。
国別の源泉徴収税および顧客獲得料を表示します。payment_details.​country_whtpayment_details.​user_acquisition_feeオブジェクトがウェブフックに含めて送信されます。このトグルはデフォルトでオンになっています。
3DS情報を送信します。3-Dセキュア認証に関するデータを含むcardsオブジェクトがウェブフックで渡されます。

Advanced 
settings

パブリッシャーアカウントでウェブフックをテストする

ウェブフックをテストすると、ユーザー側とエクソーラ側の両方でプロジェクトが正しく設定されていることを確認できます。

ウェブフックが正常にセットアップした場合、ウェブフック設定セクションの下にウェブフックのテストセクションが表示されます。

Webhooks testing 
section

パブリッシャーアカウントのテストセクションは、ウェブフック受信オプションによって異なります。

2025年1月22日以降にパブリッシャーアカウントに登録した場合、以下の統合されたウェブフックを受信します:

ウェブフックテストのタブ名ウェブフック名とタイプ
決済ソリューションとストアユーザー検証 >ユーザー検証user_validation
ゲームサービス > まとめたウェブフック >注文支払い完了order_paid
ゲームサービス > まとめたウェブフック >注文キャンセルorder_canceled
サブスクリプションユーザー検証 >ユーザー検証user_validation
決済ソリューション >支払いpayment

2025年1月22日以前にパブリッシャーアカウントに登録した場合、個別のウェブフックが送信されます:

ウェブフックテストのタブ名ウェブフック名とタイプ
ストアゲームサービス> 個別のウェブフック>注文支払い完了order_paid
ゲームサービス > 個別のウェブフック >注文キャンセルorder_canceled
決済ソリューションユーザー検証 >ユーザー検証user_validation
決済ソリューション >支払いpayment
サブスクリプションユーザー検証 >ユーザー検証user_validation
決済ソリューション >支払いpayment

注意

テストセクションにテストがパスしていないという警告が表示された場合は、ウェブフックリスナーのウェブフック応答設定を確認します。テストでのエラーの理由はテスト結果に示されます。

例:

テストには、専門サイトwebhook.siteを使用します。

無効な署名に対する応答のテスト」セクションにエラーが表示されます。

エクソーラが間違った署名を持つウェブフックを送信し、ハンドラーがINVALID_SIGNATUREエラーコードを指定する4xx HTTPコードで応答することを期待しているために発生します。

webhook.siteは、署名が間違ったウェブフックを含むすべてのウェブフックに応答して200 HTTPコードを送信します。期待される4xx HTTPコードが得られないため、テスト結果にエラーが表示されます。

まとめたウェブフックを使用したシナリオのテストプロセスを以下に説明します。

決済ソリューションとストア

決済ソリューションとストア」タブでは、次のウェブフックをテストできます:

ウェブフックをテストするには:

  1. ウェブフックのテストセクションで、「決済ソリューションとストア」タブに移動します。
  2. ドロップダウンリストからアイテムタイプを選択してください。パブリッシャーアカウントでこのアイテムタイプをまだ設定していない場合は、ボタンをクリックして設定してく ださい。アイテム作成後、ウェブフックテストセクションに戻り、次のステップに進んでください。
  3. 必要なフィールドに入力します:
    • ユーザーID — テスト時には、任意の文字と数字の組み合わせを使用できます。
    • エクソーラ注文ID」フィールドに任意の値を入力してください。
    • エクソーラインボイスID — エクソーラ側のトランザクションID。テスト時には、任意の数値を使用できます。
    • インボイスID ゲーム側のトランザクションID。テスト時には、任意の文字と数字の組み合わせを使用できます。これは成功した支払いに必須のパラメータではありませんが、トランザクショ ンIDをエクソーラ側のトランザクションIDとリンクさせるために渡すことができます。
    • 金額 — 決済金額。テスト時には、任意の数値を使用できます。
    • 通貨 — ドロップダウンリストから通貨を選択します。
    • ドロップダウンリストからアイテムのSKUを選択し、数量を指定します。同じタイプの複数のアイテムを選択するには、「+」をクリックして新しい行に追加します。
  4. ウェブフックをテスト」をクリックします。

指定されたデータを含むユーザー検証注文支払い完了および注文キャンセルウェブフックが、指定されたURLに送信されます。各ウェブフックタイプのテスト結果は、「ウェブフックをテス 」ボタンの下に表示されます。

プロジェクト設定 > 統合設定セクションで公開ユーザーIDを使用するボックスにチェックが入っている場合、 ユーザー検索ウェブフックは、お客様のウェブフックサーバーのURLにも送信され、テスト結果が表示されます。

各ウェブフックについて、成功したシナリオとエラーが発生したシナリオの両方の処理を設定する必要があります。

Payments testing 
section

サブスクリプション

注意

ウェブフックをテストするには、パブリッシャーアカウントのアイテムカタログ > サブスクリプションセクションで少なくとも1つのサブスクリプションプランが作成されている必要があります。

サブスクリプション」タブでは、次のウェブフックをテストできます:

注意

その他のサブスクリプション管理シナリオのテストに関する詳細情報については、統合ガイドを参照してください。

ウェブフックをテストするには:

  1. テストセクションで、サブスクリプションタブに移動します。
  2. 必要なフィールドに入力します:
    • ユーザーID — テスト時には、任意の文字と数字の組み合わせを使用できます。
    • エクソーラインボイスID — エクソーラ側のトランザクションID。テスト時には、任意の数値を使用できます。
    • 公開ユーザーID — メールアドレスやニックネームなど、ユーザーに知られているIDです。このフィールドは、プロジェクトのプロジェクト設定 > 統合設定セクションで公開ユーザーIDを使 用するチェックボックスにチェックを入れている場合に表示されます。
    • 金額 — 決済金額。テスト時には、任意の数値を使用できます。
    • 通貨 — ドロップダウンリストから通貨を選択します。
    • プランID — サブスクリプションプラン。ドロップダウンリストからプランを選択します。
    • サブスクリプション製品 — ドロップダウンリストから製品を選択します(オプション)。このリストは、プロジェクトで製品が設定されている場合に表示されます。
    • インボイスID ゲーム側のトランザクションID。テスト時には、任意の文字と数字の組み合わせを使用できます。これは成功した支払いに必須のパラメータではありませんが、トランザクショ ンIDをエクソーラ側のトランザクションIDとリンクさせるために渡すことができます。
    • 試行期間お試し期間なしでのサブスクリプションの購入をテストす るか、またはサブスクリプションの更新 をテストするには、値を0に指定します。
    1. テスト」をクリックします。

指定したURLに、データが入力されたウェブフックを受け取ります。各ウェブフックのテスト結果は、成功したシナリオとエラーが発生したシナリオの両方で、「テスト 」ボタンの下に表示されます。

ウェブフックリスナー

ウェブフックリスナーは、指定されたURLアドレスでウェブフックを受信し、署名を生成しエクソーラウェブフックサーバーに応答を送信することができるプログラムコードです。

注意

Pay Station PHP SDKライブラリには、ウェブフックを処理するための既製のクラスが含まれています。

アプリケーション側で、以下のIPアドレスからのウェブフックの受信を実装してください:

  • 185.30.20.0/24
  • 185.30.21.0/24
  • 185.30.22.0/24
  • 185.30.23.0/24
  • 34.102.38.178
  • 34.94.43.207
  • 35.236.73.234
  • 34.94.69.44
  • 34.102.22.197

もし「ログイン」製品を統合している場合、以下のIPアドレスからのウェブフックの処理も追加してください:

  • 34.94.0.85
  • 34.94.14.95
  • 34.94.25.33
  • 34.94.115.185
  • 34.94.154.26
  • 34.94.173.132
  • 34.102.48.30
  • 35.235.99.248
  • 35.236.32.131
  • 35.236.35.100
  • 35.236.117.164

制限:

  • アプリケーションのデータベースに同じIDで成功したトランザクションが複数存在することは許可されていません。
  • ウェブフックリスナーがデータベースにすでに存在するIDを持つウェブフックを受信した場合、このトランザクションの以前の処理結果を返す必要があります。ユーザーに重複 した購入をクレジットし、データベースに重複したレコードを作成することは推奨されません。

署名の生成

安全なデータ転送を確保するには、ウェブフックが実際にエクソーラサーバーから送信され、転送中に改ざんされていないことを確認する必要があります。これを行うには、受信 したリクエスト本文のペイロードに基づいて独自の署名を生成し、それを着信リクエストのauthorizationヘッダーで提供される署名と比較してください。両方 の署名が一致する場合、そのウェブフックは正規のものであり、安全に処理できます。

検証ステップ:

  1. 着信ウェブフックリクエストのauthorizationヘッダーから署名を取得します。ヘッダーの形式はSignature <signature_value>です。

  2. ウェブフックのリクエスト本文をJSON形式で取得してください。

    注意

    JSONペイロードは、受信したものをそのまま使用してください。ペイロード をパースしたり再エンコードしたりしないでください。フォーマットが変更され、署名検証が失敗する原因となります。

  3. 比較用に独自の署名を生成します:

    1. JSONペイロードとプロジェクトの秘密鍵を連結します。秘密鍵は文字列の末尾に追加してください。
    2. 結果の文字列にSHA-1暗号ハッシュ関数を適用します。結果は小文字の16進数文字列になります。
    3. 生成した署名をauthorizationヘッダーからの署名と比較してください。両者が一致すれば、ウェブフックは信頼できるものです。

    以下に、署名生成の実装例を各種プログラミング言語で示します: C#、C++、Go、PHP、Node.js。

    ウェブフック(HTTP)の例:

    POST /your_uri HTTP/1.1
    host: your.host
    accept: application/json
    content-type: application/json
    content-length: 165
    authorization: Signature 52eac2713985e212351610d008e7e14fae46f902
    {
      "notification_type":"user_validation",
      "user":{
          "ip":"127.0.0.1",
          "phone":"18777976552",
          "email":"email@example.com",
          "id":1234567,
          "name":"Xsolla User",
          "country":"US"
      }
    }

    ウェブフック(curl)の例:

    curl -v 'https://your.hostname/your/uri' \
    -X POST \
    -H 'authorization: Signature 52eac2713985e212351610d008e7e14fae46f902' \
    -d '{
      "notification_type":
        "user_validation",
        "user":
          {
            "ip": "127.0.0.1",
            "phone": "18777976552",
            "email": "email@example.com",
            "id": 1234567,
            "name": "Xsolla User",
            "country": "US"
          }
        }'

    C#で署名生成の実装例(一般サンプル):

    このコードサンプルは、.NET Framework 4.0以降、および.NET Coreやその他の最新の.NETバージョンと互換性があります。署名検証には、タイミング攻撃を防ぐために、ConstantTimeEqualsメソッドによる定数時間比較が使用されています。

    using System;
    using System.Security.Cryptography;
    using System.Text;
    public static class XsollaWebhookSignature
    {
        public static string ComputeSha1(string jsonBody, string secretKey)
        {
            // Concatenation of the JSON from the request body and the project's secret key
            string dataToSign = jsonBody + secretKey;
            using (SHA1 sha1 = SHA1.Create())
            {
                byte[] hashBytes = sha1.ComputeHash(Encoding.UTF8.GetBytes(dataToSign));
                // Convert hash bytes to lowercase hexadecimal string
                var hexString = new StringBuilder(hashBytes.Length * 2);
                foreach (byte b in hashBytes)
                {
                    hexString.Append(b.ToString("x2"));
                }
                return hexString.ToString();
            }
        }
        public static bool VerifySignature(string jsonBody, string secretKey, string receivedSignature)
        {
            string computedSignature = ComputeSha1(jsonBody, secretKey);
            string receivedSignatureLower = receivedSignature.ToLower();
            // Use constant-time comparison to prevent timing attacks
            return ConstantTimeEquals(computedSignature, receivedSignatureLower);
        }
        private static bool ConstantTimeEquals(string a, string b)
        {
            if (a.Length != b.Length)
            {
                return false;
            }
            int result = 0;
            for (int i = 0; i < a.Length; i++)
            {
                result |= a[i] ^ b[i];
            }
            return result == 0;
        }
    }

    C#による署名生成の実装例(.NET 5.0以降):

    Convert.ToHexStringメソッドを使用するには、.NET 5.0 以降が必要です。

    .NET 7.0以降をお持ちの場合は、 CryptographicOperations.FixedTimeEqualsメソッドの代わりにConstantTimeEqualsを使用することもできます。

    // For .NET 5.0 and later, you can use the more concise Convert.ToHexString method:
    using System;
    using System.Security.Cryptography;
    using System.Text;
    public static class XsollaWebhookSignature
    {
        public static string ComputeSha1(string jsonBody, string secretKey)
        {
            string dataToSign = jsonBody + secretKey;
            using var sha1 = SHA1.Create();
            byte[] hashBytes = sha1.ComputeHash(Encoding.UTF8.GetBytes(dataToSign));
            return Convert.ToHexString(hashBytes).ToLower();
        }
        public static bool VerifySignature(string jsonBody, string secretKey, string receivedSignature)
        {
            string computedSignature = ComputeSha1(jsonBody, secretKey);
            string receivedSignatureLower = receivedSignature.ToLower();
            // Use constant-time comparison to prevent timing attacks
            return ConstantTimeEquals(computedSignature, receivedSignatureLower);
        }
        private static bool ConstantTimeEquals(string a, string b)
        {
            if (a.Length != b.Length)
            {
                return false;
            }
            int result = 0;
            for (int i = 0; i < a.Length; i++)
            {
                result |= a[i] ^ b[i];
            }
            return result == 0;
        }
    }

    C#による署名生成の実装例(.NET 7.0以降):

    .NET 7.0以降をお持ちの場合は、CryptographicOperations.FixedTimeEqualsメソッドを使用できます。

    // For .NET 7.0+, you can use the built-in CryptographicOperations.FixedTimeEquals:
    using System.Security.Cryptography;
    public static bool VerifySignature(string jsonBody, string secretKey, string receivedSignature)
    {
        string computedSignature = ComputeSha1(jsonBody, secretKey);
        byte[] computedBytes = Encoding.UTF8.GetBytes(computedSignature);
        byte[] receivedBytes = Encoding.UTF8.GetBytes(receivedSignature.ToLower());
        return CryptographicOperations.FixedTimeEquals(computedBytes, receivedBytes);
    }

    C++での署名生成の実装例:

    #include <string>
    #include <sstream>
    #include <iomanip>
    #include <openssl/sha.h>
    class XsollaWebhookSignature {
    public:
        static std::string computeSha1(const std::string& jsonBody, const std::string& secretKey) {
            // Concatenation of the JSON from the request body and the project's secret key
            std::string dataToSign = jsonBody + secretKey;
            unsigned char digest[SHA_DIGEST_LENGTH];
            // Create SHA1 hash
            SHA1(reinterpret_cast<const unsigned char*>(dataToSign.c_str()),
                 dataToSign.length(), digest);
            // Convert to lowercase hexadecimal string
            std::ostringstream hexStream;
            hexStream << std::hex << std::setfill('0');
            for (int i = 0; i < SHA_DIGEST_LENGTH; ++i) {
                hexStream << std::setw(2) << static_cast<unsigned int>(digest[i]);
            }
            return hexStream.str();
        }
        static bool verifySignature(const std::string& jsonBody, const std::string& secretKey, const std::string& receivedSignature) {
            std::string computedSignature = computeSha1(jsonBody, secretKey);
            // Timing-safe comparison
            if (computedSignature.length() != receivedSignature.length()) {
                return false;
            }
            volatile unsigned char result = 0;
            for (size_t i = 0; i < computedSignature.length(); ++i) {
                result |= (computedSignature[i] ^ receivedSignature[i]);
            }
            return result == 0;
        }
    };

    Goでの署名生成の実装例:

    package main
    import (
    	"crypto/sha1"
        "crypto/subtle"
    	"encoding/hex"
    	"strings"
    )
    type XsollaWebhookSignature struct{}
    func (x *XsollaWebhookSignature) ComputeSha1(jsonBody, secretKey string) string {
    	// Concatenation of the JSON from the request body and the project's secret key
    	dataToSign := jsonBody + secretKey
    	// Create SHA1 hash
    	h := sha1.New()
    	h.Write([]byte(dataToSign))
    	signature := h.Sum(nil)
    	// Convert to lowercase hexadecimal string
    	return strings.ToLower(hex.EncodeToString(signature))
    }
    func (x *XsollaWebhookSignature) VerifySignature(jsonBody, secretKey, receivedSignature string) bool {
    	computedSignature := x.ComputeSha1(jsonBody, secretKey)
    	receivedSignatureLower := strings.ToLower(receivedSignature)
    	// Use constant time comparison to prevent timing attacks
    	return subtle.ConstantTimeCompare([]byte(computedSignature), []byte(receivedSignatureLower)) == 1
    }

    PHPでの署名生成の実装例:

    <?php
    class XsollaWebhookSignature
    {
        /**
         * Compute SHA1 signature from webhook JSON body and secret key
         *
         * @param string $jsonBody The raw JSON body from webhook
         * @param string $secretKey The project's secret key
         * @return string The lowercase SHA1 signature
         */
        public static function computeSha1(string $jsonBody, string $secretKey): string
        {
            // Concatenation of the JSON from the request body and the project's secret key
            $dataToSign = $jsonBody . $secretKey;
            // Generate SHA1 signature
            $signature = sha1($dataToSign);
            return strtolower($signature);
        }
        /**
         * Verify webhook signature using timing-safe comparison
         *
         * @param string $jsonBody The raw JSON body from webhook
         * @param string $secretKey The project's secret key  
         * @param string $receivedSignature The signature from authorization header
         * @return bool True if signature is valid, false otherwise
         */
        public static function verifySignature(string $jsonBody, string $secretKey, string $receivedSignature): bool
        {
            $computedSignature = self::computeSha1($jsonBody, $secretKey);
            // Use hash_equals for timing-safe comparison
            return hash_equals($computedSignature, strtolower($receivedSignature));
        }
    }
    ?>

    Node.jsでの署名生成の実装例:

    const crypto = require('crypto');
    class XsollaWebhookSignature {
        // IMPORTANT: jsonBody must be the raw JSON string exactly as received from Xsolla
        static computeSha1(jsonBody, secretKey) {
            // Concatenation of the JSON from the request body and the project's secret key
            const dataToSign = jsonBody + secretKey;
            // Create SHA1 hash
            const hash = crypto.createHash('sha1');
            hash.update(dataToSign, 'utf8');
            // Convert to lowercase hexadecimal string
            return hash.digest('hex').toLowerCase();
        }
        static verifySignature(jsonBody, secretKey, receivedSignature) {
            const computedSignature = this.computeSha1(jsonBody, secretKey);
            const cleanReceivedSignature = receivedSignature.toLowerCase();
            // Check if signatures have the same length before using timingSafeEqual
            if (computedSignature.length !== cleanReceivedSignature.length) {
                return false;
            }
            try {
                return crypto.timingSafeEqual(
                    Buffer.from(computedSignature, 'hex'),
                    Buffer.from(cleanReceivedSignature, 'hex')
                );
            } catch (error) {
                // Return false if there's any error (e.g., invalid hex characters)
                return false;
            }
        }
    }

    ウェブフックへの応答の送信

    ウェブフックの受信を確認するには、サーバーは以下を返す必要があります:

    • 成功した応答の場合は、200201、または204HTTPコード。
    • 400HTTPコードは問題の説明を含む、指定されたユーザーが見つからないか、無効な署名が渡 された場合に送信されます。ウェブフックハンドラーは、サーバーで一時的な問題が発生した場合に5xxHTTPコードを返すこともあります。

    エクソーラサーバーが 注文支払い完了注文キャンセルへのレスポンスを受け取らなかった場合、または5xxコードのレスポンスを受け取った場合、ウェブフックは以下の スケジュールに従って再送されます:

    • 5分間隔で2回の試行
    • 15分間隔で7回の試行
    • 60分間隔で10回の試行

    ウェブフックの送信は、最初の送信から12時間以内に最大20回まで試行されます。

    決済返金ウェブフックの再試行ロジックは、対応するウェーブフックページに記載されています。

    注意

    以下の条件がすべて満たされている場合でも、支払いはユーザーに返金されます:

    • 返金はエクソーラによって開始されました。
    • ウェーブフックに対する応答として、4xxステータスコードが返された、またはすべての再試行後に応答がなかった、あるいは5xxステータスコードが返された場合。

    エクソーラサーバーがユーザー認証ウェブフックへの応答を受信しなかった場合、または400または5xxのコードで応答を受信した場合、ユーザー認証ウェブフックは再送信されません。この場合、ユーザーにはエラーが表示され、支払い注文支払い完了ウェブフックは送信されません。

    エラー

    HTTPコード400のエラーコード:

    コードメッセージ
    INVALID_USER無効なユーザー
    INVALID_PARAMETER無効なパラメータ
    INVALID_SIGNATURE無効な署名
    INCORRECT_AMOUNT不正確な金額
    INCORRECT_INVOICE不正確なインボイス
    HTTP/1.1 400 Bad Request
    {
        "error":{
            "code":"INVALID_USER",
            "message":"Invalid user"
        }
    }

    適用事例

    セキュリティ

    以下のガイドラインに従ってください:

    • 有効な証明書を備えたHTTPSのみを使用してください。
    • 署名の検証は必ずリクエスト本文の生データに対して行ってください。データの解析や再エンコードは行わないでください
    • 機密データをURLに含めたり、エラーメッセージに技術的な詳細情報を記載したりしないでください。
    • ウェーブフックのエンドポイントをCSRFミドルウェアの対象から除外してください — エクソーラからの受信リクエストにはCSRFトークンが含まれていないため、この設定がないと拒否されます。
    • エクソーラIPアドレスを許可リストに追加してください。

    ウェブフックハンドラのアーキテクチャ

    以下のガイドラインに従ってください:

    1. 本文とヘッダーを変更することなく、そのままの状態でPOSTリクエストを受け取ります。
    2. ウェブフックの署名を検証し 、適切なステータスコードを返してください。
      • 4xx — 署名が一致しない場合。
      • 2xx —成功した場合。メインのビジネスロジックを実行するに、「204 No Content」を返すことを推奨します。「200 OK」も受け入れ可能です。
    3. ペイロードを非同期ジョブまたはキューに渡し、さらなる処理を行います。
    4. 冪等性を実装してくだ さい。同じウェーブフックを複数回受信した場合でも、システムが適切に処理できるようにする必要があります。

    フローの例:

    HTTP POST /webhooks/xsolla
      read raw_body, headers
      if !verify_signature(raw_body, headers['authorization']):
         return 400 {"error":{"code":"INVALID_SIGNATURE","message":"Invalid signature"}}
      enqueue(raw_body)
      return 204  # or 200

    冪等性と重複

    以下のガイドラインに従ってください:

    • トランザクションIDおよび/または external ID、注文IDを冪等性キーとし て使用してください。
    • 処理済みのIDを保存し、重複するリクエストを受信した場合は前回の結果を返却します。
    • アイテムの重複付与、データベースへの二重登録、および二重課金を回避してください。
    • 逐次配信においては、前のイベントでエラーが発生すると、それ以降のすべてのイベントの処理がブロックされる点に注意してください。

    システムの回復性

    以下のガイドラインに従ってください:

    • サードパーティへのAPIコール、請求処理、アイテム付与などのリソース消費の激しい操作には、キューと非同期処理を使用してください。
    • ウェブフックハンドラにタイムアウト(1〜3秒)を設定してください。一時的な障害の場合は、エクソーラのの再試行メカニズムを活用してください。
    • フックハンドラ内で再試行を実装しないでください。再配信はエクソーラによって処理されます。
    • ウェブフックの配信日時と処理ステータスをログに記録してください。また、5xx エラーの急増や再配信の発生に対するアラートを設定してください。
    • ウェブフックに含まれる相関IDを、自システムのログやモニタリングシステム(APM)に伝播させてください。
    • エラーログの記録とモニタリングをセットアップしてください。修復不可能な障害については、ジョブをデッドレターキュー(DLQ)に移動させてください。また、冪等性メカ ニズムによって保護された、イベントを再実行するための安全なツールを開発してください。

    実装例

    購入成功 - 初回試行でアイテムが付与されました:

    購入

    重複配信(初回試行時にパートナーのタイムアウトが発生しました)

    タイムアウト

    返金:

    返金

    パートナー側の機能障害

    パートナー側の機能障害

    よくある質問

    ウェブフックプロトコルにはHTTPSを使用する必要がありますか?

    はい。

    複数のURLで支払いに関するウェブフックを受信することはできますか?

    いいえ。支払いウェブフックはサーバー間プロトコルを使用しており、プロジェクト設定で指定された単一のURLに送信されます。ゲーム、ウェブサイト、またはモバイルアプリケーションで通知を受け取りたい場合は、お客様のサーバー側でウェ ブフックの送信設定を行い、エクソーラとお使いのゲーム間でデータを渡すようにしてください。また、開発者コンソールからウェブフックのテストを行うことも可能です。

    注意

    ローカル環境で統合のテストを行っている場合、エクソーラからの`POST`リクエストはhttp://localhost:3000/my-webhook-endpointのようなURLには届きません。外部からのアクセスを可能にするトンネルを作成できるNgrokなどのサービスを使用することで、ローカル環境でエクソーラからのリクエストを受信できるようになります。詳細については、ngrokに関するドキュメントを参照してください。

    エクソーラからの通知がウェブフックURLに送信されなかったのはなぜですか?

    ウェブフックサーバーが、HTTPリクエストのPOSTおよびGETメソッドをサポートしていることを確認してください。

    処理中のトランザクションIDの重複を防ぐにはどうすればよいですか?

    external IDを使用してください。これはお客様のシステム内の注文に割り当てられた、ゲーム内でのトランザクションIDを指します。エクソーラ側では、external IDはトランザクションIDにリンクされており、これによりエクソーラは同じトランザクションに対する重複支払いを防止できます。設定の詳細については、こちらのドキュ メントを参照してください。

    ウェブフックを利用する際の適用事例はありますか?

    以下の対応を推奨します:

    • 署名検証後、直ちに「204」または「200」を返します。
    • 変更を加えず、生のリクエスト本文に対してウェブフックの署名を検証します。
    • すべての演算に対して冪等性を実装します。
    • すべてのイベントをログに記録し、エラーモニタリングをセットアップします。
    • URLに機密データを含めることを避け、エラーメッセージに技術的な詳細情報を記載したりしないでください。

    詳細については、適用事例セクションを参照してください。

    ウェブフック統合のチェックリスト

    ウェブフックを正しく機能させるために、本番環境へのリリース前に以下のことが整っていることを確認してください:

    • HTTPSが使用されています。
    • ウェブフックの署名検証が、リクエスト本文を変更することなく、生データに対して実装されています。
    • 署名が確認されるとすぐに「204/200」という応答が返されます。
    • すべての操作に対して、冪等性が実装されています。
    • エラーログの記録とモニタリングが設定されています。
    • 機密データはURLには含まれず、技術的な詳細はエラーメッセージにも表示されません。
    • エクソーラの再試行ロジックに基づき、ウェブフックの再試行がサポートされています。
    • 統合プロセス全体がドキュメント化されています。

    ウェブフックリスト

    注意

    通知タイプはnotification_typeパラメータで送信されます。

    ウェブフック通知タイプ説明
    ユーザー検証user_validationユーザーがゲーム内に存在するかどうかを確認するために送信されます。
    ユーザー検索user_searchパブリックユーザーIDに基づいてユーザー情報を取得するために送信されます。
    決済paymentユーザーが決済を完了した場合に送信されます。
    返金refund何らかの理由で決済をキャンセルする必要がある場合に送信されます。
    一部返金partial_refund何らかの理由で決済を一部キャンセルする必要がある場合に送信されます。
    支払いが拒否されましたps_declined支払いが決済システムによって拒否されたときに送信されます。
    AFSが拒否したトランザクションafs_rejectAFSチェック中にトランザクションが拒否された場合に送信されます。
    AFSが更新したトランザクションafs_black_listAFSブロックリストが更新される場合に送信されます。
    作成されたサブスクリプションcreate_subscriptionユーザーがサブスクリプションを作成する場合に送信されます。
    更新されたサブスクリプションupdate_subscriptionサブスクリプションが更新または変更された場合に送信されます。
    キャンセルされたサブスクリプションcancel_subscriptionサブスクリプションがキャンセルされた場合に送信されます。
    非更新サブスクリプションnon_renewal_subscriptionステータスが非更新に設定される場合に送信されます。
    決済アカウントを追加するpayment_account_addユーザーが支払いアカウントを追加または保存した場合に送信されます。
    決済アカウントを削除するpayment_account_removeユーザーが保存済みアカウントから決済アカウントを削除する場合に送信されます。
    ウェブショップでのユーザー検証-ウェブショップのサイトから送信され、ゲーム内にユーザーが存在するかどうかを確認します。
    パートナー側でのカタログ個人用設定partner_side_catalogユーザーがストアと直接交信する時に送信されます。
    注文支払い完了order_paid注文が支払われたときに送信されます。
    注文キャンセルorder_canceled注文がキャンセルされたときに送信されます。
    紛争dispute新しい紛争手続きが開かれたときに送信されます。
    OpenAPI記述をダウンロード
    言語
    サーバー
    https://api.xsolla.com/merchant/v2/
    Mock server
    https://xsolla.redocly.app/_mock/ja/webhooks/

    ユーザー検証

    Webhook

    決済ソリューション

    Webhook

    まとめたウェブフック

    Webhook

    個別のウェブフック

    Webhook

    注文キャンセル(支払いおよび取引の詳細なし)Webhook

    リクエスト

    ユーザー、パートナー、またはシステムによって支払いがキャンセルされた場合、エクソーラは指定されたURLにorder_canceled ェーブフックを送信します。このウェーブフックには、キャンセルされたアイテムに関する情報と、キャンセルされた注文の詳細が含まれています。

    支払いが成功しなかった場合、ウェブフックは送信されません。例:

    • 決済UIは開かれましたが、ユーザーが注文の支払いを行われません
    • 決済UIが開かれましたが、支払いの実行中にエラーが発生しました

    推奨されるウェーブフックの処理時間は3秒以内です。

    ボディapplication/json
    custom_parametersobject

    追加情報。

    itemsArray of バージョン = 1 (object) or バージョン = 2 (object)必須

    ユーザーが購入したアイテムのリスト。

    配列に含まれるパラメータのセットは、ウェブフックのバージョンによって異なります。バージョン2は、追加のパラメータが含まれています:is_freeis_b onusおよびis_bundle_content。バージョンを切り替えるには、ウェブフック設定に関する情報を更新するAPIコールでversionパラメータにその番号を渡します。

    One of:
    items[].​amountstring必須

    数量に基づいたアイテムの総コスト。

    items[].​custom_attributesobject

    アイテムの属性と値を含むJSONオブジェクト。

    items[].​is_pre_orderboolean必須

    true」の場合、アイテムは先行予約です。

    items[].​promotionsArray of objects(items.promotions)必須

    注文内の特定のアイテムに適用されたプロモーションです。 この配列は以下のいずれかのケースで返されます:

    • 特定のアイテムに対して割引プロモーションが設定されている場合。
    • 選択されたアイテムの割引設定がされたプロモーションコードが適用されている場合。

    アイテムレベルのプロモーションが適用されていない場合は、空の配列が返されます。

    items[].​promotions[].​amount_with_discountstring

    割引なしのアイテムの総コスト。

    items[].​promotions[].​amount_without_discountstring

    割引なしのアイテムの総コスト。

    items[].​promotions[].​sequenceinteger

    プロモーションアプリケーションの注文。

    items[].​quantityinteger必須

    アイテムの数量。

    items[].​skustring(items.sku)必須

    アイテムの一意のID。「game_key」タイプのアイテムの場合、「sku_drm」形式の値が使用されます。

    items[].​typestring(items.type)必須

    アイテムタイプ。 仮想通貨パッケージを含むbundleタイプアイテムの場合は、items配列には以下が表示されます:

    • バンドルまたは仮想通貨パッケージのパラメータ
    • バンドルに含まれるアイテムまたはパッケージに含まれる通貨

    value_pointタイプは、ロイヤルティポイントの操作、つまりポイントが使用または付与される際に使用されます。

    列挙型"virtual_good""virtual_currency""game_key""bundle""value_point"
    notification_typestring(notification_type)必須

    通知タイプ。

    orderobject必須

    注文に関する情報。

    order.​amountstring必須

    選択された通貨に基づくカートの合計金額です。

    order.​commentstring or null必須

    注文に対するユーザーのコメント。

    order.​couponsArray of objects

    適用されたクーポン。クーポンが適用されていない場合は、配列は返されません。

    order.​coupons[].​codestring

    適用されたクーポンのコードです。

    order.​coupons[].​external_idstring

    External ID。

    order.​currencystring必須

    注文の通貨。仮想通貨はSKUを使用し、実際通貨は3文字のISO4217コードを使用します。

    order.​currency_typestring(currency-type)必須

    決済通貨タイプ。無料注文の場合はunknownの値が指定されています。

    列挙型 値説明
    loyalty_point

    ロイヤルティポイント

    real

    実際通貨

    unknown

    無料注文

    virtual

    仮想通貨

    order.​idinteger必須

    エクソーラ側でのユーザーの注文の一意の識別子。

    order.​invoice_idstring or null必須

    実際通貨による支払い請求書ID。仮想通貨の決済また無料アイテムは、nullの値を使用します。

    order.​modestring必須

    決済モード。defaultは実際の支払いに、sandboxはテスト支払いに使用されます。

    列挙型"default""sandbox"
    order.​platformstring or null必須

    決済プラットフォーム。xsollaの値は、Xsollaを介した支払いに使用されます。その他の支払いについては、ゲームパブリッシングプラットフォームの名前に対応する値が使用されます:playstation_networkxbox_livepc_standalonenintendo_shopgoogle_playapp_store_iosandroid_standaloneios_standaloneandroid_otherios_otherpc_other

    列挙型"xsolla""playstation_network""xbox_live""pc_standalone""nintendo_shop""google_play""app_store_ios""android_standalone""ios_standalone""android_other"
    order.​promocodesArray of objects

    適用されたプロモーションコード。プロモーションコードが適用されていない場合、配列は返されません。

    order.​promocodes[].​codestring

    適用されたプロモーションコードのコードです。

    order.​promocodes[].​external_idstring

    External ID。

    order.​promotionsArray of objects(order.promotions)必須

    注文全体に適用されたプロモーションです。 この配列は、次のいずれかのケースで返されます。:

    • 購入割引 設定のプロモーションコードなど、購入合計金額に影響するプロモーションが設定されている場合。
    • 購入に割引は適用されませんが、ボーナスアイテムが注文に追加される場合。この場合、割引ありのコスト(amount_with_discount)と割引なしのコスト(amount_without_discount)の値が返され、割引が適用されていないため両者は同じ値になります。

    注文レベルのプロモーションが適用されていない場合は、空の配列が返されます。

    order.​promotions[].​amount_with_discountstring

    割引なしのアイテムの総コスト。

    order.​promotions[].​amount_without_discountstring

    割引なしのアイテムの総コスト。

    order.​promotions[].​sequenceinteger

    プロモーションアプリケーションの注文。

    order.​statusstring必須

    注文状況。

    userobject必須

    ユーザー情報。

    user.​countrystring(user.country)

    ユーザーの国。2文字の国コード(大文字)は、ISO 3166-1 alpha-2に従って使用されます。

    user.​emailstring必須

    ユーザーのメールアドレス。

    user.​external_idstring必須

    ユーザーID。

    curl -v 'https://your.hostname/your/uri' \
    -X POST \
    -H 'accept: application/json' \
    -H 'content-type: application/json' \
    -H 'authorization: Signature d09695066c52c1b8bdae92f2d6eb59f5b5f89843' \
    -d '{
        "notification_type": "order_canceled",
        "items": [
          {
            "sku": "com.xsolla.v.item_1",
            "type": "virtual_good",
            "is_pre_order": false,
            "quantity": 3,
            "amount": "1000",
            "promotions": [
              {
                "amount_without_discount": "6000",
                "amount_with_discount": "5000",
                "sequence": 1
              },
              {
                "amount_without_discount": "5000",
                "amount_with_discount": "4000",
                "sequence": 2
              }
            ],
            "custom_attributes": {
                "purchased": 0,
                "attr": "value"
              }
          },
          {
            "sku": "com.xsolla.v.item_new_1",
            "type": "bundle",
            "is_pre_order": false,
            "quantity": 1,
            "amount": "1000",
            "promotions": []
          },
          {
            "sku": "com.xsolla.gold_1",
            "type": "virtual_currency",
            "is_pre_order": false,
            "quantity": 1500,
            "amount": "[null]",
            "promotions": []
          }
        ],
        "order": {
          "id": 1,
          "mode": "default",
          "currency_type": "virtual",
          "currency": "sku_currency",
          "amount": "2000",
          "status": "paid",
          "platform": "xsolla",
          "comment": null,
          "invoice_id": "1",
          "promotions": [
            {
              "amount_without_discount": "4000",
              "amount_with_discount": "2000",
              "sequence": 1
            }
          ],
          "promocodes": [
            {
              "code": "promocode_some_code",
              "external_id": "promocode_sku"
            }
          ],
          "coupons": [
            {
              "code": "WINTER2021",
              "external_id": "coupon_sku"
            }
          ]
        },
        "user": {
          "external_id": "id_xsolla_login_1",
          "email": "email@example.com",
          "country": "US"
        }
    
    }'

    レスポンス

    処理が成功したことを示すために戻ります。

    注文支払い完了(支払いおよび取引の詳細なし)Webhook

    リクエスト

    エクソーラは、次の条件が満たされると、指定されたURLにorder_paidウェブフックを送信します:

    1. ユーザーは注文の支払いに成功しました。
    2. エクソーラは、決済ウェブフックの正常な処理に関する応答を受け取りました。

    order_paidウェブフックには、購入したアイテムとトランザクションの詳細に関する情報が含まれています。

    次の場合、order_paidウェブフックは送信されません:

    • 決済が失敗しました。例:
      • 決済フォームは開かれましたが、ユーザーは注文の支払いをしていません
      • 決済フォームが開かれましたが、支払い中にエラーが発生しました
    • 決済ウェブフックの正常な処理に関する応答が受信されていません。

    order_paidウェブフックの処理時間は3秒未満にすることをお勧めします。

    予想される回答は、「応答」セクションに記載されています。他の応答コードを使用できます。応答コードと自動返金機能の接続に応じて、エクソーラ側のウェブ フック処理ロジックは以下のようになります:

    応答コード自動返金は無効になっています(デフォルト)自動返金が有効になっています
    400401402403404409422415操作なしユーザーへの自動返金
    200201204操作なし操作なし
    別のコードまたはウェブフックへの応答なし指定された時間間隔内に複数のウェブフックが送信されます。5分間隔で2回、15分間隔で7回、60分間隔で10回試行されます。指定された時間間隔内に複数のウェブフックが送信されます。5分間隔で2回、15分間隔で7回、60分間隔で10回試行されます。すべてのウェブフックが送信されても正常な応答が受信されない場合、ユーザーに自動返金が発行されます。

    自動返金機能を接続するには、カスタマーサクセスマネージャーにお問い合わせいただくか、csm@xsolla.comまで電子メールをお送りください。

    ボディapplication/json
    custom_parametersobject

    追加情報。

    itemsArray of バージョン = 1 (object) or バージョン = 2 (object)必須

    ユーザーが購入したアイテムのリスト。

    配列に含まれるパラメータのセットは、ウェブフックのバージョンによって異なります。バージョン2は、追加のパラメータが含まれています:is_freeis_b onusおよびis_bundle_content。バージョンを切り替えるには、ウェブフック設定に関する情報を更新するAPIコールでversionパラメータにその番号を渡します。

    One of:
    items[].​amountstring必須

    数量に基づいたアイテムの総コスト。

    items[].​custom_attributesobject

    アイテムの属性と値を含むJSONオブジェクト。

    items[].​is_pre_orderboolean必須

    true」の場合、アイテムは先行予約です。

    items[].​promotionsArray of objects(items.promotions)必須

    注文内の特定のアイテムに適用されたプロモーションです。 この配列は以下のいずれかのケースで返されます:

    • 特定のアイテムに対して割引プロモーションが設定されている場合。
    • 選択されたアイテムの割引設定がされたプロモーションコードが適用されている場合。

    アイテムレベルのプロモーションが適用されていない場合は、空の配列が返されます。

    items[].​promotions[].​amount_with_discountstring

    割引なしのアイテムの総コスト。

    items[].​promotions[].​amount_without_discountstring

    割引なしのアイテムの総コスト。

    items[].​promotions[].​sequenceinteger

    プロモーションアプリケーションの注文。

    items[].​quantityinteger必須

    アイテムの数量。

    items[].​skustring(items.sku)必須

    アイテムの一意のID。「game_key」タイプのアイテムの場合、「sku_drm」形式の値が使用されます。

    items[].​typestring(items.type)必須

    アイテムタイプ。 仮想通貨パッケージを含むbundleタイプアイテムの場合は、items配列には以下が表示されます:

    • バンドルまたは仮想通貨パッケージのパラメータ
    • バンドルに含まれるアイテムまたはパッケージに含まれる通貨

    value_pointタイプは、ロイヤルティポイントの操作、つまりポイントが使用または付与される際に使用されます。

    列挙型"virtual_good""virtual_currency""game_key""bundle""value_point"
    notification_typestring(notification_type)必須

    通知タイプ。

    orderobject必須

    注文に関する情報。

    order.​amountstring必須

    選択された通貨に基づくカートの合計金額です。

    order.​commentstring or null必須

    注文に対するユーザーのコメント。

    order.​couponsArray of objects

    適用されたクーポン。クーポンが適用されていない場合は、配列は返されません。

    order.​coupons[].​codestring

    適用されたクーポンのコードです。

    order.​coupons[].​external_idstring

    External ID。

    order.​currencystring必須

    注文の通貨。仮想通貨はSKUを使用し、実際通貨は3文字のISO4217コードを使用します。

    order.​currency_typestring(currency-type)必須

    決済通貨タイプ。無料注文の場合はunknownの値が指定されています。

    列挙型 値説明
    loyalty_point

    ロイヤルティポイント

    real

    実際通貨

    unknown

    無料注文

    virtual

    仮想通貨

    order.​idinteger必須

    エクソーラ側でのユーザーの注文の一意の識別子。

    order.​invoice_idstring or null必須

    実際通貨による支払い請求書ID。仮想通貨の決済また無料アイテムは、nullの値を使用します。

    order.​modestring必須

    決済モード。defaultは実際の支払いに、sandboxはテスト支払いに使用されます。

    列挙型"default""sandbox"
    order.​platformstring or null必須

    決済プラットフォーム。xsolla値は、エクソーラを介した決済ソリューションに使用されます。その他の決済ソリューションについては、ゲームパブリッシングプラットフォームの名前に対応する値が使用されます。

    列挙型"xsolla""playstation_network""xbox_live""pc_standalone""nintendo_shop""google_play""app_store_ios""android_standalone""ios_standalone""android_other"
    order.​promocodesArray of objects

    適用されたプロモーションコード。プロモーションコードが適用されていない場合、配列は返されません。

    order.​promocodes[].​codestring

    適用されたプロモーションコードのコードです。

    order.​promocodes[].​external_idstring

    External ID。

    order.​promotionsArray of objects(order.promotions)必須

    注文全体に適用されたプロモーションです。 この配列は、次のいずれかのケースで返されます。:

    • 購入割引 設定のプロモーションコードなど、購入合計金額に影響するプロモーションが設定されている場合。
    • 購入に割引は適用されませんが、ボーナスアイテムが注文に追加される場合。この場合、割引ありのコスト(amount_with_discount)と割引なしのコスト(amount_without_discount)の値が返され、割引が適用されていないため両者は同じ値になります。

    注文レベルのプロモーションが適用されていない場合は、空の配列が返されます。

    order.​promotions[].​amount_with_discountstring

    割引なしのアイテムの総コスト。

    order.​promotions[].​amount_without_discountstring

    割引なしのアイテムの総コスト。

    order.​promotions[].​sequenceinteger

    プロモーションアプリケーションの注文。

    order.​statusstring必須

    注文状況。

    userobject必須

    ユーザー情報。

    user.​countrystring(user.country)

    ユーザーの国。2文字の国コード(大文字)は、ISO 3166-1 alpha-2に従って使用されます。

    user.​emailstring必須

    ユーザーのメールアドレス。

    user.​external_idstring必須

    ユーザーID。

    curl -v 'https://your.hostname/your/uri' \
    -X POST \
    -H 'accept: application/json' \
    -H 'content-type: application/json' \
    -H 'authorization: Signature d09695066c52c1b8bdae92f2d6eb59f5b5f89843' \
    -d '{
        "notification_type": "order_paid",
        "items": [
          {
            "sku": "com.xsolla.v.item_1",
            "type": "virtual_good",
            "is_pre_order": false,
            "quantity": 3,
            "amount": "1000",
            "promotions": [
              {
                "amount_without_discount": "6000",
                "amount_with_discount": "5000",
                "sequence": 1
              },
              {
                "amount_without_discount": "5000",
                "amount_with_discount": "4000",
                "sequence": 2
              }
            ],
            "custom_attributes":
              {
                "purchased": 0,
                "attr": "value"
              }
          },
          {
            "sku": "com.xsolla.v.item_new_1",
            "type": "bundle",
            "is_pre_order": false,
            "quantity": 1,
            "amount": "1000",
            "promotions": []
          },
          {
            "sku": "com.xsolla.gold_1",
            "type": "virtual_currency",
            "is_pre_order": false,
            "quantity": 1500,
            "amount": "[null]",
            "promotions": []
          }
        ],
        "order": {
          "id": 1,
          "mode": "default",
          "currency_type": "virtual",
          "currency": "sku_currency",
          "amount": "2000",
          "status": "paid",
          "platform": "xsolla",
          "comment": null,
          "invoice_id": "1",
          "promotions": [
            {
              "amount_without_discount": "4000",
              "amount_with_discount": "2000",
              "sequence": 1
            }
          ],
          "promocodes": [
            {
              "code": "promocode_some_code",
              "external_id": "promocode_sku"
            }
          ],
          "coupons": [
            {
              "code": "WINTER2021",
              "external_id": "coupon_sku"
            }
          ]
        },
        "user": {
          "external_id": "id_xsolla_login_1",
          "email": "gc_user@xsolla.com",
          "country": "US"
        }
    
    }'

    レスポンス

    処理が成功したことを示すために戻ります。

    個人用設定ウェブフック

    Webhook

    不正決済防止

    Webhook

    サブスクリプション

    Webhook