chore: 恢复PAYMENT系列文件

This commit is contained in:
shaw
2026-04-22 18:48:40 +08:00
parent 45065c23d5
commit c6d25f69d5
6 changed files with 833 additions and 7 deletions

View File

@@ -0,0 +1,243 @@
# ADMIN_PAYMENT_INTEGRATION_API
> 单文件中英双语文档 / Single-file bilingual documentation (Chinese + English)
---
## 中文
### 目标
本文档用于对接外部支付系统(如 `sub2apipay`)与 Sub2API 的 Admin API覆盖
- 支付成功后充值
- 用户查询
- 人工余额修正
- 前端购买页参数透传
### 基础地址
- 生产:`https://<your-domain>`
- Beta`http://<your-server-ip>:8084`
### 认证
推荐使用:
- `x-api-key: admin-<64hex>`
- `Content-Type: application/json`
- 幂等接口额外传:`Idempotency-Key`
说明:管理员 JWT 也可访问 admin 路由,但服务间调用建议使用 Admin API Key。
### 1) 一步完成创建并兑换
`POST /api/v1/admin/redeem-codes/create-and-redeem`
用途:原子完成“创建兑换码 + 兑换到指定用户”。
请求头:
- `x-api-key`
- `Idempotency-Key`
请求体示例:
```json
{
"code": "s2p_cm1234567890",
"type": "balance",
"value": 100.0,
"user_id": 123,
"notes": "sub2apipay order: cm1234567890"
}
```
幂等语义:
-`code``used_by` 一致:`200`
-`code``used_by` 不一致:`409`
- 缺少 `Idempotency-Key``400``IDEMPOTENCY_KEY_REQUIRED`
curl 示例:
```bash
curl -X POST "${BASE}/api/v1/admin/redeem-codes/create-and-redeem" \
-H "x-api-key: ${KEY}" \
-H "Idempotency-Key: pay-cm1234567890-success" \
-H "Content-Type: application/json" \
-d '{
"code":"s2p_cm1234567890",
"type":"balance",
"value":100.00,
"user_id":123,
"notes":"sub2apipay order: cm1234567890"
}'
```
### 2) 查询用户(可选前置校验)
`GET /api/v1/admin/users/:id`
```bash
curl -s "${BASE}/api/v1/admin/users/123" \
-H "x-api-key: ${KEY}"
```
### 3) 余额调整(已有接口)
`POST /api/v1/admin/users/:id/balance`
用途:人工补偿 / 扣减,支持 `set` / `add` / `subtract`
请求体示例(扣减):
```json
{
"balance": 100.0,
"operation": "subtract",
"notes": "manual correction"
}
```
```bash
curl -X POST "${BASE}/api/v1/admin/users/123/balance" \
-H "x-api-key: ${KEY}" \
-H "Idempotency-Key: balance-subtract-cm1234567890" \
-H "Content-Type: application/json" \
-d '{
"balance":100.00,
"operation":"subtract",
"notes":"manual correction"
}'
```
### 4) 购买页 / 自定义页面 URL Query 透传iframe / 新窗口一致)
当 Sub2API 打开 `purchase_subscription_url` 或用户侧自定义页面 iframe URL 时,会统一追加:
- `user_id`
- `token`
- `theme``light` / `dark`
- `lang`(例如 `zh` / `en`,用于向嵌入页传递当前界面语言)
- `ui_mode`(固定 `embedded`
示例:
```text
https://pay.example.com/pay?user_id=123&token=<jwt>&theme=light&lang=zh&ui_mode=embedded
```
### 5) 失败处理建议
- 支付成功与充值成功分状态落库
- 回调验签成功后立即标记“支付成功”
- 支付成功但充值失败的订单允许后续重试
- 重试保持相同 `code`,并使用新的 `Idempotency-Key`
### 6) `doc_url` 配置建议
- 查看链接:`https://github.com/Wei-Shaw/sub2api/blob/main/ADMIN_PAYMENT_INTEGRATION_API.md`
- 下载链接:`https://raw.githubusercontent.com/Wei-Shaw/sub2api/main/ADMIN_PAYMENT_INTEGRATION_API.md`
---
## English
### Purpose
This document describes the minimal Sub2API Admin API surface for external payment integrations (for example, `sub2apipay`), including:
- Recharge after payment success
- User lookup
- Manual balance correction
- Purchase page query parameter forwarding
### Base URL
- Production: `https://<your-domain>`
- Beta: `http://<your-server-ip>:8084`
### Authentication
Recommended headers:
- `x-api-key: admin-<64hex>`
- `Content-Type: application/json`
- `Idempotency-Key` for idempotent endpoints
Note: Admin JWT can also access admin routes, but Admin API Key is recommended for server-to-server integration.
### 1) Create and Redeem in one step
`POST /api/v1/admin/redeem-codes/create-and-redeem`
Use case: atomically create a redeem code and redeem it to a target user.
Headers:
- `x-api-key`
- `Idempotency-Key`
Request body:
```json
{
"code": "s2p_cm1234567890",
"type": "balance",
"value": 100.0,
"user_id": 123,
"notes": "sub2apipay order: cm1234567890"
}
```
Idempotency behavior:
- Same `code` and same `used_by`: `200`
- Same `code` but different `used_by`: `409`
- Missing `Idempotency-Key`: `400` (`IDEMPOTENCY_KEY_REQUIRED`)
curl example:
```bash
curl -X POST "${BASE}/api/v1/admin/redeem-codes/create-and-redeem" \
-H "x-api-key: ${KEY}" \
-H "Idempotency-Key: pay-cm1234567890-success" \
-H "Content-Type: application/json" \
-d '{
"code":"s2p_cm1234567890",
"type":"balance",
"value":100.00,
"user_id":123,
"notes":"sub2apipay order: cm1234567890"
}'
```
### 2) Query User (optional pre-check)
`GET /api/v1/admin/users/:id`
```bash
curl -s "${BASE}/api/v1/admin/users/123" \
-H "x-api-key: ${KEY}"
```
### 3) Balance Adjustment (existing API)
`POST /api/v1/admin/users/:id/balance`
Use case: manual correction with `set` / `add` / `subtract`.
Request body example (`subtract`):
```json
{
"balance": 100.0,
"operation": "subtract",
"notes": "manual correction"
}
```
```bash
curl -X POST "${BASE}/api/v1/admin/users/123/balance" \
-H "x-api-key: ${KEY}" \
-H "Idempotency-Key: balance-subtract-cm1234567890" \
-H "Content-Type: application/json" \
-d '{
"balance":100.00,
"operation":"subtract",
"notes":"manual correction"
}'
```
### 4) Purchase / Custom Page URL query forwarding (iframe and new tab)
When Sub2API opens `purchase_subscription_url` or a user-facing custom page iframe URL, it appends:
- `user_id`
- `token`
- `theme` (`light` / `dark`)
- `lang` (for example `zh` / `en`, used to pass the current UI language to the embedded page)
- `ui_mode` (fixed: `embedded`)
Example:
```text
https://pay.example.com/pay?user_id=123&token=<jwt>&theme=light&lang=zh&ui_mode=embedded
```
### 5) Failure handling recommendations
- Persist payment success and recharge success as separate states
- Mark payment as successful immediately after verified callback
- Allow retry for orders with payment success but recharge failure
- Keep the same `code` for retry, and use a new `Idempotency-Key`
### 6) Recommended `doc_url`
- View URL: `https://github.com/Wei-Shaw/sub2api/blob/main/ADMIN_PAYMENT_INTEGRATION_API.md`
- Download URL: `https://raw.githubusercontent.com/Wei-Shaw/sub2api/main/ADMIN_PAYMENT_INTEGRATION_API.md`

287
docs/PAYMENT.md Normal file
View File

@@ -0,0 +1,287 @@
# Payment System Configuration Guide
Sub2API has a built-in payment system that enables user self-service top-up without deploying a separate payment service.
---
## Table of Contents
- [Supported Payment Methods](#supported-payment-methods)
- [Quick Start](#quick-start)
- [System Settings](#system-settings)
- [Provider Configuration](#provider-configuration)
- [Provider Instance Management](#provider-instance-management)
- [Webhook Configuration](#webhook-configuration)
- [Payment Flow](#payment-flow)
- [Migrating from Sub2ApiPay](#migrating-from-sub2apipay)
---
## Supported Payment Methods
| Provider | Payment Methods | Description |
|----------|----------------|-------------|
| **EasyPay** | Alipay, WeChat Pay | Third-party aggregation via EasyPay protocol |
| **Alipay (Direct)** | Desktop QR code, mobile Alipay redirect | Direct integration with Alipay Open Platform, returning desktop QR codes and mobile WAP/app launch links |
| **WeChat Pay (Direct)** | Native QR, H5, MP/JSAPI Pay | Direct integration with WeChat Pay APIv3 with environment-aware routing |
| **Stripe** | Card, Alipay, WeChat Pay, Link, etc. | International payments, multi-currency support |
> Alipay/WeChat Pay direct and EasyPay can both exist as backend provider instances, but the frontend always exposes only two visible buttons: `Alipay` and `WeChat Pay`. Admins choose exactly one source for each visible method: direct or EasyPay. Direct channels connect to payment APIs directly with lower fees; EasyPay aggregates through third-party platforms with easier setup.
> **EasyPay Provider Recommendations**: Both options below are third-party aggregators compatible with the EasyPay protocol. Pick based on the funding channel and settlement currency you need:
>
> - **Domestic channel / CNY settlement** — [ZPay](https://z-pay.cn/?uid=23808) (`https://z-pay.cn/?uid=23808`): direct integration with official Alipay / WeChat Pay APIs, fee **1.6%**; funds go straight to the merchant account with **T+1 automatic settlement**. Supports **individual users** (no business license required) with up to 10,000 CNY daily transactions; business-licensed accounts have no limit. Link contains the referral code of [Sub2ApiPay](https://github.com/touwaeriol/sub2apipay) original author [@touwaeriol](https://github.com/touwaeriol) — feel free to remove it.
> - **International channel / USDT or USD settlement** — [Kyren Topup](https://kyren.top/?code=SUB2API) (`https://kyren.top/?code=SUB2API`): a ready-to-launch global payment stack for AI startups with WeChat Pay and Alipay support, local-currency checkout, and USD settlement. Fees: WeChat 2%, Alipay 2.5%; withdrawal 0.1% (min $40, max $150), settled in **USDT or USD**. No qualification review required — sign up and use immediately, making it the lowest barrier to entry. Withdrawal threshold is relatively high, recommended for users **who do not use domestic Chinese payment channels, cannot tolerate Stripe's 6%+ fees, have high transaction volume, and have USD or USDT channels to receive withdrawn funds**. Kyren Topup charges a $200 account opening fee; signing up via this link (which contains Sub2Api author [@Wei-Shaw](https://github.com/Wei-Shaw)'s referral code) **waives the opening fee**. Feel free to remove it if you prefer.
>
> Please evaluate the security, reliability, and compliance of any third-party payment provider on your own — this project does not endorse or guarantee any of them.
---
## Quick Start
1. Go to Admin Dashboard → **Settings****Payment Settings** tab
2. Enable **Payment**
3. Configure basic parameters (amount range, timeout, etc.)
4. Add at least one provider instance in **Provider Management**
5. Users can now top up from the frontend
---
## System Settings
Configure the following in Admin Dashboard **Settings → Payment Settings**:
### Basic Settings
| Setting | Description | Default |
|---------|-------------|---------|
| **Enable Payment** | Enable or disable the payment system | Off |
| **Product Name Prefix** | Prefix shown on payment page | - |
| **Product Name Suffix** | Suffix (e.g., "Credits") | - |
| **Minimum Amount** | Minimum single top-up amount | 1 |
| **Maximum Amount** | Maximum single top-up amount (empty = unlimited) | - |
| **Daily Limit** | Per-user daily cumulative limit (empty = unlimited) | - |
| **Order Timeout** | Order timeout in minutes (minimum 1) | 30 |
| **Max Pending Orders** | Maximum concurrent pending orders per user | 3 |
| **Load Balance Strategy** | Strategy for selecting provider instances | Round Robin |
### Frontend Visible Method Routing
The current payment UX keeps the frontend method list unified and does not expose provider brands directly:
- **Alipay**: when enabled, this button must be routed to either `Alipay (Direct)` or `EasyPay Alipay`
- **WeChat Pay**: when enabled, this button must be routed to either `WeChat Pay (Direct)` or `EasyPay WeChat`
- Each visible method can route to only one source at a time
- If a visible method is enabled without a selected source, the frontend will not expose that method
### Load Balance Strategies
| Strategy | Description |
|----------|-------------|
| **Round Robin** | Distribute orders to instances in rotation |
| **Least Amount** | Prefer instances with the lowest daily cumulative amount |
### Cancel Rate Limiting
Prevents users from repeatedly creating and canceling orders:
| Setting | Description |
|---------|-------------|
| **Enable Limit** | Toggle |
| **Window Mode** | Sliding / Fixed window |
| **Time Window** | Window duration |
| **Window Unit** | Minutes / Hours |
| **Max Cancels** | Maximum cancellations allowed within the window |
### Help Information
| Setting | Description |
|---------|-------------|
| **Help Image** | Customer service QR code or help image (supports upload) |
| **Help Text** | Instructions displayed on the payment page |
---
## Provider Configuration
Each provider type requires different credentials. Select the type when adding a new provider instance in **Provider Management → Add Provider**.
> **Callback URLs are auto-generated**: When adding a provider, the Notify URL and Return URL are automatically constructed from your site domain. You only need to confirm the domain is correct.
### EasyPay
Compatible with any payment service that implements the EasyPay protocol.
| Parameter | Description | Required |
|-----------|-------------|----------|
| **Merchant ID (PID)** | EasyPay merchant ID | Yes |
| **Merchant Key (PKey)** | EasyPay merchant secret key | Yes |
| **API Base URL** | EasyPay API base address | Yes |
| **Alipay Channel ID** | Specify Alipay channel (optional) | No |
| **WeChat Channel ID** | Specify WeChat channel (optional) | No |
### Alipay (Direct)
Direct integration with Alipay Open Platform. Desktop flows return a QR code for in-page display, while mobile flows return an Alipay WAP/app redirect URL.
| Parameter | Description | Required |
|-----------|-------------|----------|
| **AppID** | Alipay application AppID | Yes |
| **Private Key** | RSA2 application private key | Yes |
| **Alipay Public Key** | Alipay public key | Yes |
### WeChat Pay (Direct)
Direct integration with WeChat Pay APIv3. Supports Native QR code payment, H5 payment, and MP/JSAPI payment inside the WeChat environment.
| Parameter | Description | Required |
|-----------|-------------|----------|
| **AppID** | WeChat Pay AppID | Yes |
| **Merchant ID (MchID)** | WeChat Pay merchant ID | Yes |
| **Merchant API Private Key** | Merchant API private key (PEM format) | Yes |
| **APIv3 Key** | 32-byte APIv3 key | Yes |
| **WeChat Pay Public Key** | WeChat Pay public key (PEM format) | Yes |
| **WeChat Pay Public Key ID** | WeChat Pay public key ID | Yes |
| **Certificate Serial Number** | Merchant certificate serial number | Yes |
### Stripe
International payment platform supporting multiple payment methods and currencies.
| Parameter | Description | Required |
|-----------|-------------|----------|
| **Secret Key** | Stripe secret key (`sk_live_...` or `sk_test_...`) | Yes |
| **Publishable Key** | Stripe publishable key (`pk_live_...` or `pk_test_...`) | Yes |
| **Webhook Secret** | Stripe Webhook signing secret (`whsec_...`) | Yes |
---
## Provider Instance Management
You can create **multiple instances** of the same provider type for load balancing and risk control:
- **Multi-instance load balancing** — Distribute orders via round-robin or least-amount strategy
- **Independent limits** — Each instance can have its own min/max amount and daily limit
- **Independent toggle** — Enable/disable individual instances without affecting others
- **Refund control** — Enable or disable refunds per instance
- **Payment methods** — Each instance can support a subset of payment methods
- **Ordering** — Drag to reorder instances
### Instance Limit Configuration
Each instance supports these limits:
| Limit | Description |
|-------|-------------|
| **Minimum Amount** | Minimum order amount accepted by this instance |
| **Maximum Amount** | Maximum order amount accepted by this instance |
| **Daily Limit** | Daily cumulative transaction limit for this instance |
> During load balancing, instances that exceed their limits are automatically skipped.
---
## Webhook Configuration
Payment callbacks are essential for the payment system to work correctly.
### Callback URL Format
When adding a provider, the system auto-generates callback URLs from your site domain:
| Provider | Callback Path |
|----------|-------------|
| **EasyPay** | `https://your-domain.com/api/v1/payment/webhook/easypay` |
| **Alipay (Direct)** | `https://your-domain.com/api/v1/payment/webhook/alipay` |
| **WeChat Pay (Direct)** | `https://your-domain.com/api/v1/payment/webhook/wxpay` |
| **Stripe** | `https://your-domain.com/api/v1/payment/webhook/stripe` |
> Replace `your-domain.com` with your actual domain. For EasyPay / Alipay / WeChat Pay, the callback URL is auto-filled when adding the provider — no manual configuration needed.
### Stripe Webhook Setup
1. Log in to [Stripe Dashboard](https://dashboard.stripe.com/)
2. Go to **Developers → Webhooks**
3. Add an endpoint with the callback URL
4. Subscribe to events: `payment_intent.succeeded`, `payment_intent.payment_failed`
5. Copy the generated Webhook Secret (`whsec_...`) to your provider configuration
### Important Notes
- Callback URLs must use **HTTPS** (required by Stripe, strongly recommended for others)
- Ensure your firewall allows callback requests from payment platforms
- The system automatically verifies callback signatures to prevent forgery
- Balance top-up is processed automatically upon successful payment — no manual intervention needed
---
## Payment Flow
```
User selects amount and payment method
Create Order (PENDING)
├─ Validate amount range, pending order count, daily limit
├─ Load balance to select provider instance
└─ Call provider to get payment info
User completes payment
├─ EasyPay → QR code / H5 redirect
├─ Alipay → Desktop QR / mobile Alipay redirect
├─ WeChat Pay → Desktop Native QR / non-WeChat H5 / in-WeChat JSAPI
└─ Stripe → Payment Element (card/Alipay/WeChat/etc.)
Webhook callback verified → Order PAID
Auto top-up to user balance → Order COMPLETED
```
### Order Status Reference
| Status | Description |
|--------|-------------|
| `PENDING` | Waiting for user to complete payment |
| `PAID` | Payment confirmed, awaiting balance credit |
| `COMPLETED` | Balance credited successfully |
| `EXPIRED` | Timed out without payment |
| `CANCELLED` | Cancelled by user |
| `FAILED` | Balance credit failed, admin can retry |
| `REFUND_REQUESTED` | Refund requested |
| `REFUNDING` | Refund in progress |
| `REFUNDED` | Refund completed |
### Timeout and Fallback
- Before marking an order as expired, the background job queries the upstream payment status first
- If the user has actually paid but the callback was delayed, the system will reconcile automatically
- The background job runs every 60 seconds to check for timed-out orders
---
## Migrating from Sub2ApiPay
If you previously used [Sub2ApiPay](https://github.com/touwaeriol/sub2apipay) as an external payment system, you can migrate to the built-in payment system:
### Key Differences
| Aspect | Sub2ApiPay | Built-in Payment |
|--------|-----------|-----------------|
| Deployment | Separate service (Next.js + PostgreSQL) | Built into Sub2API, no extra deployment |
| Payment Methods | EasyPay, Alipay, WeChat, Stripe | Same |
| Configuration | Environment variables + separate admin UI | Unified in Sub2API admin dashboard |
| Top-up Integration | Via Admin API callback | Internal processing, more reliable |
| Subscription Plans | Supported | Not yet (planned) |
| Order Management | Separate admin interface | Integrated in Sub2API admin dashboard |
### Migration Steps
1. Enable payment in Sub2API admin dashboard and configure providers (use the same payment credentials)
2. Update webhook callback URLs to Sub2API's callback endpoints
3. Verify that new orders are processed correctly via built-in payment
4. Decommission the Sub2ApiPay service
> **Note**: Historical order data from Sub2ApiPay will not be automatically migrated. Keep Sub2ApiPay running for a while to access historical records.

287
docs/PAYMENT_CN.md Normal file
View File

@@ -0,0 +1,287 @@
# 支付系统配置指南
Sub2API 内置支付系统,支持用户自助充值,无需部署独立的支付服务。
---
## 目录
- [支持的支付方式](#支持的支付方式)
- [快速开始](#快速开始)
- [系统设置](#系统设置)
- [服务商配置](#服务商配置)
- [服务商实例管理](#服务商实例管理)
- [Webhook 配置](#webhook-配置)
- [支付流程](#支付流程)
- [从 Sub2ApiPay 迁移](#从-sub2apipay-迁移)
---
## 支持的支付方式
| 服务商 | 支付方式 | 说明 |
|--------|---------|------|
| **EasyPay易支付** | 支付宝、微信支付 | 兼容易支付协议的第三方聚合支付 |
| **支付宝官方** | 桌面二维码扫码、移动端支付宝跳转 | 直接对接支付宝开放平台,桌面端返回二维码,移动端返回 WAP/唤起链接 |
| **微信官方** | Native 扫码、H5、公众号/JSAPI 支付 | 直接对接微信支付 APIv3按终端环境自动分流 |
| **Stripe** | 银行卡、支付宝、微信支付、Link 等 | 国际支付,支持多币种 |
> 支付宝官方 / 微信官方与易支付可以同时作为后台服务商实例存在,但前台始终只展示 `支付宝`、`微信支付` 两个可见按钮。管理员需要分别为这两个按钮选择唯一支付来源:官方或易支付。官方渠道直接对接 API资金直达商户账户手续费更低易支付通过第三方平台聚合接入门槛更低。
> **易支付服务商推荐**:以下两家均为兼容易支付协议的第三方聚合支付,按资金通道与结算方式选择:
>
> - **国内渠道 / 人民币结算** — [ZPay](https://z-pay.cn/?uid=23808)`https://z-pay.cn/?uid=23808`):支付宝 / 微信官方 API 直连,手续费 **1.6%**;资金直达商家账户,**T+1 自动到账**。支持**个人用户**(无营业执照)每日 1 万元以内交易;拥有营业执照则无限额。链接含 [Sub2ApiPay](https://github.com/touwaeriol/sub2apipay) 原作者 [@touwaeriol](https://github.com/touwaeriol) 的邀请码,介意可去掉。
> - **国际渠道 / USDT 或美元结算** — [启润支付](https://kyren.top/?code=SUB2API)`https://kyren.top/?code=SUB2API`):为 AI 项目提供低门槛国际收款通道,支持国际版微信支付与支付宝,本地货币支付、美元结算。手续费:微信 2%、支付宝 2.5%;提现 0.1%(最低 40 美元、最高 150 美元),以 **USDT 或美元**到账。无资质审核、注册即用,使用门槛最低;提现门槛略高,适合**不使用国内支付渠道、无法接受 Stripe 高达 6%+ 手续费、流水较大,且拥有美元或 USDT 渠道可接收提现资金**的用户。启润支付开户费 200 美元,通过本链接注册(含 Sub2Api 作者 [@Wei-Shaw](https://github.com/Wei-Shaw) 邀请码)可**免开户费**,介意可去掉。
>
> 支付渠道的安全性、稳定性及合规性请自行鉴别,本项目不对任何第三方支付服务商做担保或背书。
---
## 快速开始
1. 进入管理后台 → **设置****支付设置** 标签页
2. 开启 **启用支付**
3. 配置基本参数(金额范围、超时时间等)
4.**服务商管理** 中添加至少一个服务商实例
5. 用户即可在前端页面进行充值
---
## 系统设置
在管理后台 **设置 → 支付设置** 中配置以下参数:
### 基本设置
| 设置项 | 说明 | 默认值 |
|--------|------|--------|
| **启用支付** | 启用或禁用支付系统 | 关闭 |
| **商品名前缀** | 支付页面显示的商品名前缀 | - |
| **商品名后缀** | 商品名后缀(如"元" | - |
| **最低金额** | 单笔最低充值金额 | 1 |
| **最高金额** | 单笔最高充值金额(留空表示不限制) | - |
| **每日限额** | 每用户每日累计充值上限(留空表示不限制) | - |
| **订单超时时间** | 订单超时分钟数,至少 1 分钟 | 30 |
| **最大待支付订单数** | 同一用户最大并行待支付订单数 | 3 |
| **负载均衡策略** | 多服务商实例时的选择策略 | 轮询 |
### 前台可见支付方式路由
当前版本对用户统一展示支付方式,不区分官方渠道还是易支付:
- **支付宝**:后台启用后,需要额外指定该按钮路由到 `支付宝官方``易支付支付宝`
- **微信支付**:后台启用后,需要额外指定该按钮路由到 `微信官方``易支付微信`
- 同一个可见支付方式在同一时刻只能路由到一个来源
- 支付来源未选择时,即使对应按钮被开启,前台也不会暴露该支付方式
### 负载均衡策略
| 策略 | 说明 |
|------|------|
| **轮询round-robin** | 按顺序轮流分配到各服务商实例 |
| **最少金额least-amount** | 优先分配到当日累计金额最少的实例 |
### 取消频率限制
防止用户频繁创建并取消订单:
| 设置项 | 说明 |
|--------|------|
| **启用限制** | 开关 |
| **窗口模式** | 滚动窗口 / 固定窗口 |
| **时间窗口** | 窗口长度 |
| **窗口单位** | 分钟 / 小时 |
| **最大次数** | 窗口内允许的最大取消次数 |
### 帮助信息
| 设置项 | 说明 |
|--------|------|
| **帮助图片** | 充值页面显示的客服二维码等图片(支持上传) |
| **帮助文本** | 充值页面显示的说明文字 |
---
## 服务商配置
每种服务商需要不同的凭证和参数。在 **服务商管理 → 添加服务商** 中选择类型后填写。
> **回调地址自动生成**添加服务商时异步回调地址Notify URL和同步跳转地址Return URL由系统根据你的站点域名自动拼接无需手动填写。管理员只需确认域名正确即可。
### EasyPay易支付
兼容任何 EasyPay 协议的支付服务商。
| 参数 | 说明 | 必填 |
|------|------|------|
| **商户 IDPID** | EasyPay 商户 ID | 是 |
| **商户密钥PKey** | EasyPay 商户密钥 | 是 |
| **API 地址** | EasyPay API 基础地址 | 是 |
| **支付宝通道 ID** | 指定支付宝通道(可选) | 否 |
| **微信通道 ID** | 指定微信通道(可选) | 否 |
### 支付宝官方
直接对接支付宝开放平台。桌面端返回二维码供页面内展示和扫码,移动端返回支付宝手机网站支付跳转链接。
| 参数 | 说明 | 必填 |
|------|------|------|
| **AppID** | 支付宝应用 AppID | 是 |
| **应用私钥** | RSA2 应用私钥 | 是 |
| **支付宝公钥** | 支付宝公钥 | 是 |
### 微信官方
直接对接微信支付 APIv3支持 Native 扫码支付、H5 支付,以及在微信环境内的公众号/JSAPI 支付。
| 参数 | 说明 | 必填 |
|------|------|------|
| **AppID** | 微信支付 AppID | 是 |
| **商户号MchID** | 微信支付商户号 | 是 |
| **商户 API 私钥** | 商户 API 私钥PEM 格式) | 是 |
| **APIv3 密钥** | 32 位 APIv3 密钥 | 是 |
| **微信支付公钥** | 微信支付公钥PEM 格式) | 是 |
| **微信支付公钥 ID** | 微信支付公钥 ID | 是 |
| **商户证书序列号** | 商户证书序列号 | 是 |
### Stripe
国际支付平台,支持多种支付方式和币种。
| 参数 | 说明 | 必填 |
|------|------|------|
| **Secret Key** | Stripe 密钥(`sk_live_...``sk_test_...` | 是 |
| **Publishable Key** | Stripe 可公开密钥(`pk_live_...``pk_test_...` | 是 |
| **Webhook Secret** | Stripe Webhook 签名密钥(`whsec_...` | 是 |
---
## 服务商实例管理
同一种服务商可以创建**多个实例**,实现负载均衡和风控:
- **多实例负载均衡** — 按轮询或最少金额策略分流订单
- **独立限额** — 每个实例可独立配置单笔最小/最大金额和每日限额
- **独立启停** — 可单独启用/禁用某个实例,不影响其他实例
- **退款控制** — 每个实例可单独开启或关闭退款功能
- **支付方式** — 每个实例可选择支持的支付方式子集
- **排序** — 拖拽调整实例顺序
### 实例限额配置
每个实例支持以下限额:
| 限额项 | 说明 |
|--------|------|
| **单笔最小金额** | 该实例接受的最小订单金额 |
| **单笔最大金额** | 该实例接受的最大订单金额 |
| **每日限额** | 该实例每日累计交易上限 |
> 负载均衡时,系统会自动跳过超出限额的实例。
---
## Webhook 配置
支付回调是支付系统的核心环节,必须正确配置:
### 回调地址格式
添加服务商时,系统会自动根据站点域名拼接回调地址,格式如下:
| 服务商 | 回调路径 |
|--------|---------|
| **EasyPay** | `https://your-domain.com/api/v1/payment/webhook/easypay` |
| **支付宝官方** | `https://your-domain.com/api/v1/payment/webhook/alipay` |
| **微信官方** | `https://your-domain.com/api/v1/payment/webhook/wxpay` |
| **Stripe** | `https://your-domain.com/api/v1/payment/webhook/stripe` |
> 将 `your-domain.com` 替换为你的实际域名。EasyPay / 支付宝 / 微信的回调地址在添加服务商时自动填入,无需手动配置。
### Stripe Webhook 设置
1. 登录 [Stripe Dashboard](https://dashboard.stripe.com/)
2. 进入 **Developers → Webhooks**
3. 添加端点,填写回调地址
4. 订阅事件:`payment_intent.succeeded``payment_intent.payment_failed`
5. 将生成的 Webhook Secret`whsec_...`)填入服务商配置
### 注意事项
- 回调地址必须是 **HTTPS**Stripe 强制要求,其他服务商强烈推荐)
- 确保服务器防火墙允许支付平台的回调请求
- 系统会自动进行签名验证,防止伪造回调
- 支付成功后自动完成余额充值,无需人工干预
---
## 支付流程
```
用户选择充值金额和支付方式
创建订单 (PENDING)
├─ 校验金额范围、待支付订单数、每日限额
├─ 负载均衡选择服务商实例
└─ 调用服务商获取支付信息
用户完成支付
├─ EasyPay → 扫码 / H5 跳转
├─ 支付宝官方 → 桌面二维码 / 移动端支付宝跳转
├─ 微信官方 → 桌面 Native 扫码 / 非微信 H5 / 微信内 JSAPI
└─ Stripe → Payment Element银行卡/支付宝/微信等)
支付回调验签 → 订单 PAID
自动充值到用户余额 → 订单 COMPLETED
```
### 订单状态说明
| 状态 | 说明 |
|------|------|
| `PENDING` | 待支付,等待用户完成支付 |
| `PAID` | 已支付,等待充值到账 |
| `COMPLETED` | 已完成,余额已到账 |
| `EXPIRED` | 已过期,超时未支付 |
| `CANCELLED` | 已取消,用户主动取消 |
| `FAILED` | 充值失败,可管理员重试 |
| `REFUND_REQUESTED` | 已申请退款 |
| `REFUNDING` | 退款处理中 |
| `REFUNDED` | 已退款 |
### 超时与兜底
- 订单超时后,后台任务会先查询上游支付状态再标记过期
- 如果用户实际已支付但回调延迟,系统会通过查询补单
- 后台任务每 60 秒执行一次超时检查
---
## 从 Sub2ApiPay 迁移
如果你之前使用 [Sub2ApiPay](https://github.com/touwaeriol/sub2apipay) 作为外部支付系统,现在可以迁移到内置支付:
### 主要差异
| 对比项 | Sub2ApiPay | 内置支付 |
|--------|-----------|---------|
| 部署方式 | 独立服务Next.js + PostgreSQL | 内置于 Sub2API无需额外部署 |
| 支付方式 | EasyPay、支付宝、微信、Stripe | 相同 |
| 配置方式 | 环境变量 + 独立管理后台 | Sub2API 管理后台内统一配置 |
| 充值对接 | 通过 Admin API 回调 | 内部直接处理,更可靠 |
| 订阅套餐 | 支持 | 暂不支持(计划中) |
| 订单管理 | 独立管理界面 | 集成在 Sub2API 管理后台 |
### 迁移步骤
1. 在 Sub2API 管理后台启用支付并配置服务商(使用相同的支付凭证)
2. 更新 Webhook 回调地址为 Sub2API 的回调地址
3. 确认新订单通过内置支付正常处理
4. 停用 Sub2ApiPay 服务
> **注意**Sub2ApiPay 中的历史订单数据不会自动迁移。建议保留 Sub2ApiPay 一段时间以便查询历史记录。