Waffo Pancake
如何设置和使用 Waffo Pancake 处理支付和订阅
TanStarter 使用 Waffo Pancake 进行支付管理,支持一次性支付和订阅支付。Waffo Pancake 是一家 Merchant of Record(MoR,记录商) 平台,它以法定卖家身份处理全球税务计算、代收、合规和结算。
该集成使用官方 @waffo/pancake-ts SDK,并采用 Waffo 托管的结账页面和消费者门户,因此卡信息不会经过您的服务器。
设置
TanStarter 模板默认提供三种价格计划:免费计划、专业版订阅计划(月度/年度)和终身计划(一次性支付),按照以下步骤设置:
创建 Waffo 账户
在 Waffo Pancake 注册 Waffo Pancake 账户,并在引导过程中创建一个商店。更多基础信息请参考 Waffo 快速入门。
获取 API 密钥
从 Waffo 控制台获取您的 Merchant ID 和私钥:
- 进入到 Waffo 控制台 >
API & Development,点击Create API Key生成新的密钥对 - 复制 Merchant ID(以
MER_开头)和私钥 - 将其保存到环境变量文件中作为
WAFFO_MERCHANT_ID和WAFFO_PRIVATE_KEY
WAFFO_MERCHANT_ID 指的是 Merchant ID——不是 storeId,也不是 URL 中的商店标识。API 密钥在创建时就绑定到测试或生产环境,因此请为每个环境创建独立的密钥。
私钥只能存放在服务端。将 PEM 私钥写入环境变量时,需要用转义的 \n 保留换行:
WAFFO_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nMIIEv...\n-----END PRIVATE KEY-----"更多关于 API 密钥认证 的信息请参考 Waffo 官方文档。
设置 Webhook
设置 Webhook 并订阅支付事件:
- 进入到 Waffo 控制台 >
Settings>Webhooks,点击Add Webhook - 选择 Raw 负载格式(只有 Raw 格式会携带用于验签的
X-Waffo-Signature请求头) - 输入 Webhook URL:
https://YOUR-DOMAIN.com/api/webhooks/waffo - 所有事件默认都会订阅,请至少保留以下事件:
order.completedsubscription.activatedsubscription.payment_succeededsubscription.updatedsubscription.cancelingsubscription.uncanceledsubscription.canceledsubscription.past_duerefund.succeededrefund.failed
与 Stripe 和 Creem 不同,Waffo 没有 Webhook 签名密钥这样的环境变量。@waffo/pancake-ts SDK 内置了验证公钥并自动识别环境,verifyWebhook() 会为您完成签名验证。
更多关于 Webhook 和 Webhook 签名验证 的信息请参考 Waffo 官方文档。
创建产品和价格计划
在 Waffo 中创建产品并设置价格计划。Waffo 使用 Product ID(以 PROD_ 开头)进行结账,而不是价格 ID:
- 进入到 Waffo 控制台 >
Products,点击Create Product - 创建专业版订阅计划的产品:
- 产品类型:
Subscription - 名称:
专业版计划 - 计费周期:
Monthly——保存并复制产品 ID,用于VITE_WAFFO_PRODUCT_PRO_MONTHLY - 再创建一个计费周期为
Yearly的订阅产品——保存并复制产品 ID,用于VITE_WAFFO_PRODUCT_PRO_YEARLY
- 产品类型:
- 创建终身计划的产品:
- 产品类型:
One-time - 名称:
终身计划 - 保存并复制产品 ID,用于
VITE_WAFFO_PRODUCT_LIFETIME
- 产品类型:
建议为每个计费周期(月度/年度)分别创建订阅产品,详见 Waffo 订阅指南。新创建的产品处于测试模式;在接收真实支付前需要先发布到生产环境,参见 发布产品。
添加环境变量
添加以下环境变量:
# 支付提供商
VITE_PAYMENT_PROVIDER=waffo
# Waffo API 凭据(仅服务端使用)
WAFFO_MERCHANT_ID=MER_...
WAFFO_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nMIIEv...\n-----END PRIVATE KEY-----"
# 可选:在生产构建中接受测试模式 Webhook(仅用于冒烟测试)
# WAFFO_DEBUG=true
# Product IDs
VITE_WAFFO_PRODUCT_PRO_MONTHLY=PROD_...
VITE_WAFFO_PRODUCT_PRO_YEARLY=PROD_...
VITE_WAFFO_PRODUCT_LIFETIME=PROD_...更新网站配置
更新 src/config/website.ts 中的 payment 部分,配置价格计划 — 金额、货币、周期和计划元数据。enable、provider 和 priceId 字段会根据环境变量(VITE_PAYMENT_PROVIDER 和 VITE_WAFFO_PRODUCT_*)自动解析,无需硬编码。
您必须配置此部分,使其与您在 Waffo 中创建的产品一致:
payment: {
enable: isPaymentEnabled, // ← 自动:当 VITE_PAYMENT_PROVIDER 设置时为 true
provider: isPaymentEnabled ? paymentProvider : undefined, // ← 自动:'waffo'
price: {
plans: {
free: {
id: 'free',
prices: [],
isFree: true,
isLifetime: false,
},
pro: {
id: 'pro',
prices: [
{
type: 'subscription',
priceId: priceIds.proMonthly, // ← 自动:来自 VITE_WAFFO_PRODUCT_PRO_MONTHLY
amount: 990, // 金额,单位为分($9.90)
currency: 'USD',
interval: 'month',
},
{
type: 'subscription',
priceId: priceIds.proYearly, // ← 自动:来自 VITE_WAFFO_PRODUCT_PRO_YEARLY
amount: 9900, // 金额,单位为分($99.00)
currency: 'USD',
interval: 'year',
},
],
isFree: false,
isLifetime: false,
popular: true,
},
lifetime: {
id: 'lifetime',
prices: [
{
type: 'one_time',
priceId: priceIds.lifetime, // ← 自动:来自 VITE_WAFFO_PRODUCT_LIFETIME
amount: 19900, // 金额,单位为分($199.00)
currency: 'USD',
allowPromotionCode: true,
},
],
isFree: false,
isLifetime: true,
},
},
},
},如果您正在设置环境,现在可以回到环境配置文档并继续。本文档的其余部分可以稍后阅读。
环境配置
设置环境变量
核心功能
- 一次性支付成为终身会员功能
- 定期订阅支付(月度/年度)
- 支持免费试用期
- 托管结账页面,支持买家归属(认证结账)
- 支付、订阅和退款事件的 Webhook 处理
- 税务、合规和结算由 Waffo 处理
- 消费者门户,支持 Magic Link 登录
- 内置价格组件(表格、卡片、按钮)
- 安全支付操作的服务器端操作
- 多种价格计划支持(免费、专业版、终身制)
开发环境
本地开发时,需要使用 HTTPS 隧道将本地服务器暴露到公网,以便 Waffo 能够发送 Webhook 事件。官方文档推荐使用 ngrok,cloudflared 也可以。不要使用 localtunnel——它会剥离 X-Waffo-Signature 等自定义请求头:
ngrok http 3000
# 或
cloudflared tunnel --url http://localhost:3000然后:
- 在 Waffo 控制台 >
Settings>Webhooks中,将隧道 URL(例如https://xxxx.ngrok-free.app/api/webhooks/waffo)设置为测试环境 Webhook URL。永远不要将临时隧道 URL 配置到生产 Webhook。 - 在网站上进行一次测试支付,验证事件处理流程是否符合预期。
模板还附带 Waffo 沙盒 E2E 测试套件:
pnpm e2e:waffoWaffo 提供完整的测试环境,使用测试卡即可模拟支付,不会产生真实交易。在托管的沙盒结账页面中,您可以选择 Credit/Debit Card,并使用 Quick Fill 的 Success 选项立即完成一笔测试支付。更多信息请参考 Waffo 官方文档中的 测试模式。
生产环境
- 完成商店审核 / KYB,以启用生产支付——参见 账户审核
- 将订阅和一次性产品从测试环境发布到生产环境。发布是单向、仅首次的操作——参见 发布产品
- 创建生产环境的 API 密钥,用于
WAFFO_MERCHANT_ID/WAFFO_PRIVATE_KEY - 在 Waffo 控制台 >
Settings>Webhooks中添加生产 Webhook URL:https://YOUR-DOMAIN.com/api/webhooks/waffo - 保持
WAFFO_DEBUG不设置(或设为false),这样生产环境会拒绝测试模式事件——沙盒购买绝不能授予真实访问权限
客户门户
Waffo 提供托管的消费者门户:https://pancake.waffo.ai/consumer/portal/login。客户使用购买时填写的邮箱并通过一次性 Magic Link 登录,无需密码。在门户中他们可以:
- 查看有效订阅、下次扣款日期和支付历史
- 取消或重新激活订阅
- 下载 PDF 发票和收据
- 更新账单信息
- 申请退款
Billing 页面(/settings/billing)通过"Manage subscription"按钮将客户引导至该门户。更多信息请参考 Waffo 官方文档中的 消费者门户。
Webhook 事件
Waffo 支持以下 Webhook 事件:
| 事件 | 描述 |
|---|---|
order.completed | 一次性订单支付成功 |
subscription.activated | 订阅首次支付成功 |
subscription.payment_succeeded | 续费支付成功(非首次) |
subscription.updated | 订阅产品变更(升级/降级) |
subscription.canceling | 已申请取消——在当前周期结束前仍然有效 |
subscription.uncanceled | 取消申请被撤回 |
subscription.canceled | 订阅终止(周期结束) |
subscription.past_due | 续费支付失败,Waffo 正在重试 |
refund.succeeded | 退款完成——访问权限被撤销 |
refund.failed | 退款失败 |
Waffo 将测试和生产事件投递到同一个端点,每个负载都带有 mode 字段。模板会拒绝与当前运行环境不匹配的事件;在生产构建中,仅当使用沙盒商户对已部署的 Worker 做冒烟测试时,才将 WAFFO_DEBUG 设置为 true。
测试卡
要测试 Waffo 集成,请使用 Waffo 测试模式和以下测试卡:
| 卡号 | 类型 | 结果 |
|---|---|---|
4576 7500 0000 0110 | Visa Credit | 成功 |
2226 9000 0000 0110 | Mastercard Credit | 成功 |
4576 7500 0000 0220 | Visa Credit | 拒绝 |
使用任意未来有效期和任意 3 位 CVC 即可。您可以在 Waffo 官方文档中找到更多关于测试模式和测试卡的信息。
最佳实践
- 保护 API 密钥:永远不要在客户端代码中暴露
WAFFO_PRIVATE_KEY或 Merchant ID - 验证 Webhook 签名:始终验证
X-Waffo-Signature请求头(SDK 的verifyWebhook()会完成验证) - 匹配环境:使用与当前运行环境对应的 API 密钥和 Webhook URL
- 优雅处理错误:当支付失败时提供用户友好的错误消息
- 彻底测试 Webhooks:上线前先在测试模式下完成一次完整购买
参考资料
最后更新于
