支付集成

项目中关于Creem支付相关配置

发给 ChatGPT / Claude 等 AI,可更快消化本页并上手上站。

Created: 09/05/2026
Updated: 10/19/2026

朋友,可能你看到这篇文章的时候和我写的时候相隔很久,文章中所说可能已经不是对应官网的最新信息,需要你将文章发给AI让其确认是否还可行后再去做,感谢理解

接入 Creem 支付与订阅指南

本指南介绍如何在基于 TanStack 模板的 SaaS 应用中接入与配置 Creem 支付,支持一次性点数购买与周期性自动续费订阅。

写在前面

image

申请提示:若 Creem 处于「邀请制 + 排队」模式,可在注册时说明自身 SaaS 业务背景,或直接向 Creem 团队发送邮件申请:
Creem申请说明

We are building a SaaS product targeting global users.
Currently looking for a reliable payment solution to replace Stripe.

Expected monthly volume: $3k-$10k initially
Tech stack: TanStack Start / Next.js + Supabase / PostgreSQL

We are ready to integrate immediately once approved.

出海收单方案:对于尚未办理个人香港银行卡或海外实体的独立开发者,采用 Creem + Wise + 国内借记卡 是目前低门槛实现收付款资金闭环的可靠组合;若已有境外卡,则可直接绑定提现。
未办理港卡看过来,试试 Creem + Wise 组合


1. 开通 Creem 商户与环境准备

登录 Creem 控制台 创建商户账户(无需信用卡即可开启沙盒测试)。

Creem 原生支持 沙盒测试模式(Sandbox) 与 生产环境(Production):

  • 沙盒模式(Sandbox):API 交互地址为 https://test-api.creem.io,API 密钥通常以 creem_test_ 开头。
  • 生产模式(Production):API 交互地址为 https://api.creem.io,API 密钥以 creem_live_ 开头。

Creem商户注册示意1
Creem商户注册示意2
Creem控制台概览


2. 获取 API 密钥与配置管理后台

在系统架构中,所有支付凭据均通过 管理后台(/admin/settings -> Payment 支付设置) 统一持久化管理,环境变量仅作为系统底层兜底。

2.1 获取 API Key

  1. 进入 Creem 控制台 > Developers > API & Webhooks。
  2. 点击新建 API Key,复制生成的密钥(测试环境以 creem_test_ 开头,生产环境以 creem_live_ 开头)。

新建API Key

2.2 填写管理后台配置

image

进入系统管理后台 http://localhost:3000/admin/settings(生产环境对应 https://你的域名/admin/settings),切换至 Payment(支付) 标签页,找到 Creem 配置卡片:

配置项 键名 说明
Enable Creem creem_enabled 开关,设为启用(开启后前台支付弹窗才可选该渠道)
Environment creem_environment 选择 Sandbox(本地开发测试)或 Production(正式上线)
API Key creem_api_key 填入 Creem 控制台获取的 creem_test_... 或 creem_live_...
Signing Secret creem_signing_secret Webhook 验签密钥,格式为 whsec_...(见下文 Webhook 章节)
Product IDs Mapping creem_product_ids_mapping 本地商品 ID 与 Creem 产品 ID 映射(JSON 对象,必需)
Test amount (cents) creem_test_amount 可选。填入测试扣费金额(如填 1 则扣款 $0.01,留空按实际价格)
Default Provider default_payment_provider 设置系统默认首选的支付渠道(如设为 creem)

3. 在 Creem 控制台创建产品

Creem 支持 一次性商品(One-time) 与 周期性订阅(Subscription)。请在 Creem 控制台 > Commerce > Products 创建与业务对应的产品:

创建产品

3.1 一次性充值积分包(示例)

  • Starter Pack:
    • 名称:Starter Pack
    • 计费模式:One-time
    • 价格:$9.90(USD),对应本地商品 starter_lifetime
    • 保存并记录产品 ID(以 prod_ 开头,如 prod_starter_xxx)
  • Pro Pack:
    • 名称:Pro Pack
    • 计费模式:One-time
    • 价格:$29.90(USD),对应本地商品 pro_lifetime
    • 保存并记录产品 ID(如 prod_pro_yyy)
  • Ultra Pack:
    • 名称:Ultra Pack
    • 计费模式:One-time
    • 价格:$69.90(USD),对应本地商品 enterprise_lifetime
    • 保存并记录产品 ID(如 prod_ultra_zzz)

