Overview
The terms “Continuous Monthly Subscription”, “Periodic Deduction”, and “Auto-Renewal” refer to the same core functionality:
- Periodic Deduction - Official Alipay terminology
- Continuous Monthly Subscription - Common implementation pattern (also supports daily/quarterly)
- Auto-Renewal - User-facing behavior of automatic payment
Deduction Scenarios
Two implementation models:
-
Sign-then-Deduct
- Redirect to agreement signing page
- User signs agreement
- Alipay async callback + immediate deduction
-
Pay-then-Sign
- Redirect to payment page (user can disable auto-renewal)
- User completes payment
- Receive two async notifications: payment & agreement
Recommendation: Prefer Sign-then-Deduct to prevent users from disabling renewal during payment.
Platform Requirements
- Alipay: Requires enabling “Periodic Deduction” via Alipay Open Platform
- WeChat Pay: More complex application process requiring additional Template ID
Agreement Signing Flow
Signature Generation (Go Implementation)
We use modified gopay library (PR #295 merged 2023-01-01):
Key implementation notes:
- Generate
contract_code
as merchant agreement ID - Create signature parameters for mobile app deep linking:
// Example signature parameters
bm := gopay.BodyMap{}
bm.Set("personal_product_code", "GENERAL_WITHHOLDING")
bm.Set("sign_scene", "INDUSTRY|OTHER")
bm.Set("external_agreement_no", contractCode)
// ... other required fields
- Construct deep link URL:
alipays://platformapi/startapp?appId=60000157&sign_params={URL-Encoded_Params}
Database Design
Core subscription table structure (simplified):
CREATE TABLE subscriptions (
id INT PRIMARY KEY,
order_no VARCHAR(64) UNIQUE, -- Merchant order ID
trade_no VARCHAR(64), -- Payment platform ID
user_id INT, -- User reference
contract_code VARCHAR(64) UNIQUE, -- Custom agreement ID
contract_id VARCHAR(64), -- Platform agreement ID
expire_time DATETIME -- Next deduction date
);
Order Processing Flow
- Create order with generated
contract_code
- Generate signing parameters and return deep link to client
- Handle async notification to store
contract_id
- Initial payment via
alipay.trade.pay
(synchronous API) - Client polling for payment status
- Scheduled task for recurring deductions:
// Cron job example (executed daily)
func CheckSubscriptions() {
// Query subscriptions expiring in 5 days
subscriptions := GetExpiringSubscriptions()
for _, sub := range subscriptions {
// Initiate payment via Alipay API
resp, err := alipay.TradePay(sub)
// Handle payment result
}
}
Platform-Specific Notes
Platform | Deduction Lead Time | Example Timeline |
---|---|---|
2 days | Sign 15th → Deduct 13th → Result 15th | |
Alipay | 5 days | Sign 15th → Deduct 10th → Result 15th |
Key Implementation Points
- Use separate async handlers for payment & agreement notifications
- Implement idempotency checks for all payment operations
- Maintain detailed audit logs for deduction attempts
- Provide clear cancellation UI/API endpoints
Complete implementation example available at: github.com/yourrepo/subscription-service