「アクティビティデータ送信」は、指定したプロジェクトの回答とポイントカードの活動を、ご利用のCRM、会員システム、景品交換システムへ送信する機能です。会員データスペースがなくても作成できます。会員データスペースの有無によって、受信できるイベントが変わります。送信設定ごとに専用の署名キーがあり、アカウントのAPIキーは使いません。
現在、「アクティビティデータ送信」はBetaテスト対象のアカウントにのみ提供しています。まだ対象になっていない場合は、引き続き「Webhook」をご利用ください。テストへの参加をご希望の場合は、お問い合わせください。
始める前の準備
- 一般公開されたHTTPS 443の受信URL。社内ネットワークへ向かうURLや、リダイレクトされるURLは使えません。
- 受信側で
eventIdを保存でき、同じトランザクション内で重複排除と業務処理の書き込みを完了できること。 - 「回答完了」イベントだけを受け取る場合:会員データスペースは不要です。そのまま次のセクションに進んで作成してください。
- 「ミッション完了」「ポイント付与」「プラットフォーム引き換え」を受け取りたい場合や、同じプレイヤーをクイズをまたいで同一人物として識別したい場合:先に会員データスペースと会員ログイン連携を作成し、少なくとも1つのプロジェクトでそのログインを有効にしてください。
アクティビティデータ送信を作成する
- 「アカウント設定」の「開発者」を開きます。
- 「アクティビティデータ送信」で、この送信設定で使う会員IDを選びます。会員データスペースを1つ選ぶか、「会員IDに紐付けない」を選びます。
- 名前とデータの送信先(HTTPS 443)を入力します。
- 「新形式(推奨)」または「既存のWebhook形式」を選びます。形式は作成後に変更できません。別の形式が必要な場合は、別の送信設定を作成してください。
- イベントと、送信を許可するプロジェクトにチェックを入れます。「会員IDに紐付けない」を選んだ場合に実際に送信されるのは「回答完了」のみで、残りの3種類のイベントには会員データスペースが必要です。
- 作成後、すぐに署名キーを保管してください。画面に表示されるのは1回だけです。
- 「テストイベントを送信」を押し、ステータスが「送達済み」になることを確認します。HTTP 200は受信側がデータを受け取ったことを示すだけで、クーポン発行やポイント付与などの処理が完了したことを意味しません。
選べるイベントは「回答完了」「ミッション完了」「ポイント付与」「プラットフォーム引き換え」です。アクティビティデータ送信には「開始」イベントがありません。「会員IDに紐付けない」を選んだ場合、イベントの識別子は回答ごとに生成される匿名コードになるため、同じ人が2回回答すると2件として扱われ、クイズをまたいで同一人物を識別することはできません。クイズをまたいで同一人物を識別するには、会員データスペースが提供する会員IDが必要です。
活動に合わせてイベントを選ぶ
- Maggieさんは美容ブランドのクイズを運営しており、まだ会員データスペースを作っていません。「会員IDに紐付けない」を選んで「回答完了」にチェックを入れ、
answerIdで診断結果をひもづけて、プレイヤーの好みごとにセグメント分けします。 - Kevinさんは2ステージのポイント企画を代行運営しており、「ミッション完了」と「ポイント付与」が必要です。まず会員データスペースを作成して、この送信設定で使う会員IDとして選び、受信側で完了の証跡と実際に付与されたポイントをそれぞれ記録します。
- Danielさんは会員デーのクーポン配布を運営しており、「回答完了」と「プラットフォーム引き換え」を選びます。こちらも会員データスペースが必要です。まず
eventIdで重複排除し、クーポンを発行するかどうかは自社の会員システムで判断します。
新形式のデータと署名
新形式では、正規のイベント全体を送信します。以下は「回答完了」イベントの構造です。
{
"brandId": "brand_123",
"campaignId": "campaign_123",
"eventId": "64-character-sha256-event-id",
"externalUserId": "brand:v2:canonical-member-id",
"occurredAt": "2026-09-15T08:00:00.000Z",
"payload": { "answerId": "answer_123" },
"schemaVersion": 2,
"source": {
"firebaseProject": "ooopen-project",
"path": "answers/answer_123",
"id": "answer_123"
},
"sourceProjectId": "quiz_123",
"type": "finish",
"webhookConnectionId": "connection_123"
}
「会員IDに紐付けない」を選んだ場合、brandId は予約値の __no-brand__、campaignId は __no-campaign__ に固定され、externalUserId は answerId から生成された匿名コード(anon:v1:...)になります。3つとも実在のブランド・キャンペーン・会員データではないため、「該当なし」として扱ってください。
まず、パースする前のリクエストボディを読み取ります。X-OOOPEN-Webhook-Timestamp、半角ピリオド1つ、元のボディのバイト列全体をこの順に連結し、この送信設定の署名キーでHMAC-SHA256を計算します。出力はbase64urlです。タイムスタンプが5分以上古い場合は、リクエストを拒否してください。
const signedBytes = Buffer.concat([
Buffer.from(timestamp + ".", "utf8"),
rawBody
]);
const expected = crypto
.createHmac("sha256", signingSecret)
.update(signedBytes)
.digest("base64url");
「回答完了」イベントのペイロードに含まれるフィールド
payload には、回答レコードのうち、回答完了の時点ですでに存在していたフィールドだけが含まれます。その時点のクイズ内容は別途読み取らないため、クイズ名、結果名、質問や選択肢のテキストは含まれません。この本文は署名付きで再送される可能性があるためです。再送時に「現在」のクイズ内容を読み取ると、作成者があとからクイズを編集した場合に、古いイベントの再送が実際には存在しなかった履歴になってしまいます。名称が必要な場合は、quizId と result を使って、Creator Data APIの /api/v1/quizzes/{quizId}/answers/{answerId} をご自身で呼び出して取得してください。
answerId:この回答のID。必ず含まれます。quizId:この回答が属するプロジェクト。必ず含まれます。startedAt:プレイヤーが回答を開始した時刻(完了時刻ではありません)。値がある場合のみ含まれます。ref:回答レコードに記録された流入元コード。値がある場合のみ含まれます。result:結果コード(結果名ではありません)。値がある場合のみ含まれます。answers:プレイヤーが送信した回答。元の形式のまま提供されます。値がある場合のみ含まれます。answersTruncated:内容が大きすぎて省略された場合はtrueになります。このフィールドがある場合、answersは含まれません。utm:流入元の帰属データ。アカウントで追加機能「UTM レコードのエクスポート」が有効な場合のみ含まれます。
メールアドレスなどの連絡先情報は含まれず、utm.code(引き換えコード)も含まれません。
既存のWebhook形式のデータと署名
受信側が data、type、timestamp の外側の構造を必要とする場合は、「既存のWebhook形式」を選べます。このオプションでも、新しい送信設定専用の署名キーを使います。従来のWebhookを呼び出すことはなく、旧版のカード・会員・残高のフィールドを補って作ることもありません。会員IDの予約値のルールは新形式と同じで、「会員IDに紐付けない」場合、brandId / campaignId はそれぞれ __no-brand__ / __no-campaign__ に固定されます。
{
"data": {
"wireSchema": "ooopen-brand-activity-webhook-legacy-envelope/1",
"eventId": "64-character-sha256-event-id",
"type": "finish",
"occurredAt": "2026-09-15T08:00:00.000Z",
"brandId": "brand_123",
"sourceProjectId": "quiz_123",
"campaignId": "campaign_123",
"webhookConnectionId": "connection_123",
"externalUserId": "brand:v2:canonical-member-id",
"payload": { "answerId": "answer_123" }
},
"type": "finish",
"timestamp": "2026-09-15T08:00:00.000Z"
}
受信した data の元のJSONバイト列と署名キーでHMAC-SHA256を計算し、小文字のhexで出力して、x-ooopenlab-signature と比較します。検証に成功したら、外側の type が data.type と、外側の timestamp が data.occurredAt と一致することを確認します。最後に wireSchema とイベント名を検証してください。
const expected = crypto
.createHmac("sha256", signingSecret)
.update(rawDataBytes)
.digest("hex");
受信側では先に重複排除を行う
OOOPEN Labは、一時的に失敗したリクエストを再試行することがあります。手動での再送信でも、元の本文、eventId、deliveryId、形式はそのまま保持されます。次の順序で処理してください。
- 署名と形式を検証します。
- データベースのトランザクション内で
eventIdを検索します。 - すでに処理済みなら、そのままHTTP 200を返し、クーポン発行やポイント付与を再度行わないでください。
- 未処理なら、同じトランザクション内で
eventIdと業務結果を書き込みます。 - トランザクション完了後にHTTP 200を返します。
ステータスが「結果不明」の場合、受信側がすでにそのイベントを処理している可能性があります。まず eventId を検索してから、手動で再送信するかどうかを判断してください。再送信しても、別の形式に変わることはありません。
署名キーの再生成と送信設定の無効化
署名キーを再生成すると、古いキーはすぐに無効になります。先に受信側を更新し、新しいキーでテストイベントを送信してください。送信設定を無効化すると以降の送信が停止し、無効化した送信設定ではテストも再送信もできません。
既存のWebhookから切り替える
既存のWebhookはアカウント単位で、デフォルトではこのアカウントのすべてのクイズが対象です(単一のクイズだけを指定することもできます)。プロジェクトを1つずつ選ぶ必要はありません。アクティビティデータ送信では、作成時に送信するプロジェクトを明示的に選ぶ必要があり、1つの送信設定につき最大50件までです。既存のWebhookには「開始」イベントがありますが、アクティビティデータ送信にはこのイベントが一切なく、切り替えると、ほかのイベントで置き換えられることもなく、そのまま使えなくなります。従来の start イベントをアクティビティデータ送信へ移行することもできません。
署名キーが変わるため、切り替え期間中は新しいURLを使うのがおすすめ
既存のWebhookは、アカウントのAPIキーで署名します。アクティビティデータ送信で「既存のWebhook形式」を選んだ場合、ヘッダー名は同じ x-ooopenlab-signature ですが、署名キーはアカウントのAPIキーではなく、その送信設定専用の署名キーになります。受信側がまだアカウントのAPIキーでこのヘッダーを検証していると、新しい送信設定から届くすべてのリクエストで署名検証に失敗します。また、切り替え期間中に新旧のWebhookを同じURLへ送信し、受信側が1つのキーしか認識しない場合は、どちらか一方が必ず署名検証に失敗します。
同じ受信側で新旧両方のデータを処理する必要がある場合は、まず本文で見分けられます。新しい「既存のWebhook形式」の本文では、data オブジェクトに wireSchema と eventId の2つのフィールドが必ず含まれます。既存のWebhookが送るデータには、この2つのフィールドがまったくありません。ただし、より簡単でミスが起きにくい方法は、切り替え期間中、新しいアクティビティデータ送信には新しい受信URLを設定し、既存のWebhookと同じURLを共用しないことです。そうすれば、それぞれが自分のキーで検証でき、同じプログラム内で「このデータは新旧どちらか」を判定する必要がなくなります。新しい送信設定が正常に動作することを確認できたら、「既存の Webhook(既存設定の管理のみ)」に戻って古い設定を削除してください。
「新形式」を選べば、この問題は起きません。3つの独立したヘッダー(X-OOOPEN-Webhook-Timestamp、X-OOOPEN-Webhook-Event-Id、X-OOOPEN-Webhook-Signature)を固定で送信し、署名はタイムスタンプと元のボディを連結して計算します。5分以上古いタイムスタンプは拒否されるため、既存のWebhookのヘッダーと混同されることもありません。
切り替えの手順
- 先に受信側を新形式の署名検証に対応させ、
eventIdで重複排除するようにします。切り替え期間中に旧データも受け取る場合は、別途answerIdでも重複排除してください。 - 「アクティビティデータ送信」で、この送信設定で使う会員ID(会員データスペースまたは「会員IDに紐付けない」)、プロジェクト、イベント、形式を選び直します。
- 新しい署名キーを保管し、テストを完了します。
- 先に新しい送信設定を有効にし、受信ログを確認します。
- データが正常に届くことを確認したら、「既存の Webhook(既存設定の管理のみ)」に戻って古い設定を削除します。
切り替えで重複イベントがまったく発生しないことは保証できません。先に受信側の重複排除を完了させてから、古い設定を停止してください。