
Supabase Stripe Sync Engine将 Stripe 客户、订阅、发票与付款数据一键同步到 Postgres 的集成机制详解【免费下载链接】supabaseThe Postgres development platform. Supabase gives you a dedicated Postgres database to build your web, mobile, and AI applications.项目地址: https://gitcode.com/GitHub_Trending/supa/supabase本篇技术文章基于 Supabase DashboardStudio内置的 Stripe Sync Engine 集成概览文档 overview.md 展开。读完后你将理解 Stripe Sync Engine 同步哪些数据、以何种机制Webhook 实时事件 定时回填把数据写入 Postgres并能结合 Studio 源码看清从点击 Install 到数据可用的完整调用链安装表单、后端 API 路由、安装状态机、设置页与卸载流程以及如何在 SQL 中消费同步后的stripeschema。一、Stripe Sync Engine 是什么overview.md 对该集成给出了精炼定义Stripe 是一个 API 驱动的支付处理与订阅管理平台。Stripe Sync Engine 会将你 Stripe 账户中的数据——包括客户customers、订阅subscriptions、发票invoices和付款payments——同步到你 Supabase 账户中的 Postgres 表里。这段话是整篇文档的核心命题也是所有后续内容的骨架它不是一次性的 API 查询工具而是一个持续运行的同步引擎把 Stripe 侧的计费数据物化为本地 Postgres 表。这份文档并非孤立的说明文件而是 Studio 集成市场Integrations的内置概览注册表的一部分。在 overviews.ts 中stripe_sync_engine与stripe_wrapper、airtable_wrapper、snowflake_wrapper等 29 个集成一起以惰性import()函数的形式注册stripe_sync_engine: () import(/static-data/integrations/stripe_sync_engine/overview.md),文件头部注释解释了为什么必须使用字符串字面量导入webpack/Turbopack 与 Vite 的 md-as-string loader 只能静态分析确定的导入路径模板字符串动态导入会在 TanStack 构建下抛出TypeError: Failed to resolve module specifier。配套的 overviews.test.ts 会断言该映射表与磁盘上的overview.md文件保持同步——新增集成目录时必须同步补登记这是一条由测试强制执行的仓库约定。运行时Studio 通过loadIntegrationOverview(integrationId)加载这份 markdown 并在集成详情页渲染即 Dashboard 中 Stripe Sync Engine 集成页的 Overview 正文来源。二、集成定义所需的数据库扩展与安装步骤在 Studio 的集成常量文件 Integrations.constants.tsx 中stripe_sync_engine被声明为一个template类型、Partner来源的集成定义这是理解其运行依赖的关键配置{ id: stripe_sync_engine, type: template, source: Partner, requiredExtensions: [pgmq, supabase_vault, pg_cron, pg_net], missingExtensionsAlert: UpgradeDatabaseAlert minimumVersion15.6.1.143 /, name: Stripe Sync Engine, status: alpha, ... }从这份源码可以读出几条硬约束依赖四个数据库扩展pgmq消息队列用于增量同步任务分发、supabase_vault密钥托管、pg_cron定时任务、pg_net从 Postgres 发起 HTTP 请求。这解释了后文定时回填机制为何能在数据库内部可靠排队与重试。数据库最低版本 15.6.1.143低于该版本的项目会显示升级提醒UpgradeDatabaseAlert。分类与入口它被归入billing分类并且与cron、queues一起被列入集成落地页的FEATURED_INTEGRATIONS见 integrations/index.tsx即在 Dashboard 集成首页获得推荐位。同一定义中还声明了安装的四步摘要steps字段这是官方口径的安装行为清单steps: [ { label: Creates a new database schema named stripe }, { label: Creates tables and views in the stripe schema for synced Stripe data }, { label: Deploys Edge Functions to handle incoming webhooks from Stripe }, { label: Schedules automatic Stripe data syncs using Supabase Queues }, ]即建stripeschema → 在其中建表与视图 → 部署处理 Stripe Webhook 的 Edge Functions → 用 Supabase Queues 调度自动同步。三、同步机制Webhook 实时更新 定时增量回填仓库内的官方博客 2025-12-19-stripe-sync-engine-integration.mdx 对同步原理有明确说明引擎通过两个机制保持数据最新——Webhook 负责实时增量更新scheduled backfills定时回填负责补齐历史数据启用集成后 Supabase 会自动配置好这两者。回填backfill的可靠性来自 Supabase Queues底层是 pgmq安装完成后回填进程自动启动把工作量切分进队列由多个 Edge Function 并发地从 Stripe API 拉取数据遇到失败或限流时自动重试。这也解释了第二节中pgmq、pg_cron、pg_net三个扩展存在的意义——队列、定时调度、库内出站 HTTP 各自对应回填管线的关键环节。博客还指出了同步后数据的关键存储形态Stripe 工程师为开源同步引擎贡献了JSONB 存储 生成列generated columns方案既保留 JSONB 的灵活查询能力又通过生成列维持索引与查询性能同时引入了基于 Stripe 游标分页的增量同步、面向 Stripe Connect 平台的多账户支持以及一个保证事件顺序的CLI。四、安装流程的源码级拆解4.1 前端安装表单与密钥权限要求在集成概览页组件 OverviewTab.tsx 中安装入口是一个 Sheet 抽屉表单使用 zod 做校验const installFormSchema z.object({ stripeSecretKey: z.string().min(1, Stripe API key is required), })表单对 Stripe 密钥的权限要求与集成常量中的inputs定义一致Integrations.constants.tsx输入字段stripe_api_key类型为password必填说明文字要求该密钥对 Webhook Endpoints 具备写权限对其余类别为只读权限——官方建议创建一个受限restricted密钥而非主账号 secret key。提交时表单调用installStripeSync({ projectRef, stripeSecretKey, startTime: Date.now() })。此外组件在渲染安装按钮前会检查FUNCTIONS_SECRET_WRITE权限useAsyncCheckPermissions权限不足的成员看到的按钮会禁用并提示需要额外权限才能升级/安装/卸载 Stripe Sync Engine见 IntegrationActions.tsx。4.2 数据层安装 Mutationstripe-sync-install-mutation.ts 定义了请求形态export type StripeSyncInstallVariables { projectRef: string stripeSecretKey: string startTime: number }它携带Authorization: Bearer accessToken向${BASE_PATH}/api/integrations/stripe-sync发起 POST成功后onSuccess做两件事上报integration_install_submitted埋点以及同时使databaseKeys.schemas(projectRef)与stripeSyncKeys.all两组查询失效让 UI 感知到数据库 schema 的变化。4.3 后端 API 路由密钥校验与后台执行安装的实际执行入口是 stripe-sync.ts这是一个 Next.js API 路由完整流程如下请求体校验zodconst InstallBodySchema z.object({ projectRef: z.string().min(1), stripeSecretKey: z.string().min(1), startTime: z.number().positive().optional(), })前置验证 Stripe 密钥有效性在安装真正启动之前路由先以 Bearer 方式调用 Stripe 的/v1/account端点如果返回非 2xx则直接以 400 把 Stripe 的错误信息回传前端stripe-sync.ts#L104-L130。这一步保证密钥无效这类错误在安装启动前就被拦截而不是埋在漫长的后台安装中。后台异步安装校验通过后通过waitUntil()Vercel Functions API把install()挂到响应之后执行并立即返回 200waitUntil( install({ supabaseAccessToken: supabaseToken, supabaseProjectRef: projectRef, stripeKey: stripeSecretKey, baseProjectUrl: process.env.NEXT_PUBLIC_CUSTOMER_DOMAIN, supabaseManagementUrl: process.env.NEXT_PUBLIC_API_DOMAIN, packageVersion: VERSION, startTime, }).catch((error) { console.error(Stripe Sync Engine installation failed., error) throw error }) ) return res.status(200).json({ data: { message: Stripe Sync setup initiated, version: VERSION }, error: null })注意install、uninstall、VERSION全部来自开源包stripe/sync-engine及其/supabase子导出——Dashboard 本身不实现同步逻辑只是调用开源引擎的 Supabase 适配层。路由还配置了maxDuration: 3005 分钟注释说明即使后台执行安装过程也可能耗时较长。DELETE 方法对应对称的卸载流程校验 Bearer 令牌与请求体后用同样的waitUntil模式调用uninstall()立即返回 uninstallation initiatedstripe-sync.ts#L54-L86。五、安装状态机如何知道装好了没有安装是后台异步过程Studio 用一套基于schema 注释schema comment的状态机来跟踪进度。stripe-sync-status.ts 定义了状态判定函数StripeSchemaComment与SchemaInstallationStatus类型同样来自stripe/sync-engine/supabase即安装状态被持久化在stripeschema 的注释元数据中状态判定函数installed/uninstalledisInstalled/isUninstalledinstalling/uninstallingisInstalling/isUninstallinginstall error/uninstall errorhasInstallError/hasUninstallError围绕这个状态机概览页组件还实现了三块逻辑OverviewTab.tsx升级检测比较 schema 注释中的oldVersion/newVersion与latestAvailableVersion即stripe/sync-engine的VERSION。两者不一致即视为有升级可用此时 CTA 文案从 Install 变为 Upgrade成功提示也从 installation started 变为 upgrade started。轮询刷新安装/卸载进行中时useSchemasQuery以refetchInterval: 5000每 5 秒轮询一次 schema 列表实时跟踪状态迁移完成后停止轮询。错误展示install error/uninstall error时渲染 InstallationError.tsx提示重新安装或联系支持并区分 install/uninstall 与 upgrade 三种失败场景。checkInstallationStatus集成常量中的 CLI 友好入口也基于同一状态机读取 schema 注释install error时抛出带错误信息的异常installed时返回安装完成否则报告仍在安装中——这使得命令行安装路径与 Dashboard 路径共享同一套状态语义。六、同步中Settings 页与stripeschema安装完成后集成的 Settings 页StripeSyncSettingsPage.tsx展示实时同步状态数据来自useStripeSyncStatus()返回的syncState同步进行中显示旋转图标 Sync in progress并展示syncState.started_at的相对时间全部就绪显示 All up to date 最近一次syncState.closed_at时间未安装直接显示 Stripe Sync Engine is not installed. 的提示块。页面同时给出数据消费指引所有同步数据存放在stripeschema中可以直接在 Table Editor 中查看并提供了直达/project/{ref}/editor?schemastripe的 Open Table Editor 按钮。卸载操作的确认弹窗OverviewTab.tsx#L365-L389明确列出了破坏性影响值得在运维文档中照录删除stripeschema 及其所有表删除全部已同步的 Stripe 数据移除关联的 Edge Functions移除定时同步任务且不可撤销。这与第四节中的四步安装清单恰好互为镜像装什么卸什么。七、与 Stripe Foreign Data Wrapper 的取舍同一集成注册表中还有另一个 Stripe 集成 stripe_wrapper/overview.md它是一层外部数据包装器FDW可以在 Postgres 内直接读写 Stripe 数据。仓库博客 2025-12-19-stripe-sync-engine-integration.mdx 对二者的区别有清晰总结FDW 是查询翻译层执行select * from stripe.customers时FDW 把 SQL 翻译成 Stripe API 调用把 JSON 响应转成行返回。适合偶发的简单查询如查某客户的订阅状态但多表 join、跨数千条记录的聚合会导致逐表、逐批的 API 请求延迟从毫秒级劣化到秒级且高频查询会撞上 Stripe 的速率限制。Sync Engine 是数据复制层把 Stripe 数据复制成真正的、带索引的 Postgres 表。查询跑在本地数据上join 与聚合都很快且不再触碰外部 API、不受速率限制约束。官方给出的选型口径是偶发查询用 FDW需要把计费数据当作数据库一等公民的应用用 Sync Engine。八、同步后的 SQL 实战三类高频查询博客给出了三个有本地数据后变得平凡的典型查询它们正好覆盖了 overview.md 提到的 customers / subscriptions / invoices / payments 四类对象与业务数据的 join1. 找出注册但从未转化的用户joinauth.users与stripe.customers/stripe.subscriptionsselect users.email, users.created_at as signed_up, now() - users.created_at as days_since_signup from auth.users left join stripe.customers on customers.email users.email left join stripe.subscriptions on subscriptions.customer customers.id where subscriptions.id is null and users.created_at now() - interval 7 days order by users.created_at;2. 按计划计算 MRR订阅 × 价格 × 产品三表聚合unit_amount以分为单位select products.name as plan, count(*) as subscribers, sum(prices.unit_amount) / 100.0 as mrr from stripe.subscriptions as subscriptions join stripe.prices as prices on prices.id (subscriptions.plan::json-id)::text join stripe.products as products on products.id prices.product where subscriptions.status active group by products.name order by mrr desc;注意subscriptions.plan::json-id的写法正体现了前文提到的 JSONB 存储 生成列设计外键关系保存在 JSONB 内同时保持可索引查询。3. 识别流失风险账户Stripe 计费数据 join 应用行为数据通过customers.metadata-user_id关联select customers.email, subscriptions.current_period_end as renewal_date, max(user_events.created_at) as last_active from stripe.customers as customers join stripe.subscriptions as subscriptions on subscriptions.customer customers.id join public.user_events as user_events on user_events.user_id customers.metadata-user_id where subscriptions.status active group by customers.email, subscriptions.current_period_end having max(user_events.created_at) now() - interval 30 days order by subscriptions.current_period_end;九、独立使用npm 包与 Edge Function 部署Dashboard 一键集成之外Sync Engine 本身是开源库可脱离 Dashboard 使用。博客 2025-07-15-stripe-engine-as-sync-library.mdx 说明其本质是把 Stripe Webhook 转换为结构化 Postgres 写入的 webhook 监听器监听invoice.payment_failed、customer.subscription.updated等事件并规范化落库。核心 APIimport { StripeSync } from supabase/stripe-sync-engine const sync new StripeSync({ databaseUrl: postgres://user:passhost:port/db, stripeSecretKey: sk_test_..., stripeWebhookSecret: whsec_..., }) // 处理一个 Stripe Webhook await sync.processWebhook(payload, signature)用于 Supabase Edge Function 时建议先把 schema 迁移跑在函数之外runMigrations({ databaseUrl, schema: stripe, logger: console })再在函数中初始化StripeSync可用backfillRelatedEntities: false、autoExpandLists: true等选项在Deno.serve中读取原始 body 与stripe-signature头调用processWebhook。密钥通过supabase secrets set --env-file注入DATABASE_URL、STRIPE_WEBHOOK_SECRET、STRIPE_SECRET_KEY三个环境变量连接串建议使用专用 pooler6532 端口。十、开源协作与代码库归属该引擎由 Supabase 于 2021 年开源解决计费数据在 Stripe、业务数据在 Postgres、两者无法 join的问题后与 Stripe 深度合作演进为 Dashboard 的一键集成Stripe 工程师贡献了增量同步、JSONB 存储、多账户支持与 CLI 等改进。根据仓库内的公告 2026-04-14-stripe-sync-engine-transfer.mdx项目保持 Apache 2.0 开源代码库已从 Supabase 组织迁移到 Stripe 组织名下supabase/stripe-sync-engine会重定向现有用户与 Dashboard 中的一键集成行为不受影响。Studio 代码中import { VERSION } from stripe/sync-engine的包名见 stripe-sync.ts#L1-L2也印证了这一归属Dashboard 消费的是 Stripe 维护的 npm 包。关键文件索引内容路径集成概览文档本文主体apps/studio/static-data/integrations/stripe_sync_engine/overview.md概览 markdown 注册表与加载器apps/studio/static-data/integrations/overviews.ts注册表同步测试apps/studio/static-data/integrations/overviews.test.ts安装/卸载 API 路由apps/studio/pages/api/integrations/stripe-sync.ts安装 Mutationapps/studio/data/database-integrations/stripe/stripe-sync-install-mutation.ts集成定义扩展依赖、步骤、输入apps/studio/components/interfaces/Integrations/Landing/Integrations.constants.tsx安装/升级/卸载 UIapps/studio/components/interfaces/Integrations/templates/StripeSyncEngine/OverviewTab.tsx状态机判定函数apps/studio/components/interfaces/Integrations/templates/StripeSyncEngine/stripe-sync-status.ts同步状态与数据入口页apps/studio/components/interfaces/Integrations/templates/StripeSyncEngine/StripeSyncSettingsPage.tsx同步机制与 SQL 示例博客apps/www/_blog/2025-12-19-stripe-sync-engine-integration.mdxnpm 包用法博客apps/www/_blog/2025-07-15-stripe-engine-as-sync-library.mdx代码库迁移公告apps/www/_blog/2026-04-14-stripe-sync-engine-transfer.mdx适用前提小结该集成需要数据库版本不低于 15.6.1.143、具备pgmq/supabase_vault/pg_cron/pg_net扩展操作者需具备FUNCTIONS_SECRET_WRITE权限使用的 Stripe 密钥须能写 Webhook Endpoints。满足这些条件后初始回填会按账户数据量耗时从数分钟到数小时不等而 Webhook 事件在安装完成后即开始实时捕获。【免费下载链接】supabaseThe Postgres development platform. Supabase gives you a dedicated Postgres database to build your web, mobile, and AI applications.项目地址: https://gitcode.com/GitHub_Trending/supa/supabase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考