拓冰建站拓冰建站
首页 / 资讯中心 / 正文

InsForge Stripe 支付实现指南:开发者自有账户模型、目录镜像与运行时支付流程全解析

InsForge Stripe 支付实现指南开发者自有账户模型、目录镜像与运行时支付流程全解析【免费下载链接】InsForgeThe all-in-one, open-source backend platform for agentic coding. InsForge gives your coding agent database, auth, storage, compute, hosting, and AI gateway to ship full-stack apps end-to-end.项目地址: https://gitcode.com/GitHub_Trending/in/InsForgeInsForge 是一站式开源后端平台为 Agent 编程提供数据库、鉴权、存储、计算与 AI 网关能力。本文以仓库内.internal/docs/plans/2026-04-30-stripe-payments-implementation.md的实现规范为骨架结合backend源码、payments数据库迁移与共享 Schema系统讲解 InsForge 如何基于「开发者自有 Stripe 账户」模型落地完整的 Stripe 支付基础能力从密钥管理、目录同步、Checkout / Billing Portal 运行时流程到 Webhook 驱动的支付投影。读完本文你将掌握这些 API 的调用方式、数据表语义、幂等与安全边界以及如何在此基础上为 Agent 生成的应用接入收款与订阅能力。产品方向Stripe 是事实来源InsForge 是本地镜像当前阶段 InsForge 采用开发者自有 Stripe 账户模型developer-owned Stripe account model开发者通过 Dashboard 配置自己的STRIPE_TEST_SECRET_KEY和/或STRIPE_LIVE_SECRET_KEY也可以把它们作为环境变量种子导入到 InsForge 的密钥库secret store中。本版本不实现Stripe Connected Accounts、Express/Custom 账户接入、可认领沙箱claimable sandboxes或 test-to-live 发布。该模型确立了三条核心原则Stripe 是事实来源source of truth。所有变更先打到 StripeStripe 成功后才更新 InsForge 的本地镜像。InsForge 维护本地镜像与运行时投影。这样 Agent 和 Dashboard 可以推理支付状态而不必为每个动作反复回查 Stripe。系统是 Agent 优先agent-first。Dashboard 只提供可视性与控制入口真正面向 Agent、CLI、SDK 和生成应用的是后端 API 与共享 Schemapackages/shared-schemas/src/payments-api.schema.ts。测试与生产是两个相互独立的目标环境。所有支付表都通过environment test | live字段区分而不是复制一套 test/live 表。密钥管理密钥库为准环境变量只是种子密钥的规范运行时来源是 InsForge 的 secret store环境变量只是 seed 输入。规范定义了四个密钥名称见 backend/src/services/payments/stripe/constants.ts用途密钥名测试环境 Secret KeySTRIPE_TEST_SECRET_KEY生产环境 Secret KeySTRIPE_LIVE_SECRET_KEY测试环境 Webhook 签名密钥STRIPE_TEST_WEBHOOK_SECRET生产环境 Webhook 签名密钥STRIPE_LIVE_WEBHOOK_SECRET其中 Webhook 签名密钥由 InsForge 托管生成并写入 secret store不是、也不需要作为环境变量配置。保存密钥时StripeConfigService.setStripeSecretKey 会按以下步骤处理校验前缀validateStripeSecretKey强制测试密钥以sk_test_开头、生产密钥以sk_live_开头stripe.provider.ts。获取 Stripe 账户 id用新密钥调用retrieveAccount拿到账户标识。与既有 connection 行对比分三种情况密钥完全相同且 connection 已有账户 id →no-op直接返回密钥不同但指向同一 Stripe 账户→ 更新密钥与 connection 元数据跳过 Webhook 重建和同步密钥指向不同账户→ 清空该环境的全部镜像支付数据、尽力重建托管 Webhook、持久化新密钥与账户元数据然后运行统一同步。整个过程在环境级 advisory lockpayments_environment_${environment}内执行避免并发配置互相覆盖payments-advisory-lock.ts。Webhook 创建失败不阻塞密钥配置。如果后端 URL 不可公网访问导致 Webhook 创建失败密钥保存与同步照常进行开发者之后可从 Dashboard 的 Webhooks 标签页重试或在本地用 Stripe CLI 做 Webhook 测试。密钥的删除DELETE /api/payments/:environment/config会先 best-effort 删除托管 Webhook endpoint再软删除 secret store 中的密钥并把 connection 重置为unconfigured见 config.service.ts。数据模型payments Schema 的九类核心表payments Schema 由 backend/src/infra/database/migrations/039_create-payments-schema.sql 创建后续由 040_create-payments-customers-table.sql 与 049_add-multi-provider-payments-foundation.sql 演进后者引入了 provider 维度为 Stripe / Razorpay 多支付商提供通用基础。各表的职责如下stripe_connections演进后为provider_connectionsproviderstripe每个环境一行记录 Stripe 账户身份stripe_account_id、邮箱、livemode、密钥/配置状态、托管 Webhook endpoint 元数据、最近同步时间/状态/错误与同步计数。products/pricesStripe 目录的本地镜像。同步会用 Stripe 数据覆盖本地漂移并删除该环境中 Stripe 已不存在的本地行。checkout_sessions短生命周期 Checkout 尝试记录。状态从initialized→Stripe 建会后open→ 通过 Webhook 或后端错误更新为completed/expired/failed。默认不启用 RLS以减少开发摩擦开发者可在需要更严格的 Checkout 尝试策略时让 Agent 后续补充。customer_portal_sessionsBilling Portal 创建尝试记录。默认启用 RLS因为 Portal 创建必须由应用的 subject 归属模型把关。stripe_customer_mappings演进后为customer_mappings把任意应用计费主体映射到 Stripe Customer。subject 是刻意保持通用的subject_typesubject_id可以表示用户、团队、组织、租户、群组、工作区或任何应用自定义的计费所有者。customersStripe Customer 行的镜像用于管理可见性与排障从应用视角是只读的不替代stripe_customer_mappings作为运行时 subject→customer 桥。subscriptions/subscription_items订阅当前状态的镜像。同步与 Webhook 在 Stripe 分页需要时会拉取完整订阅项列表然后删除 Stripe 中已不存在的本地订阅项。payment_history演进后由transactions承担记录一次性支付、订阅账单、失败支付、退款及原始支付的退款状态。由 Webhook 驱动设计上容忍 Stripe 事件乱序。webhook_eventsStripe Webhook 处理状态记录按(environment, stripe_event_id)去重可重试失败/待处理事件忽略已处理事件。后端 API 面运行时路由与管理路由支付路由分为两层见 backend/src/api/routes/payments/stripe/index.routes.ts运行时路由verifyUser生成应用可用 InsForge 用户令牌调用匿名一次性结账可用 anon 令牌POST /api/payments/:environment/checkout-sessions先创建本地 Checkout 尝试再创建 Stripe Checkout Session订阅模式必须带subject。POST /api/payments/:environment/customer-portal-sessions在调用者上下文下创建本地 Portal 尝试检查stripe_customer_mappings再创建 Stripe Billing Portal Session拒绝匿名用户。POST /api/webhooks/stripe/:environment接收 Stripe Webhook要求原始请求体并校验 Stripe 签名stripe.routes.ts。管理路由verifyAdmin面向 Dashboard、Agent、CLI 与 SDK 管理面GET /api/payments/status环境连接、同步与 Webhook 状态。GET /api/payments/configStripe 密钥可用性与脱敏密钥信息maskStripeKey对长度超过 8 的密钥只暴露首尾stripe.provider.ts。PUT /api/payments/:environment/config保存 Stripe Secret Key 到密钥库新账户触发托管 Webhook 配置与统一同步。DELETE /api/payments/:environment/config停用密钥并 best-effort 删除托管 Webhook endpoint。POST /api/payments/sync与POST /api/payments/:environment/sync分别对全部已配置环境 / 单环境同步产品、价格、客户与订阅。GET /api/payments/:environment/customers列出镜像 Stripe 客户。POST /api/payments/:environment/webhook重建该环境的托管 Webhook endpoint。GET /api/payments/:environment/catalog读取镜像产品与价格。GET|POST|PATCH|DELETE /api/payments/:environment/catalog/products...与.../catalog/prices...管理 Stripe 产品与价格价格删除即归档 Stripe 价格见 catalog.routes.ts。GET /api/payments/:environment/subscriptions读取镜像订阅Dashboard/管理用。GET /api/payments/:environment/payment-history与/transactions读取支付历史Dashboard/管理用。Checkout 流程先落本地再打 StripeCheckout 创建是「本地 Stripe」两步流程核心实现在 checkout.service.ts第一步本地插入。insertInitializedCheckoutSession使用调用者的 Postgres 角色与 JWT 上下文插入checkout_sessions行withUserContext状态为initialized。这保证未来开发者定义 RLS 策略时无需改动路由。表上有(environment, idempotency_key)的唯一部分索引与request_hash对请求做稳定序列化后 SHA-256ON CONFLICT DO NOTHING保证并发重试不会插入重复行。第二步创建 Stripe Session。本地插入成功后调用 Stripe Checkout APIStripe 创建成功 → 本地行更新为open写入stripe_checkout_session_id、url等。Stripe 创建失败 → 本地行标记为failed并记录last_error。幂等是双层设计的本地层用唯一索引 请求哈希去重Stripe 层用buildStripeIdempotencyKey把idempotencyKey ?? checkoutRecord.id组合成幂等键传给 Stripe SDK。若调用者重试同一请求且已存在行的 Stripe URL 可用直接返回该行若已存在行不完整则用同一本地行重试 Stripe 创建。整个流程还叠加了payments_environment_${environment}共享锁与payments_checkout_${environment}_${idempotencyKey}幂等锁。保留元数据前缀insforge_调用者提供的 metadata 不能使用以insforge_开头的键payments-api.schema.ts因为 Webhook 依赖这些保留键insforge_checkout_mode、insforge_checkout_session_id恢复 Checkout 模式、Session id 与计费 subjectconstants.ts。客户映射的自动建立已识别身份带subject的一次性结账若没有既有客户映射InsForge 会让 Stripe Checkout 以customer_creation always创建客户Checkout 完成返回customer_id后再创建或更新stripe_customer_mappings。匿名一次性结账则直接允许无需映射。一次结账不会单独建立 line item 投影——Checkout 尝试行本身记录行项目而持久履约状态由 Webhook 驱动的支付历史与应用自身业务表表达。请求体字段来自共享 SchemacreateCheckoutSessionBodySchemapayments-api.schema.ts的字段如下字段类型/约束说明modepayment \| subscription结账模式订阅模式必填subjectlineItems数组1–100 项每项{ priceId, quantity }quantity 为 1–999 的正整数默认 1successUrl/cancelUrl合法 URL结账成功 / 取消回跳地址subject{ type, id }可选计费主体订阅必填customerEmail邮箱可选匿名结账时提供给 Stripe 的邮箱metadata字符串映射可选不得使用insforge_前缀键idempotencyKey字符串可选幂等键Stripe 幂等与本地去重共用一个典型的一次性结账请求示例POST /api/payments/test/checkout-sessions Authorization: Bearer insforge-user-token { mode: payment, lineItems: [{ priceId: price_1ABC123, quantity: 1 }], successUrl: https://app.example.com/success, cancelUrl: https://app.example.com/cancel, customerEmail: buyerexample.com, idempotencyKey: order-2026-0001 }订阅结账只需增加subject{ mode: subscription, lineItems: [{ priceId: price_1PRO, quantity: 1 }], subject: { type: team, id: team_123 }, successUrl: https://app.example.com/billing/success, cancelUrl: https://app.example.com/billing/cancel }Customer Portal 流程认证用户专属RLS 决定授权Billing Portal Session仅限认证用户匿名用户不能创建。请求体包含subject必填与可选的returnUrl、configurationpayments-api.schema.ts。流程customer-portal.service.ts以调用者角色与 JWT 上下文插入customer_portal_sessions状态initialized。开发者或 Agent 可在此表上添加应用专属 RLS 策略决定谁可以为哪个 subject 创建 Portal Session。本地插入成功后在stripe_customer_mappings中查找 subject无映射 → 返回404有映射 → 创建 Stripe Billing Portal Session把返回的 portal URL 写入本地行状态created。这种「先落库、再查映射、最后打 Stripe」的顺序确保了授权判定发生在任何 Stripe 调用之前。Webhook 投影流程签名校验 去重 乱序容忍托管 Webhook 监听的事件集定义在 constants.ts涵盖结账、订阅、支付历史与退款投影所需checkout.session.completed / async_payment_succeeded / async_payment_failed / expired invoice.paid / invoice.payment_failed payment_intent.succeeded / payment_intent.payment_failed charge.refunded refund.created / updated / failed customer.subscription.created / updated / deleted / paused / resumed customer.created / updated / deleted处理入口在 webhook.service.ts从 secret store 取该环境的STRIPE_*_WEBHOOK_SECRET缺失则返回 500用provider.constructWebhookEvent(rawBody, signature, webhookSecret)校验 Stripe 签名路由层要求请求体必须是原始 Buffer 且带stripe-signature头否则 401/400按(environment, stripe_event_id)记录事件开始已处理/已忽略事件直接返回 already handled处理成功标记processed业务上不关心的事件标记ignored异常标记failed并记录last_error失败/待处理事件可重试重试会递增attempt_count。退款乱序处理payment_history容忍乱序退款事件。当本地缺少退款上下文时InsForge 会从 Stripe 取回 PaymentIntent、Charge 与 Invoice Payments 上下文尽力水合原始支付/账单行并用COALESCE保留先前已知字段而非用 null 覆盖。既有 Stripe 账户的订阅投影同步进来的订阅若没有 InsForge 计费 subject 映射仍以可空的 subject 字段导入并计为 unmapped保证已有 Stripe 账户可以平滑接入。Dashboard 面Products、Subscriptions 与 SettingsPayments 功能在 Dashboard 中有 Products 与 Subscriptions 两个二级菜单packages/dashboard/srcProductstest/live 标签页密钥缺失时显示环境专属空状态产品行沿用 Realtime Messages 的视觉风格产品详情行展示关联价格。Subscriptionstest/live 标签页与订阅详情行展示订阅项未映射 subject 的既有 Stripe 订阅也能正常显示。Payments Settings 对话框有三个标签页Stripe Keys配置或移除 test/live Secret KeySync对已配置环境运行统一同步Webhooks查看托管 Webhook 状态并重试自动 Webhook 配置。服务边界单一编排器 聚焦子服务PaymentService演进后的多支付商实现见 transaction.service.ts 与 payment-customer.service.ts是主编排器把跨服务协调收敛在一处具体工作委托给聚焦的小服务PaymentConfigService密钥存储、账户状态、托管 Webhook 配置、账户变更时清空镜像、目录快照写入config.service.ts。PaymentProductService/PaymentPriceService产品与价格的 list/get/create/update/delete(archive) 及本地镜像写入product.service.ts、price.service.ts。PaymentCheckoutService/PaymentCustomerPortalService本地 Checkout/Portal 会话插入、重试查找与状态更新checkout.service.ts。PaymentHistoryService/PaymentSubscriptionService从结账、账单、支付意图、Charge 与退款事件投影支付历史从同步与 Webhook 投影订阅及订阅项transaction.service.ts、subscription.service.ts。PaymentWebhookServiceWebhook 事件去重与处理状态记录。StripeProvider唯一包裹官方 Stripe SDK 的层负责所有 Stripe API 调用、分页、Webhook 签名构造与可选幂等请求选项stripe.provider.ts。Helpershelpers.ts是纯工具函数不查 Postgres、不调 Stripe。本阶段明确的非目标不实现 Stripe Connected Accounts、Express/Custom 账户接入、可认领沙箱与平台托管商户账户不实现 test-to-live 发布或目录 diff 应用——Agent 需在产品/价格 API 中显式指定test或live不暴露面向终端用户的运行时安全读 API管理读存在终端用户读因权限语义依赖各应用 subject 模型而延后不镜像 invoice、charge、payment method 与 Checkout line item客户投影除外不为支付历史、订阅、客户映射、Portal Session 定义默认应用 RLS 策略——Agent 应根据开发者的应用 Schema 生成策略。CLI / SDK / 文档 / OpenAPI 面CLI 与 SDK 应优先暴露运行时路由对创建 Checkout Session、创建 Customer Portal Session——这是生成应用收款与让客户管理订阅所需的最小 API 集。管理 SDK/CLI 随后再暴露密钥配置、状态、统一同步、Webhook 配置、目录读取、产品/价格 CRUD、订阅读取与支付历史读取。当前/api/payments与/api/webhooks/stripe/:environment面已由 openapi/payments.yaml 文档化包含环境定位以及运行时路由与管理路由的区分。面向 Agent 的文档应聚焦以下工作流配置 Stripe test/live 密钥同步 Stripe 状态创建产品与一次性/周期价格构建带 success/cancel URL 的结账流构建带计费 subject 的订阅结账通过payments.customer_portal_sessions上的应用 RLS 接入客户 Portal用 Webhook 与支付投影更新应用专属 entitlement 表。公开文档则应说明开发者自有账户模型、本地开发 Webhook 限制、Stripe CLI 测试方式以及「Stripe 始终是事实来源」这一事实。验证清单改动支付实现时的自检项规范附带的验证清单可视为回归基准后端单元测试覆盖 config、sync、catalog CRUD、checkout、portal session、webhook、refund、subscription 与迁移幂等可参考 backend/tests/unit 下的stripe-*.test.ts、payments-*.test.ts系列后端 lint、typecheck、build 通过共享 Schema lint、typecheck、build 通过Dashboard 支付 UI 变更时其 lint/typecheck/build 通过payments 迁移保持幂等039/040 之后所有 create/index/trigger/grant/alter 可安全重跑Stripe Webhook 密钥不作为必需的环境变量文档化产品与价格变更先调 StripeStripe 成功后才更新本地镜像同步以 Stripe 为事实来源且仅在 Stripe 账户 id 变更时清空镜像见 sync.service.ts 的账户变更检测。这套「Stripe 为事实来源 本地镜像 Agent 优先 API Webhook 投影」的组合让 InsForge 的支付能力既可被 Agent 程序化调用又能在 Dashboard 中可视化排障是生成式应用接入真实收款基础设施的可靠底座。【免费下载链接】InsForgeThe all-in-one, open-source backend platform for agentic coding. InsForge gives your coding agent database, auth, storage, compute, hosting, and AI gateway to ship full-stack apps end-to-end.项目地址: https://gitcode.com/GitHub_Trending/in/InsForge创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门