> ## Documentation Index
> Fetch the complete documentation index at: https://docs.waffo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# クーポンの作成

> クーポンをそのコードと一緒に、必要に応じてプロモーションコードも含めて 1 回のリクエストで作成する

購入者がチェックアウトで入力できる自身の `code` を持つクーポンを作成します。プロモーションコードを最大 20 個まで同時に作成できます。すべて 1 回のリクエストで作成され、クーポン、そのコード、すべてのプロモーションコードは一緒に有効になるか、どれも作成されないかのどちらかです。クーポンの使用制限は有効期限（`redeemBy`）と合計使用回数（`maxRedemptions`）のみです。購入者の制限（購入者のメールアドレス、購入者ごとの回数、最低金額）はプロモーションコードに設定します。[チェックアウトセッション](https://docs.waffo.ai/ja/api-reference/endpoints/orders/create-checkout-session.md)で `couponId` を指定してクーポンを適用することもできます。プロモーションコードは後から[プロモーションコードの作成](https://docs.waffo.ai/ja/api-reference/endpoints/promotion-codes/create-promotion-code.md)で追加できます。

```
POST /v1/actions/coupon/create-coupon
```

**認証：** API Key（ストアの owner または admin）

## リクエストボディ

| フィールド | 型 | 必須 | 説明 |
| - | - | - | - |
| `storeId` | string | はい | ストア ID（Short ID 形式 `STO_xxx`） |
| `name` | string | はい | 内部用の名前（最大 64 文字）。購入者には表示されません |
| `code` | string | いいえ | クーポン自身のコード。購入者がチェックアウトで入力します：英字・数字・`-` の 3–32 文字。大文字・小文字は区別せず、大文字で保存されます。同じストア・同じ環境の有効なコード、および `promotionCodes` 内のコードと重複できません。省略すると 10 文字のランダムなコードが生成されます |
| `discount` | object | はい | `{ "type": "percentage", "percentOff": 20 }` または `{ "type": "fixed_amount", "amountOff": { "USD": "5.00" } }`（下記参照） |
| `duration` | string | いいえ | サブスクリプションで割引する請求期間：`once`（デフォルト）、`repeating`、`forever`。単発注文では 1 回のみ割引されます |
| `durationInPeriods` | integer | `repeating` の場合 | 請求期間の回数（≥ 1）。`duration` が `repeating` のときのみ指定可能 |
| `productIds` | string\[] | いいえ | 対象商品（`PROD_xxx`、最大 100 件）。空または省略時はストア全体が対象 |
| `maxRedemptions` | integer \| null | いいえ | クーポンのコードとすべてのプロモーションコードを合計した使用回数の上限（≥ 1）。返金しても回数は戻りません。`null` は無制限 |
| `redeemBy` | string \| null | いいえ | 有効期限（ISO 8601、現在から 60 秒より先の時刻）。サブスクリプションに適用済みの割引もこの時刻に終了します |
| `promotionCodes` | object\[] | いいえ | クーポンと一緒に作成するプロモーションコード、0–20 個（[プロモーションコードオブジェクト](#プロモーションコードオブジェクト)を参照）。省略するとコードのないクーポンになります |

## 割引オブジェクト

| フィールド | 型 | 説明 |
| - | - | - |
| `type` | string | `percentage` または `fixed_amount` |
| `percentOff` | number | `percentage` の場合は必須。0 \< x ≤ 100、小数第 2 位まで。`100` で注文が無料になります |
| `amountOff` | object | `fixed_amount` の場合は必須。ISO 4217 通貨ごとの割引額（表示形式の文字列）。小数桁数は通貨の桁数（USD 2 桁、JPY 0 桁、BHD 3 桁）以内で、超えると 400 を返し四捨五入はしない。含まれない通貨の注文には使用できません。為替換算は行いません |

```json theme={"system"}
{
  "discount": {
    "type": "fixed_amount",
    "amountOff": { "USD": "5.00", "EUR": "4.50", "JPY": "800" }
  }
}
```

## プロモーションコードオブジェクト

`promotionCodes` の各要素は、[プロモーションコードの作成](https://docs.waffo.ai/ja/api-reference/endpoints/promotion-codes/create-promotion-code.md)と同じフィールドを受け付けます（`couponId` を除く）：

| フィールド | 型 | 必須 | 説明 |
| - | - | - | - |
| `code` | string | いいえ | 購入者が入力するコード：英字・数字・`-` の 3–32 文字。大文字・小文字は区別せず、大文字で保存されます。同じストア・同じ環境の有効なコード、およびリクエスト内の他の要素、クーポンの `code`と重複できません。省略すると 10 文字のランダムなコードが生成されます |
| `restrictions` | object | いいえ | `customerEmails`、`perCustomerLimit`、`maxRedemptions`（クーポンの `maxRedemptions` 以下）、`expiresAt`（現在から 60 秒より先、かつクーポンの `redeemBy` 以前。省略時は `redeemBy`）、`minimumAmount` — [制限オブジェクト](https://docs.waffo.ai/ja/api-reference/endpoints/promotion-codes/create-promotion-code.md#制限オブジェクト)を参照。`perCustomerLimit`・`maxRedemptions`・`expiresAt`・`minimumAmount` は `null` を指定でき、未設定として扱われます（`expiresAt: null` はクーポンの `redeemBy`）。`customerEmails` は `null` を受け付けません。未設定にするには省略するか、`[]` を指定します |

## リクエスト例

```typescript SDK theme={"system"}
import { WaffoPancake } from "@waffo/pancake-ts";

const client = new WaffoPancake({
  merchantId: process.env.WAFFO_MERCHANT_ID!,
  privateKey: process.env.WAFFO_PRIVATE_KEY!,
});

const { coupon } = await client.coupons.create(
  {
    storeId: "STO_2aUyqjCzEIiEcYMKj7TZtw",
    name: "Black Friday 20% off",
    discount: { type: "percentage", percentOff: 20 },
    duration: "repeating",
    durationInPeriods: 3,
    maxRedemptions: 1000,
    redeemBy: "2026-12-01T00:00:00.000Z",
    code: "bf2026",
    promotionCodes: [{ code: "bf-new", restrictions: { perCustomerLimit: 1 } }],
  },
  { idempotencyKey: "MER_2aUyqjCzEIiEcYMKj7TZtw-0f8e2a9c-5b1d-4e7a-9c3f-2d6b8e1a4c70" },
);
console.log(coupon.status, coupon.code, coupon.promotionCodes[0].code); // => "active" "BF2026" "BF-NEW"
```

```bash cURL theme={"system"}
MERCHANT_ID="MER_2aUyqjCzEIiEcYMKj7TZtw"
IDEMPOTENCY_KEY="MER_2aUyqjCzEIiEcYMKj7TZtw-0f8e2a9c-5b1d-4e7a-9c3f-2d6b8e1a4c70"
TIMESTAMP=$(date +%s)
BODY='{"storeId":"STO_2aUyqjCzEIiEcYMKj7TZtw","name":"Black Friday 20% off","discount":{"type":"percentage","percentOff":20},"duration":"repeating","durationInPeriods":3,"maxRedemptions":1000,"redeemBy":"2026-12-01T00:00:00.000Z","code":"bf2026","promotionCodes":[{"code":"bf-new","restrictions":{"perCustomerLimit":1}}]}'
BODY_HASH=$(echo -n "$BODY" | openssl dgst -sha256 -binary | base64 | tr -d '\n')
CANONICAL_REQUEST="POST
/v1/actions/coupon/create-coupon
$TIMESTAMP
$BODY_HASH"

SIGNATURE=$(echo -n "$CANONICAL_REQUEST" | openssl dgst -sha256 -sign private_key.pem | base64 | tr -d '\n')

curl -X POST "https://api.waffo.ai/v1/actions/coupon/create-coupon" \
  -H "Content-Type: application/json" \
  -H "X-Merchant-Id: $MERCHANT_ID" \
  -H "X-Timestamp: $TIMESTAMP" \
  -H "X-Signature: $SIGNATURE" \
  -H "X-Idempotency-Key: $IDEMPOTENCY_KEY" \
  -d "$BODY"
```

```python Python theme={"system"}
import hashlib, time, base64, json, requests
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding

merchant_id = "MER_2aUyqjCzEIiEcYMKj7TZtw"
timestamp = str(int(time.time()))
body = {
    "storeId": "STO_2aUyqjCzEIiEcYMKj7TZtw",
    "name": "Black Friday 20% off",
    "discount": {"type": "percentage", "percentOff": 20},
    "duration": "repeating",
    "durationInPeriods": 3,
    "maxRedemptions": 1000,
    "redeemBy": "2026-12-01T00:00:00.000Z",
    "code": "bf2026",
    "promotionCodes": [{"code": "bf-new", "restrictions": {"perCustomerLimit": 1}}],
}

body_json = json.dumps(body, separators=(",", ":"))
body_hash = base64.b64encode(hashlib.sha256(body_json.encode()).digest()).decode()
path = "/v1/actions/coupon/create-coupon"
canonical = f"POST\n{path}\n{timestamp}\n{body_hash}"

with open("private_key.pem", "rb") as f:
    private_key = serialization.load_pem_private_key(f.read(), password=None)

signature = base64.b64encode(
    private_key.sign(canonical.encode(), padding.PKCS1v15(), hashes.SHA256())
).decode()

resp = requests.post(
    f"https://api.waffo.ai{path}",
    headers={
        "Content-Type": "application/json",
        "X-Merchant-Id": merchant_id,
        "X-Timestamp": timestamp,
        "X-Signature": signature,
        "X-Idempotency-Key": "MER_2aUyqjCzEIiEcYMKj7TZtw-0f8e2a9c-5b1d-4e7a-9c3f-2d6b8e1a4c70",
    },
    data=body_json,
)
print(resp.json())
```

## 成功レスポンス (200)

```json theme={"system"}
{
  "data": {
    "coupon": {
      "id": "CPN_5dXBtmF2HLlHfbPNm0Wcnz",
      "storeId": "STO_2aUyqjCzEIiEcYMKj7TZtw",
      "name": "Black Friday 20% off",
      "code": "BF2026",
      "status": "active",
      "discountType": "percentage",
      "percentOff": 20,
      "amountOff": null,
      "duration": "repeating",
      "durationInPeriods": 3,
      "productIds": [],
      "maxRedemptions": 1000,
      "redeemBy": "2026-12-01T00:00:00.000Z",
      "createdAt": "2026-11-01T08:00:00.000Z",
      "updatedAt": "2026-11-01T08:00:00.000Z",
      "promotionCodes": [
        {
          "id": "PMC_7fZDvoH4JNnJhdRPo2Yep1",
          "couponId": "CPN_5dXBtmF2HLlHfbPNm0Wcnz",
          "code": "BF-NEW",
          "status": "active",
          "restrictions": {
            "customerEmails": [],
            "perCustomerLimit": 1,
            "maxRedemptions": null,
            "expiresAt": "2026-12-01T00:00:00.000Z",
            "minimumAmount": null
          },
          "batchId": null,
          "createdAt": "2026-11-01T08:00:00.000Z"
        }
      ]
    }
  }
}
```

## レスポンスフィールド

レスポンスは `data.coupon` にラップされます。

| フィールド | 型 | 説明 |
| - | - | - |
| `id` | string | クーポン ID（`CPN_xxx`） |
| `storeId` | string | ストア ID（`STO_xxx`） |
| `name` | string | 内部用の名前 |
| `code` | string | クーポン自身のコード（大文字）。購入者がチェックアウトで入力できます |
| `status` | string | このレスポンスでは常に `active`（[クーポンのステータス値](https://docs.waffo.ai/ja/api-reference/endpoints/coupons/overview.md)を参照） |
| `discountType` | string | `percentage` または `fixed_amount` |
| `percentOff` | number \| null | 割引率。`fixed_amount` の場合は `null` |
| `amountOff` | object \| null | 通貨ごとの割引額（表示形式の文字列）。`percentage` の場合、および [warnings 付きレスポンス](#warnings-付きレスポンス)では `null` |
| `duration` | string | `once`、`repeating`、`forever` |
| `durationInPeriods` | integer \| null | `repeating` の請求期間の回数。それ以外は `null` |
| `productIds` | string\[] | 対象商品。空の場合はストア全体 |
| `maxRedemptions` | integer \| null | クーポンのコードとすべてのプロモーションコードを合計した使用回数の上限 |
| `redeemBy` | string \| null | 有効期限（ISO 8601） |
| `createdAt` | string | 作成日時（ISO 8601） |
| `updatedAt` | string | 最終更新日時（ISO 8601） |
| `promotionCodes` | object\[] | このリクエストで作成されたプロモーションコード（リクエストの順。フィールドは[プロモーションコードの作成](https://docs.waffo.ai/ja/api-reference/endpoints/promotion-codes/create-promotion-code.md)のレスポンスと同じ。[warnings 付きレスポンス](#warnings-付きレスポンス)では `restrictions.minimumAmount` が `null`）。指定しなかった場合は空配列 |

> [!NOTE]
>
> 作成はリクエスト内で成功か失敗のどちらかに確定します。`200` レスポンスのクーポンは常に `active` です。決済プロバイダーが拒否した場合や作成を確認できなかった場合は `502` が返り、クーポンは `failed` として記録され、リクエストのコードはすべて解放されます。そのまま作成し直せます（同じコードも使用できます）。リクエストが完了前に中断された場合、クーポンが `pending` のままコードを占有することがあります。このようなクーポンは作成から 10 分を過ぎると、同じストア・同じ環境での次のクーポン作成、プロモーションコード作成、またはプロモーションコード一括生成のリクエスト時にその場でクリーンアップされます（`failed` として記録され、コードは解放されます）。

## warnings 付きレスポンス

クーポンが `active` になった時点でそのコードは使用可能になり、リクエストはそれ以降失敗しません。その時点で Pancake が金額を表示形式に変換できなかった場合も、`active` のクーポンとともに `200` を返します。このとき `amountOff` とすべての `promotionCodes[].restrictions.minimumAmount` は `null` になり（レスポンスの形は変わりません）、レスポンスのトップレベルに金額が変換されなかったことを示す `warnings` 配列が付きます。その他のフィールドは通常どおり返されます。

```json theme={"system"}
{
  "data": {
    "coupon": {
      "id": "CPN_5dXBtmF2HLlHfbPNm0Wcnz",
      "status": "active",
      "discountType": "fixed_amount",
      "amountOff": null,
      "...": "...",
      "promotionCodes": [
        {
          "code": "BF-NEW",
          "restrictions": { "minimumAmount": null, "...": "..." },
          "...": "..."
        }
      ]
    }
  },
  "warnings": [
    {
      "message": "Coupon was created, but amounts could not be converted to display format; amountOff and restrictions.minimumAmount are returned as null",
      "layer": "product",
      "aiHint": "- Query: read the coupon with the GraphQL `coupon(id)` query to get the display amounts; do not retry the creation"
    }
  ]
}
```

クーポンはリクエストどおりに作成済みです。再作成しないでください。金額は GraphQL `coupon(id)` でクーポンを取得して確認します。

## エラー

> **リトライポリシー**：4xx は一切リトライしない — リクエストを修正してから再送信。5xx は指数バックオフでリトライ（5s 開始、最大 3 回）。リトライ時は必ず同じ `X-Idempotency-Key` を使用。

| ステータス | `errors[0].message` | 意味 | 推奨処理 |
| - | - | - | - |
| 400 | `Missing header: x-context-merchant-id` | マーチャントコンテキスト header が転送されていない | SDK 設定を修正 |
| 400 | `Missing or invalid header: x-context-environment` | 環境 header が欠落、または `test` / `prod` ではない | `X-Environment` を `test` または `prod` に設定 |
| 400 | `Invalid JSON body` | ボディが正しい JSON ではない | ボディを修正して再送信 |
| 400 | `Missing required field: storeId` / `Missing required field: name` | 必須フィールド欠落 | フィールドを追加して再送信 |
| 400 | `Expected format: STO_xxx, got "X"` | `storeId` が正しい Short ID ではない | `STO_` 接頭辞付きの Short ID を使用 |
| 400 | `name must not exceed 64 characters` | `name` が長すぎる | `name` を短くして再送信 |
| 400 | `code must be a string` / `promotionCodes[N].code must be a string` | `code`、または `promotionCodes` の要素 `N`（0 始まり）の `code` が文字列ではない | 文字列を指定するか、省略してランダムに生成 |
| 400 | `code must be 3-32 characters of letters, digits or '-'` / `promotionCodes[N].code must be 3-32 characters of letters, digits or '-'` | `code`、または要素 `N`（0 始まり）の `code` に使用できない文字が含まれる、または長さが範囲外 | コードを修正して再送信 |
| 400 | `promotionCodes must not exceed 20 entries` | プロモーションコードが 20 個を超えている | クーポンと一緒に作成するのは 20 個まで。残りはプロモーションコードの作成で追加 |
| 400 | `promotionCodes[N].code "X" duplicates another promotion code in this request` | 要素 `N`（0 始まり）のコードがそれより前の要素と同じ（大文字・小文字は区別しない） | 重複を取り除く |
| 400 | `promotionCodes[N].code "X" duplicates the coupon code` | 要素 `N`（0 始まり）のコードが `code` と同じ（大文字・小文字は区別しない） | その要素に別のコードを使用 |
| 400 | `promotionCodes[N].restrictions.maxRedemptions must not exceed the coupon's maxRedemptions (M)` / `promotionCodes[N].restrictions.expiresAt must be more than 60 seconds in the future` / `promotionCodes[N].restrictions.expiresAt must not be later than the coupon's redeemBy (T)` | `N` 番目（0 始まり）の要素がクーポンの制限を超えている、またはその `expiresAt` が現在から 60 秒未満 | その要素の制限を修正 |
| 400 | `discount.type must be percentage or fixed_amount` / `discount: discount.type must be percentage or fixed_amount` | `discount.type` が許可値ではない（前者）、または `discount` が欠落しているかオブジェクトではない（後者） | `type` が `percentage` または `fixed_amount` の `discount` を指定 |
| 400 | `discount.percentOff is required for percentage` / `discount.percentOff must be greater than 0` / `discount.percentOff must not exceed 100` / `discount.percentOff allows at most 2 decimal places` | `percentOff` が欠落、または範囲外 | 0 \< x ≤ 100、小数第 2 位までの数値を使用 |
| 400 | `discount.amountOff: At least one currency is required` / `promotionCodes[N].restrictions.minimumAmount: At least one currency is required` | `amountOff`、または `promotionCodes` の要素 `N`（0 始まり）の `minimumAmount` が空のオブジェクト | 通貨を 1 つ以上指定 |
| 400 | `discount.amountOff: Invalid currency code: "X". Must be 3 uppercase letters (e.g., "USD", "EUR", "JPY")` / `promotionCodes[N].restrictions.minimumAmount: Invalid currency code: "X". Must be 3 uppercase letters (e.g., "USD", "EUR", "JPY")` | `amountOff`、または要素 `N` の `minimumAmount` のキーが ISO 4217 コードに準拠していない | 3 文字の大文字を使用 |
| 400 | `discount.amountOff: Invalid amount for X: "Y". Must be a positive number string (e.g., "5.00", "500")` / `promotionCodes[N].restrictions.minimumAmount: Invalid amount for X: "Y". Must be a positive number string (e.g., "5.00", "500")` | `amountOff`、または要素 `N` の `minimumAmount` の値が正の数値文字列ではない | 正の十進数文字列を使用 |
| 400 | `discount.amountOff: Invalid amount for X: "Y". X allows at most D decimal places` / `discount.amountOff: Invalid amount for X: "Y". X does not allow decimal places` / `promotionCodes[N].restrictions.minimumAmount: Invalid amount for X: "Y". X allows at most D decimal places` / `promotionCodes[N].restrictions.minimumAmount: Invalid amount for X: "Y". X does not allow decimal places` | `amountOff`、または要素 `N` の `minimumAmount` の金額が通貨の小数桁数を超えている（例：USD `"0.001"`、JPY `"5.5"`）。四捨五入は行わない | 通貨の小数桁数に合わせる（USD 2 桁、JPY 0 桁、BHD 3 桁） |
| 400 | `discount.amountOff: Invalid amount for X: "Y". Must be at least Z X` / `promotionCodes[N].restrictions.minimumAmount: Invalid amount for X: "Y". Must be at least Z X` | `amountOff`、または要素 `N` の `minimumAmount` の金額が通貨の最小単位 1 つ分に満たない | 少なくとも通貨の最小単位を指定（例：USD `"0.01"`） |
| 400 | `duration must be once, repeating or forever` | `duration` が許可値ではない | `once`、`repeating`、`forever` のいずれかを使用 |
| 400 | `durationInPeriods is required when duration is repeating, and only allowed then` | `repeating` で `durationInPeriods` が欠落、または他の `duration` で指定されている | `durationInPeriods` は `repeating` のときのみ指定 |
| 400 | `durationInPeriods must be an integer` / `durationInPeriods must be at least 1` / `durationInPeriods must not exceed 2147483647` | `durationInPeriods` が正の整数ではない、または大きすぎる | 1〜2147483647 の整数を使用 |
| 400 | `maxRedemptions must be an integer` / `maxRedemptions must be at least 1` / `maxRedemptions must not exceed 2147483647` | クーポンの `maxRedemptions` が正の整数ではない、または大きすぎる | 1〜2147483647 の整数を使用。無制限なら `null` |
| 400 | `promotionCodes[N].restrictions.X must be an integer` / `promotionCodes[N].restrictions.X must be at least 1` / `promotionCodes[N].restrictions.X must not exceed 2147483647` | エントリ `N`（0 始まり）の `X`（`perCustomerLimit`・`maxRedemptions`）が正の整数ではない、または大きすぎる（例: `promotionCodes[1].restrictions.perCustomerLimit must be at least 1`） | 1〜2147483647 の整数を使用。無制限なら `null` |
| 400 | `productIds must not exceed 100 entries` | 商品が多すぎる | 商品 ID は最大 100 件まで |
| 400 | `Expected format: PROD_xxx, got "X"` | `productIds` に正しくない Short ID が含まれる | `PROD_` 接頭辞付きの Short ID を使用 |
| 400 | `redeemBy must be an ISO 8601 datetime` / `redeemBy must be more than 60 seconds in the future` | `redeemBy` の形式が不正、または現在から 60 秒未満 | タイムゾーンオフセット（例：`Z`）付きで、現在から 60 秒より先の ISO 8601 時刻を指定 |
| 400 | `restrictions is not a coupon field; set it in promotionCodes[].restrictions` | 購入者の制限をクーポンに指定した。クーポンにあるのは `redeemBy` と `maxRedemptions` のみ | `promotionCodes[].restrictions`（または後から作成するプロモーションコード）に移す |
| 400 | `dailyRedemptionLimit is not supported` | クーポンに `dailyRedemptionLimit` を指定した（`null` を含む任意の値）。このフィールドはサポートされていない | フィールドを削除 |
| 400 | `promotionCodes[N].restrictions.firstTimeOnly is not supported` / `promotionCodes[N].restrictions.dailyRedemptionLimit is not supported` | 要素 `N`（0 始まり）の `restrictions` に `firstTimeOnly` または `dailyRedemptionLimit` を指定した（`null` / `false` を含む任意の値）。これらのフィールドはサポートされていない | フィールドを削除 |
| 400 | `promotionCodes[N].restrictions.expiresAt must be an ISO 8601 datetime` | 要素 `N`（0 始まり）の `expiresAt` の形式が正しくない | タイムゾーンオフセット（例: `Z`）付きの ISO 8601 時刻を指定 |
| 400 | `promotionCodes[N].restrictions.customerEmails[M] must be a valid email address` / `promotionCodes[N].restrictions.customerEmails must not exceed 100 entries` | 要素 `N`（0 始まり）の `customerEmails` の `M` 番目（0 始まり）が有効なメールアドレスではない、またはリストが 100 件を超える | リストを修正して再送信 |
| 400 | `X: Invalid input: expected Y, received Z` | フィールド `X` の JSON 型が正しくない。`X` はフィールドの完全なパス（例: `promotionCodes[0].restrictions.maxRedemptions: Invalid input: expected number, received string`、`promotionCodes[0].restrictions.customerEmails: Invalid input: expected array, received null`） | 上記の型でフィールドを指定 |
| 401 | `Authentication required` | 認証失敗 | API Key、タイムスタンプ、署名を確認 |
| 403 | `Access denied` | ストアが存在しない、または呼び出し元がそのストアの owner / admin ではない | ストアの owner または admin の API Key を使用し、`storeId` を確認 |
| 404 | `Product not found in this store: PROD_xxx` | `productIds` の商品がこのストアに存在しない | 商品 ID を削除または修正 |
| 409 | `Code "X" is already used by an active code in this store` | 同じストア・同じ環境の有効なコード（他のクーポンのコードまたはプロモーションコード）がこのコードを使用中。`code` とすべての `promotionCodes[].code` が対象で、冪等キーなしでリトライした場合は最初のリクエストで作成されたコードも含まれる。使用中のコードごとに `errors` に 1 件ずつ入り、何も作成されない | 別のコードを選ぶ。リトライの場合は再作成せず、GraphQL でクーポンを確認 |
| 409 | `A generated code collided with an existing code; retry the request` | ランダムなコード（クーポンまたはプロモーションコード）は使用中のコードを避けて生成されるが、書き込み時にそのいずれかが直前に使用された（並行リクエストなど）。Pancake は試行ごとにランダムなコードを再生成し、最大 3 回試行したがすべて衝突した。何も作成されない | リクエストをリトライ |
| 409 | `Request is being processed` | 同じ `X-Idempotency-Key` のリクエストがまだ処理中 | **数秒待ってから同じキーでリトライ** |
| 502 | `Payment provider rejected the coupon (code: X); its codes have been released` | 決済プロバイダーがクーポンを拒否した。クーポンは `failed` として記録され、すべてのコードは解放済み | 割引設定を確認し、新しい冪等キーで作成し直す |
| 502 | `Payment provider did not confirm the coupon creation; its codes have been released, please retry` | 決済プロバイダーが作成を確認できず（タイムアウトやプロバイダーのエラー）、Pancake もプロバイダー側でクーポンを見つけられなかった。失敗として扱われ、クーポンは `failed` として記録され、すべてのコードは解放済み | **リクエストをリトライ** — 同じコードを再び使用できる |
| 500 | `Internal server error` | クーポンが `active` になる前のサーバ側の予期しない障害。クーポンがすでに記録されていた場合は `failed` として記録され、コードは解放される。クーポンが `active` になった後は `500` ではなく必ず `200` を返す（[warnings 付きレスポンス](#warnings-付きレスポンス)を参照） | 指数バックオフでリトライ（5s 開始、最大 3 回）。冪等キーは同じものを使用 |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.