# 订阅与余额

平台有**两种计费模式**，搞清楚区别，才知道钱怎么花、怎么续。控制台还提供订单恢复/验证、退款预览、发票下载/取消和订阅额度进度。

---

## 两种计费模式

### 1. 钱包余额（按量计费）

**用多少付多少。** 你充值进钱包，每次调用按 token 实时扣费，余额实时显示。

- 适合：用量不固定、想灵活控制成本的人
- 可设**额度上限**（给密钥设额度限制），防止失控
- 余额为 0 时调用会报“余额不足”

### 2. 订阅 / 套餐

按**周期**（如包月）提供配额的套餐。控制台会显示**订阅类型**、**订阅到期**和额度进度；用户侧订阅数据来自 `/subscriptions`、`/subscriptions/active`、`/subscriptions/progress`、`/subscriptions/summary`。

- 适合：用量稳定、想要固定成本的人
- 部分分组**以套餐形式提供**；如果调用报 `No active subscription found for this group`，说明该分组需要先开通/续订套餐
- 到期后需续订才能继续用该分组
- 订阅额度进度会显示日/周/月已用比例、重置倒计时、到期时间和剩余天数，用来判断是否需要升级或续订

> 简单说：**钱包余额 = 按量付费，订阅 = 按周期包量。** 不同分组可能采用不同模式，以控制台显示为准。

真实边界：订阅分组命中有效订阅时，通常扣订阅 usage，不扣钱包余额；余额/标准分组会在请求前检查余额，成功后按 `actual_cost` 扣余额。用户级 platform quota 在订阅模式通常豁免。API Key quota、API Key 金额限速、RPM 是额外限制，不等同于钱包余额或订阅余额。余额没有逐请求冻结；高并发下可能先通过预检，结束后统一按用量扣费并刷新缓存。

---

## 充值与支付中恢复

入口：控制台「**充值 / 订阅**」（或仪表盘「现在充值」）。页面主入口读取 `/payment/checkout-info`，该接口会聚合当前可用支付方式、全局/单笔金额上下限、套餐、余额充值倍率、手续费率、帮助文案/图片、Stripe publishable key、支付宝是否强制二维码等信息。`/payment/limits`、`/payment/plans`、`/payment/channels` 是独立接口，不要把它们理解成当前页面一定会首批全部请求。

- 按页面提示扫码/在线支付，**余额自动到账**，无需手动兑换
- **建议先小额测试**：确认速度、模型表现满意后再追加
- 有**兑换码**时，在兑换页通过 `/redeem` 核销；兑换历史可通过 `/redeem/history` 或分页 `/redeem/history-page` 查看 `code`、`type`、`value`、`status`、`used_at`，订阅兑换还会显示 `group_id`、有效天数和分组信息。兑换请求字段是 `code`;历史分页支持 `type`、`page`、`page_size`;输错/过期/重复使用会返回 `REDEEM_CODE_NOT_FOUND`、`REDEEM_CODE_USED`、`REDEEM_CODE_EXPIRED`、`REDEEM_RATE_LIMITED`、`REDEEM_CODE_LOCKED`
- 如果付款页关闭、网络中断或状态一直停在“支付中”，回到「订单」页点击恢复/验证；已登录场景使用 `/payment/orders/verify`,公开恢复页可用 `/payment/public/orders/resolve` 的签名 `resume_token` 解析订单,或旧版 `/payment/public/orders/verify` 的 `out_trade_no` verify
- 创建订单时页面会提交 `amount`、`payment_type`、`openid`、`wechat_resume_token`、`return_url`、`payment_source`、`order_type`、`plan_id`、`is_mobile` 等字段。`payment_source` 常见为普通托管/跳转支付的 `hosted_redirect`，以及微信内浏览器恢复支付的 `wechat_in_app_resume`。创建订单响应可能包含 `result_type`、`out_trade_no`、`pay_url`、`qr_code`、`client_secret`、`intent_id`、`currency`、`country_code`、`payment_env`、`payment_mode`、`resume_token`、`oauth`、`jsapi`/`jsapi_payload`；`result_type` 常见为 `order_created`、`oauth_required`、`jsapi_ready`。微信恢复场景若 token 缺失/不匹配,可能返回 `INVALID_WECHAT_PAYMENT_RESUME_TOKEN`、`wechat payment resume context is missing`、`wechat payment resume token missing openid`、`wechat payment resume token payment type mismatch`。
- Stripe/弹窗/扫码恢复支付会使用 signed `resume_token` 公开查询订单，推荐接口是 `POST /payment/public/orders/resolve`。普通 `resume_token` 默认约 24 小时有效；微信内恢复 token 默认约 15 分钟有效。未配置签名 key 时会返回 `PAYMENT_RESUME_NOT_CONFIGURED`；普通 token 解析、过期、签名或订单/用户/provider/支付类型不匹配时统一返回 `INVALID_RESUME_TOKEN`;订单不存在返回 `NOT_FOUND`。不要把旧订单或另一渠道的 resume token 复制到新订单继续支付。
- `return_url` 必须是绝对 `http/https` URL，路径必须是 `/payment/result`，host 必须等于当前请求 host 或 Referer host。后端会去掉 fragment，并追加 `order_id`、`out_trade_no`、`resume_token`、`status=success`。只有 `return_url` 合法且支付恢复签名已配置时才会返回 `resume_token`。
- 微信内没有 `openid` 时，创建订单可能返回 `result_type=oauth_required` 和 `oauth.authorize_url`，前端跳转微信 OAuth；回调回到前端 URL fragment，带 `wechat_resume_token` 和 `redirect`。再次创建订单时提交该 token，后端会使用 token 里的 `openid/payment_type/amount/order_type/plan_id` 等值。
- 不同支付渠道可能有单笔金额、每日金额、退款和发票开关限制。页面只展示当前可用渠道,以控制台实时配置为准；退款入口还会受 `/payment/orders/refund-eligible-providers` 限制,发票入口会受 `/payment/orders/invoice-eligible-providers` 限制。

