PRD: CREEM Web Payment Integration
Background
iOS App 路线已放弃,需改用 CREEM (Merchant of Record) 进行 Web 端支付。现有 Apple IAP 代码保留但不再活跃使用。
Goals
- Web 端用户可通过 CREEM 托管支付页购买积分
- 商品价格从 CREEM API 动态获取,不在本地硬编码
- 支付成功后通过 webhook 自动发放积分
- 保留现有 Apple IAP 架构,不破坏
CREEM Product Mapping
| 内部 product_code |
CREEM Product ID |
积分 |
| new_user_pack |
prod_2x9LzVlR3ot1HLgbIZALPd |
60 |
| starter_pack |
prod_697ay0pXFXrBYEVC7HS0MR |
100 |
| popular_pack |
prod_5ivxlPnZWN6dIhnOxctThy |
210 |
| premium_pack |
prod_2L13k70jlpPYkdHhexHP2s |
415 |
Pricing Notes
- CREEM 最低支持 $1.00,因此新人专享包价格从原 $0.99 调整为 $1.00
- 价格由 CREEM Dashboard 管理,后端通过 API 动态获取,不硬编码在 mapping.yaml 中
- mapping.yaml 只存储: creem_product_id, credits, type, sort_order, enabled
Architecture
Payment Flow
API Endpoints
| Method |
Endpoint |
Auth |
Description |
| POST |
/api/v1/payments/creem/checkouts |
User |
Create checkout session, return checkout_url |
| POST |
/api/v1/payments/creem/webhook |
None |
CREEM callback (verify signature) |
Existing Endpoint Changes
| Method |
Endpoint |
Change |
| GET |
/api/v1/points/packages |
Add priceCents and currency fields from CREEM API |
Implementation Details
Phase 1: Backend Infrastructure
- settings.py - Add
CreemSettings (api_key, webhook_secret, base_url, success_url)
- creem_client.py - HTTP client for CREEM API (get_products, create_checkout)
- models/creem_transaction.py - New DB table for CREEM transactions
- alembic migration - Create
creem_transactions table
- repository.py - Add CREEM transaction CRUD methods
Phase 2: Backend Business Logic
- creem_service.py - Checkout creation + webhook handling
- service.py - Update
ProductMapping to include creem_product_id
- schemas.py - Add
CreateCheckoutRequest/Response, update PackageInfo with price fields
- dependencies.py - Add
get_creem_service DI
- router.py - Add 2 new CREEM endpoints
- points/service.py -
get_available_packages merges CREEM product prices
Phase 3: Frontend
- api.ts - Add
createCheckout() function and types
- StorePage.tsx - Use dynamic price from API, add buy button that redirects to checkout_url
DB Schema: creem_transactions
| Column |
Type |
Description |
| id |
UUID PK |
|
| user_id |
UUID FK |
|
| product_code |
String(32) |
Internal product code |
| creem_product_id |
String(128) |
CREEM product ID |
| checkout_id |
String(128) UNIQUE |
CREEM checkout session ID |
| order_id |
String(128) nullable |
CREEM order ID |
| customer_id |
String(128) nullable |
CREEM customer ID |
| status |
enum(pending, completed, failed, refunded) |
|
| credits |
BigInt |
Points to grant |
| amount_cents |
BigInt |
Payment amount in cents |
| currency |
String(8) |
Currency code |
| creem_payload |
JSONB |
Full CREEM webhook payload |
| ledger_event_id |
String(128) nullable |
Points ledger event ID |
| created_at, updated_at |
Timestamp |
|
Environment Variables
Frontend Behavior
- 支付成功后跳转到
ERYAO_CREEM_SUCCESS_URL
- 前端检测 URL 参数
?payment=success,显示成功提示并刷新积分
- 价格从后端 API 动态获取,不再使用翻译文件中的硬编码价格
- 翻译文件保留:套餐名称、描述、badge 文字(如"限购一次"、"推荐")
Security
- Webhook must verify
creem-signature HMAC-SHA256 header
- API key never exposed to frontend
- Checkout idempotency: prevent duplicate credit grants via checkout_id unique constraint
- Starter pack eligibility check shared with Apple IAP logic
Out of Scope
- CREEM subscription management (one-time purchases only)
- CREEM license keys
- Removing Apple IAP code (preserved for potential future use)
- Customer portal integration