3.2 周期订阅计划(示例)

  • Lite Monthly:
    • 名称:Lite Monthly
    • 计费模式:Recurring(周期:every-month)
    • 价格:$9.90(USD/月),对应本地商品 starter_monthly
    • 保存并记录产品 ID(如 prod_sub_lite_monthly_xxx)
  • Pro Monthly:
    • 名称:Pro Monthly
    • 计费模式:Recurring(周期:every-month)
    • 价格:$19.90(USD/月),对应本地商品 pro_monthly
    • 保存并记录产品 ID(如 prod_sub_pro_monthly_yyy)
  • Ultra Monthly:
    • 名称:Ultra Monthly
    • 计费模式:Recurring(周期:every-month)
    • 价格:$39.90(USD/月),对应本地商品 enterprise_monthly
    • 保存并记录产品 ID(如 prod_sub_ultra_monthly_zzz)

4. 定价目录与产品 ID 映射(核心代码配置)

4.1 定价目录:服务端唯一可信源 (src/config/pricing.ts)

客户端提交的金额、积分和计划信息服务端一律忽略。所有结账均以 src/config/pricing.ts 中的 pricingCatalog 为准:

const pricingCatalogRaw: Record<string, PricingProduct> = {
  // 周期订阅型(例如 Lite 按月订阅)
  starter_monthly: {
    productId: 'starter_monthly',
    productName: 'Lite',
    planName: 'Lite',
    description: 'Lite Monthly',
    type: PaymentType.SUBSCRIPTION,
    priceInCents: 990,
    currency: 'usd',
    credits: 2000,
    creditsValidDays: 30,
    monthlyDisplayPrice: '$9.9',
    originalPrice: '$14.9',
    copyKey: 'lite',
    buttonKey: 'subscribe',
    creditsKey: 'month',
    plan: { name: 'Lite', interval: PaymentInterval.MONTH, intervalCount: 1 },
  },
  // 热门周期订阅(例如 Pro 按月订阅)
  pro_monthly: {
    productId: 'pro_monthly',
    productName: 'Pro',
    planName: 'Pro',
    description: 'Pro Monthly',
    featured: true,
    badgeKey: 'popular',
    type: PaymentType.SUBSCRIPTION,
    priceInCents: 1990,
    currency: 'usd',
    credits: 4800,
    creditsValidDays: 30,
    monthlyDisplayPrice: '$19.9',
    originalPrice: '$29.9',
    copyKey: 'pro',
    buttonKey: 'subscribe',
    creditsKey: 'month',
    plan: { name: 'Pro', interval: PaymentInterval.MONTH, intervalCount: 1 },
  },
  // 一次性积分包(例如 Starter Pack)
  starter_lifetime: {
    productId: 'starter_lifetime',
    productName: 'Starter Pack',
    planName: 'Starter Pack',
    description: 'Starter credit pack',
    type: PaymentType.ONE_TIME,
    priceInCents: 990,
    currency: 'usd',
    credits: 1500,
    creditsValidDays: 365,
    monthlyDisplayPrice: '$9.9',
    copyKey: 'starter_pack',
    buttonKey: 'buy_once',
    creditsKey: 'pack',
  },
};

4.2 配置产品映射 (creem_product_ids_mapping)

在系统发起 Creem Checkout 会话时,服务端 src/modules/payment/service.ts 会自动读取管理后台配置的映射字典,将本地的 productId 转化为 Creem 真实的 prod_xxx:

在后台 Product IDs Mapping(creem_product_ids_mapping)字段中填入 JSON 映射字典:

