免費道具
讓玩家無需輸入兌換碼或付款即可領取活動獎勵。您的伺服器查詢活動狀態、為玩家提交領取請求,再處理 redemption.completed Webhook,在遊戲中發放獎勵。
完整的請求與回應結構請參閱免費道具 API 參考。
身份驗證與玩家識別碼
從伺服器使用金鑰呼叫 API。查詢狀態需要 FreeItemStatus 許可權,領取需要 FreeItemClaim 許可權。金鑰只儲存在後端,playerId 應來自遊戲中已登入並通過身份驗證的玩家。
playerId 是您自己的玩家識別碼。Tokenz 不會查詢遊戲帳號,只根據這個字串識別玩家。
- 會去除首尾空白,不允許空白值。
- 最多 100 個字元。超長值會返回
request.decoding-failed,不會被截斷。 - 區分大小寫。
Player_123和player_123是不同玩家,各有獨立額度。 - 所有呼叫都應使用同一個穩定識別碼,不要轉為小寫或通過其他方式合併不同識別碼。
- 相同識別碼在不同裝置、會話或店面中共享領取額度。
活動設定與狀態
在 Tokenz Dashboard 中配置活動時間、獎勵、活動總額度、每位玩家的額度以及重複週期,並管理暫停、恢復和結束操作。如果看不到免費道具設定,請聯絡 Tokenz 支援,確認您的帳號是否已開放此功能。
draft:草稿,不能領取,所有欄位可編輯。scheduled:已釋出,等待開始;到達startAt即可領取。active:活動進行中,可以領取。paused:已暫停,不能領取,可恢復為active。ended:已結束,不能領取,此狀態不可撤銷。
查詢與領取要求活動類型為免費道具,狀態為 active,或為 scheduled 且已到達 startAt,並且尚未到達 endAt。即使儲存的狀態尚未更新,已到開始時間的 scheduled 活動也可使用。時間按絕對時刻比較,玩家所在地不會改變活動結束時刻。
額度與重複週期
每次領取都會檢查兩個獨立的額度:
- 活動總額度:所有玩家的領取次數總和。達到上限後返回
campaign.limit-reached。 - 每位玩家的額度:同一
playerId的領取次數。一次性活動達到上限返回campaign.player-limit-reached;重複活動返回campaign.player-period-limit-reached。其他玩家不受影響。
一次性活動的兩個額度均適用於活動整個生命週期,不會重置。重複活動的兩個額度都會在每個週期開始時重置。被拒絕的領取不會消耗任一額度。
| 頻率 | 週期開始時間 |
|---|---|
| 一次性 | 不重置 |
| 每日 | 當地時間午夜 |
| 每週 | 週一當地時間午夜 |
| 每月 | 每月第一天當地時間午夜 |
使用活動的時區,而非玩家時區。API 不返回該時區,因此不要自行計算週期邊界。使用 nextResetAt 顯示倒計時,到達該時刻後重新查詢狀態。該時刻及之後的領取屬於新週期。重置不會延長 endAt。
例如,每日活動總額度為 100 次、每位玩家限 1 次,則每天最多 100 位玩家各領取一次。次日重置後,總額度恢復到 100 次,前一天已領取的玩家也可再次領取。
領取流程
- 在自己的系統中儲存
campaignId。 - 伺服器呼叫
GET /v1/free-items/{campaignId}?playerId=...,顯示獎勵與剩餘額度。 - 玩家點選領取後,伺服器呼叫
POST /v1/free-items/claim。 - Tokenz 建立領取記錄,返回
201,並發送redemption.completedWebhook。 - 後端驗證簽名,使用
redemptionId防止重複發放,再發放獎勵。
查詢狀態
campaignId 是必需的路徑引數,playerId 是可選的查詢引數。狀態查詢不會預留額度,提交領取時可用額度可能已改變。額度耗盡時,狀態介面返回剩餘次數 0,而不是額度錯誤。
curl --request GET \
--url 'https://api.tokenz.one/v1/free-items/campaign_1p4LPTRKB5Z_t?playerId=player_98765' \
--header 'Authorization: Bearer secret_test_YOUR_KEY_HERE'
成功回應(200)
{
"campaign": {
"id": "campaign_1p4LPTRKB5Z_t",
"name": "Weekly Free Pack"
},
"rewardPreview": {
"name": "Marathon Energy Gift",
"imageUrl": "https://images.example.com/rewards/energy.png",
"quantity": 1
},
"campaignRemaining": 842,
"remainingForPlayer": 1,
"nextResetAt": "2026-09-14T00:00:00Z"
}
campaignRemaining:所有玩家可用的剩餘次數。重複活動為當前週期,一次性活動為整個生命週期。未設定活動總額度時省略。remainingForPlayer:此玩家的剩餘次數。未提供playerId或未設定玩家額度時省略。nextResetAt:兩個額度下次重置的絕對時刻。一次性活動省略。
領取免費道具
請求主體中的 campaignId 和 playerId 均為必填項。活動必須可領取,且兩個額度都未耗盡。API 建立記錄;實際獎勵由您的後端處理 Webhook 時發放。
curl --request POST \
--url https://api.tokenz.one/v1/free-items/claim \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer secret_test_YOUR_KEY_HERE' \
--data '{
"campaignId": "campaign_1p4LPTRKB5Z_t",
"playerId": "player_98765"
}'
成功回應(201)
{
"redemption": {
"redemptionId": "redemption_1p4LPTRKB5Z_t",
"playerId": "player_98765",
"campaign": {
"id": "campaign_1p4LPTRKB5Z_t",
"name": "Weekly Free Pack"
},
"reward": {
"skuRedemptionReward": {
"type": "EXTERNAL_SKU",
"sku": "ITEM_ENERGY_GIFT",
"name": "Marathon Energy Gift",
"quantity": 1
}
},
"redeemedAt": "2026-09-10T08:10:00Z",
"kind": "FREE_ITEM_CLAIM",
"source": "FREE_ITEM_CLAIM",
"nextPeriodStart": "2026-09-14T00:00:00Z"
},
"remainingForPlayer": 0,
"nextResetAt": "2026-09-14T00:00:00Z"
}
remainingForPlayer 是本次領取後的剩餘次數,未設定玩家額度時省略。一次性活動省略 nextResetAt。redemption 物件欄位與下方 Webhook 相同。
Webhook 與獎勵發放
Tokenz 向訂閱此事件的端點發送 redemption.completed,與兌換碼兌換使用同一事件。
發放獎勵前先驗證 Tokenz-Signature。 針對原始請求主體驗證,再解析內容。跳過驗證會使偽造請求獲得獎勵。請參閱保護你的 webhook 端點。
{
"id": "f75ff6f0-bdf9-4b25-bb96-968f8733a7e3",
"object": "redemption.completed",
"createdAt": "2026-09-10T08:10:00Z",
"test": true,
"eventData": {
"type": "redemption",
"version": "v1",
"data": {
"redemption": {
"redemptionId": "redemption_1p4LPTRKB5Z_t",
"campaign": {
"id": "campaign_1p4LPTRKB5Z_t",
"name": "Weekly Free Pack"
},
"playerId": "player_98765",
"reward": {
"skuRedemptionReward": {
"type": "EXTERNAL_SKU",
"sku": "ITEM_ENERGY_GIFT",
"name": "Marathon Energy Gift",
"quantity": 1
}
},
"redeemedAt": "2026-09-10T08:10:00Z",
"kind": "FREE_ITEM_CLAIM",
"source": "FREE_ITEM_CLAIM",
"nextPeriodStart": "2026-09-14T00:00:00Z"
}
}
}
}
kind:免費道具為FREE_ITEM_CLAIM,兌換碼為CODE_REDEMPTION。新事件都會設定此欄位,但較早進入佇列的事件可能省略。source:已棄用,僅為相容現有整合保留。新整合使用kind。code:僅兌換碼兌換包含此欄位,免費道具領取會省略。請檢查現有處理程序是否錯誤地要求其存在。nextPeriodStart:僅重複免費道具活動包含。它根據redeemedAt時的活動週期計算下一週期開始時刻,而非根據 Webhook 投遞時間計算。一次性領取和兌換碼兌換均省略。
通常只需根據 redemptionId、playerId 和 reward 共用一套發放邏輯。kind 缺失或未知時不要猜測類型,仍使用這三個欄位發放,並標記事件以供核對。頂層事件 id 用於追蹤投遞,redemptionId 用於防止重複發放。
重試與回應丟失
領取請求沒有冪等性鍵。額度允許時,重複請求會建立另一條領取記錄。回應丟失後不要盲目重試。
Webhook 可確認領取成功,但只標識活動和玩家,未必能唯一對應某次超時請求。請結合自己的請求日誌核對。如果既無回應也無 Webhook,公開 API 目前無法重新查詢領取記錄,請在重試前聯絡 Tokenz 支援。Webhook 去重不能防止重複的領取請求。
端點未接受 Webhook 時,Tokenz 會逐漸增加間隔並加入隨機變化進行重試。重試安排在首次嘗試後的最長 72 小時視窗內;這不是保證在視窗內送達,實際執行可能延後。不要依賴固定次數或準確時間。投遞可能晚到數天,因此應將已發放的 redemptionId 持久儲存,而非放入短期快取,並保證同一 ID 的獎勵只發放一次。
錯誤處理
400/request.decoding-failed:無效 ID、空白或超長的playerId,或格式錯誤的請求。401:缺少或無效的 API 金鑰。403:缺少所需許可權。404/entity.not-found:活動不存在、屬於其他商戶,或測試模式與金鑰不匹配。422/campaign.kind-invalid:不是免費道具活動。422/campaign.status-invalid:草稿、暫停、結束,或尚未開始的預定活動。422/campaign.expired:已到結束時刻;結束狀態也可能返回campaign.status-invalid。422/campaign.limit-reached:總額度耗盡;重複活動為當前週期,一次性活動為整個生命週期。422/campaign.player-limit-reached:玩家額度耗盡。422/campaign.player-period-limit-reached:當前週期的玩家額度耗盡,可在nextResetAt後重試。429:超過速率限制。兩個介面均按 API 金鑰限制;提供玩家識別碼時,也按玩家限制。500:意外的伺服器錯誤。
測試
使用以 secret_test_ 開頭的金鑰,在 Dashboard 測試模式下建立活動。測試與正式資料隔離,金鑰只能操作模式匹配的活動。測試 ID 以 _t 結尾;測試 Webhook 僅傳送到測試端點,承載內容包含 "test": true。
測試成功領取與獎勵發放、兩個額度耗盡、週期重置、暫停與過期、重複投遞。也應驗證空白和超長 playerId、速率限制以及測試與正式模式隔離,並確認每個 redemptionId 只發放一次獎勵。