docs(api): 补全福利/钱包/提现/签到/任务/省钱/看广告 21 个接口文档

按 docs/api 一接口一文件约定新增:
- 钱包(11): account / coin-transactions / cash-transactions / exchange-info / exchange / bind-wechat / unbind-wechat / withdraw-info / withdraw / withdraw/status / withdraw-orders
- 签到(2): status / 执行签到
- 任务(2): list / {task_key}/claim
- 省钱(3): summary / battle / records
- 看广告发奖(3): pangle-callback(S2S验签) / reward-status / test-grant(仅联调)
- README 索引补 12–32 行 + 新增「游标分页约定」+ 修正鉴权说明 + 注明金额以分为单位

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
OuYingJun1024
2026-05-27 17:50:01 +08:00
parent 0722d7b0d5
commit 18ab7eab92
22 changed files with 537 additions and 1 deletions
+35 -1
View File
@@ -22,9 +22,36 @@
| 9 | `POST /api/v1/meituan/coupons` | 无 | [详情](./meituan-coupons.md) |
| 10 | `POST /api/v1/meituan/feed` | 无 | [详情](./meituan-feed.md) |
| 11 | `POST /api/v1/meituan/referral-link` | 无 | [详情](./meituan-referral-link.md) |
| **钱包 / 我的资产**(前缀 `/api/v1/wallet` |||
| 12 | `GET /api/v1/wallet/account` | Bearer | [详情](./wallet-account.md) |
| 13 | `GET /api/v1/wallet/coin-transactions` | Bearer | [详情](./wallet-coin-transactions.md) |
| 14 | `GET /api/v1/wallet/cash-transactions` | Bearer | [详情](./wallet-cash-transactions.md) |
| 15 | `GET /api/v1/wallet/exchange-info` | 无 | [详情](./wallet-exchange-info.md) |
| 16 | `POST /api/v1/wallet/exchange` | Bearer | [详情](./wallet-exchange.md) |
| 17 | `POST /api/v1/wallet/bind-wechat` | Bearer | [详情](./wallet-bind-wechat.md) |
| 18 | `POST /api/v1/wallet/unbind-wechat` | Bearer | [详情](./wallet-unbind-wechat.md) |
| 19 | `GET /api/v1/wallet/withdraw-info` | Bearer | [详情](./wallet-withdraw-info.md) |
| 20 | `POST /api/v1/wallet/withdraw` | Bearer | [详情](./wallet-withdraw.md) |
| 21 | `GET /api/v1/wallet/withdraw/status` | Bearer | [详情](./wallet-withdraw-status.md) |
| 22 | `GET /api/v1/wallet/withdraw-orders` | Bearer | [详情](./wallet-withdraw-orders.md) |
| **签到**(前缀 `/api/v1/signin` |||
| 23 | `GET /api/v1/signin/status` | Bearer | [详情](./signin-status.md) |
| 24 | `POST /api/v1/signin` | Bearer | [详情](./signin-do.md) |
| **任务**(前缀 `/api/v1/tasks` |||
| 25 | `GET /api/v1/tasks` | Bearer | [详情](./tasks-list.md) |
| 26 | `POST /api/v1/tasks/{task_key}/claim` | Bearer | [详情](./tasks-claim.md) |
| **省钱**(前缀 `/api/v1/savings` |||
| 27 | `GET /api/v1/savings/summary` | Bearer | [详情](./savings-summary.md) |
| 28 | `GET /api/v1/savings/battle` | Bearer | [详情](./savings-battle.md) |
| 29 | `GET /api/v1/savings/records` | Bearer | [详情](./savings-records.md) |
| **看广告发奖**(前缀 `/api/v1/ad` |||
| 30 | `GET /api/v1/ad/pangle-callback` | 验签 | [详情](./ad-pangle-callback.md) |
| 31 | `GET /api/v1/ad/reward-status` | Bearer | [详情](./ad-reward-status.md) |
| 32 | `POST /api/v1/ad/test-grant` | Bearer | [详情](./ad-test-grant.md) |
> ⚠️ 美团三个接口当前**无鉴权**,且 `referral-link` 的 `sid` 允许客户端传值覆盖默认渠道——见各接口"备注"。
> `coupon/step` 是后端**唯一需要 JWT 鉴权的业务接口**
> 福利相关业务接口(wallet/signin/tasks/savings、`ad/reward-status`)均需 **Bearer**;`wallet/exchange-info` 是静态规则无鉴权;`ad/pangle-callback` 不走 JWT、靠穿山甲**验签**;`ad/test-grant` **仅本地联调**(开关控制,生产 404)
> 金额字段一律以**分**为单位(`*_cents`)。
---
@@ -40,6 +67,13 @@
- `502` 上游调用失败(极光验证/解密失败、美团接口失败)
- **接口文档(交互式)**:`APP_ENV` 非 prod 时开放 `GET /docs`Swagger UI)、`GET /redoc`;生产环境关闭。
### 游标分页约定
钱包流水 / 提现单 / 省钱明细等列表接口统一用**游标分页**:
- 请求 query:`limit`(每页条数,1100,默认 20)、`cursor`(上一页返回的 `next_cursor`,首页不传)。
- 响应:`{ "items": [...], "next_cursor": <int|null> }``next_cursor` 为**末条记录的 id**;为 `null` 表示已到底,无更多数据。
- `items``id` 倒序(最新在前)。
---
## 复用数据结构
+28
View File
@@ -0,0 +1,28 @@
# GET /api/v1/ad/pangle-callback — 穿山甲激励视频发奖回调(S2S)
> 所属:Ad 组(前缀 `/api/v1/ad` | 鉴权:**无 JWT,靠验签**(穿山甲服务器调用) | 限流:同 IP ≤300 次/分 | [← 返回 API 索引](./README.md)
## 入参(query,由穿山甲拼装)
穿山甲在激励视频播完后回调,带一组 query 参数,关键:
| 字段 | 类型 | 说明 |
|---|---|---|
| `user_id` | string | 客户端起播时传入的用户标识(须为数字 = 本系统 user.id) |
| `trans_id` | string | 穿山甲交易号(**幂等键**) |
| `sign` | string | 穿山甲签名(用 `PANGLE_REWARD_SECRET` 验) |
| `reward_name` | string | 奖励名(可选,入库备注) |
| … | | 其余参与签名的参数 |
## 出参
响应 `200`:`PangleCallbackOut`
| 字段 | 类型 | 说明 |
|---|---|---|
| `is_valid` | bool | `true`=已受理(发奖成功 或 当日达上限 或 user 非法,均不让穿山甲重试) |
## 错误码
- `403` 验签失败(`bad sign`,留给真请求重试)
- `503` 回调未配置(`pangle_callback_configured=false`
## 说明
**发奖唯一可信入口**:验签 → 取 `user_id`/`trans_id` → 幂等发金币(按 `trans_id` 去重 + 每日上限)。客户端不参与发奖,被破解也刷不到钱。验签过但参数缺/坏或 user 不存在 → 受理但不发(`is_valid` 仍据情况返回,避免无意义重试)。
+19
View File
@@ -0,0 +1,19 @@
# GET /api/v1/ad/reward-status — 今日看广告发奖进度
> 所属:Ad 组(前缀 `/api/v1/ad` | 鉴权:Bearer | [← 返回 API 索引](./README.md)
## 入参
无(用户由 token 确定)。
## 出参
响应 `200`:`AdRewardStatusOut`
| 字段 | 类型 | 说明 |
|---|---|---|
| `used_today` | int | 今日已成功发奖次数 |
| `daily_limit` | int | 每日发奖次数上限 |
| `remaining` | int | 今日剩余可领次数 |
| `coin_per_ad` | int | 看完一个激励视频发的金币 |
## 说明
福利页「看视频赚金币」用:展示「今日还能看 N 次」「看一次得 M 金币」。真正发奖走 [ad-pangle-callback](./ad-pangle-callback.md)(穿山甲 S2S)。
+27
View File
@@ -0,0 +1,27 @@
# POST /api/v1/ad/test-grant — [仅本地联调]模拟穿山甲回调发奖
> 所属:Ad 组(前缀 `/api/v1/ad` | 鉴权:Bearer | 限流:同 IP ≤60 次/分 | [← 返回 API 索引](./README.md)
>
> ⚠️ **仅本地联调**,受 `AD_REWARD_TEST_GRANT_ENABLED` 开关控制,**生产必须关闭**(默认 False → 一律 404)。
## 入参
无(用户由 token 确定)。
## 出参
响应 `200`:`TestGrantOut`
| 字段 | 类型 | 说明 |
|---|---|---|
| `granted` | bool | 本次是否真发了金币(达每日上限则 false) |
| `status` | string | `granted` / `capped`(达上限) |
| `coin` | int | 本次发放金币(capped 时 0 |
| `used_today` | int | 今日已成功发奖次数 |
| `daily_limit` | int | 每日发奖次数上限 |
| `remaining` | int | 今日剩余可领次数 |
| `coin_per_ad` | int | 看完一个激励视频发的金币 |
## 错误码
- `404` 开关未开(伪装不存在) / 用户不存在
## 说明
没公网、穿山甲 S2S 回调打不到本地时,debug 客户端看完广告后调它,直接走与 [ad-pangle-callback](./ad-pangle-callback.md) 相同的发奖逻辑(每次新 `trans_id`,幂等 + 每日上限)。它让已登录客户端能自助发奖 = 绕过反作弊,**严禁在生产开启**。
+18
View File
@@ -0,0 +1,18 @@
# GET /api/v1/savings/battle — 省钱战绩
> 所属:Savings 组(前缀 `/api/v1/savings` | 鉴权:Bearer | [← 返回 API 索引](./README.md)
## 入参
无(用户由 token 确定)。
## 出参
响应 `200`:`SavingsBattleOut`
| 字段 | 类型 | 说明 |
|---|---|---|
| `week_saved_cents` | int | 本周已省(分) |
| `beat_percent` | int | 超过百分之多少用户 |
| `streak_days` | int | 连续省钱天数 |
## 说明
「我的」页「省钱战绩」卡数据源。接口已通但无真实业务写入,实际多为 0。
+29
View File
@@ -0,0 +1,29 @@
# GET /api/v1/savings/records — 省钱明细(游标分页)
> 所属:Savings 组(前缀 `/api/v1/savings` | 鉴权:Bearer | [← 返回 API 索引](./README.md)
## 入参(query
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
| `limit` | int | ❌ | 20 | 1100 |
| `cursor` | int | ❌ | null | 上一页末条 `id`,首页不传 |
## 出参
响应 `200`:`{ items: SavingsRecordOut[], next_cursor: int|null }`(分页见 [索引#游标分页约定](./README.md#游标分页约定)
**SavingsRecordOut**
| 字段 | 类型 | 说明 |
|---|---|---|
| `id` | int | 记录 id(也是游标) |
| `order_amount_cents` | int | 订单金额(分) |
| `saved_amount_cents` | int | 本单省下(分) |
| `platform` | string \| null | 平台(美团/饿了么等) |
| `title` | string \| null | 标题 |
| `shop_name` | string \| null | 店铺名 |
| `dishes` | string[] | 菜品列表 |
| `created_at` | datetime | 时间 |
## 说明
订单/省钱明细页(`RECORDS`)数据源。
+18
View File
@@ -0,0 +1,18 @@
# GET /api/v1/savings/summary — 累计帮你省了
> 所属:Savings 组(前缀 `/api/v1/savings` | 鉴权:Bearer | [← 返回 API 索引](./README.md)
## 入参
无(用户由 token 确定)。
## 出参
响应 `200`:`SavingsSummaryOut`
| 字段 | 类型 | 说明 |
|---|---|---|
| `total_saved_cents` | int | 累计省下(分) |
| `order_count` | int | 累计省钱订单数 |
| `avg_saved_cents` | int | 平均每单省(分) |
## 说明
「我的」页「累计帮你省了」卡数据源。当前比价上报未接入,实际多为 0。
+22
View File
@@ -0,0 +1,22 @@
# POST /api/v1/signin — 执行今日签到
> 所属:Signin 组(前缀 `/api/v1/signin`,本接口 POST 到前缀本身) | 鉴权:Bearer | [← 返回 API 索引](./README.md)
## 入参
无(用户由 token 确定)。
## 出参
响应 `200`:`SigninResultOut`
| 字段 | 类型 | 说明 |
|---|---|---|
| `coin_awarded` | int | 本次签到发放金币 |
| `cycle_day` | int | 本次签到落在循环第几天 |
| `streak` | int | 签到后的连续天数 |
| `coin_balance` | int | 签到后金币余额 |
## 错误码
- `409` 今日已签(`already signed today`
## 说明
发金币已计入 [wallet-account](./wallet-account.md) 的余额(客户端就地刷新即可,不必另叠)。
+29
View File
@@ -0,0 +1,29 @@
# GET /api/v1/signin/status — 今日签到状态 + 7 天档位
> 所属:Signin 组(前缀 `/api/v1/signin` | 鉴权:Bearer | [← 返回 API 索引](./README.md)
## 入参
无(用户由 token 确定)。
## 出参
响应 `200`:`SigninStatusOut`
| 字段 | 类型 | 说明 |
|---|---|---|
| `today_signed` | bool | 今日是否已签 |
| `consecutive_days` | int | 当前连续签到天数 |
| `today_cycle_day` | int | 今日处于循环内第几天(1..7) |
| `today_coin` | int | 今日签到可得金币 |
| `can_claim` | bool | 今日是否可领(= 未签) |
| `steps` | SigninStepOut[] | 7 天档位 |
**SigninStepOut**
| 字段 | 类型 | 说明 |
|---|---|---|
| `day` | int | 循环内第几天 1..7 |
| `coin` | int | 该档金币 |
| `status` | string | `claimed`(已领) / `today`(今日待领) / `locked`(未到) |
## 说明
福利页签到行 + 签到弹窗 7 档 timeline 数据源。
+25
View File
@@ -0,0 +1,25 @@
# POST /api/v1/tasks/{task_key}/claim — 领取任务奖励
> 所属:Tasks 组(前缀 `/api/v1/tasks` | 鉴权:Bearer | [← 返回 API 索引](./README.md)
## 入参(path
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `task_key` | string | ✅ | 任务标识(见 [tasks-list](./tasks-list.md) 的 `task_key` |
## 出参
响应 `200`:`TaskClaimResultOut`
| 字段 | 类型 | 说明 |
|---|---|---|
| `task_key` | string | 任务标识 |
| `coin_awarded` | int | 本次发放金币 |
| `coin_balance` | int | 领奖后金币余额 |
## 错误码
- `404` 未知任务(`unknown task`
- `409` 任务已领取(`task already claimed`
## 说明
发奖端 gate 由后端把控(如「打开消息提醒」须客户端确认权限已开后才调)。金币已计入余额。
+20
View File
@@ -0,0 +1,20 @@
# GET /api/v1/tasks — 任务及领取状态
> 所属:Tasks 组(前缀 `/api/v1/tasks`,本接口 GET 前缀本身) | 鉴权:Bearer | [← 返回 API 索引](./README.md)
## 入参
无(用户由 token 确定)。
## 出参
响应 `200`:`TaskListOut` = `{ items: TaskOut[] }`
**TaskOut**
| 字段 | 类型 | 说明 |
|---|---|---|
| `task_key` | string | 任务标识,如 `enable_notification`(打开消息提醒) |
| `coin` | int | 完成可得金币 |
| `claimed` | bool | 是否已领取 |
## 说明
福利页一次性任务行(如「打开消息提醒」)的状态源。领取走 [tasks-claim](./tasks-claim.md)。
+18
View File
@@ -0,0 +1,18 @@
# GET /api/v1/wallet/account — 金币 + 现金余额(我的资产)
> 所属:Wallet 组(前缀 `/api/v1/wallet` | 鉴权:Bearer | [← 返回 API 索引](./README.md)
## 入参
无(用户由 token 确定)。
## 出参
响应 `200`:`CoinAccountOut`
| 字段 | 类型 | 说明 |
|---|---|---|
| `coin_balance` | int | 当前金币余额 |
| `cash_balance_cents` | int | 当前现金余额(分) |
| `total_coin_earned` | int | 累计赚取金币 |
## 说明
账户不存在时自动创建(零余额)。福利页「我的资产」卡的数据源。
+26
View File
@@ -0,0 +1,26 @@
# POST /api/v1/wallet/bind-wechat — 微信授权 code 换 openid 并绑定
> 所属:Wallet 组(前缀 `/api/v1/wallet` | 鉴权:Bearer | 限流:同 IP ≤10 次/分 | [← 返回 API 索引](./README.md)
## 入参
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `code` | string | ✅ | 微信授权返回的 code(客户端 OAuth 拿到) |
## 出参
响应 `200`:`BindWechatResultOut`
| 字段 | 类型 | 说明 |
|---|---|---|
| `bound` | bool | 固定 `true` |
| `wechat_nickname` | string \| null | 微信昵称 |
| `wechat_avatar_url` | string \| null | 微信头像 URL |
## 错误码
- `400` code 无效 / 换 openid 失败
- `409` 该微信已绑定其他账号
- `503` 微信支付未配置(`wxpay_configured=false`
## 说明
后端用 `code` 调微信 `jscode2session`(或 OAuth)换 `openid` 并写入 user。提现前置:必须先绑定。`openid` 全局唯一(DB 唯一约束),一个微信只能绑一个账号。
+28
View File
@@ -0,0 +1,28 @@
# GET /api/v1/wallet/cash-transactions — 现金流水(游标分页)
> 所属:Wallet 组(前缀 `/api/v1/wallet` | 鉴权:Bearer | [← 返回 API 索引](./README.md)
## 入参(query
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
| `limit` | int | ❌ | 20 | 1100 |
| `cursor` | int | ❌ | null | 上一页末条 `id`,首页不传 |
## 出参
响应 `200`:`{ items: CashTransactionOut[], next_cursor: int|null }`(分页见 [索引#游标分页约定](./README.md#游标分页约定)
**CashTransactionOut**
| 字段 | 类型 | 说明 |
|---|---|---|
| `id` | int | 流水 id(也是游标) |
| `amount_cents` | int | 现金变动(分),正=兑入 负=提现 |
| `balance_after_cents` | int | 变动后现金余额(分) |
| `biz_type` | string | 业务类型(兑换/提现等) |
| `ref_id` | string \| null | 关联业务 id(如提现单号) |
| `remark` | string \| null | 备注 |
| `created_at` | datetime | 时间 |
## 说明
现金历史页(`CASH_HISTORY`)数据源。
+28
View File
@@ -0,0 +1,28 @@
# GET /api/v1/wallet/coin-transactions — 金币流水(游标分页)
> 所属:Wallet 组(前缀 `/api/v1/wallet` | 鉴权:Bearer | [← 返回 API 索引](./README.md)
## 入参(query
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
| `limit` | int | ❌ | 20 | 1100 |
| `cursor` | int | ❌ | null | 上一页末条 `id`,首页不传 |
## 出参
响应 `200`:`{ items: CoinTransactionOut[], next_cursor: int|null }`(分页见 [索引#游标分页约定](./README.md#游标分页约定)
**CoinTransactionOut**
| 字段 | 类型 | 说明 |
|---|---|---|
| `id` | int | 流水 id(也是游标) |
| `amount` | int | 金币变动,正=入账 负=出账 |
| `balance_after` | int | 变动后余额 |
| `biz_type` | string | 业务类型(签到/任务/兑换等) |
| `ref_id` | string \| null | 关联业务 id |
| `remark` | string \| null | 备注 |
| `created_at` | datetime | 时间 |
## 说明
金币历史页(`COIN_HISTORY`)数据源。
+18
View File
@@ -0,0 +1,18 @@
# GET /api/v1/wallet/exchange-info — 金币兑现金 汇率/规则
> 所属:Wallet 组(前缀 `/api/v1/wallet` | 鉴权:**无**(返回静态配置,不读用户) | [← 返回 API 索引](./README.md)
## 入参
无。
## 出参
响应 `200`:`ExchangeInfoOut`
| 字段 | 类型 | 说明 |
|---|---|---|
| `coin_per_yuan` | int | 多少金币兑 1 元 |
| `min_coin` | int | 单次兑换最少金币 |
| `step_coin` | int | 兑换金币需为该值的整数倍(对齐整分) |
## 说明
给兑换页展示汇率与规则用。值来自 `app/core/rewards.py``COIN_PER_YUAN` / `MIN_EXCHANGE_COIN` / `COIN_PER_CENT`)。
+26
View File
@@ -0,0 +1,26 @@
# POST /api/v1/wallet/exchange — 金币兑现金
> 所属:Wallet 组(前缀 `/api/v1/wallet` | 鉴权:Bearer | [← 返回 API 索引](./README.md)
## 入参
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `coin_amount` | int | ✅(>0) | 要兑换的金币数,须 ≥ `min_coin` 且为 `step_coin` 整数倍 |
## 出参
响应 `200`:`ExchangeResultOut`
| 字段 | 类型 | 说明 |
|---|---|---|
| `coin_amount` | int | 本次扣除的金币 |
| `cash_added_cents` | int | 本次兑入的现金(分) |
| `coin_balance` | int | 兑换后金币余额 |
| `cash_balance_cents` | int | 兑换后现金余额(分) |
## 错误码
- `400` `coin_amount` 不满足 ≥ `min_coin` 且为 `step_coin` 整数倍
- `409` 金币余额不足
## 说明
兑换规则见 [wallet-exchange-info](./wallet-exchange-info.md)。金币与现金的扣加在同一事务内完成。
+16
View File
@@ -0,0 +1,16 @@
# POST /api/v1/wallet/unbind-wechat — 解绑微信(清空 openid)
> 所属:Wallet 组(前缀 `/api/v1/wallet` | 鉴权:Bearer | [← 返回 API 索引](./README.md)
## 入参
无(用户由 token 确定)。
## 出参
响应 `200`:`UnbindWechatResultOut`
| 字段 | 类型 | 说明 |
|---|---|---|
| `bound` | bool | 固定 `false` |
## 说明
清空当前用户的 `wechat_openid` / `wechat_nickname` / `wechat_avatar_url`。幂等:未绑定时调用也返回 `bound=false`。解绑后该微信可被其他账号绑定。
+20
View File
@@ -0,0 +1,20 @@
# GET /api/v1/wallet/withdraw-info — 提现额度 / 绑定状态
> 所属:Wallet 组(前缀 `/api/v1/wallet` | 鉴权:Bearer | [← 返回 API 索引](./README.md)
## 入参
无(用户由 token 确定)。
## 出参
响应 `200`:`WithdrawInfoOut`
| 字段 | 类型 | 说明 |
|---|---|---|
| `min_cents` | int | 单次最低提现(分) |
| `max_cents` | int | 单次最高提现(分) |
| `wechat_bound` | bool | 是否已绑定微信 |
| `wechat_nickname` | string \| null | 微信昵称(可能脱敏/空) |
| `wechat_avatar_url` | string \| null | 微信头像 URL(可能空) |
## 说明
提现页进入时拉一次:决定展示额度区间、是否需先去绑定微信。额度来自 `rewards.py``WITHDRAW_MIN_CENTS` / `WITHDRAW_MAX_CENTS`)。
+28
View File
@@ -0,0 +1,28 @@
# GET /api/v1/wallet/withdraw-orders — 提现单列表(游标分页)
> 所属:Wallet 组(前缀 `/api/v1/wallet` | 鉴权:Bearer | [← 返回 API 索引](./README.md)
## 入参(query
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
| `limit` | int | ❌ | 20 | 1100 |
| `cursor` | int | ❌ | null | 上一页末条 `id`,首页不传 |
## 出参
响应 `200`:`{ items: WithdrawOrderOut[], next_cursor: int|null }`(分页见 [索引#游标分页约定](./README.md#游标分页约定)
**WithdrawOrderOut**
| 字段 | 类型 | 说明 |
|---|---|---|
| `id` | int | 单 id(也是游标) |
| `out_bill_no` | string | 商户提现单号 |
| `amount_cents` | int | 提现额(分) |
| `status` | string | `pending` / `success` / `failed` |
| `wechat_state` | string \| null | 微信侧原始状态 |
| `fail_reason` | string \| null | 失败原因 |
| `created_at` | datetime | 发起时间 |
## 说明
提现记录页数据源。
+25
View File
@@ -0,0 +1,25 @@
# GET /api/v1/wallet/withdraw/status — 查提现单状态(轮询)
> 所属:Wallet 组(前缀 `/api/v1/wallet` | 鉴权:Bearer | [← 返回 API 索引](./README.md)
## 入参(query
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `out_bill_no` | string | ✅ | 商户提现单号([withdraw](./wallet-withdraw.md) 返回的) |
## 出参
响应 `200`:`WithdrawStatusOut`
| 字段 | 类型 | 说明 |
|---|---|---|
| `out_bill_no` | string | 商户提现单号 |
| `status` | string | `pending` / `success` / `failed` |
| `wechat_state` | string \| null | 微信侧原始状态 |
| `amount_cents` | int | 提现额(分) |
## 错误码
- `404` 提现单不存在(或不属于当前用户)
## 说明
App 从微信确认页返回后调此接口刷新单状态。**副作用**:若查时仍是 `WAIT_USER_CONFIRM`(用户在确认页放弃),后端会**撤销该单并退回余额**(`cancel_if_unconfirmed=True`)。
+34
View File
@@ -0,0 +1,34 @@
# POST /api/v1/wallet/withdraw — 发起提现到微信零钱
> 所属:Wallet 组(前缀 `/api/v1/wallet` | 鉴权:Bearer | 限流:同 IP ≤20 次/分 | [← 返回 API 索引](./README.md)
## 入参
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `amount_cents` | int | ✅(>0) | 提现金额(分),须落在 `[min_cents, max_cents]` |
| `user_name` | string | ❌ | 实名(达额时微信商家转账要求,可空) |
| `out_bill_no` | string | ❌ | **客户端幂等键(商户单号)**:同号重试不重复转账;不传则服务端生成 |
## 出参
响应 `200`:`WithdrawResultOut`
| 字段 | 类型 | 说明 |
|---|---|---|
| `out_bill_no` | string | 商户提现单号(查单用) |
| `status` | string | `pending` / `success` / `failed` |
| `wechat_state` | string \| null | 微信侧原始状态 |
| `amount_cents` | int | 本次提现额(分) |
| `cash_balance_cents` | int | 提现后现金余额(分) |
| `package_info` | string \| null | 拉起微信确认页用(`WXOpenBusinessView` requestMerchantTransfer |
| `mch_id` | string \| null | 商户号 |
| `app_id` | string \| null | 微信 AppID |
## 错误码
- `400` 金额越界 / 未绑定微信
- `409` 现金余额不足
- `502` 微信转账调用失败(余额已退回)
- `503` 微信支付未配置
## 说明
走微信「商家转账到零钱」V3。先扣余额建单再调微信,转账失败则退回余额。`out_bill_no` 幂等防止网络重试重复打款。返回的 `package_info`/`mch_id`/`app_id` 供 App 拉起微信确认页;确认结果由 [wallet-withdraw-status](./wallet-withdraw-status.md) 轮询。