1. MainTabs: "按量付费"→"余额充值","包月套餐"→"套餐订阅" 2. subscription-utils: 去掉所有智能转换,配置什么就显示什么(1月/30天/2周) 3. platform-style: 新增 modelTag 样式字段,每个平台独立颜色 4. ChannelCard: 模型标签颜色跟随平台(橙/绿/蓝/粉/紫)而非统一蓝色
Sub2ApiPay
Language: 中文 | English (current)
Sub2ApiPay is a self-hosted recharge payment gateway built for the Sub2API platform. It supports Alipay, WeChat Pay (via EasyPay aggregator), and Stripe. Once a payment is confirmed, the system automatically calls the Sub2API management API to credit the user's balance — no manual intervention required.
Table of Contents
- Features
- Tech Stack
- Quick Start
- Environment Variables
- Deployment
- Sub2API Integration
- Admin Panel
- Payment Flow
- Development
Features
- Multiple Payment Methods — Alipay, WeChat Pay (EasyPay), Stripe credit card
- Auto Balance Credit — Automatically calls Sub2API after payment verification, fully hands-free
- Full Order Lifecycle — Auto-expiry, user cancellation, admin cancellation, refunds
- Limit Controls — Configurable per-transaction cap and daily cumulative cap per user
- Security — Token auth, MD5/Webhook signature verification, timing-safe comparison, full audit log
- Responsive UI — PC + mobile adaptive layout, dark mode support, iframe embed support
- Admin Panel — Order list (pagination/filtering), order details, retry recharge, refunds
Tech Stack
| Category | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| Language | TypeScript 5 + React 19 |
| Styling | TailwindCSS 4 |
| ORM | Prisma 7 (adapter-pg mode) |
| Database | PostgreSQL 16 |
| Container | Docker + Docker Compose |
| Package Manager | pnpm |
Quick Start
Using Docker Hub Image (Recommended)
No Node.js or pnpm required on the server — just Docker.
mkdir -p /opt/sub2apipay && cd /opt/sub2apipay
# Download Compose file and env template
curl -O https://raw.githubusercontent.com/touwaeriol/sub2apipay/main/docker-compose.hub.yml
curl -O https://raw.githubusercontent.com/touwaeriol/sub2apipay/main/.env.example
cp .env.example .env
# Fill in required environment variables
nano .env
# Start (includes bundled PostgreSQL)
docker compose -f docker-compose.hub.yml up -d
Build from Source
git clone https://github.com/touwaeriol/sub2apipay.git
cd sub2apipay
cp .env.example .env
nano .env
docker compose up -d --build
Environment Variables
See .env.example for the full template.
Core (Required)
| Variable | Description |
|---|---|
SUB2API_BASE_URL |
Sub2API service URL, e.g. https://sub2api.com |
SUB2API_ADMIN_API_KEY |
Sub2API admin API key |
ADMIN_TOKEN |
Admin panel access token (use a strong random string) |
NEXT_PUBLIC_APP_URL |
Public URL of this service, e.g. https://pay.example.com |
DATABASE_URLis automatically injected by Docker Compose when using the bundled database.
Payment Providers & Methods
Step 1: Declare which payment providers to load via PAYMENT_PROVIDERS (comma-separated):
# EasyPay only
PAYMENT_PROVIDERS=easypay
# Stripe only
PAYMENT_PROVIDERS=stripe
# Both
PAYMENT_PROVIDERS=easypay,stripe
Step 2: Control which channels are shown to users via ENABLED_PAYMENT_TYPES:
# EasyPay supports: alipay, wxpay | Stripe supports: stripe
ENABLED_PAYMENT_TYPES=alipay,wxpay
EasyPay (Alipay / WeChat Pay)
Any payment provider compatible with the EasyPay protocol can be used, such as ZPay (https://z-pay.cn/?uid=23808) (this link contains the author's referral code — feel free to remove it).
Disclaimer: Please evaluate the security, reliability, and compliance of any third-party payment provider on your own. This project does not endorse or guarantee any specific provider.
| Variable | Description |
|---|---|
EASY_PAY_PID |
EasyPay merchant ID |
EASY_PAY_PKEY |
EasyPay merchant secret key |
EASY_PAY_API_BASE |
EasyPay API base URL |
EASY_PAY_NOTIFY_URL |
Async callback URL: ${NEXT_PUBLIC_APP_URL}/api/easy-pay/notify |
EASY_PAY_RETURN_URL |
Redirect URL after payment: ${NEXT_PUBLIC_APP_URL}/pay/result |
EASY_PAY_CID_ALIPAY |
Alipay channel ID (optional) |
EASY_PAY_CID_WXPAY |
WeChat Pay channel ID (optional) |
Stripe
| Variable | Description |
|---|---|
STRIPE_SECRET_KEY |
Stripe secret key (sk_live_...) |
STRIPE_PUBLISHABLE_KEY |
Stripe publishable key (pk_live_...) |
STRIPE_WEBHOOK_SECRET |
Stripe webhook signing secret (whsec_...) |
Stripe webhook endpoint:
${NEXT_PUBLIC_APP_URL}/api/stripe/webhookSubscribe to:payment_intent.succeeded,payment_intent.payment_failed
Business Rules
| Variable | Description | Default |
|---|---|---|
MIN_RECHARGE_AMOUNT |
Minimum amount per transaction (CNY) | 1 |
MAX_RECHARGE_AMOUNT |
Maximum amount per transaction (CNY) | 1000 |
MAX_DAILY_RECHARGE_AMOUNT |
Daily cumulative max per user (0 = unlimited) |
10000 |
ORDER_TIMEOUT_MINUTES |
Order expiry in minutes | 5 |
PRODUCT_NAME |
Product name shown on payment page | Sub2API Balance Recharge |
UI Customization (Optional)
Display a support contact image and description on the right side of the payment page.
| Variable | Description |
|---|---|
PAY_HELP_IMAGE_URL |
Help image URL — external URL or local path (see below) |
PAY_HELP_TEXT |
Help text; use \n for line breaks, e.g. Scan to add WeChat\nMon–Fri 9am–6pm |
Two ways to provide the image:
-
External URL (recommended — no Compose changes needed): any publicly accessible image link (CDN, OSS, image hosting).
PAY_HELP_IMAGE_URL=https://cdn.example.com/help-qr.jpg -
Local file: place the image in
./uploads/and reference it as/uploads/<filename>. The directory must be mounted indocker-compose.app.yml(included by default):volumes: - ./uploads:/app/public/uploads:roPAY_HELP_IMAGE_URL=/uploads/help-qr.jpg
Clicking the help image opens it full-screen in the center of the screen.
Docker Compose Variables
| Variable | Description | Default |
|---|---|---|
APP_PORT |
Host port mapping | 3001 |
DB_PASSWORD |
PostgreSQL password (bundled DB) | password (change in production) |
Deployment
Option 1: Docker Hub Image + Bundled Database
Use docker-compose.hub.yml — the simplest deployment:
docker compose -f docker-compose.hub.yml up -d
Image: touwaeriol/sub2apipay:latest
Option 2: Docker Hub Image + External Database
For existing PostgreSQL instances (shared with other services):
- Set
DATABASE_URLin.env - Use
docker-compose.app.yml(app only, no DB):
docker compose -f docker-compose.app.yml up -d
Option 3: Build from Source
For custom builds after modifications:
# On the build server
docker compose build
docker tag sub2apipay-app:latest touwaeriol/sub2apipay:latest
docker push touwaeriol/sub2apipay:latest
# On the deploy server
docker compose -f docker-compose.hub.yml pull
docker compose -f docker-compose.hub.yml up -d
Reverse Proxy
The default host port is 3001 (configurable via APP_PORT). Use Nginx or Caddy as a reverse proxy with HTTPS:
server {
listen 443 ssl;
server_name pay.example.com;
location / {
proxy_pass http://127.0.0.1:3001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Database Migrations
Migrations run automatically on container startup via prisma migrate deploy. To run manually:
docker compose exec app npx prisma migrate deploy
Sub2API Integration
The following page URLs can be configured in the Sub2API admin panel:
| Page | URL | Description |
|---|---|---|
| Payment | https://pay.example.com/pay |
User recharge entry |
| My Orders | https://pay.example.com/pay/orders |
User views their own recharge history |
| Order Management | https://pay.example.com/admin |
Sub2API admin only |
Sub2API v0.1.88 and above will automatically append the following parameters — no manual query string needed:
| Parameter | Description |
|---|---|
user_id |
Sub2API user ID |
token |
User login token (required to view order history) |
theme |
light (default) or dark |
ui_mode |
standalone (default) or embedded (for iframe) |
Admin Panel
Access: https://pay.example.com/admin?token=YOUR_ADMIN_TOKEN
| Feature | Description |
|---|---|
| Order List | Filter by status, paginate, choose 20/50/100 per page |
| Order Detail | View all fields and audit log timeline |
| Retry Recharge | Re-trigger recharge for paid-but-failed orders |
| Cancel Order | Force-cancel pending orders |
| Refund | Issue refund and deduct Sub2API balance |
Payment Flow
User submits recharge amount
│
▼
Create Order (PENDING)
├─ Validate user status / pending order count / daily limit
└─ Call payment provider to get payment link
│
▼
User completes payment
├─ EasyPay → QR code / H5 redirect
└─ Stripe → Payment Element (PaymentIntent)
│
▼
Payment callback (signature verified) → Order PAID
│
▼
Auto-call Sub2API recharge API
├─ Success → COMPLETED, balance credited automatically
└─ Failure → FAILED (admin can retry)
Development
Requirements
- Node.js 22+
- pnpm
- PostgreSQL 16+
Local Setup
pnpm install
cp .env.example .env
# Edit .env with DATABASE_URL and other required values
pnpm prisma migrate dev
pnpm dev
Commands
pnpm dev # Dev server with hot reload
pnpm build # Production build
pnpm test # Run tests
pnpm typecheck # TypeScript type check
pnpm lint # ESLint
pnpm format # Prettier format
pnpm prisma generate # Generate Prisma client
pnpm prisma migrate dev # Create and apply migration (dev)
pnpm prisma migrate deploy # Apply migrations (production)
pnpm prisma studio # Visual database browser
License
MIT
