> ## 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.

# 创建优惠券

> 在一次请求中创建优惠券及它的码，并可同时创建它的促销码

创建优惠券及它自己的 `code` —— 买家可在收银台输入 —— 并可同时创建最多 20 个促销码。全部内容在一次请求中创建：优惠券、它的码与全部促销码一起生效，或者都不创建。优惠券只按到期时间（`redeemBy`）与总兑换次数（`maxRedemptions`）限制兑换；买家限制（限定买家邮箱、每位买家次数、最低消费）设置在促销码上。优惠券也可在[结账会话](https://docs.waffo.ai/zh/api-reference/endpoints/orders/create-checkout-session.md)上通过 `couponId` 使用；之后可用[创建促销码](https://docs.waffo.ai/zh/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`。一次性订单只优惠一次 |
| `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/zh/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`，默认取它）、`minimumAmount` —— 见[限制对象](https://docs.waffo.ai/zh/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/zh/api-reference/endpoints/coupons/overview.md)） |
| `discountType` | string | `percentage` 或 `fixed_amount` |
| `percentOff` | number \| null | 减免百分比；`fixed_amount` 时为 `null` |
| `amountOff` | object \| null | 按币种的减免金额（显示格式字符串）；`percentage` 时为 `null`，[带 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/zh/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 无法把金额换算为显示格式，仍返回 `200` 和 `active` 的优惠券：`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`、`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` 是空对象 | 至少提供一个币种 |
| 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` 的 key 不是合法 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 为整数、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` 传了该字段 | 仅在 `repeating` 时传 `durationInPeriods` |
| 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` | 商品数量过多 | 最多传 100 个商品 ID |
| 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` 中的一项；本次未创建任何内容 | 换别的码。如果是重试，请改用 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` 后只会返回 `200`，不会返回 `500`（见[带 warnings 的响应](#带-warnings-的响应)） | 指数退避重试（起步 5s，最多 3 次），沿用同一个幂等键 |


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