Creem 配置
配置 Creem 产品、Edge secrets 与 Webhook。
Creem 运行在桌面应用之外。Electron 模板只在 renderer 中携带公开 product IDs,并用 server-side Edge Functions 保存 Creem API key、验证 webhooks、写入 Supabase entitlement rows。
创建 products
在 Creem 中创建你要销售的 products:
| 模板 plan | Creem product type | App env |
|---|---|---|
| Pro monthly | Subscription | VITE_CREEM_PRODUCT_PRO_MONTHLY=prod_... |
| Pro yearly | Subscription | VITE_CREEM_PRODUCT_PRO_YEARLY=prod_... |
| Lifetime | One-time | VITE_CREEM_PRODUCT_LIFETIME=prod_... |
把这些 IDs 放进 soar-electron/.env。它们是 renderer-public,安全可打包。不要把
CREEM_API_KEY 放进 app .env。
Creem API 选择由 Edge secret CREEM_SERVER_IDX 控制:
| 值 | API base |
|---|---|
0 | Production API (https://api.creem.io) |
1 | Test API (https://test-api.creem.io) |
验证 checkout 和 webhook handling 时使用 test mode。
设置 Edge secrets
在 Supabase 项目中设置 secrets:
supabase secrets set \
CREEM_API_KEY=creem_test_xxx \
CREEM_WEBHOOK_SECRET=whsec_xxx \
CREEM_SERVER_IDX=1 \
--project-ref <ref>或者复制 supabase/functions/.env.example 到 gitignored 的
supabase/functions/.env,填入值后上传:
supabase secrets set --env-file supabase/functions/.env --project-ref <ref>| Secret | 使用方 | 说明 |
|---|---|---|
CREEM_API_KEY | create-checkout、customer-portal、activate-license | Server-side Creem API key。 |
CREEM_WEBHOOK_SECRET | creem-webhook | 必须与 Creem 中配置的 signing secret 一致。 |
CREEM_SERVER_IDX | 所有 Creem functions | 0 production,1 test。 |
BILLING_SUCCESS_URL | create-checkout | 可选托管页面,把浏览器 bounce 回桌面 app。 |
Supabase 会向 Edge Functions 注入 SUPABASE_URL、SUPABASE_ANON_KEY 和
SUPABASE_SERVICE_ROLE_KEY。不要在 app 或 Edge secret file 中设置它们。
部署 functions
部署 functions 前先应用 billing migration:
supabase db push --project-ref <ref>然后部署:
pnpm supabase:deploy
pnpm supabase:deploy <project-ref>Helper script 会部署 supabase/functions/ 下除 _shared 外的每个目录。它还会对
creem-webhook 传入 --no-verify-jwt;其他 functions 通过
supabase/config.toml 保持 JWT verification on。
预期 functions:
| Function | JWT | 作用 |
|---|---|---|
create-checkout | 开 | 为已登录用户创建 Creem checkout,并记录 pending payment row。 |
customer-portal | 开 | 使用已登录用户保存的 customer id 创建 Creem portal URL。 |
activate-license | 开 | 可选 license-key 激活与停用。 |
creem-webhook | 关 | Public Creem webhook;验证 creem-signature 后写入 entitlements。 |
用下面命令验证部署:
supabase functions list --project-ref <ref>配置 webhook
在 Creem 中添加 webhook URL:
https://<ref>.supabase.co/functions/v1/creem-webhookWebhook signing secret 必须与你保存为 CREEM_WEBHOOK_SECRET 的值一致。
当前 handler 实现的 event set 是:
| Event | 行为 |
|---|---|
checkout.completed | 按 object.request_id / order_no 找到 payments 行,更新为 status = 'success',保存 Creem order/customer ids,然后返回。 |
subscription.paid | 从 object.metadata.userId、product、customer 和 subscription period data upsert 用户的 subscriptions 行。 |
其他 event types 今天会被忽略。如果你的产品需要 cancellation、refund、pause 或 past-due
状态反映到 app,请扩展 supabase/functions/_shared/creem.ts,并保持客户端 read model 不变。
Webhook trust 与 idempotency:
creem-webhook在 JSON parse 前读取 raw request body。verifyCreemSignature()使用CREEM_WEBHOOK_SECRET重新计算 HMAC-SHA256,并与creem-signatureheader 比较。payments.order_no是 unique,因此重复的checkout.completeddeliveries 会收敛到同一行。subscriptions.user_id是 unique,因此重复的subscription.paiddeliveries 会 upsert 同一个 entitlement row。- Handler errors 返回
500,让 Creem 可以 retry。
Checkout return page
桌面应用不能依赖浏览器 redirect 直接落回 app,所以 BILLING_SUCCESS_URL 可以指向一个很小的
托管 bounce page。模板包含 supabase/pay-success.sample.html。
托管前,把 sample 中过时的 soar:// 链接改成当前 scheme:
soar-electron://billing?status=success&orderId=...运行 pnpm rebrand --scheme 后使用你改名后的 scheme。
然后把托管页面设置为 Edge secret:
supabase secrets set BILLING_SUCCESS_URL=https://your-domain.com/pay-success --project-ref <ref>create-checkout 会在发送给 Creem 前追加 status=success&orderId=<orderNo>。
如果没有设置 BILLING_SUCCESS_URL,Creem 会回退到 product 中配置的 redirect。
本地测试
用本地 Edge env file 启动 functions:
supabase functions serve --env-file supabase/functions/.env本地 functions 地址是:
http://localhost:54321/functions/v1/<name>如果你也需要本地 Postgres/Auth stack,再运行 supabase start。完整 hosted sandbox
checkout 通常使用 remote deploy 更简单,因为 Creem 需要访问 webhook URL。
Sandbox checkout 后检查 rows:
select order_no, user_id, product_id, status, customer_id, updated_at
from public.payments
order by created_at desc
limit 10;
select user_id, product_id, product_type, status, period_end, customer_id, subscription_id
from public.subscriptions
order by updated_at desc
limit 10;生产检查清单
- 桌面构建中设置了
VITE_BILLING_ENABLED=true。 -
VITE_CREEM_PRODUCT_*与你使用的 Creem environment 匹配。 - 已应用 billing migration。
-
CREEM_API_KEY、CREEM_WEBHOOK_SECRET和CREEM_SERVER_IDX已作为 Supabase Edge secrets 设置。 -
pnpm supabase:deploy已部署四个 functions。 - Creem webhook 指向
https://<ref>.supabase.co/functions/v1/creem-webhook。 - 如果托管 bounce page,
BILLING_SUCCESS_URL使用soar-electron://billing或你改名后的 scheme。 - Sandbox checkout 写入了
payments和subscriptions。 - 如果产品需要 cancellations、refunds 或 past-due 状态在 app 中体现,已扩展 webhook handling。
