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

# 退款端点

> 通过 REST + GraphQL 请求和查询退款

退款端点允许商户为已成功的支付发起退款。退款分为两种模型：**退款工单**（请求）和**退款记录**（PSP 确认后写入的执行结果）。

***

## 业务规则

<Note>
  * 退款必须在原始支付成功后 **14 天**内请求
  * 退款金额可以是**部分金额**（`> 0` 且 `≤ payment.amount`），但必须使用与支付**相同的货币**
  * 原始支付必须已经**完全被 PSP 确认** — 在 payment webhook 到达后立即调用退款可能会瞬时失败；几秒后重试
  * 已有 pending 或 succeeded 退款的支付**不能同时创建另一个退款工单**
  * 商户通过服务端 API Key 提交退款时，工单**自动批准**直接进入 processing — 不经过人工审核
</Note>

***

## 退款工单状态值

| 状态           | 商户视角含义                             |
| ------------ | ---------------------------------- |
| `pending`    | 等待 Waffo 审核（仅 customer 自主发起时可见）    |
| `approved`   | 已批准，即将分发到 PSP                      |
| `rejected`   | 已拒绝 — 通过 GraphQL 查询 `rejectReason` |
| `processing` | 已分发到 PSP，等待上游完成                    |
| `succeeded`  | 资金已返还给 customer                    |
| `failed`     | PSP 返回失败 — 可重新审核并重新提交              |

<Tip>
  商户发起的退款会**跳过** `pending` 和 `approved`，创建后直接显示为 `processing`。
</Tip>

***

## 业务侧标识 — 关联你的业务记录

你可以在两个创建端点上各自附加一个业务侧标识（最大 **128 字符**），对外用扁平 key 命名,以便同一份载荷同时承载两者不产生歧义:

| 创建端点                          | 请求体字段                            | 落库为                                                         |
| ----------------------------- | -------------------------------- | ----------------------------------------------------------- |
| `checkout/create-session`     | `orderMerchantExternalId`        | `orders.merchant_external_id`（首笔 + 订阅续期均继承）                 |
| `refund-ticket/create-ticket` | `refundTicketMerchantExternalId` | `refund_tickets.merchant_external_id`（PSP 成功后继承到 refund 记录） |

端到端透传（请求体、webhook 载荷、GraphQL 类型，三处使用同一组扁平双 key 命名）：

```
checkout/create-session         (请求体: orderMerchantExternalId)
                                    │
                                    ├──► OnetimeOrder / SubscriptionOrder . orderMerchantExternalId
                                    ├──► Payment                          . orderMerchantExternalId   (首笔 + 订阅续期)
                                    │
refund-ticket/create-ticket     (请求体: refundTicketMerchantExternalId)
                                    │
                                    ├──► RefundTicket                     . refundTicketMerchantExternalId
                                    │
                                    └──► Refund 同时承载两者:
                                         • orderMerchantExternalId           (从原始订单继承)
                                         • refundTicketMerchantExternalId    (从原始退款工单继承)
```

这些标识**不是**幂等键 — Waffo 不强制唯一性。同一 reference 可以附加到多条记录上,唯一性由你自己保证。

请求体、webhook 载荷、GraphQL 三处使用同一组字段名,所以你在 checkout / refund-ticket 创建时写入的值可以原样读回,无需做命名转换。

通过 GraphQL 使用这些标识**查询** Payments、Refunds、Refund Tickets — 详见 [GraphQL 订单与支付](/zh/api-reference/endpoints/graphql/orders-and-payments) 指南。

***

## 端点

<CardGroup cols={2}>
  <Card title="创建退款工单" icon="ticket" href="/zh/api-reference/endpoints/refunds/create-refund-ticket">
    为已成功的支付请求退款。支持全额、部分退款。
  </Card>

  <Card title="重新提交退款工单" icon="rotate" href="/zh/api-reference/endpoints/refunds/resubmit-refund-ticket">
    修订并重新提交被拒绝或失败的退款工单。
  </Card>
</CardGroup>

<Tip>
  使用 [GraphQL](/zh/api-reference/endpoints/graphql/orders-and-payments) 查询退款工单和执行的退款记录。在 `Refund` 上，两个业务号以扁平字段暴露：`refund.orderMerchantExternalId` 和 `refund.refundTicketMerchantExternalId`（与 webhook 载荷同名）。按退款工单业务号过滤执行的退款，使用 `refunds(filter: { refundTicketMerchantExternalId: ... })`。
</Tip>