{
  "starter_monthly": "prod_sub_lite_monthly_xxx",
  "pro_monthly": "prod_sub_pro_monthly_xxx",
  "enterprise_monthly": "prod_sub_ultra_monthly_xxx",
  "starter_yearly": "prod_sub_lite_yearly_xxx",
  "pro_yearly": "prod_sub_pro_yearly_xxx",
  "enterprise_yearly": "prod_sub_ultra_yearly_xxx",
  "starter_lifetime": "prod_starter_pack_xxx",
  "pro_lifetime": "prod_pro_pack_xxx",
  "enterprise_lifetime": "prod_ultra_pack_xxx"
}

5. 配置 Webhook 回调(防止掉单与自动续费)

为什么必须配置 Webhook:

  1. 防止掉单(兜底保障):用户在收银台付款成功后若直接关闭网页或网络异常,前端同步跳回不会触发。服务端通过 Webhook 异步解耦处理,确保订单顺利履约入账。
  2. 处理订阅自动续费:订阅用户按月/年静默扣款成功时,Creem 会通过 Webhook 通知系统延长订阅有效期并下发新周期额度。
  3. 订阅状态与计划变更同步:当用户在管理中心取消续订、恢复续订或扣款逾期时,由 Webhook 实时同步本地状态。
  4. 退款自动冲减:当在 Creem 控制台发起退款时,系统自动识别原交易并按比例安全扣减尚未消耗的权益额度。
  5. 安全防伪验签:请求头附带 creem-signature,服务端基于 Web Crypto API 使用 creem_signing_secret 计算 HMAC-SHA256 签名,并配合时序安全比较(timingSafeEqual)杜绝伪造回调。

5.1 系统支持的核心 Webhook 事件清单

系统在 src/core/payment/creem.ts 与 src/modules/payment/service.ts 中针对以下核心事件进行了严格的状态机处理与业务履约:

Creem 事件类型 内部事件映射 业务履约逻辑
checkout.completed CHECKOUT_SUCCESS 初次结账成功:一次性点数包即时发放入账;订阅首期扣款成功并激活用户订阅。
subscription.paid PAYMENT_SUCCESS 订阅自动续费成功:延长用户订阅有效期,发放新周期配额额度,记录对账流水。
subscription.update SUBSCRIBE_UPDATED 订阅变更:方案升降级或订阅属性更新,同步最新周期与方案。
subscription.active SUBSCRIBE_UPDATED 订阅激活/恢复:订阅恢复正常状态时同步本地订阅状态为生效。
subscription.paused SUBSCRIBE_UPDATED 订阅暂停:同步订阅暂停状态。
subscription.scheduled_cancel SUBSCRIBE_UPDATED 预定到期取消:用户设置了到期不再续费,系统标记 cancel_at_period_end,当前权益保留至期末。
subscription.past_due SUBSCRIBE_UPDATED 扣款逾期:续费扣款失败进入宽限期,系统记录逾期告警。
subscription.canceled SUBSCRIBE_CANCELED 订阅终止/取消:订阅期满或立即取消后正式停权,将本地订阅置为已取消。
refund.created PAYMENT_REFUNDED 退款创建:自动匹配关联订单,按退款比例安全冲减用户积分并记录退款账本流水。

💡 提示:未在上述映射中的事件(如 subscription.expired、subscription.trialing、dispute.created)会被系统安全忽略(抛出 WebhookIgnoredError),接口自动返回 HTTP 200 确认送达。

