ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Cal.diy Stripe 支付集成完全指南:从 Connect OAuth 授权到预约收款与订阅管理

Cal.diy Stripe 支付集成完全指南:从 Connect OAuth 授权到预约收款与订阅管理 Cal.diy Stripe 支付集成完全指南从 Connect OAuth 授权到预约收款与订阅管理【免费下载链接】cal.diyScheduling infrastructure for absolutely everyone.项目地址: https://gitcode.com/GitHub_Trending/ca/cal.diyStripe 是 Cal.diy 内置的支付应用stripe_payment承担预约收费、付费用户名Premium、团队与组织订阅等核心商业化能力。本文以仓库中的 Stripe 支付模块说明 与 集成 README 为主线结合packages/app-store/stripepayment/下的真实源码完整讲解支付基础设施定位、环境变量配置、Connect OAuth 授权链路、事件类型级收费参数、Webhook 回调解读与客户门户实现帮助你在自托管环境中从零跑通 Stripe 收款全流程。Stripe 是什么支付基础设施定位模块描述文档 DESCRIPTION.md 给出了 Stripe 在 Cal.diy 中的定位Stripe 为从初创公司到 Fortune 500 企业的各类规模公司提供支付基础设施既提供支付处理软件payment processing software也提供面向移动应用与电商网站的应用程序接口APIs。其收款能力覆盖但不限于以下支付方式信用卡 / 借记卡credit cards, debit cards数字钱包digital walletsGoogle Pay、Apple Pay银行转账Bank TransfersAlipay支付宝、WeChat微信支付这解释了为什么 Cal.diy 选择 Stripe 作为默认支付提供方一套 API 即可覆盖主流卡组织与本地化钱包让预约系统具备全球化收款能力。需要注意的是DESCRIPTION.md 中“覆盖 Alipay / WeChat”等能力取决于 Stripe 平台在你所在区域的开放情况最终可用支付方式以 Stripe 官方账户配置为准。仓库中的 Stripe 模块结构Stripe 支付应用在仓库中位于packages/app-store/stripepayment/主要组成如下路径职责_metadata.ts应用元数据slug、category、installed 状态判定zod.ts应用密钥 Schema 与事件类型级支付数据 Schemaapi/Next.js API 端点add、callback、portal、subscription、paymentCallbacklib/支付服务、客户、订阅、Billing Portal 等业务逻辑components/事件类型设置界面EventTypeAppCard / SettingsInterfacepages/setup/Connect OAuth 授权引导页的服务端渲染逻辑static/模块图标与说明图片模块的_metadata.ts定义了核心身份type: stripe_payment、category: payment、isOAuth: true、extendsFeature: EventType即这是一个扩展了事件类型EventType能力的 OAuth 支付应用。installed状态由三个环境变量同时存在决定我们下面逐一配置。环境准备与 .env 配置按照 README.md 的 “Setting up Stripe” 章节完整配置分为 8 步创建 Stripe 账户注册新账户或使用已有账户测试阶段建议开启仪表盘右上角的 Test-Mode 开关所有操作均在测试模式下进行。获取 API 密钥在 Stripe Dashboard 的 API Keys 页面保存密钥。以pk_...开头的公钥写入NEXT_PUBLIC_STRIPE_PUBLIC_KEY以sk_...开头的私钥写入STRIPE_PRIVATE_KEY。开启 Connect OAuth在 Stripe Connect 设置中激活 Standard Accounts 的 OAuth。配置 OAuth 回调地址将CALENDSO URL/api/integrations/stripepayment/callback添加为重定向 URL。保存 Client ID复制ca_...开头的 client id 写入STRIPE_CLIENT_ID。配置 Webhook在 Stripe Webhooks 页面为已连接的应用程序添加CALENDSO URL/api/integrations/stripepayment/webhook作为 Webhook 地址。订阅 Webhook 事件为该 Webhook 勾选全部payment_intent事件。保存 Webhook 密钥将whsec_...开头的密钥写入STRIPE_WEBHOOK_SECRET。上述密钥的格式约束在 zod.ts 中被编码为运行时校验规则export const appKeysSchema z.object({ client_id: z.string().startsWith(ca_).min(1), client_secret: z.string().startsWith(sk_).min(1), public_key: z.string().startsWith(pk_).min(1), webhook_secret: z.string().startsWith(whsec_).min(1), });也就是说如果环境变量值不符合ca_/sk_/pk_/whsec_前缀约定密钥解析会在应用初始化时直接失败。密钥的读取通过 lib/getStripeAppKeys.ts 调用通用的getParsedAppKeysFromSlug(stripe, appKeysSchema)完成。其他相关环境变量除上述必填项外lib/constants.ts 还读取一组可选订阅价格变量NEXT_PUBLIC_STRIPE_PREMIUM_PLAN_PRICE_MONTHLYPremium 月度套餐价格NEXT_PUBLIC_STRIPE_PREMIUM_PLAN_PRODUCT_IDPremium 套餐产品 IDNEXT_PUBLIC_STRIPE_TEAM_MONTHLY_PRICE_ID团队月度套餐价格 IDSTRIPE_PHONE_NUMBER_MONTHLY_PRICE_ID电话号码月度订阅价格 ID这些变量缺失时对应常量为空字符串相关订阅功能会不可用需按你的定价策略在 Stripe 中先创建产品/价格再回填。Stripe SDK 实例化lib/server.ts 使用STRIPE_PRIVATE_KEY创建全局 Stripe 客户端并固定apiVersion: 2020-08-27同一文件还定义了 Connect OAuth 令牌解析 SchemastripeOAuthTokenSchema包含access_token、stripe_user_id、stripe_publishable_key、default_currency等字段用于校验 OAuth 回调返回的凭据结构。仓库的 package.json 显示模块依赖stripe9.16.0、stripe/stripe-js1.35.0、stripe/react-stripe-js1.10.0均为当前仓库锁定版本。Stripe Connect OAuth 授权链路Cal.diy 的 Stripe 集成基于Stripe ConnectStandard AccountOAuth每个用户用自己的 Stripe 账户完成授权平台通过该用户的账户收款。链路由三个文件串联1. 发起授权api/add.ts 读取client_id拼装scope: read_write、response_type: code的授权参数并将回调地址指向WEBAPP_URL/api/integrations/stripepayment/callback最终 302 到https://connect.stripe.com/oauth/authorize。值得注意的是代码中预填了stripe_user.email与first_name来自当前登录用户便于 Stripe 端预填信息E2E 测试环境下还会强制country: US源码注释说明是为了让国际化用户的端到端测试不失败。2. 服务端引导pages/setup/_getServerSideProps.ts 在服务端完成同样的授权 URL 拼装并将state参数编码为IntegrationOAuthCallbackState含returnTo、onErrorReturnTo、fromApp: true用于授权完成后跳回用户原本所在的页面未登录用户会被重定向到登录页密钥缺失时则跳转到/apps/installed/payment?errorstripe_oauth_failed。3. 回调换令牌api/callback.ts 接收授权code调用stripe.oauth.token({ grant_type: authorization_code, code })换取访问令牌随后stripe.accounts.retrieve(stripe_user_id)获取账户默认币种default_currency最后通过createOAuthAppCredential以type: stripe_payment落库成为该用户的 OAuth 凭据。若用户在 Stripe 端拒绝access_denied会依据state.onErrorReturnTo安全跳回使用 getSafeRedirectUrl 防开放重定向默认回到/apps/installed/payment。OAuth 成功后lib/server.ts 中定义的StripeData含default_currency就作为凭据 JSON 存储后续 lib/PaymentService.ts 通过stripeCredentialKeysSchema解析出stripe_user_id、default_currency、stripe_publishable_key用于收款。Stripe Connect 账户管理界面示例授权完成后平台侧可在 Connect Accounts 中查看已连接账户的状态与交易活动。事件类型级支付配置安装完成后Stripe 应用以 AppCard 形式出现在**每个事件类型Event Type**的设置页。入口组件 components/EventTypeAppCardInterface.tsx 负责开关与多支付应用互斥当另一个支付应用已启用时checkForMultiplePaymentApps本应用的开关会被禁用并提示other_payment_app_enabled避免同一事件类型同时挂两个收费方。具体配置表单由 components/EventTypeAppSettingsInterface.tsx 渲染。可配置字段由 zod.ts 的appDataSchema定义export const appDataSchema eventTypeAppCardZod.merge( z.object({ price: z.number(), // 预约价格 currency: z.string(), // 币种 paymentOption: paymentOptionEnum.optional(),// 收费时机 enabled: z.boolean().optional(), // 是否启用 refundPolicy: z.nativeEnum(RefundPolicy).optional(), // 退款策略 refundDaysCount: z.number().optional(), // 退款窗口天数 refundCountCalendarDays: z.boolean().optional(), // 是否按自然日计算 autoChargeNoShowFeeIfCancelled: z.boolean().optional(), // 爽约/取消是否自动扣费 autoChargeNoShowFeeTimeValue: z.number().optional(), // 扣费时间值 autoChargeNoShowFeeTimeUnit: autoChargeNoShowFeeTimeUnitEnum.optional(), // 扣费时间单位 }) );其中paymentOption的可选值定义在 lib/constants.tsexport const paymentOptions [ { label: on_booking_option, value: ON_BOOKING }, // 预约时立即收款 { label: hold_option, value: HOLD }, // 先冻结/保留后续再扣款 ];currency的候选值来自 lib/currencyOptions.ts覆盖 usd、eur、cny、gbp、jpy、inr 等上百种币种与 Stripe 支持的结算币种对齐用户可在设置界面直接选择。refundPolicy枚举由 packages/lib/payment/types.ts 提供如按天窗口内可退款配合refundDaysCount、refundCountCalendarDays实现灵活的退款策略。支付服务与预约扣款流程真正执行扣款的是 lib/PaymentService.ts它实现IAbstractPaymentService抽象接口构造时再次用STRIPE_PRIVATE_KEY实例化 Stripe 客户端并解析凭据中的stripe_user_id等字段。其核心职责包括create在预约时创建 PaymentIntent 收款。方法开头校验paymentOption必须为ON_BOOKINGHOLD走另外的扣款路径并校验凭据存在否则抛出 Stripe credentials not found。pay/prepay等完成实际扣款动作依赖retrieveOrCreateStripeCustomerByEmaillib/customer.ts按邮箱找到或创建 Stripe Customer保证同一用户的支付可追溯。支付记录通过 Prisma 的Payment模型持久化externalId即 Stripe 侧的 PaymentIntent / SetupIntent ID若记录存在但缺少externalId代码会抛出异常以标识无效状态。在预约界面的支付侧static/stripe2.jpg 展示了 Stripe 支付表单信用卡输入区与 Apple Pay 快捷支付的典型形态——这正是stripe/stripe-js与stripe/react-stripe-js在 booking 页面渲染的收银台效果Stripe 支付表单示例预约者可在 Checkout 界面使用信用卡、Apple Pay 等方式完成支付。Webhook 与支付回调从扣款到状态回写支付完成后Stripe 通过 Webhook 与回调把状态同步回 Cal.diyWebhook 端点README 要求把CALENDSO URL/api/integrations/stripepayment/webhook配置为连接应用的 Webhook并订阅全部payment_intent事件用于异步获知支付成功、失败等状态变化。需要说明的是api/index.ts 中保留了一行注释// TODO: Figure out how to handle webhook endpoints from App Store即当前该 Webhook 处理器尚未在 App Store 框架内正式落位payment_intent状态的权威同步在现有实现中主要通过下面的回调端点完成。paymentCallback 端点api/paymentCallback.ts 处理付费用户Premium username支付成功/失败的回调。流程要点解析callbackUrl与checkoutSessionId查询参数callbackUrl若非完整 URL 会自动补上WEBAPP_URL。调用 lib/getCustomerAndCheckoutSession.ts 通过stripe.checkout.sessions.retrieve取回 Checkout Session再取出并校验 Stripe Customer支持 customer 为 ID 字符串或对象两种形态已删除的客户返回 null。依次按邮箱、metadata.stripeCustomerId查找本系统用户找不到则 404。若checkoutSession.payment_status ! paid携带email、username、paymentStatus参数重定向回 callbackUrl 展示失败状态。支付成功后把stripeCustomer.metadata.username写回用户username并在metadata中置isPremium: true此处冲突会返回 400 提示联系支持。通过 VerificationTokenService 创建有效期 1 天86400 * 1000ms的验证令牌拼接/api/auth/callback/email邮箱魔法链接调用sendVerificationRequest给用户发送登录邮件实现支付即登录激活 Premium。配套测试 api/tests/paymentCallback.test.ts 覆盖了上述成功/失败/找不到用户等分支。客户门户与订阅管理对需要长期订阅的场景Premium、团队、组织模块提供了 Billing Portal自助账单门户能力API 端点 api/portal.ts 对外暴露门户入口服务层采用工厂 按主体拆分的模式位于 lib/services/UserBillingPortalService.ts个人用户TeamBillingPortalService.ts团队OrganizationBillingPortalService.ts组织三者共用 base/BillingPortalService.ts 基类由 factory/BillingPortalServiceFactory.ts 按上下文创建门户相关测试见 api/tests/portal.test.ts。订阅数据查询由 lib/subscriptions.ts 提供retrieveSubscriptionIdFromStripeCustomerId通过stripe.customers.retrieve(customerId, { expand: [subscriptions.data.plan] })找到客户首个订阅 ID客户被删除或无订阅时返回 Not foundgetSubscriptionFromId则按订阅 ID 取回订阅详情。此外 lib/team-billing.ts 承载团队维度的计费逻辑与STRIPE_TEAM_MONTHLY_PRICE_ID等常量配合。测试覆盖与验证Stripe 模块的测试集中在三个位置可作为配置与二次开发的回归依据api/tests/paymentCallback.test.ts验证付费回调的完整分支api/tests/portal.test.ts验证 Billing Portal 端点行为pages/setup/tests/_getServerSideProps.test.ts验证授权引导页的服务端跳转逻辑lib/repositories/VerificationTokenRepository.test.ts 与 lib/VerificationTokenService.test.ts验证验证令牌仓储与服务的读写。小结Cal.diy 的 Stripe 集成是一套完整的商业化支付闭环以 Stripe Connect OAuth 完成账户授权以事件类型级appDataSchema定义价格、币种、收费时机与退款策略以PaymentService在预约时创建 PaymentIntent以 Webhook / paymentCallback 回写支付状态并激活 Premium最后以 Billing Portal 与订阅服务支撑长期计费。自托管部署时只需按 README 的 8 步完成 Test-Mode 配置并正确回填STRIPE_CLIENT_ID、STRIPE_PRIVATE_KEY、NEXT_PUBLIC_STRIPE_PUBLIC_KEY、STRIPE_WEBHOOK_SECRET四个关键变量即可在预约流程中启用真实的 Stripe 收款能力。【免费下载链接】cal.diyScheduling infrastructure for absolutely everyone.项目地址: https://gitcode.com/GitHub_Trending/ca/cal.diy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表