创建订单常见错误:

系统生成的订单号通常类似 `sub2_YYYYMMDDxxxxxxxx`，非空订单号有唯一约束。公开恢复页的旧版 `/payment/public/orders/verify` 使用 `out_trade_no` 主动查单并可能触发上游对账补记。`out_trade_no` 为空、超过 64 字符，或包含字母/数字/下划线/连字符以外字符时，会返回 `INVALID_OUT_TRADE_NO`。

| 错误 | 含义 |
|---|---|
| `BALANCE_PAYMENT_DISABLED` / `balance recharge has been disabled` | 余额充值关闭 |
| `PAYMENT_METHOD_DISABLED` / `method_not_configured` | 支付方式关闭或未配置 |
| `INVALID_AMOUNT` / `amount must be a positive number` / `amount out of range` | 金额为空、非正数或超出范围 |
| `INVALID_INPUT` / `subscription order requires a plan` | 订阅订单缺套餐 |
| `PLAN_NOT_AVAILABLE` | 套餐不可用 |
| `GROUP_NOT_FOUND` / `GROUP_TYPE_MISMATCH` | 套餐/分组不匹配 |
| `INVALID_RETURN_URL` | 回跳地址不允许或格式错误 |
| `INVALID_WECHAT_PAYMENT_RESUME_TOKEN` | 微信支付恢复 token 缺失、过期、payload 非法、支付类型/金额不匹配 |
| `PAYMENT_DISABLED` / `USER_INACTIVE` | 支付系统关闭或用户状态不可支付 |
| `TOO_MANY_PENDING` / `DAILY_LIMIT_EXCEEDED` | 待支付订单过多或当日金额限制 |
| `NO_AVAILABLE_INSTANCE` / `PAYMENT_GATEWAY_ERROR` / `PAYMENT_PROVIDER_MISCONFIGURED` | 当前支付实例/通道不可用或服务商配置异常 |
| `WECHAT_PAYMENT_MP_NOT_CONFIGURED` / `WECHAT_H5_NOT_AUTHORIZED` | 微信 JSAPI/MP 配置缺失或商户未开通 H5 支付 |

---

## 订单状态

「**订单**」页可查历史充值记录：`amount`、实际支付 `pay_amount`、`fee_rate`、`payment_type`、`out_trade_no`、`order_type`、创建/过期/支付/完成时间、失败原因、退款金额与发票关联状态。列表来自 `GET /payment/orders/my`,支持 `page`、`page_size`、`status`、`order_type`、`payment_type` 过滤;返回中还可能看到 `provider_instance_id`、`invoice_status`、`invoice_id`。对账或售后时，提供 `out_trade_no`、订单 ID、支付渠道和付款时间能更快定位。

未支付订单可在详情页取消，页面会调用 `POST /payment/orders/{id}/cancel`。取消只允许 `PENDING` 订单；如果支付已经完成或订单已过期/已取消，请重新下单或走退款/工单流程。站点可能配置取消频率限制，短时间反复创建/取消订单会被限制。

取消订单常见错误:`FORBIDDEN` 表示不是你的订单,`NOT_FOUND` 表示订单不存在,`INVALID_STATUS` 表示当前状态不能取消,`ORDER_ALREADY_PAID` 表示取消前与上游对账发现已付款。用户取消频率超限会返回 `CANCEL_RATE_LIMITED`,metadata 会带 `max`、`window`、`unit`。

常见状态：

