Connect Stripe to PostgreSQL
Pull your Stripe data — customers, invoices, subscriptions, charges and more — into a sheet or database to track revenue, MRR and churn without a BI tool.
What you can pull from Stripe
Stripe exposes 8 objects you can pull, each as its own job. Every run pulls the records into a flat table, so nested fields arrive as ordinary columns that PostgreSQL can sort, filter and total without further work.
Customers
The customer list with metadata.
Subscriptions
Plans, status and interval - the raw material for MRR.
Invoices
Billing history and outstanding amounts.
Charges
Individual payments and their status.
Payment intents
Attempts, including the ones that failed.
Balance transactions
What actually hit your balance, with fees.
Products
Your catalogue.
Prices
Price points against those products.
Options you can set
- resource
- Which Stripe object to fetch — defaults to
customers - created_after
- Only objects created at or after this time
- created_before
- Only objects created at or before this time
How it lands in PostgreSQL
PostgreSQL accepts append, replace, upsert writes. Upsert is the one that matters on a schedule: it merges on a key you choose, so matching rows are updated in place and only genuinely new records are created. Append instead, and a daily job multiplies your data.
Upsert uses key_columns as the conflict target.
- Rows are written in chunks of 1,000 by default, configurable up to 50,000.
- Replace truncates the target table before writing.
Authentication
Stripe authenticates with an API key held as a stored connection, so it never appears in a spreadsheet cell, a formula, or a shared copy of a sheet.
Keeping runs incremental
Yes. Filter with created_after and created_before so a run fetches a window rather than your whole history.
Pair a narrowed read with an upsert write and a re-run costs almost nothing: the rows it already knows are updated, and nothing is duplicated. That combination is what makes a frequent schedule affordable.
Limits and pacing
These are the provider-side ceilings that shape a schedule, not ours. Knowing them up front is the difference between a job that runs quietly every morning and one that starts failing the week your data grows.
| Limit | Value | Applies to |
|---|---|---|
| Page size Stripe's own maximum per request. | 100 records | Stripe |
Common gotchas
Most of what goes wrong with a scheduled sync is not a bug — it is a detail of how one side behaves that nobody wrote down. These are the ones that come up for this pair.
Amounts are in the smallest currency unit
A value of 5000 on a USD object is $50.00, not $5,000. Divide by 100 in a computed field, or you will present a number a hundred times too large.
Annual plans are not monthly revenue
A yearly subscription at $1,200 is $100 of MRR. If you have mixed billing intervals, normalise before summing.
Set either table or query, never both
The config rejects both being set, and rejects neither - caught when the job is saved rather than on its first run.
Set it up in four steps
- 1
Connect Stripe
A Stripe API key. A restricted read-only key is enough - this never writes.
- 2
Connect PostgreSQL
Host, port, database, user and password, stored encrypted.
- 3
Shape the data
Select the columns you want, filter rows, cast types and add computed fields. Everything else is dropped before it reaches the destination.
- 4
Schedule it
Run once, or on a cron. Every run refreshes PostgreSQL with the latest Stripe data.
Do I need an add-on or extension for this?
No. The job runs server-side and writes into PostgreSQL through its API, so there is nothing installed in the destination itself. It keeps running when nobody has the file open, and a copy of the file does not need anything installed to work.
How often does the data refresh?
On whatever schedule you set with a cron expression — hourly, daily, or a specific time on specific days. Each run pulls the latest from Stripe.
Do I need to write any code?
No. You connect both sides, map the fields in a wizard and set a schedule. Computed fields accept small expressions — abs, round, min, max, len — but there is nothing to host or maintain.
Does this need write access to Stripe?
No. A restricted read-only API key is enough - the connector only ever reads.
Why are the amounts wrong by a factor of 100?
They are not wrong, they are in the smallest currency unit: 5000 means $50.00. Divide by 100 in a computed field before it reaches a currency column.
Can I run my own SQL rather than reading a table?
Yes. Set a query instead of a table and aggregate in the database, which is usually far cheaper than moving raw rows and aggregating downstream. One statement only - multi-statement queries are rejected.
Does it need a superuser?
No. A user with SELECT on what you are reading is enough for a source; a destination needs INSERT and, for upsert, UPDATE on the target table.
Is the Stripe connector free to use?
You can connect Stripe and start syncing on the free plan.
Other sources into PostgreSQL
Related reading
Airtable upsert: stop creating duplicate records
Appending on every run turns a tidy base into six copies of every row. Here is how upsert works in Airtable, and how to choose a merge key that holds up.
Export Stripe data to Google Sheets
Stripe's dashboard exports are manual and stale the moment you download them. Here is how to keep customers, invoices and charges fresh in a sheet instead.
Get data into Google Sheets without an add-on
Every major Sheets data tool is an add-on you install, authorise and keep updated inside the spreadsheet. Here is how to schedule the same imports without one.