Sub2API v1.0 - AI API 网关(二开初始版本,基于上游 Wei-Shaw/sub2api)
Release / update-version (push) Has been cancelled
Release / build-frontend (push) Has been cancelled
Release / release (push) Has been cancelled
Release / sync-version-file (push) Has been cancelled
CI / shell (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
Security Scan / backend-security (push) Canceled after 0s
Security Scan / frontend-security (push) Canceled after 0s
Release / update-version (push) Has been cancelled
Release / build-frontend (push) Has been cancelled
Release / release (push) Has been cancelled
Release / sync-version-file (push) Has been cancelled
CI / shell (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
Security Scan / backend-security (push) Canceled after 0s
Security Scan / frontend-security (push) Canceled after 0s
This commit is contained in:
@@ -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`
|
||||
@@ -0,0 +1,166 @@
|
||||
# Asynchronous Image Tasks
|
||||
|
||||
Asynchronous image tasks let clients submit long-running OpenAI-compatible image requests without keeping one HTTP connection open. This avoids proxy/CDN response timeouts such as Cloudflare 524 while preserving the existing image routing, billing, moderation, concurrency, and failover behavior.
|
||||
|
||||
## Endpoints
|
||||
|
||||
The authenticated gateway exposes both `/v1` paths and their existing no-prefix aliases:
|
||||
|
||||
```text
|
||||
POST /v1/images/generations/async
|
||||
POST /v1/images/edits/async
|
||||
GET /v1/images/tasks/{task_id}
|
||||
```
|
||||
|
||||
The aliases are `/images/generations/async`, `/images/edits/async`, and `/images/tasks/{task_id}`.
|
||||
|
||||
Only OpenAI and Grok groups are supported. Requests use the same JSON or multipart payload as the corresponding synchronous endpoint. Streaming image requests are rejected because a polled task returns one final JSON result.
|
||||
|
||||
## Enabling the feature (object storage)
|
||||
|
||||
Asynchronous image tasks are **disabled by default** and gated on object storage. When the switch is off — or the S3 credentials are incomplete — the async endpoints return `404` and never create a task or write to Redis. This is deliberate: without offloading, large `b64_json` results (several MB each, e.g. `gpt-image-1`) would accumulate in Redis and exhaust its memory.
|
||||
|
||||
### From the admin UI (recommended)
|
||||
|
||||
**Admin → Backup → Async image object storage.** Saving the form takes effect immediately — the object-storage client is rebuilt on the next request, so there is no container restart.
|
||||
|
||||
Because the async image storage and the database backup share one S3 client, the form defaults to **reusing the backup S3 configuration**: it borrows the endpoint, region and credentials already configured above and keeps only its own bucket and prefix, so backups stay under `backups/` while images go to `images/`. Leave the bucket empty to use the backup bucket as well. Untick the box to point images at a completely separate account.
|
||||
|
||||
Saving requires step-up 2FA when that gate is enabled, for the same reason the backup S3 form does: changing the target redirects generated content to another account.
|
||||
|
||||
Turning the switch off stops new submissions but keeps already-accepted tasks pollable, so nothing in flight is stranded.
|
||||
|
||||
### From the config file
|
||||
|
||||
The admin setting takes precedence. When nothing has ever been saved there, the `image_storage` block in `config.yaml` is used instead, so deployments that enabled the feature before the admin UI existed keep working untouched.
|
||||
|
||||
Configure an S3-compatible object store (AWS S3, Cloudflare R2, Aliyun OSS, MinIO, …) in `config.yaml` (all keys also accept the `IMAGE_STORAGE_*` environment overrides):
|
||||
|
||||
```yaml
|
||||
image_storage:
|
||||
enabled: true
|
||||
endpoint: "https://<account_id>.r2.cloudflarestorage.com" # AWS 官方可留空
|
||||
region: "auto"
|
||||
bucket: "my-images"
|
||||
access_key_id: "..."
|
||||
secret_access_key: "..."
|
||||
prefix: "images/"
|
||||
force_path_style: false # MinIO/path-style buckets set true
|
||||
public_base_url: "" # set to return public_base_url/key直链; empty → presigned URL
|
||||
presign_expiry_hours: 24 # presigned link TTL when public_base_url is empty
|
||||
max_download_bytes: 33554432 # cap when re-hosting an upstream image URL (32MB)
|
||||
```
|
||||
|
||||
When a task completes, each generated image is uploaded to the bucket and the result is rewritten to a compact form: `data[].url` points at the stored object (a permanent `public_base_url/key` link, or a time-limited presigned URL) and `b64_json` is removed. Only this small JSON is stored in Redis. If an upload fails, the task is marked `failed` rather than persisting the raw base64.
|
||||
|
||||
To support a different vendor beyond the S3-compatible client, implement the `service.ImageStorage` interface (`Save(ctx, key, contentType, data) (url, error)`) and provide it in place of the S3 implementation.
|
||||
|
||||
### Troubleshooting: the endpoints return 404 after enabling
|
||||
|
||||
`404 async image tasks are not enabled` means `image_storage` did not resolve to a complete configuration, so the feature stayed off. The route exists either way — the 404 comes from the handler, not from an unregistered path, which makes it easy to mistake for a missing build.
|
||||
|
||||
Check the startup log for:
|
||||
|
||||
```text
|
||||
WARN image_storage.enabled is true but object storage is not fully configured; async image tasks are disabled missing_keys=[...]
|
||||
```
|
||||
|
||||
`missing_keys` names exactly which credentials were empty when the config was loaded.
|
||||
|
||||
Note that releases **before v0.1.161 silently dropped `IMAGE_STORAGE_ENDPOINT`, `_BUCKET`, `_ACCESS_KEY_ID`, `_SECRET_ACCESS_KEY` and `_PUBLIC_BASE_URL`** when they were supplied only through the environment: those keys had no registered default, and viper cannot see an environment variable for a key it does not already know about. Deployments driven purely by `environment:` — which is what `deploy/docker-compose.yml` does by default — therefore reported `enabled: true` with empty credentials and 404'd on every async call. On an affected release the workaround is to also place the `image_storage` block in `/app/data/config.yaml` (copy it from `deploy/config.example.yaml`); once the keys exist in the file, the environment overrides apply normally.
|
||||
|
||||
Two further causes of a 404 that are unrelated to storage: the API key's group must be on the **OpenAI or Grok** platform (any other platform, or a key with no group at all, yields `Images API is not supported for this platform`), and a task may only be polled with the **same API key that submitted it** — polling with a different key of the same user returns `image task not found` by design.
|
||||
|
||||
## Submit a task
|
||||
|
||||
```bash
|
||||
curl -i https://api.example.com/v1/images/generations/async \
|
||||
-H 'Authorization: Bearer sk-...' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"model": "gpt-image-1",
|
||||
"prompt": "A lighthouse during a winter storm",
|
||||
"size": "1536x1024"
|
||||
}'
|
||||
```
|
||||
|
||||
The server stores the initial task in Redis and responds with `202 Accepted`:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "imgtask_0123456789abcdef",
|
||||
"task_id": "imgtask_0123456789abcdef",
|
||||
"object": "image.generation.task",
|
||||
"status": "processing",
|
||||
"created_at": 1784092800,
|
||||
"expires_at": 1784179200,
|
||||
"poll_url": "/v1/images/tasks/imgtask_0123456789abcdef"
|
||||
}
|
||||
```
|
||||
|
||||
`Location` contains the polling path and `Retry-After: 3` provides the recommended polling interval.
|
||||
|
||||
## Poll a task
|
||||
|
||||
Use the same API key that submitted the task:
|
||||
|
||||
```bash
|
||||
curl https://api.example.com/v1/images/tasks/imgtask_0123456789abcdef \
|
||||
-H 'Authorization: Bearer sk-...'
|
||||
```
|
||||
|
||||
While work is in progress:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "imgtask_0123456789abcdef",
|
||||
"task_id": "imgtask_0123456789abcdef",
|
||||
"object": "image.generation.task",
|
||||
"status": "processing",
|
||||
"created_at": 1784092800,
|
||||
"expires_at": 1784179200
|
||||
}
|
||||
```
|
||||
|
||||
On success, `result` mirrors the synchronous image API body, except each image has been offloaded to object storage: `data[].url` points at the stored object and `b64_json` is stripped (so both URL and base64 upstream formats end up as compact stored links):
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "imgtask_0123456789abcdef",
|
||||
"task_id": "imgtask_0123456789abcdef",
|
||||
"object": "image.generation.task",
|
||||
"status": "completed",
|
||||
"http_status": 200,
|
||||
"image_url": "https://...",
|
||||
"result": {
|
||||
"created": 1784092923,
|
||||
"data": [{"url": "https://..."}]
|
||||
},
|
||||
"created_at": 1784092800,
|
||||
"completed_at": 1784092923,
|
||||
"expires_at": 1784179323
|
||||
}
|
||||
```
|
||||
|
||||
For URL responses, `image_url` mirrors the first `data[].url` for simple clients. On failure, the task reaches `failed` and exposes the original OpenAI-compatible error object where available:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "imgtask_0123456789abcdef",
|
||||
"task_id": "imgtask_0123456789abcdef",
|
||||
"object": "image.generation.task",
|
||||
"status": "failed",
|
||||
"http_status": 502,
|
||||
"error": {
|
||||
"type": "api_error",
|
||||
"message": "Upstream request failed"
|
||||
},
|
||||
"created_at": 1784092800,
|
||||
"completed_at": 1784092923,
|
||||
"expires_at": 1784179323
|
||||
}
|
||||
```
|
||||
|
||||
All submit and poll responses include `Cache-Control: no-store`, preventing a CDN from caching the `processing` state. Tasks and results expire 24 hours after their latest state update. A task executes for at most 30 minutes.
|
||||
|
||||
Task ownership is scoped to both user and API key. Unknown task IDs and IDs owned by another key both return `404`, avoiding task-existence disclosure. Polling remains available when the completed generation used the key's remaining balance; normal authentication, disabled-key, user, IP, and group checks still apply.
|
||||
+287
@@ -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://kyrenpay.com/?code=SUB2API) (`https://kyrenpay.com/?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.5%, Alipay 2.5%; Multiple withdrawal methods are available. Withdrawals to overseas company accounts incur a $20 fee, while USDT withdrawals incur a $30 fee plus a 0.4% transaction fee, 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. Mobile flows return an Alipay WAP/app redirect URL. Desktop flows prefer Face-to-Face Precreate QR payloads; if the merchant has not enabled that product, the provider falls back to Computer Website Pay and also returns the cashier URL so the frontend can render a QR code or open the hosted checkout page directly.
|
||||
|
||||
| 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 payload (Face-to-Face preferred, Website Pay fallback) / 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.
|
||||
@@ -0,0 +1,295 @@
|
||||
# 支付系统配置指南
|
||||
|
||||
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://merchant.kyrenpay.com/?code=SUB2API)(`https://merchant.kyrenpay.com/?code=SUB2API`):为 AI 项目提供低门槛国际收款通道,支持国际版微信支付与支付宝,本地货币支付、美元结算。微信 2.5%、支付宝 2.5%;多种提现方式,海外公司账户提现手续费 20 美金,USDT 提现手续费 30 美金 + 0.4% 流水,以 **USDT 或美元** 到账。无资质审核、注册即用,使用门槛最低;提现门槛略高,适合**不使用国内支付渠道、无法接受 Stripe 高达 6%+ 手续费、流水较大,且拥有美元或 USDT 渠道可接收提现资金**的用户。启润支付开户费 200 美元,通过本链接注册(含 Sub2Api 作者 [@Wei-Shaw](https://github.com/Wei-Shaw) 邀请码)可**免开户费**,介意可去掉。
|
||||
>
|
||||
> 支付渠道的安全性、稳定性及合规性请自行鉴别,本项目不对任何第三方支付服务商做担保或背书。
|
||||
|
||||
---
|
||||
|
||||
## 快速开始
|
||||
|
||||
1. 进入管理后台 → **设置** → **支付设置** 标签页
|
||||
2. 开启 **启用支付**
|
||||
3. 配置基本参数(金额范围、超时时间等)
|
||||
4. 在 **服务商管理** 中添加至少一个服务商实例
|
||||
5. 用户即可在前端页面进行充值
|
||||
|
||||
---
|
||||
|
||||
## 系统设置
|
||||
|
||||
在管理后台 **设置 → 支付设置** 中配置以下参数:
|
||||
|
||||
### 基本设置
|
||||
|
||||
| 设置项 | 说明 | 默认值 |
|
||||
|--------|------|--------|
|
||||
| **启用支付** | 启用或禁用支付系统 | 关闭 |
|
||||
| **商品名前缀** | 支付页面显示的商品名前缀 | - |
|
||||
| **商品名后缀** | 商品名后缀(如"元") | - |
|
||||
| **最低金额** | 单笔最低充值金额 | 1 |
|
||||
| **最高金额** | 单笔最高充值金额(留空表示不限制) | - |
|
||||
| **每日限额** | 每用户每日累计充值上限(留空表示不限制) | - |
|
||||
| **订单超时时间** | 订单超时分钟数,至少 1 分钟 | 30 |
|
||||
| **最大待支付订单数** | 同一用户最大并行待支付订单数 | 3 |
|
||||
| **负载均衡策略** | 多服务商实例时的选择策略 | 轮询 |
|
||||
|
||||
### 支付宝移动端当面付唤起
|
||||
|
||||
`支付宝移动端当面付唤起` 默认关闭,仅对前台路由到 **支付宝官方** 的移动端订单生效。开启后,服务端调用 `alipay.trade.precreate` 获取动态二维码,前端立即使用支付宝 Scheme 尝试唤起 App;页面未进入后台时会自动展示动态二维码备用页,继续轮询订单状态。桌面端仍保持“当面付二维码优先,电脑网站支付回退”的既有行为。
|
||||
|
||||
- 需要为该支付宝应用开通 **当面付 / 扫码支付**;未开通时保持关闭。
|
||||
- 管理后台开关保存为 `ALIPAY_MOBILE_PRECREATE_DEEP_LINK`;部署环境变量 `ALIPAY_MOBILE_PRECREATE_DEEP_LINK=true` 可强制开启,未设置时使用后台值。
|
||||
- 与“支付宝强制二维码支付”同时开启时,当面付唤起优先。关闭本开关即可恢复移动端手机网站支付。
|
||||
|
||||
### 前台可见支付方式路由
|
||||
|
||||
当前版本对用户统一展示支付方式,不区分官方渠道还是易支付:
|
||||
|
||||
- **支付宝**:后台启用后,需要额外指定该按钮路由到 `支付宝官方` 或 `易支付支付宝`
|
||||
- **微信支付**:后台启用后,需要额外指定该按钮路由到 `微信官方` 或 `易支付微信`
|
||||
- 同一个可见支付方式在同一时刻只能路由到一个来源
|
||||
- 支付来源未选择时,即使对应按钮被开启,前台也不会暴露该支付方式
|
||||
|
||||
### 负载均衡策略
|
||||
|
||||
| 策略 | 说明 |
|
||||
|------|------|
|
||||
| **轮询(round-robin)** | 按顺序轮流分配到各服务商实例 |
|
||||
| **最少金额(least-amount)** | 优先分配到当日累计金额最少的实例 |
|
||||
|
||||
### 取消频率限制
|
||||
|
||||
防止用户频繁创建并取消订单:
|
||||
|
||||
| 设置项 | 说明 |
|
||||
|--------|------|
|
||||
| **启用限制** | 开关 |
|
||||
| **窗口模式** | 滚动窗口 / 固定窗口 |
|
||||
| **时间窗口** | 窗口长度 |
|
||||
| **窗口单位** | 分钟 / 小时 |
|
||||
| **最大次数** | 窗口内允许的最大取消次数 |
|
||||
|
||||
### 帮助信息
|
||||
|
||||
| 设置项 | 说明 |
|
||||
|--------|------|
|
||||
| **帮助图片** | 充值页面显示的客服二维码等图片(支持上传) |
|
||||
| **帮助文本** | 充值页面显示的说明文字 |
|
||||
|
||||
---
|
||||
|
||||
## 服务商配置
|
||||
|
||||
每种服务商需要不同的凭证和参数。在 **服务商管理 → 添加服务商** 中选择类型后填写。
|
||||
|
||||
> **回调地址自动生成**:添加服务商时,异步回调地址(Notify URL)和同步跳转地址(Return URL)由系统根据你的站点域名自动拼接,无需手动填写。管理员只需确认域名正确即可。
|
||||
|
||||
### EasyPay(易支付)
|
||||
|
||||
兼容任何 EasyPay 协议的支付服务商。
|
||||
|
||||
| 参数 | 说明 | 必填 |
|
||||
|------|------|------|
|
||||
| **商户 ID(PID)** | EasyPay 商户 ID | 是 |
|
||||
| **商户密钥(PKey)** | EasyPay 商户密钥 | 是 |
|
||||
| **API 地址** | EasyPay API 基础地址 | 是 |
|
||||
| **支付宝通道 ID** | 指定支付宝通道(可选) | 否 |
|
||||
| **微信通道 ID** | 指定微信通道(可选) | 否 |
|
||||
|
||||
### 支付宝官方
|
||||
|
||||
直接对接支付宝开放平台。移动端默认走支付宝手机网站支付跳转;开启“支付宝移动端当面付唤起”后改为调用当面付,前端尝试打开支付宝 App,失败时显示动态二维码备用页。桌面端优先使用当面付返回扫码串,若商户未开通当面付则回退到电脑网站支付,并将收银台链接同时返回给前端用于渲染二维码或直接打开支付页。
|
||||
|
||||
| 参数 | 说明 | 必填 |
|
||||
|------|------|------|
|
||||
| **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 跳转
|
||||
├─ 支付宝官方 → 桌面扫码单(当面付优先,电脑网站支付回退)/ 移动端 WAP 或当面付唤起 + 动态二维码备用页
|
||||
├─ 微信官方 → 桌面 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 一段时间以便查询历史记录。
|
||||
@@ -0,0 +1,49 @@
|
||||
# Sub2API Deployment and Operation Compliance Commitment
|
||||
|
||||
Version: v2026.06.10
|
||||
|
||||
This document applies to any individual, organization, or authorized representative that deploys, configures, manages, operates, or effectively controls a Sub2API instance. Before continuing to access or use console functions, the acknowledging party must read, understand, and accept this document in full.
|
||||
|
||||
## 1. Scope
|
||||
|
||||
Sub2API is open-source software. Any self-hosted deployment, modification, hosted operation, external service, commercial use, user management, content processing, data processing, payment settlement, customer support, or upstream account/API usage based on Sub2API is the sole responsibility of the party that deploys, operates, or controls the relevant instance.
|
||||
|
||||
This document does not replace the open-source license, upstream terms of service, user agreements, privacy policies, data processing agreements, commercial contracts, regulatory filings, administrative permits, security assessments, or any other documents, procedures, or obligations required by applicable law or contract.
|
||||
|
||||
## 2. Responsibility of the Deploying or Operating Party
|
||||
|
||||
The acknowledging party must independently assess and continuously comply with the laws, regulations, regulatory requirements, industry rules, contractual obligations, and platform policies that may apply in its location, server location, target-user location, place of actual business operation, and the locations of upstream service providers.
|
||||
|
||||
The acknowledging party must ensure that it has all authorizations, qualifications, filings, permits, assessments, contracts, risk-control capabilities, content-safety capabilities, data-protection capabilities, complaint-handling mechanisms, and emergency-response capabilities required for deploying and operating the relevant instance. Such obligations are not transferred, waived, or reduced by the use of open-source software.
|
||||
|
||||
## 3. No Affiliation and Allocation of Responsibility
|
||||
|
||||
Any third-party instance, commercial service, paid plan, user solicitation, content processing, data processing, account usage, API call, payment settlement, customer support, or promotional activity is independently carried out by the corresponding deploying, operating, or controlling party. The open-source nature of this project, code contributions, issue discussions, documentation maintenance, version releases, bug fixes, community communications, or general technical explanations do not create participation in, authorization of, approval of, warranty for, joint operation, agency, partnership, employment, authorized operation, joint control, revenue sharing, joint tort, or any other joint-and-several liability relationship between the open-source project, copyright holders, contributors, or maintainers and such activities.
|
||||
|
||||
The acknowledging party must not use the project name, marks, documentation, screenshots, community content, or open-source repository information to state or imply that its third-party instance, commercial service, paid plan, or operation is participated in, authorized, approved, warranted, or endorsed by the open-source project, copyright holders, contributors, maintainers, or community.
|
||||
|
||||
The acknowledging party is independently responsible for consequences arising from its deployment, configuration, operation, promotion, charging, user-behavior management, content processing, data processing, account usage, API calls, or violations of laws, regulations, regulatory requirements, contractual obligations, or upstream rules.
|
||||
|
||||
Any mandatory liability that cannot be excluded or limited by agreement shall be handled according to applicable law. Such statutory exception does not constitute participation in, authorization of, approval of, warranty for, or endorsement of any third-party deployment, operation, or commercial activity.
|
||||
|
||||
## 4. Compliance Commitments
|
||||
|
||||
By continuing to use console functions, the acknowledging party makes the following commitments:
|
||||
|
||||
1. It has independently reviewed and will continuously comply with the terms of service, acceptable use policies, supported countries and regions, account/API key rules, commercial-use requirements, resale restrictions, risk-control requirements, and technical restrictions of OpenAI, Anthropic, Google, and any other upstream service providers.
|
||||
2. It will not use this project to bypass, or assist others in bypassing, upstream regional restrictions, access restrictions, account restrictions, risk controls, billing restrictions, identity verification, usage limits, or terms of service.
|
||||
3. It will not provide API relay, model-call resale, account quota distribution, shared subscriptions, paid calls, top-up/payment agency, or similar services to the public or an indefinite group of users unless all necessary authorizations, qualifications, filings, permits, assessments, or contractual arrangements have been obtained.
|
||||
4. If it provides generative AI services, deep synthesis services, algorithm-related services, API relay, paid calls, or other potentially regulated services within Mainland China or to the Mainland China public, it will independently complete all potentially applicable obligations regarding internet information services, generative AI services, deep synthesis, algorithm filing, security assessment, cybersecurity, data security, personal information protection, content safety, payment settlement, taxes, and upstream authorization.
|
||||
5. It will maintain user management, access control, content review, abuse handling, log retention, privacy protection, data deletion, complaint handling, emergency takedown, and security incident response mechanisms appropriate to the scale and risk of its business.
|
||||
6. It will not make any statement, commitment, marketing representation, or warranty to any user, customer, partner, channel, regulator, or third party that conflicts with Section 3 of this document.
|
||||
7. It will be independently responsible for consequences arising from its deployment, operation, promotion, charging, user-behavior management, content processing, data processing, account usage, API calls, or violations of laws, regulations, regulatory requirements, contractual obligations, or upstream rules.
|
||||
|
||||
## 5. Risk and Responsibility Notice
|
||||
|
||||
Using Sub2API for public API services, commercial relay, quota distribution, team sharing, paid calls, or similar purposes may involve risks relating to terms of service, contractual breach, data protection, content safety, consumer protection, payment settlement, taxes, export controls, sanctions compliance, cybersecurity, industry access, and administrative regulation. Requirements vary by jurisdiction and business model and may change over time.
|
||||
|
||||
The mandatory notice, document link, exact-phrase acknowledgment, and local acknowledgment record in the console are intended to provide clear, conspicuous, and reproducible notice of deployment and operation risks, confirm that the console user has read the current version of this document, and create a clear responsibility-separation record between the open-source project, copyright holders, contributors, maintainers and any third-party deploying, operating, or controlling party.
|
||||
|
||||
## 6. Electronic Acknowledgment
|
||||
|
||||
By continuing to use the console, opening the document link, reading this document, and typing the required confirmation phrase exactly as displayed, the acknowledging party electronically confirms that it has read, understood, and agreed to this document, and agrees that the system may record necessary evidence including the acknowledged version, acknowledgment time, console account identifier, IP address, and User-Agent.
|
||||
@@ -0,0 +1,49 @@
|
||||
# Sub2API 部署与运营合规承诺
|
||||
|
||||
版本:v2026.06.10
|
||||
|
||||
本文件适用于部署、配置、管理、运营或实际控制 Sub2API 实例的个人、组织及其授权代表。继续访问或使用控制台功能前,确认主体应完整阅读、理解并接受本文件。
|
||||
|
||||
## 一、适用范围
|
||||
|
||||
Sub2API 是开源软件。任何基于 Sub2API 进行的自部署、二次开发、托管运行、对外服务、商业化使用、用户管理、内容处理、数据处理、支付结算、客户支持及上游账号或接口使用行为,均由相应实例的部署、运营或控制主体自行负责。
|
||||
|
||||
本文件不替代开源许可证、上游服务条款、用户协议、隐私政策、数据处理协议、商业合同、监管备案、行政许可、安全评估或其他依法应当具备的文件、手续或义务。
|
||||
|
||||
## 二、主体责任
|
||||
|
||||
确认主体应自行评估并持续遵守其所在地、服务器所在地、目标用户所在地、业务实际开展地以及上游服务提供方所在地可能适用的法律法规、监管要求、行业规范、合同约定和平台规则。
|
||||
|
||||
确认主体应确保其已具备部署和运营相关实例所需的授权、资质、备案、许可、评估、合同、风控能力、内容安全能力、数据保护能力、投诉处理机制和应急处置能力。相关义务不得因使用开源软件而转移、免除或降低。
|
||||
|
||||
## 三、非关联关系与责任隔离
|
||||
|
||||
任何第三方实例、商业服务、收费套餐、用户招揽、内容处理、数据处理、账号使用、接口调用、支付结算、客户支持或推广活动,均由相应部署、运营或控制主体独立实施,并不因本项目开源、代码贡献、议题讨论、文档维护、版本发布、缺陷修复、社区交流或一般性技术说明而形成开源项目、著作权人、贡献者或维护者对该等活动的参与、授权、认可、担保、共同经营、代理、合伙、雇佣、授权运营、共同控制、收益分配、共同侵权或其他连带责任关系。
|
||||
|
||||
确认主体不得以项目名称、标识、文档、截图、社区内容或开源仓库信息明示或暗示其第三方实例、商业服务、收费套餐或运营活动获得开源项目、著作权人、贡献者、维护者或社区的参与、授权、认可、担保或背书。
|
||||
|
||||
确认主体应独立承担因其部署、配置、运营、推广、收费、用户行为管理、内容处理、数据处理、账号使用、接口调用及违反法律法规、监管要求、合同约定或上游规则所产生的相关后果。
|
||||
|
||||
依法不得由协议排除或限制的强制性责任,依相关法律规定处理;该等法定例外不构成对任何第三方部署、运营或商业活动的参与、授权、认可、担保或背书。
|
||||
|
||||
## 四、合规承诺
|
||||
|
||||
确认主体在继续使用控制台功能时,作出以下承诺:
|
||||
|
||||
1. 已独立审阅并将持续遵守 OpenAI、Anthropic、Google 及其他上游服务提供方的服务条款、可接受使用政策、支持国家和地区、账号/API Key 使用规则、商业使用要求、转售限制、风控要求和技术限制。
|
||||
2. 不利用本项目规避或协助他人规避上游服务的地区限制、访问限制、账号限制、风控限制、计费限制、身份验证、使用限制或服务条款。
|
||||
3. 不在缺乏必要授权、资质、备案、许可、评估或合同安排的情况下,向公众或不特定对象提供 API 中转、模型调用转售、账号额度分发、共享订阅、付费调用、代充代付或其他类似服务。
|
||||
4. 如在中国大陆境内或面向中国大陆公众提供生成式人工智能服务、深度合成服务、算法相关服务、API 中转、付费调用或其他可能受监管服务,将自行完成可能适用的互联网信息服务、生成式人工智能服务、深度合成、算法备案、安全评估、网络安全、数据安全、个人信息保护、内容安全、支付结算、税务及上游授权等义务。
|
||||
5. 建立与业务规模和风险相匹配的用户管理、访问控制、内容审核、滥用处理、日志留存、隐私保护、数据删除、投诉处理、应急下线和安全事件响应机制。
|
||||
6. 不向任何用户、客户、合作方、渠道方、监管机构或第三方作出与本文件第三条相冲突的陈述、承诺、宣传或保证。
|
||||
7. 对其部署、运营、推广、收费、用户行为管理、内容处理、数据处理、账号使用、接口调用及违反法律法规、监管要求、合同约定或上游规则所产生的后果独立承担责任。
|
||||
|
||||
## 五、风险与责任提示
|
||||
|
||||
将 Sub2API 用于公开 API 服务、商业中转、额度分发、团队共享、付费调用或类似用途,可能涉及服务条款、合同违约、数据保护、内容安全、消费者权益、支付结算、税务、出口管制、制裁合规、网络安全、行业准入及行政监管等风险。不同司法辖区和业务场景的要求可能不同,并可能随时间变化。
|
||||
|
||||
控制台中的强制提示、协议链接、逐字输入确认和本地确认记录,旨在以清晰、显著、可留痕的方式提示部署与运营风险,确认控制台使用者已阅读当前版本文件,并在开源项目、著作权人、贡献者、维护者与第三方部署、运营或控制主体之间形成明确的责任隔离记录。
|
||||
|
||||
## 六、电子确认
|
||||
|
||||
确认主体通过继续使用控制台、打开协议链接、阅读本文件并按页面要求逐字输入确认短语,即表示其以电子方式确认已阅读、理解并同意本文件,并同意系统记录确认版本、确认时间、控制台账户标识、IP 地址和 User-Agent 等必要留痕信息。
|
||||
Reference in New Issue
Block a user