star

文章編輯: O 編 | 2026-09-15

如何設定品牌活動資料回傳?

如何設定品牌活動資料回傳?

「活動資料回傳」會把你指定專案內的填答與集點卡活動,傳到你的 CRM、會員系統或兌獎系統。不需要會員資料空間也能建立;有沒有會員資料空間,決定的是能收到哪些事件。每組回傳都有獨立簽章金鑰,不會使用帳號 API Key。

目前「活動資料回傳」僅開放給 Beta 測試名單中的帳號;尚未加入的帳號請繼續使用「Webhooks」,想參加測試請與我們聯繫。

開始前先準備

  • 一個可公開連線的 HTTPS 443 接收網址。網址不可導向內網,也不可重新導向。
  • 接收系統可以保存 eventId,並在同一筆交易中完成去重與業務寫入。
  • 只想接收「回答完成」事件:不需要會員資料空間,直接跳到下一節建立即可。
  • 想接收「任務完成」「實際加點」「平台兌換」,或想讓同一位玩家跨測驗被認成同一人:先建立會員資料空間與會員登入連線,並讓至少一個專案啟用該登入。

建立一組活動資料回傳

  1. 前往「帳號設定」的「開發人員專區」。
  2. 在「活動資料回傳」選擇這組回傳要用的身分:選一個會員資料空間,或選「不綁會員身分」。
  3. 填入名稱與 HTTPS 443 接收網址。
  4. 選擇「新格式(建議)」或「既有 Webhook 格式」。格式建立後不能切換。需要另一種格式時,請建立另一組回傳。
  5. 勾選事件與允許回傳的專案。選「不綁會員身分」時只有「回答完成」會真的送出,其餘三種事件需要會員資料空間。
  6. 建立後立即保存簽章金鑰。畫面只會顯示一次。
  7. 按「傳送測試事件」,確認狀態顯示「已送達」。HTTP 200 只代表接收端收到資料,不代表已完成發券、加點或其他處理。

可選事件有「回答完成」、「任務完成」、「實際加點」與「平台兌換」。活動資料回傳不提供「開始填答」。選「不綁會員身分」時,事件的身分是依每筆填答各自產生的匿名代碼,同一個人填兩次會被視為兩筆、無法跨測驗辨識為同一人;要跨測驗辨識同一人,需要會員資料空間提供的會員身分。

依你的活動選事件

  • Maggie 經營美妝品牌測驗,還沒建立會員資料空間:直接選「不綁會員身分」、勾「回答完成」,用 answerId 連回測驗結果,再依玩家偏好分眾。
  • Kevin 代營兩關集點活動,需要「任務完成」與「實際加點」:先建立會員資料空間並選它當這組回傳的身分,接收端分別記錄完成憑證與實際入帳的點數。
  • 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"
}

選「不綁會員身分」時,brandId 固定是保留值 __no-brand__、campaignId 固定是 __no-campaign__,externalUserId 則是依 answerId 衍生的匿名代碼(anon:v1:...)。三者都不是真的品牌、活動或會員資料,請當成「不適用」處理。

先讀取未解析的 request body。將 X-OOOPEN-Webhook-Timestamp、一個半形句點與完整原始 body bytes 串接,再用該組回傳的簽章金鑰計算 HMAC-SHA256。輸出採 base64url。時間戳記超過五分鐘時,請拒絕請求。

const signedBytes = Buffer.concat([
  Buffer.from(timestamp + ".", "utf8"),
  rawBody
]);
const expected = crypto
  .createHmac("sha256", signingSecret)
  .update(signedBytes)
  .digest("base64url");

回答完成事件的 payload 有哪些欄位

payload 只放答案紀錄裡、在完成那一刻就已經存在的欄位,不會另外去讀當時的測驗內容——不含測驗名稱、結果名稱、題目或選項文字。這是因為這包資料簽了章、可以被重送:如果重送時去讀「現在」的測驗內容,創作者事後改了測驗,舊事件重送出來的就會變成假的歷史紀錄。需要顯示名稱時,請自行用 quizId 與 result 打 Creator Data API 的 /api/v1/quizzes/{quizId}/answers/{answerId} 查詢。

  • answerId:這筆填答的 ID,一定會有。
  • quizId:這筆填答屬於哪個專案,一定會有。
  • startedAt:玩家開始作答的時間(不是完成時間),有值才會出現。
  • ref:填答紀錄上的來源代碼,有值才會出現。
  • result:結果代碼(不是結果名稱),有值才會出現。
  • answers:玩家送出的答案,依原始格式提供,有值才會出現。
  • answersTruncated:內容過大被省略時會是 true;出現這個欄位時不會同時出現 answers。
  • utm:來源歸因資料,只有你的帳號開通「UTM 匯出」這個加購功能時才會出現。

