Skip to content

Commit 997cd1e

Browse files
committed
docs+ui: add bilingual payment integration doc and rename purchase entry to recharge/subscription
1 parent 2e88e23 commit 997cd1e

4 files changed

Lines changed: 116 additions & 168 deletions

File tree

ADMIN_PAYMENT_INTEGRATION_API.md

Lines changed: 72 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,40 @@
1-
# Sub2API Admin API: Payment Integration / 支付集成接口文档
1+
# ADMIN_PAYMENT_INTEGRATION_API
22

3-
## 中文
4-
5-
### 概述
6-
7-
本文档描述外部支付系统(例如 sub2apipay)对接 Sub2API 时的最小 Admin API 集合,用于完成充值发放与对账。
8-
9-
### 基础地址
3+
> 单文件中英双语文档 / Single-file bilingual documentation (Chinese + English)
104
11-
- 生产环境:`https://<your-domain>`
12-
- Beta 环境:`http://<your-server-ip>:8084`
5+
---
136

14-
### 认证方式
7+
## 中文
158

16-
以下接口均建议使用:
9+
### 目标
10+
本文档用于对接外部支付系统(如 `sub2apipay`)与 Sub2API 的 Admin API,覆盖:
11+
- 支付成功后充值
12+
- 用户查询
13+
- 人工余额修正
14+
- 前端购买页参数透传
1715

18-
- 请求头:`x-api-key: admin-<64hex>`(服务间调用推荐)
19-
- 请求头:`Content-Type: application/json`
16+
### 基础地址
17+
- 生产:`https://<your-domain>`
18+
- Beta:`http://<your-server-ip>:8084`
2019

21-
说明:管理员 JWT 也可访问 admin 路由,但机器对机器调用建议使用 Admin API Key。
20+
### 认证
21+
推荐使用:
22+
- `x-api-key: admin-<64hex>`
23+
- `Content-Type: application/json`
24+
- 幂等接口额外传:`Idempotency-Key`
2225

23-
### 1) 一步完成:创建兑换码并兑换
26+
说明:管理员 JWT 也可访问 admin 路由,但服务间调用建议使用 Admin API Key。
2427

28+
### 1) 一步完成创建并兑换
2529
`POST /api/v1/admin/redeem-codes/create-and-redeem`
2630

27-
用途:
28-
29-
- 原子化完成“创建固定兑换码 + 兑换给指定用户”。
30-
- 常用于支付回调成功后的自动充值。
31-
32-
必需请求头:
31+
用途:原子完成“创建兑换码 + 兑换到指定用户”。
3332

33+
请求头:
3434
- `x-api-key`
3535
- `Idempotency-Key`
3636

37-
请求体:
38-
37+
请求体示例:
3938
```json
4039
{
4140
"code": "s2p_cm1234567890",
@@ -46,21 +45,12 @@
4645
}
4746
```
4847

49-
规则:
50-
51-
- `code`:外部订单映射的确定性兑换码。
52-
- `type`:当前推荐使用 `balance`
53-
- `value`:必须大于 0。
54-
- `user_id`:目标用户 ID。
55-
5648
幂等语义:
49+
-`code``used_by` 一致:`200`
50+
-`code``used_by` 不一致:`409`
51+
- 缺少 `Idempotency-Key``400``IDEMPOTENCY_KEY_REQUIRED`
5752

58-
- 同一 `code``used_by` 一致:返回 `200`(幂等回放)。
59-
- 同一 `code``used_by` 不一致:返回 `409`(冲突)。
60-
- 缺少 `Idempotency-Key`:返回 `400``IDEMPOTENCY_KEY_REQUIRED`)。
61-
62-
示例:
63-
53+
curl 示例:
6454
```bash
6555
curl -X POST "${BASE}/api/v1/admin/redeem-codes/create-and-redeem" \
6656
-H "x-api-key: ${KEY}" \
@@ -75,32 +65,20 @@ curl -X POST "${BASE}/api/v1/admin/redeem-codes/create-and-redeem" \
7565
}'
7666
```
7767

