エクスペリエンス内のすべてのイベントとユーザーからのリクエストを手動で監視するのではなく、Webhook を設定して、サードパーティのメッセージツールまたは HTTP リクエストを受信できるカスタムエンドポイントで、リアルタイム通知を受け取ることができます。これにより、通知管理ワークフローを自動化して、手動で処理される通知の負担を軽減できます。
Webhook ワークフロー
Webhook は、Roblox や第三者のメッセージツールなど、2つの異なるアプリケーションまたはサービス間でリアルタイム通知やデータを送信します。伝統的な APIとは異なり、クライアントアプリケーションを設定してサーバーにリクエストを送り、データを受信する必要があるのとは異なり、ウェブホックはイベントが発生するとすぐにクライアントエンドポイントにデータを送信します。Roblox とチームとのコラボレーションに使用するサードパーティのアプリケーション間のワークフローを自動化するのに役立ち、リアルタイムでデータの共有と処理が可能なためです。
Webhook を設定したら、ターゲットイベントが発生するたびに、Roblox は提供した Webhook URL にリクエストを送信します。その後、Webhook URL はリクエストを受信アプリケーションまたはカスタムエンドポイントにリダイレクトし、Webhook ペイロードに含まれるデータに基づいてアクションを実行できます。これには、GDPR のデータを消去する、ユーザーに確認を送信する、または別のイベントをトリガーするなどが含まれます。
サポートされるトリガー
Roblox は現在、次のイベントトリガーをサポートしています。
購読
- サブスクリプション再購読 - ユーザーがサブスクリプションに再購読すると、サブスクリプションとサブスクライバーを含むメッセージが送信されます。
- サブスクリプション更新 - ユーザーがサブスクリプションを更新すると、サブスクリプションとサブスクライバーを含むメッセージが送信されます。
- サブスクリプション返金 - ユーザーがサブスクリプションの返金を受け取ったとき、サブスクリプションとサブスクライバーを含むメッセージが送信されます。
- サブスクリプション購入 - ユーザーがサブスクリプションを購入すると、サブスクリプションとサブスクライバーを含むメッセージが送信されます。
- サブスクリプションがキャンセルされた - ユーザーがサブスクリプションをキャンセルしたとき、サブスクリプションとサブスクライバー、キャンセル理由が含まれたメッセージが送信される
サブスクリプションイベントとそのフィールドに関する詳細情報は、サブスクリプション 参照を参照してください。
準拠
- 消去リクエストの権利 - ユーザーが 一般データ保護規則 (GDPR) の下でデータ削除リクエストを提出したとき。
コマース
- 商業製品の注文が返金された - ユーザーが商業製品の注文に対して返金を受けた、または注文がキャンセルされたとき。
- 商業製品注文が支払われた - ユーザーが商業製品の注文を支払ったとき複製の Webhook イベントは可能ですので、ユニークなコマースオーダーIDを使用してイベントを削除する必要があります。
クリエイターダッシュボードで Webhook を構成する
Webhook を介して通知を受信するには、トリガーになる特定のイベントにサブスクライブする Webhook を構成する必要があります。グループ所有のエクスペリエンスの場合、グループ所有者だけが Webhook 通知を設定して受信できます。
Webhook を設定するには:
- ナビゲート to the Webhooks セクション of the クリエイターダッシュボード.
- クリックする Webhook 追加 ボタン。
- 構成フィールドを完了する:
- Webhook URL - 通知を受信したい URL を指定します。要件に関する詳細は、ウェブホック URL の設定 を参照してください。
- 名前 - カスタム名を使用して、他の構成と区別します。デフォルトでは、値は Webhook URL と同じです。
- 秘密 (オプション) - Roblox から受信した通知が来ているかどうかを確認するには、秘密を供給します。詳しくは、Webhook のセキュリティを認証する を参照してください。
- トリガー - イベントの通知を受信したいのに、リストの サポートされるトリガー の中から1つまたは複数のオプションを選択します。
- クリックする [変更を保存] ボタン。
Webhook URL を設定する
次の要件を満たしている限り、ウェブホック URL としてカスタム HTTP サービスエンドポイントを設定できます:
- リクエストの処理に公開アクセスする必要があります。
- POST リクエストを処理できます。
- 5秒以内に 2XX 応答でリクエストに応答できます。
- HTTPSリクエストを処理できます。
エンドポイントがポストリクエストを受信したとき、次のことができなければなりません:
- POST メッセージの体から、通知に必要な詳細を抽出します。
- 通知の一般的な詳細と通知に関連するイベントタイプに関する特定の詳細を使って、POST メッセージの本文を読みます。
処理する POST リクエストのスキームの詳細については、Payload スキーム を参照してください。
配信失敗再試行ポリシー
エンドポイントの不可用などのエラーにより、指定された URLに Webhook 通知が到達できない場合、Roblox は固定のウィンドウサイズを使用して、配信されたメッセージを設定された URLに 5回送信し直します。通知が 5回の試行後にまだ配信されない場合、Roblox は通知を送信しようとしなくなり、URLが無効であると仮定します。この状況では、リーチ可能で通知を受信できる新しい URL で Webhook 構成を更新する必要があります。Webhook URL が通知を受信できるかをトラブルシュートし、確認するには、Webhook テスト を参照してください。
第三者の要件
サードパーティのツールは通常、ウェブホック URL を設定するときに従う必要があるウェブホックの要件があります。ターゲットツールのサポートまたはドキュメントサイトで「webhook」というキーワードを検索して、これらの要件を見つけることができます。サポートされている 3 つのサードパーティツールについては、以下を参照してください:
テスト Web ホック
設定したウェブホックが クリエイターダッシュボード で通知を受信できるかどうかをテストできます:
- ナビゲート to the Webhooks 設定ページ。
- 設定されたウェブホックのリストから、テストしたいウェブホックを選択します。
- ターゲットの Webhook の隣にあるペンアイコンをクリックします。
- クリックする テスト応答 ボタン。
システムは次に、通知をトリガーしたユーザーの SampleNotification イベントを送信し、ここに示されたように、ユーザーの ユーザーID を含みます:
サンプル通知スキーム
{
"NotificationId": "string",
"EventType": "SampleNotification",
"EventTime": "2023-12-30T16:24:24.2118874Z",
"EventPayload": {
"UserId": 1
}
}
ウェブホックをサードパーティのサービスと統合している場合、サードパーティの URL を使用してテストして、サービスがウェブホックからの通知を受信できるかどうかを確認できます。Webhook を構成するときに秘密を提供すると、roblox-signature ロジックをテストするために使用できる roblox-signature も生成されます。
Webhook のセキュリティを認証する
サーバーを配信された負荷を受信するように構成した後、エンドポイントに送信された負荷を監視するように開始します。Webhook を構成するときに秘密を設定すると、Roblox は各 Webhook 通知に roblox-signature を送信し、リクエストが実際に Roblox から来たことを確認します。署名は、カスタムエンドポイントのペイロードヘッダーと第三者サーバーのフッターにあります。
Signature format with a secret for custom endpoints
t=<timestamp>,v1=<signature>
ウェブホックに秘密を設定しなかった場合、署名に含まれるのは通知が送信された時刻のみです:
Signature format without a secret for custom endpoints
t=<timestamp>
署名を検証するには:
タイムスタンプと署名値を抽出する。秘密を持つウェブホックのすべての署名は、プレフィックスに続いてこれらの 2つの値が付いた CSV 文字列と同じ形式を共有します:
- t : 通知が送信された時刻のタイムスタンプ。
- v1 : クリエイターダッシュボード構成によって生成された秘密を使用して生成された署名値。
再結合して roblox-signature のベースストリングを再作成する:
- 文字列としてのタイムスタンプ。
- 期間文字 . 。
- リクエストボディの JSON 文字列。
設定中に定義した秘密と、ステップ 2 で生成したメッセージのベース文字列を使用して、SHA256 ハッシュ関数を使用してハッシュベースのメッセージ認証コード (HMAC) を計算します。結果を Base64 形式に変換して、期待される署名を取得する
抽出された署名値と期待される署名を比較します。署名を正しく生成した場合、値は同じであるはずです。
(オプション) リプレイ攻撃を防ぐには、攻撃者がデータをインターセプトして再送して無許可アクセスを獲得したり、悪意のあるアクションを実行したりするタイプのサイバー攻撃で、抽出されたタイムスタンプ値と現在のタイムスタンプを比較して、適切な期間内に含まれることを確認することが有用です。たとえば、10分のウィンドウは通常、良い適切な制限時間です。
ペイロードスキーム
ウェブホックのターゲットイベントがトリガーされると、ペイロード内のイベント情報を含むウェブホック URLにリクエストが送信されます。リクエストのすべてのペイロードは、固定および変数のフィールドで構成される同じスキームを共有します。これにより、ペイロードで送信されたデータが構造化されて一貫しているため、受信アプリケーションがデータを処理して使用するのが簡単になります。 固定ペイロードスキームフィールド は、次のフィールドが利用可能で、すべての Webhook リクエストの一貫性を維持するのに役立つことができます:
NotificationId (文字列): 送信された各通知のユニークな識別子。同じ NotificationId が 2 回受信された場合、それは重複と見なされます。
EventType (文字列): 通知がトリガーされたイベントの種類を示します。
EventTime (文字列): イベントがトリガーされた時刻のタイムスタンプ。 変数ペイロードスキームフィールド は、ウェブホックが対応できるさまざまな種類のイベントを含む柔軟性を提供します:
EventPayload (オブジェクト): Webhook をトリガーした EventType に関する情報を含みます。EventPayload スキームの構造は、イベントの種類によって異なります。
次の例では、 削除リクエスト イベントのペイロードスキームを示しています:
消去リクエストの例スキーム
{
"NotificationId": "string",
"EventType": "RightToErasureRequest",
"EventTime": "2023-12-30T16:24:24.2118874Z",
"EventPayload": {
"UserId": 1,
"GameIds": [
1234, 2345
]
}
}
通知を処理する
ユーザーのユーザーIDなどの個人識別情報を保存している場合は、ユーザーがGDPRの消去権要件に従うために、この情報を削除する必要があります。データストアに PII を保存している限り、Webhook 通知を処理し、データ削除を自動化するためのボットを作成できます。「消去リクエストの自動化」で、Guilded または Discord 内のボットを作成する方法の例として、オープンクラウド API for data stores を使用して、PII データを自動化ソリューションとして削除する方法を見てください。この例は、サブスクリプションイベントなどの他の通知の処理に適応できます。
サードパーティのツールではなく、カスタムエンドポイントをウェブホックサーバーとして使用する場合、ウェブホックペイロードから削除対象のデータを抽出し、自分の自動化ソリューションを構築できます。次のコードサンプルは、タイムスタンプを検証して再生攻撃を防ぐサーバーの例で、リクエストが Roblox から来ていることを示しています:
Extracting PII from Payload
const crypto = require('crypto');
const express = require('express');
const secret = '<your_secret>' // This can be set as an environment variable
let app = express();
app.use(express.json());
app.all('/*', function (req, res) {
console.log('New request recieved');
// Extract the timestamp and signature from header
const signatureHeader = req.headers['roblox-signature'].split(',');
const timestamp = signatureHeader.find(e => e.startsWith('t=')).substring(2);
const signature = signatureHeader.find(e => e.startsWith('v1=')).substring(3);
// Ensure the request came within a 300 second window to prevent replay attacks
const requestTimestampMs = timestamp * 1000;
const windowTimeMs = 300 * 1000;
const oldestTimestampAllowed = Date.now() - windowTimeMs;
if (requestTimestampMs < oldestTimestampAllowed) {
return res.status(403).send('Expired Request');
}
// Validate signature
const message = `${timestamp}.${JSON.stringify(req.body)}`;
const hmac = crypto.createHmac('sha256', secret);
const calculatedSignature = hmac.update(message).digest('base64');
if (signature !== calculatedSignature) {
return res.status(401).send('Unauthorized Request');
}
// Your logic to handle payload
const payloadBody = req.body;
const eventType = payloadBody['EventType'];
if (eventType === 'RightToErasureRequest'){
const userId = payloadBody['EventPayload']['UserId'];
const gameIds = payloadBody['EventPayload']['GameIds'];
console.log(`Payload data: UserId=${userId} and GameIds=${gameIds}`);
// If you store PII in data stores, use the UserId and GameIds to delete the information from data stores.
}
return res.json({ message: 'Processed the message successfully' });
});
app.listen(8080, function () {
console.log('Server started');
});