| 状态 | 含义 | 你可以做什么 |
|------|------|--------------|
| `PENDING` | 已创建，等待支付 | 继续支付或取消 |
| `COMPLETED` / `PAID` | 支付完成并已入账/开通 | 查看明细、申请发票或退款 |
| `RECHARGING` | 支付已确认，正在入账或开通中 | 等待最终完成；不要重复付款 |
| `FAILED` | 支付失败或验签失败 | 重新下单；必要时提交工单 |
| `CANCELLED` / `EXPIRED` | 已取消或超时 | 重新创建订单 |
| `REFUND_REQUESTED` | 已提交退款申请 | 等待处理 |
| `REFUNDING` | 正在退款 | 等待支付渠道回调 |
| `REFUNDED` | 已全额退款 | 查看退款金额和时间 |
| `PARTIALLY_REFUNDED` | 已部分退款 | 查看剩余可退金额 |
| `REFUND_FAILED` | 退款失败 | 提交工单或重试 |

---

## 主动验证与支付结果页

`/payment/orders/verify` 会按 `out_trade_no` 查找当前登录用户的订单；当订单处于 `PENDING`、`EXPIRED`、`FAILED`、`CANCELLED` 等可恢复状态时，会主动调用上游 `QueryOrder`，如果上游显示已支付，会走本地入账/开通流程并重新加载订单。公开旧接口 `/payment/public/orders/verify` 是兼容路径，主要用于带 `out_trade_no` 的老结果页，公开恢复范围更窄，主要覆盖 `EXPIRED`、`FAILED`、`CANCELLED` 等状态；推荐恢复路径仍是 signed `resume_token` + `/payment/public/orders/resolve`。

支付结果页通常优先用 `resume_token` 恢复；失败时在有订单号上下文时回退到订单轮询或 `out_trade_no` 验证。微信扫码待支付时，前端会有限次数主动触发验证，以弥补支付回调延迟。

---

## 退款与退款预览

如需退款，可在控制台自助申请（或通过工单）。发起前先看 `/payment/orders/{id}/refund-preview` 的**退款预览**：它会展示 `max_refund_amount`、`already_refunded`、`refund_enabled`、`auto_refund`、余额可用额或订阅已用折算等信息。提交退款时常见字段是 `reason` 和可选 `amount`;订单号不合法会返回 `Invalid order ID`,重复申请可能显示 `refund requested`。

- 已消耗部分通常不能按原额退款。
- 已开票或有发票申请的订单，退款入口可能隐藏、被阻止，或需要人工确认。
- 只有支持用户自助退款的支付渠道才会显示退款入口；否则请提交工单并附订单号。
- 已经提交退款申请后,订单会进入退款申请/退款中状态,请不要重复创建多张工单催同一笔订单;如确需补充材料,在同一工单里追加支付截图、订单号和退款原因。
- 用户自助退款只允许已完成订单；存在 `APPLIED`/`ISSUED` 等 active 发票时会被拦截。若已开票后需要退款，通常要先按页面提示或工单流程处理发票作废/红冲。

订阅订单退款预览会把已用订阅额度按退款倍率折算，常见理解是：

```text
订阅折算已使用金额 = usage_amount / subscription_rate_multiplier * refund_rate_multiplier
最大可退 = 订单剩余可退金额 - 折算已使用金额
```

预览里可能出现 `usage_amount`、`subscription_rate_multiplier`、`refund_rate_multiplier`、`used_refund_value`。`refund_rate_multiplier <= 0` 会归一为 1。余额订单退款上限通常取“订单剩余可退金额”和“当前可用余额”的较小值。

退款被阻止时，常见错误包括 `INVALID_STATUS` / `only completed orders can request refund`、`REFUND_DISABLED` / `refund is not available for this order`、`refund is not enabled for this provider`、`INVOICE_STATE_UNAVAILABLE`、`INVOICE_ACTIVE` / `order has an active invoice application`、`REFUND_AMOUNT_EXCEEDED`。看到发票相关错误时，先处理发票申请或提交工单，不要重复提交退款。