78-
### 2) 查询用户(可选前置检查)
79-
68+
### 2) 查询用户(可选前置校验)
8069
`GET /api/v1/admin/users/:id`
8170

82-
用途:
83-
84-
- 支付成功后充值前,确认目标用户是否存在。
85-
86-
示例:
87-
8871
```bash
8972
curl -s "${BASE}/api/v1/admin/users/123" \
9073
-H "x-api-key: ${KEY}"
9174
```
9275

93-
### 3) 余额调整(已存在接口)
94-
76+
### 3) 余额调整(已有接口)
9577
`POST /api/v1/admin/users/:id/balance`
9678

97-
用途:
98-
99-
- 复用现有管理员接口做人工纠偏。
100-
- 支持 `set``add``subtract`
101-
102-
示例(扣减):
79+
用途:人工补偿 / 扣减,支持 `set` / `add` / `subtract`
10380

81+
请求体示例(扣减):
10482
```json
10583
{
10684
"balance": 100.0,
@@ -121,77 +99,61 @@ curl -X POST "${BASE}/api/v1/admin/users/123/balance" \
12199
}'
122100
```
123101

124-
### 4) 购买页跳转 URL Query 参数(iframe 与新窗口统一)
125-
126-
Sub2API 前端在打开 `purchase_subscription_url` 时,会给 iframe 和“新窗口打开”统一追加 query 参数,确保外部支付页拿到一致上下文。
127-
128-
追加参数:
129-
130-
- `user_id`:当前登录用户 ID
131-
- `token`:当前登录 JWT token
132-
- `theme`:当前主题(`light` / `dark`
133-
- `ui_mode`:当前 UI 模式(固定 `embedded`
102+
### 4) 购买页 URL Query 透传(iframe / 新窗口一致)
103+
当 Sub2API 打开 `purchase_subscription_url` 时,会统一追加:
104+
- `user_id`
105+
- `token`
106+
- `theme``light` / `dark`
107+
- `ui_mode`(固定 `embedded`
134108

135109
示例:
136-
137110
```text
138111
https://pay.example.com/pay?user_id=123&token=<jwt>&theme=light&ui_mode=embedded
139112
```
140113

141114
### 5) 失败处理建议
142-
143-
- 支付状态与充值状态分开落库。
144-
- 收到并验证支付回调后,立即标记“支付成功”。
145-
- 支付成功但充值失败的订单应允许后续重试。
146-
- 重试时继续使用同一 `code`,并使用新的 `Idempotency-Key`
115+
- 支付成功与充值成功分状态落库
116+
- 回调验签成功后立即标记“支付成功”
117+
- 支付成功但充值失败的订单允许后续重试
118+
- 重试保持相同 `code`,并使用新的 `Idempotency-Key`
147119

148120
### 6) `doc_url` 配置建议
149-
150-
Sub2API 已支持系统设置中的 `doc_url` 字段。
151-
152-
推荐配置:
153-
154121
- 查看链接:`https://github.com/Wei-Shaw/sub2api/blob/main/ADMIN_PAYMENT_INTEGRATION_API.md`
155122
- 下载链接:`https://raw.githubusercontent.com/Wei-Shaw/sub2api/main/ADMIN_PAYMENT_INTEGRATION_API.md`
156123

157124
---
158125

159126
## English
160127

161-
### Overview
162-
163-
This document defines the minimum Admin API surface for integrating external payment systems (for example, sub2apipay) with Sub2API for recharge fulfillment and reconciliation.
128+
### Purpose
129+
This document describes the minimal Sub2API Admin API surface for external payment integrations (for example, `sub2apipay`), including:
130+
- Recharge after payment success
131+
- User lookup
132+
- Manual balance correction
133+
- Purchase page query parameter forwarding
164134

165135
### Base URL
166-
167136
- Production: `https://<your-domain>`
168137
- Beta: `http://<your-server-ip>:8084`
169138

170139
### Authentication
171-
172140
Recommended headers:
173-
174-
- `x-api-key: admin-<64hex>` (recommended for server-to-server calls)
141+
- `x-api-key: admin-<64hex>`
175142
- `Content-Type: application/json`
143+
- `Idempotency-Key` for idempotent endpoints
176144

177-
Note: Admin JWT is also accepted by admin routes, but Admin API key is recommended for machine integrations.
178-
179-
### 1) One-step Create + Redeem
145+
Note: Admin JWT can also access admin routes, but Admin API Key is recommended for server-to-server integration.
180146

147+
### 1) Create and Redeem in one step
181148
`POST /api/v1/admin/redeem-codes/create-and-redeem`
182149

183-
Purpose:
184-
185-
- Atomically create a deterministic redeem code and redeem it to the target user.
186-
- Typical usage: called right after payment callback success.
187-
188-
Required headers:
150+
Use case: atomically create a redeem code and redeem it to a target user.
189151

152+
Headers:
190153
- `x-api-key`
191154
- `Idempotency-Key`
192155

193156
Request body:
194-
195157
```json
196158
{
197159
"code": "s2p_cm1234567890",
@@ -202,21 +164,12 @@ Request body:
202164
}
203165
```
204166

205-
Rules:
206-
207-
- `code`: deterministic code mapped from external order id.
208-
- `type`: `balance` is the recommended type.
209-
- `value`: must be greater than 0.
210-
- `user_id`: target user id.
211-
212167
Idempotency behavior:
168+
- Same `code` and same `used_by`: `200`
169+
- Same `code` but different `used_by`: `409`
170+
- Missing `Idempotency-Key`: `400` (`IDEMPOTENCY_KEY_REQUIRED`)
213171

214-
- Same `code` and same `used_by`: `200` (idempotent replay).
215-
- Same `code` and different `used_by`: `409` (conflict).
216-
- Missing `Idempotency-Key`: `400` (`IDEMPOTENCY_KEY_REQUIRED`).
217-
218-
Example:
219-
172+
curl example:
220173
```bash
221174
curl -X POST "${BASE}/api/v1/admin/redeem-codes/create-and-redeem" \
222175
-H "x-api-key: ${KEY}" \
@@ -231,32 +184,20 @@ curl -X POST "${BASE}/api/v1/admin/redeem-codes/create-and-redeem" \
231184
}'
232185
```
233186

234-
### 2) Query User (Optional Pre-check)
235-
187+
### 2) Query User (optional pre-check)
236188
`GET /api/v1/admin/users/:id`
237189

238-
Purpose:
239-
240-
- Verify target user existence before final recharge/retry.
241-
242-
Example:
243-
244190
```bash
245191
curl -s "${BASE}/api/v1/admin/users/123" \
246192
-H "x-api-key: ${KEY}"
247193
```
248194

249-
### 3) Balance Adjustment (Existing API)
250-
195+
### 3) Balance Adjustment (existing API)
251196
`POST /api/v1/admin/users/:id/balance`
252197

253-
Purpose:
254-
255-
- Reuse existing admin endpoint for manual reconciliation.
256-
- Supports `set`, `add`, `subtract`.
198+
Use case: manual correction with `set` / `add` / `subtract`.
257199

258200
Request body example (`subtract`):
259-
260201
```json
261202
{
262203
"balance": 100.0,
@@ -265,8 +206,6 @@ Request body example (`subtract`):
265206
}
266207
```
267208

268-
Example:
269-
270209
```bash
271210
curl -X POST "${BASE}/api/v1/admin/users/123/balance" \
272211
-H "x-api-key: ${KEY}" \
@@ -279,35 +218,24 @@ curl -X POST "${BASE}/api/v1/admin/users/123/balance" \
279218
}'
280219
```
281220

282-
### 4) Purchase URL Query Parameters (Iframe + New Tab)
283-
284-
When Sub2API frontend opens `purchase_subscription_url`, it appends the same query parameters for both iframe and “open in new tab” to keep context consistent.
285-
286-
Appended parameters:
287-
288-
- `user_id`: current logged-in user id
289-
- `token`: current logged-in JWT token
290-
- `theme`: current theme (`light` / `dark`)
291-
- `ui_mode`: UI mode (fixed `embedded`)
221+
### 4) Purchase URL query forwarding (iframe and new tab)
222+
When Sub2API opens `purchase_subscription_url`, it appends:
223+
- `user_id`
224+
- `token`
225+
- `theme` (`light` / `dark`)
226+
- `ui_mode` (fixed: `embedded`)
292227

293228
Example:
294-
295229
```text
296230
https://pay.example.com/pay?user_id=123&token=<jwt>&theme=light&ui_mode=embedded
297231
```
298232

299-
### 5) Failure Handling Recommendations
300-
301-
- Store payment state and recharge state separately.
302-
- Mark payment success immediately after callback verification.
303-
- Keep orders retryable when payment succeeded but recharge failed.
304-
- Reuse the same deterministic `code` and a new `Idempotency-Key` when retrying.
305-
306-
### 6) Suggested `doc_url` Value
307-
308-
Sub2API already supports `doc_url` in system settings.
309-
310-
Recommended values:
233+
### 5) Failure handling recommendations
234+
- Persist payment success and recharge success as separate states
235+
- Mark payment as successful immediately after verified callback
236+
- Allow retry for orders with payment success but recharge failure
237+
- Keep the same `code` for retry, and use a new `Idempotency-Key`
311238

239+
### 6) Recommended `doc_url`
312240
- View URL: `https://github.com/Wei-Shaw/sub2api/blob/main/ADMIN_PAYMENT_INTEGRATION_API.md`
313241
- Download URL: `https://raw.githubusercontent.com/Wei-Shaw/sub2api/main/ADMIN_PAYMENT_INTEGRATION_API.md`

frontend/src/components/layout/AppSidebar.vue

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,26 @@ const CreditCardIcon = {
290290
)
291291
}
292292
293+
const RechargeSubscriptionIcon = {
294+
render: () =>
295+
h(
296+
'svg',
297+
{ fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor', 'stroke-width': '1.5' },
298+
[
299+
h('path', {
300+
'stroke-linecap': 'round',
301+
'stroke-linejoin': 'round',
302+
d: 'M2.25 7.5A2.25 2.25 0 014.5 5.25h15A2.25 2.25 0 0121.75 7.5v9A2.25 2.25 0 0119.5 18.75h-15A2.25 2.25 0 012.25 16.5v-9z'
303+
}),
304+
h('path', {
305+
'stroke-linecap': 'round',
306+
'stroke-linejoin': 'round',
307+
d: 'M6.75 12h3m4.5 0h3m-3-3v6'
308+
})
309+
]
310+
)
311+
}
312+
293313
const GlobeIcon = {
294314
render: () =>
295315
h(
@@ -490,7 +510,7 @@ const userNavItems = computed(() => {
490510
{
491511
path: '/purchase',
492512
label: t('nav.buySubscription'),
493-
icon: CreditCardIcon,
513+
icon: RechargeSubscriptionIcon,
494514
hideInSimpleMode: true
495515
}
496516
]
@@ -515,7 +535,7 @@ const personalNavItems = computed(() => {
515535
{
516536
path: '/purchase',
517537
label: t('nav.buySubscription'),
518-
icon: CreditCardIcon,
538+
icon: RechargeSubscriptionIcon,
519539
hideInSimpleMode: true
520540
}
521541
]

0 commit comments

Comments
 (0)