5.2 设置 Webhook 步骤

  1. 登录 Creem 控制台 > Developers > API & Webhooks,点击新建 Webhook。
  2. Webhook URL 严格填写系统的标准接收地址:
    https://你的域名/api/payment/notify/creem
    
    (本地测试时使用内网穿透域名,例如 https://xxxx.ngrok-free.app/api/payment/notify/creem 或 https://xxxx.hostc.dev/api/payment/notify/creem)
  3. 勾选监听事件:
    在事件列表中勾选上述核心事件:
    • checkout.completed
    • subscription.paid
    • subscription.update
    • subscription.active
    • subscription.paused
    • subscription.scheduled_cancel
    • subscription.past_due
    • subscription.canceled
    • refund.created
  4. 保存 Webhook,复制生成的签名密钥(格式为 whsec_...)。
  5. 回到系统管理后台 /admin/settings -> Payment -> Creem,将密钥填入 Signing Secret (creem_signing_secret) 并保存。
    (如使用环境变量兜底,对应 .env 中的 CREEM_SIGNING_SECRET=whsec_xxx)

6. 完整支付执行流程

系统与 Creem 的支付链路遵循严密的状态机设计:

[用户客户端]
   │
   ├─ 1. POST /api/payment/checkout ──► [系统服务端]
   │     { product_id: 'starter_monthly',        │
   │       payment_provider: 'creem' }           ├─ 校验服务端定价目录
   │                                             ├─ 转换 Creem product_id (从后台映射表读取)
   │                                             ├─ 请求 Creem /v1/checkouts 创建 Session
   │                                             └─ 本地落库订单 (Status: PENDING)
   │◄── 2. 返回 { checkout_url } ────────────────┘
   │
   ├─ 3. 跳转至 Creem 托管支付收银台完成付款
   │
   ├─ 4. (前台同步回跳) ──► GET /api/payment/callback?order_no=...&redirect=...
   │
[Creem 平台]
   │
   └─ 5. (后台可靠异步通知) ──► POST /api/payment/notify/creem
                                      │
                                      ├─ 严格校验 creem-signature (HMAC-SHA256 + timingSafeEqual)
                                      ├─ 将订单更新为 PAID
                                      ├─ 发放积分 (增记流水账本)
                                      ├─ 创建/更新用户订阅记录
                                      └─ 返回 200 OK 确认送达

7. 客户自助门户(Customer Portal)

系统已集成 Creem 官方的 Customer Billing Portal:

  • 用户在个人中心账单页(/settings/billing)点击管理订阅时,服务端会调用 Creem 接口 /v1/customers/billing 获取 customer_portal_link;
  • 用户可在 Creem 官方门户中自助查看付款记录、下载收据发票、更新付款卡片或取消订阅;
  • 所有在门户中产生的状态变更均会通过 Webhook 实时同步回系统。

8. 本地开发与联调测试

在本地开发阶段,Creem 无法直接请求你的 localhost:3000,需使用内网穿透工具将本地通知端点暴露到公网。

推荐方案一:hostc

# 启动本地端口转发(假设项目端口为 3000)
npx hostc 3000

获得临时公网地址(如 https://your-domain.hostc.dev)。

推荐方案二:ngrok

# 启动 ngrok 隧道
ngrok http 3000

获得临时公网地址(如 https://xxxx.ngrok-free.app)。

联调验证闭环

  1. 在 Creem 沙盒控制台中添加测试 Webhook:https://你的穿透域名/api/payment/notify/creem。
  2. 将对应的 Webhook 签名密钥保存至管理后台。
  3. 访问 http://localhost:3000/pricing 选购商品并完成沙盒结账,检查服务端日志:
    Payment event [creem]: checkout.success
    
  4. 验证个人中心 /settings/credits(或 /settings/billing)权益已实时到账。

9. 常见问题与排错自检

  • Q1:前台点击支付提示 "Payment provider 'creem' is not configured"?
    • 排查:进入后台 /admin/settings,确认 creem_enabled 开关已开启,且 creem_api_key 已正确填写。
  • Q2:点击结账提示 "Product ID not mapped"?
    • 排查:确认在后台 creem_product_ids_mapping 中完整配置了当前所选本地 productId 与 Creem 控制台 prod_xxx 的映射关系,且 JSON 格式有效。
  • Q3:付款成功后权益没有到账?
    • 排查:
      1. 检查 Webhook 地址是否精确配置为 https://你的域名/api/payment/notify/creem。
      2. 检查管理后台的 creem_signing_secret 是否与 Creem 控制台生成的 whsec_... 完全一致。
      3. 在 Creem 控制台 Webhooks 列表中查看推送记录与 HTTP 响应状态码(正常应为 200 OK)。
  • Q4:沙盒测试与生产环境区分?
    • 排查:沙盒测试需在后台将环境选择为 Sandbox,并使用以 creem_test_ 开头的 API Key 与沙盒环境生成的 Webhook Secret;上线前需切换为 Production 与生产密钥。