This monorepo contains packages for synchronizing your Stripe account with a PostgreSQL database:
stripe-experiment-sync: A TypeScript library for syncing Stripe data to PostgreSQL with managed webhooks, CLI tools, and Supabase Edge Function deployment.stripe-sync-fastify: A Fastify-based server and Docker image for production deployments.
Sometimes you want to analyze your billing data using SQL. Even more importantly, you want to join your billing data to your product/business data.
This project synchronizes your Stripe account to a PostgreSQL database. It can be a new database, or an existing PostgreSQL database.
The easiest way to sync Stripe data to PostgreSQL:
import { StripeSync } from 'stripe-experiment-sync'
const sync = new StripeSync({
poolConfig: {
connectionString: process.env.DATABASE_URL,
max: 10,
},
stripeSecretKey: process.env.STRIPE_SECRET_KEY,
})
// Create a managed webhook - automatically syncs all Stripe events
const webhook = await sync.findOrCreateManagedWebhook('https://example.com/stripe-webhooks')
// Cleanup when done
await sync.close()If you need to process webhooks in your own Express/Node.js app:
import express from 'express'
import { StripeSync } from 'stripe-experiment-sync'
const app = express()
const sync = new StripeSync({
poolConfig: {
connectionString: process.env.DATABASE_URL,
max: 10,
},
stripeSecretKey: process.env.STRIPE_SECRET_KEY,
})
app.post('/stripe-webhooks', express.raw({ type: 'application/json' }), async (req, res) => {
const signature = req.headers['stripe-signature']
try {
await sync.processWebhook(req.body, signature)
res.status(200).send({ received: true })
} catch (error) {
res.status(400).send({ error: error.message })
}
})
app.listen(3000)Deploy to Supabase for serverless operation:
npx stripe-experiment-sync supabase install \
--token $SUPABASE_ACCESS_TOKEN \
--project $SUPABASE_PROJECT_REF \
--stripe-key $STRIPE_API_KEY# Run database migrations
npx stripe-experiment-sync migrate --database-url $DATABASE_URL
# Start local sync with ngrok tunnel
npx stripe-experiment-sync start \
--stripe-key $STRIPE_API_KEY \
--ngrok-token $NGROK_AUTH_TOKEN \
--database-url $DATABASE_URL
# Backfill historical data
npx stripe-experiment-sync backfill customer \
--stripe-key $STRIPE_API_KEY \
--database-url $DATABASE_URL| Option | Type | Description |
|---|---|---|
poolConfig |
object | Required. PostgreSQL connection pool configuration. Supports connectionString, max, keepAlive. |
stripeSecretKey |
string | Required. Stripe secret key (sk_...) |
stripeWebhookSecret |
string | Stripe webhook signing secret (only needed for manual webhook processing) |
stripeApiVersion |
string | Stripe API version (default: 2020-08-27) |
enableSigma |
boolean | Enable Stripe Sigma reporting data sync. Default: false |
autoExpandLists |
boolean | Fetch all list items from Stripe (not just the default 10) |
backfillRelatedEntities |
boolean | Ensure related entities exist for foreign key integrity |
revalidateObjectsViaStripeApi |
Array | Always fetch latest data from Stripe instead of trusting webhook payload |
maxRetries |
number | Maximum retry attempts for 429 rate limits. Default: 5 |
initialRetryDelayMs |
number | Initial retry delay in milliseconds. Default: 1000 |
maxRetryDelayMs |
number | Maximum retry delay in milliseconds. Default: 60000 |
logger |
Logger | Logger instance (pino-compatible) |
- Automatically runs database migrations to create the
stripeschema with tables matching Stripe objects. - Creates managed webhooks in Stripe for automatic event synchronization.
- Processes webhook events and syncs data to PostgreSQL in real-time.
- Supports backfilling historical data from Stripe.
- Tracks sync runs and provides observability into sync operations.
- Built-in retry logic for rate limits and transient errors.
Each package has its own README with installation, configuration, and usage instructions.
Deploy the sync engine to Supabase Edge Functions for serverless operation with automatic webhook processing. See the sync-engine README for detailed instructions.
npx stripe-experiment-sync supabase install \
--token $SUPABASE_ACCESS_TOKEN \
--project $SUPABASE_PROJECT_REF \
--stripe-key $STRIPE_API_KEY-
balance.available -
charge.capturedπ’ -
charge.expiredπ’ -
charge.failedπ’ -
charge.pendingπ’ -
charge.refundedπ’ -
charge.refund.updatedπ‘ - For updates on all refunds, listen torefund.updatedinstead -
charge.succeededπ’ -
charge.updatedπ’ -
charge.dispute.closedπ’ -
charge.dispute.createdπ’ -
charge.dispute.funds_reinstatedπ’ -
charge.dispute.funds_withdrawnπ’ -
charge.dispute.updatedπ’ -
checkout.session.async_payment_failedπ’ -
checkout.session.async_payment_succeededπ’ -
checkout.session.completedπ’ -
credit_note.createdπ’ -
credit_note.updatedπ’ -
credit_note.voidedπ’ -
customer.createdπ’ -
customer.deletedπ’ -
customer.source.created -
customer.source.updated -
customer.subscription.createdπ’ -
customer.subscription.deletedπ’ -
customer.subscription.pausedπ’ -
customer.subscription.pending_update_appliedπ’ -
customer.subscription.pending_update_expiredπ’ -
customer.subscription.resumedπ’ -
customer.subscription.trial_will_endπ’ -
customer.subscription.updatedπ’ -
customer.tax_id.createdπ’ -
customer.tax_id.deletedπ’ -
customer.tax_id.updatedπ’ -
customer.updatedπ’ -
invoice.createdπ’ -
invoice.deletedπ’ -
invoice.finalizedπ’ -
invoice.finalization_failedπ’ -
invoice.marked_uncollectibleπ’ -
invoice.paidπ’ -
invoice.payment_action_requiredπ’ -
invoice.payment_failedπ’ -
invoice.payment_succeededπ’ -
invoice.sentπ’ -
invoice.upcomingπ΄ - Event has no id and cannot be processed -
invoice.updatedπ’ -
invoice.overdueπ’ -
invoice.overpaidπ’ -
invoice.will_be_dueπ’ -
invoice.voidedπ’ -
issuing_authorization.request -
issuing_card.created -
issuing_cardholder.created -
payment_intent.amount_capturable_updatedπ’ -
payment_intent.canceledπ’ -
payment_intent.createdπ’ -
payment_intent.partially_refundedπ’ -
payment_intent.payment_failedπ’ -
payment_intent.processingπ’ -
payment_intent.requires_actionπ’ -
payment_intent.succeededπ’ -
payment_method.attachedπ’ -
payment_method.automatically_updatedπ’ -
payment_method.detachedπ’ -
payment_method.updatedπ’ -
plan.createdπ’ -
plan.deletedπ’ -
plan.updatedπ’ -
price.createdπ’ -
price.deletedπ’ -
price.updatedπ’ -
product.createdπ’ -
product.deletedπ’ -
product.updatedπ’ -
radar.early_fraud_warning.createdπ’ -
radar.early_fraud_warning.updatedπ’ -
refund.createdπ’ -
refund.failedπ’ -
refund.updatedπ’ -
review.openedπ’ -
review.closedπ’ -
setup_intent.canceledπ’ -
setup_intent.createdπ’ -
setup_intent.requires_actionπ’ -
setup_intent.setup_failedπ’ -
setup_intent.succeededπ’ -
subscription_schedule.abortedπ’ -
subscription_schedule.canceledπ’ -
subscription_schedule.completedπ’ -
subscription_schedule.createdπ’ -
subscription_schedule.expiringπ’ -
subscription_schedule.releasedπ’ -
subscription_schedule.updatedπ’ -
entitlements.active_entitlement_summary.updatedπ’
Issues and pull requests are welcome at https://github.com/stripe-experiments/sync-engine.
See LICENSE file.