不會有 email 等聯絡資料,utm.code(兌換碼)也不會出現。

既有 Webhook 格式的資料與簽章

如果接收系統需要 data、type、timestamp 外層,可選「既有 Webhook 格式」。這個選項仍使用新連線的獨立金鑰,不會呼叫原本的 Webhook,也不會補造舊版的卡片、會員或餘額欄位。身分保留值規則與新格式相同:不綁會員身分時 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 bytes 與簽章金鑰計算 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 可能重試暫時失敗的請求。手動重送也會保留原本的 body、eventId、deliveryId 與格式。請依下列順序處理:

  1. 驗證簽章與格式。
  2. 在資料庫交易內查詢 eventId。
  3. 如果已處理,直接回 HTTP 200,不要再次發券或加點。
  4. 如果未處理,在同一筆交易寫入 eventId 與業務結果。
  5. 交易完成後回 HTTP 200。

若狀態是「結果不明」,接收端可能已處理該事件。請先查詢 eventId,再決定是否手動重送。重送不會改成另一種格式。

更換金鑰與停用連線

更換簽章金鑰後,舊金鑰立即失效。先更新接收端,再用新金鑰傳送測試事件。停用連線會停止後續投遞,已停用的連線不能測試或重送。

從既有 Webhook 切換

既有 Webhook 是帳號層級:預設涵蓋這個帳號底下所有測驗(也可以額外指定只送單一測驗),不用逐一勾選專案。活動資料回傳則要求建立時明確勾選要送出的專案,一組回傳最多勾 50 個。既有 Webhook 有「開始填答」事件,活動資料回傳完全不提供這個事件——換過去之後它會直接消失,不會用別的事件取代。原本的 start 事件也無法升級到活動資料回傳。

簽章金鑰換了,切換期間建議用新網址

既有 Webhook 用帳號的 API Key 簽章。活動資料回傳選「既有 Webhook 格式」時,header 名稱一樣是 x-ooopenlab-signature,但簽章金鑰換成這組回傳自己的簽章金鑰,不是帳號 API Key。如果接收端還在用帳號 API Key 驗這個 header,新格式送來的每一筆都會驗章失敗;如果切換期間讓新舊 Webhook 同時對著同一個網址送資料、接收端又只認一把金鑰,兩邊一定有一邊會驗章失敗。

如果真的需要在同一個接收端同時處理新舊資料,可以先看 body 分辨:新格式的「既有 Webhook 格式」body,data 物件裡一定有 wireSchema 與 eventId 這兩個欄位;既有 Webhook 送出的資料完全沒有這兩個欄位。但更簡單、更不容易出錯的做法,是切換期間幫新的活動資料回傳連線設一個新的接收網址,不要跟既有 Webhook 共用同一個網址——這樣兩邊各自驗自己的金鑰,不用在同一支程式裡判斷「這筆資料是新是舊」。等新連線確認運作正常,再回到「既有 Webhook(僅管理現有設定)」刪除舊設定。

選「新格式」不會遇到這個問題:它固定送三個獨立的 header(X-OOOPEN-Webhook-Timestamp、X-OOOPEN-Webhook-Event-Id、X-OOOPEN-Webhook-Signature),簽章是用時間戳記接原始 body 算出來的,且時間戳記超過五分鐘會被拒絕,不會跟既有 Webhook 的 header 搞混。

切換步驟

  1. 先讓接收端依新格式驗章,並依 eventId 去重。切換期間若同時收舊資料,請另以 answerId 去重。
  2. 在「活動資料回傳」重新選擇這組回傳要用的身分(會員資料空間或不綁會員身分)、專案、事件與格式。
  3. 保存新金鑰並完成測試。
  4. 先啟用新連線,再觀察接收紀錄。
  5. 確認資料正常後,回到「既有 Webhook(僅管理現有設定)」刪除舊設定。

切換不能保證完全沒有重複事件。先完成接收端去重,再停止舊設定。


猜你也喜歡……

  • 如何使用多輪淘汰賽模組?
    去看看
  • 如何使用任務型活動頁模組?
    去看看
  • 怎麼把多個專案串起來?導外連結、串連其他模組、參與條件與任務教學
    去看看

讓溝通變好玩

回首頁關於我們關於我們使用者服務條款與
隱私權政策
外部傳送公表事項檢舉濫用行為

Copyright © 2026 OOOPEN Lab