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

# 创建退款工单

> 为已成功的支付请求退款

`POST /api/actions/refund-ticket/create-ticket`

**认证：** 商户 API Key（服务端到服务端）。

## 请求体

| 字段                               | 类型     | 必填 | 描述                                                    |
| -------------------------------- | ------ | -- | ----------------------------------------------------- |
| `paymentId`                      | string | 是  | 待退款的支付 Short ID，例如 `PAY_6eYCunG3IMmIgcQOnaXdoA`       |
| `reason`                         | string | 是  | 自由文本退款原因（展示给 customer / dashboard）                    |
| `requestedAmount.amount`         | string | 是  | 显示格式的退款金额（例如 `"10.50"`），必须 `> 0` 且 `≤ payment.amount` |
| `requestedAmount.currency`       | string | 是  | ISO 4217 代码，必须与支付货币一致                                 |
| `refundTicketMerchantExternalId` | string | 否  | 商户业务侧退款工单标识（最大 128 字符）                                |

## 成功响应 (200)

```json theme={"system"}
{
  "data": {
    "ticket": {
      "id": "TKT_3bVzrkD0FJjFdZNLk8Ualx",
      "status": "processing",
      "subjectId": "PAY_6eYCunG3IMmIgcQOnaXdoA",
      "refundTicketMerchantExternalId": "REF-2026-00891"
    }
  }
}
```

商户通过 API Key 提交时，工单自动批准，直接进入 `processing`。

## 错误响应

> **重试策略**：4xx 一律不要重试 — 修正请求后重发。5xx 指数退避重试（起步 5s，最多 3 次）。

| 状态码 | `errors[0].message`                                             | 含义                                                                               | 推荐处理                      |
| --- | --------------------------------------------------------------- | -------------------------------------------------------------------------------- | ------------------------- |
| 400 | `Missing required field: <name>`                                | 必填字段缺失（`paymentId`、`reason`、`requestedAmount.amount`、`requestedAmount.currency`） | 修正请求体后重发                  |
| 400 | `Expected format: PAY_xxx, got "..."`                           | `paymentId` Short ID 解码失败                                                        | 修正 `paymentId` 格式后重发      |
| 400 | `Invalid requestedAmount.amount format`                         | 金额字符串无法解析                                                                        | 使用显示格式如 `"10.50"`（不是最小单位） |
| 400 | `refundTicketMerchantExternalId must be at most 128 characters` | 值超过 128 字符                                                                       | 缩短到 128 字符以内              |
| 401 | `Unauthorized`                                                  | API Key 签名无效                                                                     | 检查认证请求头                   |
| 404 | `Payment not found`                                             | 支付不存在或不属于你的门店                                                                    | 验证 `paymentId`            |
| 409 | `Payment status is X, must be succeeded`                        | 原始支付不在 `succeeded` 状态                                                            | 不要重试 — 支付未成功              |
| 409 | `Payment is not yet fully processed by PSP, please retry later` | PSP 回写尚未完成                                                                       | 5–30 秒后重试（瞬时）             |
| 409 | `Refund period expired (X days, max 14)`                        | 已超过 14 天窗口                                                                       | 不要重试 — 已不允许退款             |
| 409 | `Requested amount must be greater than 0`                       | 金额 ≤ 0                                                                           | 修正金额后重发                   |
| 409 | `Requested amount exceeds payment amount`                       | 金额超过 `payment.amount`                                                            | 修正金额后重发                   |
| 409 | `Currency mismatch: requested X, payment Y`                     | 货币与支付不一致                                                                         | 使用支付的货币                   |
| 409 | `A refund record already exists for this payment`               | 此支付已有成功退款                                                                        | 不要重试 — 通过 GraphQL 查询已有退款  |
| 409 | `A refund ticket already exists for this payment`               | 已有 in-flight 工单阻塞                                                                | 等待已有工单终结后再视情况重发           |
| 500 | `Internal server error`                                         | 服务端意外失败                                                                          | 指数退避重试（起步 5s，最多 3 次）      |

<Tip>
  使用 [GraphQL](/zh/api-reference/endpoints/graphql/orders-and-payments) 查询创建的工单和执行的退款记录。按工单业务号过滤执行的退款使用 `refunds(filter: { refundTicketMerchantExternalId: ... })`。
</Tip>
