--- title: "ギフトコード" description: "Gift Codes の検証と引き換え、報酬の付与、引き換え webhook の処理を実装します。" source: "https://docs.tokenz.one/ja/v1/campaigns/gift-codes" api_version: "v1" locale: "ja" version_status: "legacy" docs_stage: "prod" --- # ギフトコード 旧称:引き換えコード。API エンドポイントとイベント名に変更はありません。 Tokenz 引き換えコード API を使用してキャンペーンコードの検証と引き換えを行う方法を学びます。 引き換えコード API は、プレイヤーがコードを入力して報酬を受け取るキャンペーンを実施するのに役立ちます。サーバーがコードを検証し、資格を確認し、引き換えを実行した後、フルフィルメントのために `redemption.completed` Webhook を処理します。 ## 概要 引き換えフローには以下が含まれます: - **検証**:コードが引き換え可能かどうかを確認し、報酬プレビューを返す - **引き換え**:特定のプレイヤーのためにコードを消費し、引き換えレコードを作成する - **Webhook フルフィルメント**:`redemption.completed` を受信し、ゲームバックエンドで報酬を付与する ## キャンペーンの設定と管理 キャンペーンと引き換えコードは、Tokenz Dashboardで作成・管理されます。マーチャントは Tokenz Dashboard を使用して以下を行います: - 有効期間と報酬設定を持つキャンペーンを作成する - 引き換えコードを生成または管理する - キャンペーンの一時停止、再開、または終了を行う ## キャンペーンのステータス キャンペーンは以下のいずれかのステータスになります: - `draft`:作業中。引き換えは不可。すべてのフィールドが編集可能 - `scheduled`:公開済みでキュー待ち。設定された `start_at` 時刻に自動的に `active` へ移行する - `active`:キャンペーンは公開中であり、引き換えが成功する - `paused`:手動で一時停止済み。引き換えは拒否される。`active` に再開可能 - `ended`:キャンペーンは終了しており、引き換えは拒否される。この状態は不可逆 `validate` と `redeem` はキャンペーンが `active` の場合に成功します。また、`scheduled` のキャンペーンでも、すでに `startAt` に達していれば成功します。`endAt` 以降は拒否されます。`scheduled` のキャンペーンは `startAt` に自動的に `active` へ移行するため、これが影響するのは移行前後の短い時間だけです。 ## コードのステータス 引き換えコードのステータスは、キャンペーンのステータスとコード自体のステータスから導出されます: - `pending`:コードは有効だが、キャンペーンが現在アクティブでない(例:draft、scheduled、paused)。引き換え不可。ただし `scheduled` のキャンペーンで `startAt` に達している場合は引き換えできる。 - `active`:コードは使用可能。キャンペーンがアクティブである必要がある。引き換え可能なステータスはこれだけではなく、`scheduled` のキャンペーンが `startAt` に達すると `pending` のコードも引き換えできる。 - `deactivated`:コードは無効。マーチャントによる手動無効化、またはキャンペーン終了時に表示される。 表示されるコードステータスはキャンペーンの状態に依存します: | キャンペーンステータス | コードステータス | | --- | --- | | `active` | `active` | | `draft`、`scheduled`、`paused` | `pending` | | `ended` | `deactivated` | キャンペーンが `endAt` を過ぎると、ステータスが `active` と表示されていてもコードは引き換えできません。この場合、API は `redemptionCode.campaign-invalid` エラーを返します。開始前のキャンペーンでも同じエラーが返ります。 マーチャントが手動でコードを無効化した場合、キャンペーンのステータスに関係なく常に `deactivated` と表示されます。 また、Tokenz Dashboardでは `currentRedemptions >= maxRedemptions` の場合、コードが**引き換え済み**と表示されますが、API ステータスは `active` のままです。これはダッシュボードのみの表示状態であり、API からは返されません。 ## 引き換えのライフサイクル 1. プレイヤーがプロモーションキャンペーン UI でコードを入力する 2. サーバーが `POST /v1/redemption-codes/validate` を呼び出す 3. サーバーがプレイヤーに報酬プレビューを表示する 4. プレイヤーが引き換えを確認する 5. サーバーが `POST /v1/redemption-codes/redeem` を呼び出す 6. Tokenz が成功した引き換えレスポンスを返す 7. Tokenz が `redemption.completed` Webhook を送信する 8. バックエンドが報酬をフルフィルメントし、重複フルフィルメントを防ぐために `redemptionId` を使用する ```mermaid sequenceDiagram; autonumber; participant P as プレイヤー; participant M as マーチャントサーバー; participant T as Tokenz API; participant W as マーチャント Webhook ハンドラー; P->>M: 引き換えコードを入力; M->>T: POST /v1/redemption-codes/validate; T-->>M: キャンペーン + rewardPreview; P->>M: 引き換えを確認; M->>T: POST /v1/redemption-codes/redeem; T-->>M: redemptionId + reward; T->>W: webhook: redemption.completed; W->>W: 報酬をフルフィルメント(重複防止に redemptionId を使用); ``` ## コードの検証 検証はキャンペーンとコードの資格を確認し、キャンペーンプレビューと報酬プレビューを返します。検証が成功するには、キャンペーンがアクティブ、または `scheduled` で `startAt` に達しており、かつ `endAt` より前である必要があります。 ```bash curl --request POST \ --url https://api.tokenz.one/v1/redemption-codes/validate \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer secret_test_YOUR_KEY_HERE' \ --data '{ "redemptionCode": "SPRING2026FREE", "playerId": "player_98765" }' ``` ### リクエストフィールド - `redemptionCode`(必須):プレイヤーが入力したコード - `playerId`(任意):マーチャントのプレイヤー識別子。指定した場合、プレイヤーごとの上限も確認される。省略した場合、コードとキャンペーンのグローバル上限のみが検証される ### 成功レスポンス(`200`) ```json { "campaign": { "id": "campaign_1AbCdEfGh12", "name": "Spring Campaign 2026" }, "rewardPreview": { "name": "SSR Reimu Card", "imageUrl": "https://images.example.com/rewards/reimu.png", "quantity": 1 } } ``` ## コードの引き換え 引き換えはプレイヤーのためにコードを消費し、引き換えレコードを作成します。引き換えが成功するには、キャンペーンがアクティブ、または `scheduled` で `startAt` に達しており、かつ `endAt` より前である必要があります。 ```bash curl --request POST \ --url https://api.tokenz.one/v1/redemption-codes/redeem \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer secret_test_YOUR_KEY_HERE' \ --data '{ "redemptionCode": "SPRING2026FREE", "playerId": "player_98765" }' ``` ### リクエストフィールド - `redemptionCode`(必須):プレイヤーが入力したコード - `playerId`(必須):マーチャントのプレイヤー識別子 ### 成功レスポンス(`201`) ```json { "redemptionId": "redemption_1XyZaBcDe34", "code": "SPRING2026FREE", "playerId": "player_98765", "campaign": { "id": "campaign_1AbCdEfGh12", "name": "Spring Campaign 2026" }, "reward": { "skuRedemptionReward": { "type": "EXTERNAL_SKU", "sku": "ITEM_SSR_REIMU", "name": "SSR Reimu Card", "quantity": 1 } }, "redeemedAt": "2026-03-25T08:10:00Z", "kind": "CODE_REDEMPTION", "source": "CODE_REDEMPTION" } ``` ## 引き換え Webhook 引き換えが成功すると、Tokenz はこのイベントを購読している Webhook エンドポイントに `redemption.completed` を送信します。 **報酬を付与する前に必ず署名を検証してください。** すべての配信には `Tokenz-Signature` ヘッダーが含まれます。検証を省略すると、エンドポイントの URL を知った第三者に報酬を付与してしまう可能性があります。生のリクエストボディに対して検証し、その後にパースしてください。手順は[Webhook エンドポイントを保護する](https://docs.tokenz.one/ja/v1/checkout/webhooks-get-started#3%29-%E3%82%A6%E3%82%A7%E3%83%96%E3%83%95%E3%83%83%E3%82%AF%E3%82%A8%E3%83%B3%E3%83%89%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88%E3%82%92%E4%BF%9D%E8%AD%B7%E3%81%99%E3%82%8B)を参照してください。以下のフィールドは、署名の検証が成功した場合にのみ信頼できます。 ```json { "id": "f75ff6f0-bdf9-4b25-bb96-968f8733a7e3", "object": "redemption.completed", "createdAt": "2026-03-24T23:10:00Z", "test": false, "eventData": { "type": "redemption", "version": "v1", "data": { "redemption": { "redemptionId": "redemption_1XyZaBcDe34", "campaign": { "id": "campaign_1AbCdEfGh12", "name": "Spring Campaign 2026" }, "code": "SPRING2026FREE", "playerId": "player_98765", "reward": { "skuRedemptionReward": { "type": "EXTERNAL_SKU", "sku": "ITEM_SSR_REIMU", "name": "SSR Reimu Card", "quantity": 1 } }, "redeemedAt": "2026-03-25T08:10:00Z", "kind": "CODE_REDEMPTION", "source": "CODE_REDEMPTION" } } } } ``` Webhook 配信のトレースにはトップレベルのイベント `id` を使用し、バックエンドでの重複フルフィルメントを防ぐために `redemptionId` を使用してください。 同じイベントは[無料アイテムの受け取り](https://docs.tokenz.one/ja/v1/free-items)でも送信されます。`kind` はコード引き換えでは `CODE_REDEMPTION`、無料アイテムでは `FREE_ITEM_CLAIM` です。`source` は互換性維持のための非推奨フィールドです。新規連携では `kind` を使用してください。過去にキューに入ったイベントでは `kind` が省略される場合があります。無料アイテムでは `code` は省略されます。 ## エラー処理 引き換えエンドポイントは、構造化されたエラーオブジェクトを伴う標準 HTTP ステータスコードを返します。 ### 一般的なエラー - `401 Unauthorized`:無効または欠落している API キー - `403 Forbidden`:API キーに必要なスコープがない - `404 Not Found`(`entity.not-found`):引き換えコードが見つからない - `422 Unprocessable Entity`(`campaign.limit-reached`):キャンペーンが合計引き換え上限に達した - `422 Unprocessable Entity`(`campaign.player-limit-reached`):プレイヤーがキャンペーンごとの引き換え上限に達した - `422 Unprocessable Entity`(`redemptionCode.campaign-invalid`):キャンペーンが有効でない、有効期間外、またはコードが無効化されている。エラーの `message` フィールドでこれらの理由を区別できます - `422 Unprocessable Entity`(`redemptionCode.limit-reached`):引き換えコードが自身の利用上限に達した - `422 Unprocessable Entity`(`redemptionCode.player-limit-reached`):プレイヤーがこのコードの引き換え上限に達した - `429 Too Many Requests`:レート制限を超過した - `500 Server Error`:予期しないサーバーエラー ## テスト テストモードを使用して引き換え機能の開発とテストを行います: 1. テスト API キー(`test_` プレフィックス付き)を使用してテストキャンペーンとコードを操作する 2. Tokenz Dashboardでテストモードを使用してテストキャンペーンを作成する 3. テスト引き換えはライブデータから完全に分離される — テスト API キーはテストコードのみ、ライブ API キーはライブコードのみ引き換え可能 4. テストエンティティ ID には `_t` サフィックスが付く(例:`redemption_1XyZaBcDe34_t`) 5. テスト Webhook はテスト Webhook エンドポイントにのみ配信され、ペイロードに `"test": true` が含まれる