23 KiB
Sub2ApiPay
⚠️ This project has been archived.
Payment functionality has been natively integrated into the Sub2API main project.
This repository is no longer maintained and is kept for historical reference only. For payment features, please use Sub2API's built-in payment module.
Language: 中文 | English (current)
Sub2ApiPay is a self-hosted payment gateway built for the Sub2API platform. It supports four payment channels — EasyPay (aggregated Alipay/WeChat Pay), Alipay (official), WeChat Pay (official), and Stripe — with both pay-as-you-go balance top-up and subscription plans. Once a payment is confirmed, the system automatically calls the Sub2API management API to credit the user's balance or activate the subscription — no manual intervention required.
Table of Contents
- Features
- Tech Stack
- Quick Start
- Environment Variables
- Deployment
- Sub2API Integration
- Payment Flow
- API Endpoints
- Development
Features
- Four Payment Channels — EasyPay aggregation, Alipay (official), WeChat Pay (official), Stripe
- Online Configuration — Payment providers, credentials, limits, and business rules can all be configured in the admin panel in real-time, no restart needed
- Multi-Instance Load Balancing — Create multiple instances per provider with round-robin or least-amount strategies, per-channel single/daily limits
- Dual Billing Modes — Pay-as-you-go balance top-up + subscription plans
- Auto Balance Credit — Automatically calls Sub2API after payment verification, fully hands-free
- Full Order Lifecycle — Auto-expiry, user cancellation, admin cancellation, refunds
- Limit Controls — Per-transaction cap, daily per-user cap, daily per-channel global cap
- Security — Token auth, RSA2/MD5/Webhook signature verification, timing-safe comparison, full audit log
- Responsive UI — PC + mobile adaptive layout, dark/light theme, iframe embed support
- Bilingual — Automatic Chinese/English interface adaptation
- Admin Panel — Dashboard, order management (pagination/filtering/retry/refund), channel & subscription management
EasyPay Recommendation: We personally recommend ZPay as an EasyPay provider (referral link — feel free to remove). ZPay supports individual users (no business license) with a daily limit of ¥10,000; business license holders have no limit. 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.
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
Payment providers and settings can be configured in two ways — choose either:
Option A: Online Configuration via Admin Panel (Recommended)
In the admin panel's Payment Config page (/admin/payment-config), you can configure everything through the web UI without editing environment variables or restarting the service:
- Override Env Variables — When enabled, database settings override environment variables. Existing env values are auto-imported on first enable
- Provider Management — Add / edit / delete payment instances, configure credentials, enable/disable, channels, load balancing strategy
- Multi-Instance — Create multiple instances per provider with round-robin or least-amount load balancing
- Instance Limits — Each instance supports per-channel single min / single max / daily total limits
- Business Settings — Recharge amount range, daily limits, order timeout, cancel rate limits — all adjustable online
Tip
: Changes take effect immediately, no container restart needed. Access: Sub2API Admin → Payment Config, or directly visit
https://pay.example.com/admin/payment-config?token=YOUR_ADMIN_TOKEN.
Option B: Environment Variable Configuration
Best for initial deployment or teams that prefer file-based configuration. Env values serve as defaults and can be overridden in the admin panel at any time.
Step 1: Declare which payment providers to load via PAYMENT_PROVIDERS (comma-separated):
# Available: easypay, alipay, wxpay, stripe
# Example: EasyPay only
PAYMENT_PROVIDERS=easypay
# Example: Alipay + WeChat Pay + Stripe (official channels)
PAYMENT_PROVIDERS=alipay,wxpay,stripe
Alipay / WeChat Pay (official) and EasyPay can coexist. Official channels connect directly to Alipay/WeChat Pay APIs with funds going straight to your merchant account and lower fees; EasyPay proxies payments through a third-party platform that forwards to official channels, with a lower barrier to entry. When using EasyPay, choose providers where funds are forwarded through official channels directly to your own account, rather than collected by a third party.
EasyPay (Alipay / WeChat Pay Aggregation)
Any payment provider compatible with the EasyPay protocol can be used.
| 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) |
Alipay (Official)
Direct integration with the Alipay Open Platform. Supports PC page payment (alipay.trade.page.pay) and mobile web payment (alipay.trade.wap.pay), automatically switching based on device type.
| Variable | Description |
|---|---|
ALIPAY_APP_ID |
Alipay application AppID |
ALIPAY_PRIVATE_KEY |
Application private key (content or file path) |
ALIPAY_PUBLIC_KEY |
Alipay public key (content or file path) |
ALIPAY_NOTIFY_URL |
Async callback URL |
ALIPAY_RETURN_URL |
Sync redirect URL (optional) |
WeChat Pay (Official)
Direct integration with WeChat Pay APIv3. Supports Native QR code payment and H5 payment, with mobile devices preferring H5 and auto-fallback to QR code.
| Variable | Description |
|---|---|
WXPAY_APP_ID |
WeChat Pay AppID |
WXPAY_MCH_ID |
Merchant ID |
WXPAY_PRIVATE_KEY |
Merchant API private key (content or file path) |
WXPAY_CERT_SERIAL |
Merchant certificate serial number |
WXPAY_API_V3_KEY |
APIv3 key |
WXPAY_PUBLIC_KEY |
WeChat Pay public key (content or file path) |
WXPAY_PUBLIC_KEY_ID |
WeChat Pay public key ID |
WXPAY_NOTIFY_URL |
Async callback URL |
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
These parameters can be set via environment variables as defaults, or configured online in the admin Payment Config page (requires "Override Env Variables" to be enabled):
| 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 |
MAX_DAILY_AMOUNT_ALIPAY |
EasyPay Alipay channel daily global limit (opt.) | Provider default |
MAX_DAILY_AMOUNT_ALIPAY_DIRECT |
Alipay official channel daily global limit (opt.) | Provider default |
MAX_DAILY_AMOUNT_WXPAY |
WeChat Pay channel daily global limit (opt.) | Provider default |
MAX_DAILY_AMOUNT_STRIPE |
Stripe channel daily global limit (opt.) | Provider default |
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
Assuming this service is deployed at https://pay.example.com.
User-Facing Pages
Configure the following URLs in the Sub2API admin panel under Recharge Settings, so users can navigate from Sub2API to the payment and order pages:
| Setting | URL | Description |
|---|---|---|
| Payment | https://pay.example.com/pay |
User top-up & subscription purchase page |
| My Orders | https://pay.example.com/pay/orders |
User views their own recharge/subscription history |
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 |
lang |
Interface language, zh (default) or en |
ui_mode |
standalone (default) or embedded (for iframe) |
Admin Panel
The admin panel is authenticated via the token URL parameter (set to the ADMIN_TOKEN environment variable). When integrating with Sub2API, just configure the paths — no query parameters needed — Sub2API will automatically append token and other parameters:
| Page | URL | Description |
|---|---|---|
| Overview | https://pay.example.com/admin |
Aggregated entry with card-style navigation |
| Orders | https://pay.example.com/admin/orders |
Filter by status, paginate, view details, retry/cancel/refund |
| Dashboard | https://pay.example.com/admin/dashboard |
Revenue stats, order trends, payment method breakdown |
| Payment Config | https://pay.example.com/admin/payment-config |
Provider management, instance config, limits, online settings |
| Channels | https://pay.example.com/admin/channels |
Configure API channels & rates, sync from Sub2API |
| Subscriptions | https://pay.example.com/admin/subscriptions |
Manage subscription plans & user subscriptions |
Tip
: When accessing directly (not via Sub2API), you need to manually append
?token=YOUR_ADMIN_TOKENto the URL. All admin pages share the same token — once you enter any page, you can navigate between modules via the sidebar.
Payment Flow
User selects top-up / subscription plan
│
▼
Create Order (PENDING)
├─ Validate user status / pending orders / daily limit / channel limit
└─ Call payment provider to get payment link
│
▼
User completes payment
├─ EasyPay → QR code / H5 redirect
├─ Alipay (official) → PC page payment / H5 mobile web payment
├─ WeChat Pay (official) → Native QR code / H5 payment
└─ Stripe → Payment Element (PaymentIntent)
│
▼
Payment callback (RSA2 / MD5 / Webhook signature verified) → Order PAID
│
▼
Auto-call Sub2API recharge / subscription API
├─ Success → COMPLETED, balance credited / subscription activated
└─ Failure → FAILED (admin can retry)
API Endpoints
All API paths are prefixed with /api.
Public API
User-facing endpoints, authenticated via user_id + token URL parameters.
| Method | Path | Description |
|---|---|---|
GET |
/api/user |
Get current user info |
GET |
/api/users/:id |
Get specific user info |
POST |
/api/orders |
Create recharge / subscription order |
GET |
/api/orders/:id |
Query order details |
POST |
/api/orders/:id/cancel |
User cancels pending order |
GET |
/api/orders/my |
List current user's orders |
GET |
/api/channels |
Get channel list (for frontend display) |
GET |
/api/subscription-plans |
Get available subscription plans |
GET |
/api/subscriptions/my |
Query current user's subscriptions |
GET |
/api/limits |
Query recharge limits & payment method availability |
Payment Callbacks
Called asynchronously by payment providers; signature verified before triggering credit flow.
| Method | Path | Description |
|---|---|---|
GET |
/api/easy-pay/notify |
EasyPay async callback |
POST |
/api/alipay/notify |
Alipay (official) callback |
POST |
/api/wxpay/notify |
WeChat Pay (official) callback |
POST |
/api/stripe/webhook |
Stripe webhook callback |
Admin API
Authenticated via token parameter set to ADMIN_TOKEN.
| Method | Path | Description |
|---|---|---|
GET |
/api/admin/orders |
Order list (paginated, filterable) |
GET |
/api/admin/orders/:id |
Order details (with audit log) |
POST |
/api/admin/orders/:id/cancel |
Admin cancels order |
POST |
/api/admin/orders/:id/retry |
Retry failed recharge / subscription |
POST |
/api/admin/refund |
Issue refund |
GET |
/api/admin/dashboard |
Dashboard (revenue stats, trends) |
GET |
/api/admin/channels |
Channel list |
POST |
/api/admin/channels |
Create channel |
PUT |
/api/admin/channels/:id |
Update channel |
DELETE |
/api/admin/channels/:id |
Delete channel |
GET |
/api/admin/subscription-plans |
Subscription plan list |
POST |
/api/admin/subscription-plans |
Create subscription plan |
PUT |
/api/admin/subscription-plans/:id |
Update subscription plan |
DELETE |
/api/admin/subscription-plans/:id |
Delete subscription plan |
GET |
/api/admin/subscriptions |
User subscription records |
GET |
/api/admin/config |
Get system configuration |
PUT |
/api/admin/config |
Update system configuration |
GET |
/api/admin/sub2api/groups |
Sync channel groups from Sub2API |
GET |
/api/admin/sub2api/search-users |
Search Sub2API users |
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