> **税费提示：** 如果是**因你一方原因**（例如已开票后又申请退款）需要承担税费，通常 **5% 的税费由你承担**；因平台原因导致的退款，税费与你无关。简单说：**没开票、未消耗时退款最省事。** 详见 [常见问题](#/faq)。

---

## 开具发票

「**发票**」页可申请开票，列表 `GET /payment/invoices` 支持 `page`、`page_size`、`status`、`keyword`。创建发票时选择 1 个或多个符合条件的已完成订单，并填写 `order_ids`(至少 1 个)、`title`、`tax_number`、`email`、`contact_name`、`contact_phone`、`request_note`。

常见发票状态：

| 状态 | 含义 | 可操作 |
|------|------|--------|
| `APPLIED` | 已提交申请，等待开票 | 可取消申请 |
| `ISSUED` | 已开票 | 可下载发票文件 |
| `CANCELLED` | 已取消 | 可重新按符合条件的订单申请 |

订单详情和发票详情页会显示关联状态；发票详情可返回关联订单列表。详情字段包括 `id`、`user_id`、`user_email`、`status`、`invoice_amount`、`order_count`、`title`、`tax_number`、`email`、`contact_name`、`contact_phone`、`request_note`、`file_media_id`、`file_name`、`file_mime_type`、`file_size_bytes`、`applied_at`、`cancelled_at`、`issued_at`、`created_at`、`updated_at` 和 `orders[]`；`orders[]` 每项通常有 `order_id`、`out_trade_no`、`pay_amount_snapshot`、`payment_type`、`created_at`。`APPLIED` 可取消，`ISSUED` 才可通过 `/payment/invoices/{id}/download` 获取签名下载链接；已开票订单退款前请先确认税费与作废规则。

发票列表 `page_size` 服务端最大 100；`keyword` 会匹配发票抬头、邮箱、用户邮箱、税号，也会通过关联订单号 `out_trade_no` 查找发票。单张发票最多 100 个订单；重复 `order_ids` 会去重；发票金额按所选订单 `pay_amount` 求和并保留 2 位。按订单号搜不到时，先确认订单是否已经关联到该发票申请。

用户侧申请按钮要求订单已完成、有 provider instance、provider 出现在 `/payment/orders/invoice-eligible-providers` 返回列表中，且没有 active 发票。active 发票通常指 `APPLIED` 或 `ISSUED`；`CANCELLED` 发票会释放订单，可重新申请。订单列表/详情里的 `invoice_status`、`invoice_id` 是通过发票关联表和 active 发票状态计算出来的，不要把它理解为订单表里永远固定的字段。

发票相关常见错误:

| 错误码 | 含义与处理 |
|---|---|
| `INVOICE_ORDER_IDS_REQUIRED` | 创建发票未传 `order_ids` |
| `INVOICE_BATCH_TOO_MANY` | 单次申请订单数超过上限 |
| `INVOICE_TITLE_REQUIRED` / `INVOICE_TAX_NUMBER_REQUIRED` / `INVOICE_EMAIL_REQUIRED` | 抬头、税号或收票邮箱缺失 |
| `INVOICE_ORDER_INELIGIBLE` | 订单不是 completed 状态 |
| `INVOICE_DISABLED` | 该支付渠道未开启发票 |
| `INVOICE_ALREADY_INVOICED` | 订单已有有效发票申请/已开票 |
| `INVOICE_CANNOT_CANCEL` | 只有 `APPLIED` 状态可取消 |
| `INVOICE_CANNOT_UPLOAD` | 当前发票状态不允许上传文件 |
| `INVOICE_NOT_ISSUED` | 发票未开具或没有文件,不能下载/重发邮件 |
| `INVOICE_FILE_STORAGE_UNAVAILABLE` / `INVOICE_FILE_REQUIRED` | 发票文件存储未配置或上传文件为空 |
| `INVOICE_EMAIL_DISABLED` | 发票邮件服务未配置 |
| `INVOICE_NOT_FOUND` / `FORBIDDEN` | 发票不存在或无权访问 |
| `INVOICE_SERVICE_UNAVAILABLE` / `Invalid id` / `Invalid request: ...` | 发票服务未初始化、ID 或请求体格式错误 |
| `INVALID_USER` / `NOT_FOUND` / `INVOICE_EMAIL_REQUIRED` | 用户、订单/发票不存在或重发邮件缺邮箱 | 刷新列表后重试,必要时提交工单 |

发票申请一般需要选择符合条件的已支付订单;已退款、退款中、已关联其他有效发票申请或渠道未开启发票能力的订单可能不会出现在可选列表。若发票服务未开启或配置异常,页面可能显示 `INVOICE_SERVICE_UNAVAILABLE` / `invoice service unavailable`。

> **建议余额消耗完后再开票。** 一旦开票即视同确认收入完成报税；若充值后未消耗就提前开票再退款，可能产生税费问题。详见 [常见问题](#/faq)。

---

## 用量日志排账提示

文本 token 为 0 不代表一定免费；图片、视频、搜索、音频可能走非 token 的 `billing_mode`。看用户扣费优先看 `actual_cost`；理解基础成本看 `total_cost`。图片排账要结合 `image_count`、`image_size`、`image_input_size`、`image_output_size`、`image_size_source`、`image_size_breakdown`、`image_output_tokens`、`image_output_cost`。导出或提交工单时保留 `request_id`，便于对账留档。

> 看每笔消耗见 [用量明细](#/console-usage)；计费原理与省钱见 [计费与额度](#/billing)。
