ウェブフックは、システムで発生するイベントに関する通知です。特定のイベントが発生すると、エクソーラはHTTPリクエストを送信し、イベントデータがアプリケーション に送信されます。通常、これはJSON形式のPOSTリクエストです。
イベントの例:
設定されたイベントが発生すると、エクソーラはウェブフック経由でシステムにそれを通知します。その結果、次のようなアクションを実行できます:
支払い処理ウェブフックのワークフローの例:
注意
使用されるソリューションとその統合のタイプに応じて、ウェブフックのセットとインタラクションのシーケンスは、提供された例とは異なる場合があります。
エクソーラウェブフック統合のビデオガイド:
エクソーラ製品およびソリューションを使用する場合のウェブフック設定:
製品/ソリューション | 必須/任意 | ウェブフックは何に使用されますか |
---|---|---|
決済ソリューション | 必須 |
|
インゲームストア | 必須 |
|
ゲーム販売 | 任意 | ゲームキーの販売では、ユーザーの検証やアイテムの付与は必要ありません。支払いや注文キャンセルなどのイベントに関する情報を受け取りたい場合は、ウェブフックを接続することができます。 ウェブフックを接続する場合は、すべての受信した必要なウェブフックを処理することが重要です。 |
サブスクリプション | 任意 | サブスクリプションの作成、更新、またはキャンセルに関する情報を受け取ります。または、API経由で情報をリクエストすることもできます。 |
ウェブショップ | 必須 |
|
デジタル配信ソリューション | 必須 |
ウェブフックの設定に関する詳細情報は、デジタル配信ソリューションのドキュメンテーションを参照してください。 |
ログイン | 任意 |
イベント情報の受信:
ウェブフックの設定の詳細については、ログインのドキュメンテーションを参照してください。 |
ウェブフックの操作が必要な製品やソリューションを使用している場合、パブリッシャーアカウントでウェブフックを有効化してテストし、その処理をセットアップします。特定のイベントが発生する時、ウェブフックが順次送信されます。したがって、1つのウェブフックを処理しない 場合、その後のウェブフックは送信されません。必要なウェブフックのリストは以下の通りです。
エクソーラ側では、サイトでアイテムを購入して返品する際に2 つのウェブフック送信オプションが設定されています。支払いと取引データ、および購入したアイテムに関する情報は、個別に提供することも、1つのウェブフックにまとめるこ ともできます。
まとめたウェブフックで情報を受け取ります:
2025年1月22日以降にパブリッシャーアカウントに登録した場合は、注文支払い完了(order_paid
)と注文キャンセル(order_canceled
)ウェブフックですべての情報を受け取ります。この場合、支払い(payment
)と返金(refund
)ウェブフックを処理する必要はありません。
個別のウェブフックで情報を受け取ります:
2025年1月22日以降にパブリッシャーアカウントに登録した場合は、以下のウェブフックを受け取ります:
payment
) そして返金 (refund
)に支払いデータと取引の詳細に関する情報が記載されます。order_paid
)と注文キャンセル(order_canceled
)。すべての受信ウェブフックを処理する必要があります。まとめたウェブフックを受信する新しいオプションに切り替えるには、カスタマーサクセスマネージャーにご連絡いただく か、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
) — 返金ウェブフックが正常に処理されたとき、またはサブスクリプションが別の理由でキャンセ
ルされたときに送信されます。サブスクリプションとユーザーデータに関する情報を含んでいます。ウェブフックデータを使用して、ユーザーから購入したサブスクリプションを
差し引きます。ウェブフックの受信を有効にするには:
https://example.com
形式で指定します。ウェブフックをテストするツールで見つけたURLを指定することもできます。注意。
データ転送にはHTTPSプロトコルが使用されます。HTTPプロトコルはサポートされていません。
注意
ウェブフックをテストするには、webhook.siteのような専用のウェブサイトか、ngrokのようなプラットフォームを選択できます。
注意
異なるURLに同時にウェブフックを送信することはできません。パブリッシャーアカウントでは、まずテスト用のURLを指定し、それを実際のURLに置き換えることができます。
ウェブフックの受信を無効にするには:
ウェブフックについては決済ソリューションとストアセクションでは、詳細設定が利用できます。「ウェブフックを取得」ボタンをクリックする と、自動的に一般設定ブロックの下に表示されます。
注意
詳細設定が表示されない場合は、一般設定でウェブフック受信が接続されていることを確認し、テスト > 決済ソリューションとストアタブにいることを確認してください。
このセクションでは、ウェブフックでの追加情報の受信を設定できます。これを行うには、対応するスイッチをアクティブポジションに設定します。各権限の行は、設定の変更に よって影響を受けるウェブフックを示します。
トグル | 説明 |
---|---|
保存された決済アカウントに関する情報を表示する | 保存された決済方法に関する情報は、payment_account カスタムオブジェクト。 |
保存された決済方法による取引に関する情報を表示する | 情報は、パラメータの以下のカスタムパラメータに渡されます:
|
注文オブジェクトをウェブフックに追加する | 注文に関する情報は、決済ウェブフックのorder オブジェクトに渡されます。 |
機密データは含まず、必要なユーザーパラメータのみを送信する | ウェブフックでは、ユーザーに関する次の情報のみが渡されます:
|
カスタムパラメータを送信する | カスタムトークンパラメータに関する情報は、ウェブフックで渡されます。 |
カードのBINとサフィックスを表示する | 銀行カード番号に関する次の情報がウェブフックで渡されます。
|
カードブランドを表示する | 決済に使用したカードのブランド。例えば、MastercardやVisaなど。 |
ウェブフックをテストすると、ユーザー側とエクソーラ側の両方でプロジェクトが正しく設定されていることを確認できます。
ウェブフックが正常にセットアップした場合、ウェブフック設定セクションの下にウェブフックのテストセクションが表示されます。
パブリッシャーアカウントのテストセクションは、ウェブフック受信オプションによって異なります。
まとめたウェブフックを受信する場合:
ウェブフックテストのタブ名 | ウェブフック名とタイプ |
---|---|
決済ソリューションとストア | ユーザー検証 > ユーザー検証(user_validation ) |
ゲームサービス > まとめたウェブフック > 注文支払い完了(order_paid ) |
|
ゲームサービス > まとめたウェブフック > 注文キャンセル(order_canceled ) |
|
サブスクリプション | ユーザー検証 > ユーザー検証(user_validation ) |
決済ソリューション > 支払い(payment ) |
個別のウェブフックを受信する場合:
ウェブフックテストのタブ名 | ウェブフック名とタイプ |
---|---|
ストア | ゲームサービス> 個別のウェブフック> 注文支払い完了(order_paid ) |
ゲームサービス > 個別のウェブフック > 注文キャンセル(order_canceled ) |
|
決済ソリューション | ユーザー検証 > ユーザー検証(user_validation ) |
決済ソリューション > 支払い(payment ) |
|
サブスクリプション | ユーザー検証 > ユーザー検証(user_validation ) |
決済ソリューション > 支払い(payment ) |
注意
テストセクションにテストがパスしていないという警告が表示された場合は、ウェブフックリスナーのウェブフック応答設定を確認します。テストでのエラーの理由はテスト結果に示されます。
例:
テストには、専門サイトwebhook.siteを使用します。
「無効な署名に対する応答のテスト」セクションにエラーが表示されます。
エクソーラが間違った署名を持つウェブフックを送信し、ハンドラーがINVALID_SIGNATURE
エラーコードを指定する4xx
HTTPコードで応答することを期待しているために発生します。
webhook.siteは、署名が間違ったウェブフックを含むすべてのウェブフックに応答して200
HTTPコードを送信します。期待される4xx
HTTPコードが得られないため、テスト結果にエラーが表示されます。
まとめたウェブフックを使用したシナリオのテストプロセスを以下に説明します。
「決済ソリューションとストア」タブでは、次のウェブフックをテストできます:
user_validation
)order_paid
)order_canceled
)テストするには:
ウェブフックのテストセクションで、「決済ソリューションとストア」タブに移動します。
ドロップダウンメニューで、アイテムのタイプを選択します。選択したタイプのアイテムがパブリッシャーアカウントに設定されていない場合は、以下をクリックします:
必要なフィールドに入力します:
「ウェブフックをテスト」をクリックします。
指定されたデータを含むユーザー検証、注文支払い完了および注文キャンセルウェブフックが、指定されたURLに送信されます。各ウェブフックタイプのテスト結果は、「ウェブフックをテス ト」ボタンの下に表示されます。
プロジェクトでパブリックユーザー IDが有効になっている場合は、ユーザー検索チェックの結果も表示されます。
各ウェブフックについて、成功したシナリオとエラーが発生したシナリオの両方の処理を設定する必要があります。
「サブスクリプション」タブでは、次のウェブフックをテストできます:
注意
パブリッシャーアカウントでは、基本的なユーザー検証および支払いウェブフックのみをテストできます。他のウェブフックタイプをテストするには、次の場所に移動します:
注意
ウェブフックをテストするには、パブリッシャーアカウント > サブスクリプション > サブスクリプションプランセクションで、少なくとも1つのサブスクリプションプランが作成されている必要があります。
テストするには:
0
を指定します。指定した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
制限:
安全なデータ転送を確保するには、ウェブフックが実際にエクソーラサーバーから送信され、転送中に改ざんされていないことを確認する必要があります。これを行うには、受信
したリクエスト本文のペイロードに基づいて独自の署名を生成し、それを着信リクエストのauthorization
ヘッダーで提供される署名と比較してください。両方
の署名が一致する場合、そのウェブフックは正規のものであり、安全に処理できます。
検証ステップ:
着信ウェブフックリクエストのauthorization
ヘッダーから署名を取得します。ヘッダーの形式はSignature <signature_value>
です。
ウェブフックのリクエスト本文をJSON形式で取得してください。
注意
JSONペイロードは、受信したものをそのまま使用してください。ペイロード をパースしたり再エンコードしたりしないでください。フォーマットが変更され、署名検証が失敗する原因となります。
比較用に独自の署名を生成します:
生成した署名をauthorization
ヘッダーからの署名と比較してください。両者が一致すれば、ウェブフックは信頼できるものです。
以下に、署名生成の実装例を各種プログラミング言語で示します: C#、C++、Go、PHP、Node.js。
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 -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"
}
}'
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 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);
return string.Equals(computedSignature, receivedSignature, StringComparison.OrdinalIgnoreCase);
}
}
#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;
}
};
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
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));
}
}
?>
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;
}
}
}
ウェブフックの受信を確認するには、サーバーは以下を返す必要があります:
200
、201
、または204
HTTPコード。400
HTTPコードは問題の説明を含む、指定されたユーザーが見つからないか、無効な署名が渡
された場合に送信されます。ウェブフックハンドラーは、サーバーで一時的な問題が発生した場合に5xx
HTTPコードを返すこともあります。エクソーラサーバーが 注文支払い完了と注文キャンセルへのレスポンスを受け取らなかった場合、または5xx
コードのレスポンスを受け取った場合、ウェブフックは以下の
スケジュールに従って再送されます:
ウェブフックの送信は、最初の送信から12時間以内に最大20回まで試行されます。
エクソーラサーバーが決済ウェブフックまたは返金ウェブフックへの応答を受け取らなかった場合、または5xx
コードの応答が受信さ
れた場合、ウェブフックは時間間隔を長くして再送信されます。12時間以内に最大12回の試行が行われます。
注意
支払いの返金がエクソーラによって開始され、返金ウェブフックに対する応答として`5xx`HTTPコードを含む応答が返された場合でも、支払いは返金されます。
エクソーラサーバーがユーザー認証ウェブフックへの応答を受信しなかった場合、または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"
}
}
注意
通知タイプはnotification_type
パラメータで送信されます。
ウェブフック | 通知タイプ | 説明 |
---|---|---|
ユーザー検証 | user_validation |
ユーザーがゲーム内に存在するかどうかを確認するために送信されます。 |
ユーザー検索 | user_search |
パブリックユーザーIDに基づいてユーザー情報を取得するために送信されます。 |
決済 | payment |
ユーザーが決済を完了した場合に送信されます。 |
返金 | refund |
何らかの理由で決済をキャンセルする必要がある場合に送信されます。 |
一部返金 | partial_refund |
何らかの理由で決済を一部キャンセルする必要がある場合に送信されます。 |
AFSが拒否したトランザクション | afs_reject |
AFSチェック中にトランザクションが拒否された場合に送信されます。 |
AFSが更新したトランザクション | afs_black_list |
AFSブロックリストが更新される場合に送信されます。 |
作成されたサブスクリプション | create_subscription |
ユーザーがサブスクリプションを作成する場合に送信されます。 |
更新されたサブスクリプション | update_subscription |
サブスクリプションが更新または変更された場合に送信されます。 |
キャンセルされたサブスクリプション | cancel_subscription |
サブスクリプションがキャンセルされた場合に送信されます。 |
非更新サブスクリプション | non_renewal_subscription |
ステータスが非更新に設定される場合に送信されます。 |
決済アカウントを追加する | payment_account_add |
ユーザーが支払いアカウントを追加または保存した場合に送信されます。 |
決済アカウントを削除する | payment_account_remove |
ユーザーが保存済みアカウントから決済アカウントを削除する場合に送信されます。 |
ウェブショップでのユーザー検証 | - |
ウェブショップのサイトから送信され、ゲーム内にユーザーが存在するかどうかを確認します。 |
パートナー側でのカタログ個人用設定 | partner_side_catalog |
ユーザーがストアと直接交信する時に送信されます。 |
注文支払い完了 | order_paid |
注文が支払われたときに送信されます。 |
注文キャンセル | order_canceled |
注文がキャンセルされたときに送信されます。 |
紛争 | dispute |
新しい紛争手続きが開かれたときに送信されます。 |