Skip to main content
20% off 3 months · code LAUNCH20 · until 31 October

How to query your Stripe data without Sigma

23 September 2026 · by Nordva, who make Nordva Launch

On this pageWhat Sigma is, and why you might skip it
  1. What Sigma is, and why you might skip it
  2. Option 1: the Dashboard’s filters and exports
  3. Option 2: the Search API, for a single question
  4. Option 3: copy your data out with a script
  5. Option 4: Data Pipeline, if you already have a warehouse
  6. Which one to use
  7. Who should not use Launch for this
  8. The faster way: Nordva Launch
  9. Back to the top

How can I query my Stripe data without paying for Sigma?

For a small account, start with the Dashboard's filters and CSV exports and the Search API for single lookups. When you ask the same questions every week, copy your data out with a short script that pages through the API with a read-only key, write it to CSV, and load it into SQLite. Data Pipeline only makes sense if you already run a data warehouse.

Most questions a small Stripe account has are simple: how much came in last month after refunds, who are the biggest customers, which payments carried a given tag. Sigma answers them in SQL inside the Dashboard, and for many accounts it is more than the question needs. Here are the other ways, from the least work to the most.

What Sigma is, and why you might skip it

Sigma is an SQL editor in the Stripe Dashboard over a read-only copy of your account: payments, subscriptions, customers, payouts and more. It is free in sandboxes and a paid subscription in live mode. Its data is not live: each query can read data_load_time to see up to when it runs.

It is the right tool when you write new questions often. If you ask the same five questions every month, a copy of your own data does the same job.

Option 1: the Dashboard’s filters and exports

The Dashboard already filters and exports. According to Stripe’s Dashboard guide, you can filter or export your transactions from the Transactions page, and export customers from the account-level Customers page.

If you use Stripe Billing, look at the Billing analytics reports before you build anything. They download as CSV and include MRR per subscriber per month, a monthly summary of subscription metrics, and a log of every MRR change per customer (new, upgrades, downgrades, reactivations and churn). That covers most subscription questions a small product has.

For money in and out, the reports include a balance report and payout reconciliation, which Stripe lists as free.

Good for: one-off answers, sending a file to an accountant. Not good for: anything you repeat every week, because the clicking is the cost.

Option 2: the Search API, for a single question

When the question is “find the payments or customers that match this”, search is faster than paging through lists. It works on charges, customers, invoices, PaymentIntents, prices, products and subscriptions, and it can match on metadata:

curl -G https://api.stripe.com/v1/charges/search \
  -u "$STRIPE_KEY:" \
  --data-urlencode "query=metadata['utm_source']:'reddit' AND status:'succeeded'"

The limits are in the same doc: up to 20 search reads a second, new data usually searchable within a minute (so not for reading back something you just wrote), and search is not available to businesses in India. It filters; it does not add things up. For totals you need the rows.

Option 3: copy your data out with a script

This is the option that replaces Sigma for a small account. A script lists every object of one type with a restricted, read-only key, writes a CSV, and you query the file with SQL. It costs nothing, the data stays on your machine, and the same script runs again next month.

The example below exports charges. The list endpoint returns up to 100 per page, newest first, and filters by created; the Node library’s auto-pagination fetches every page when you loop with for await.

npm install stripe
STRIPE_KEY=rk_live_... node export-charges.mjs            # everything
STRIPE_KEY=rk_live_... node export-charges.mjs 2026-01-01 # since a date
// export-charges.mjs: every charge, or every charge since a date, to charges.csv.
// Usage: STRIPE_KEY=rk_live_... node export-charges.mjs [2026-01-01]
import Stripe from "stripe";
import { createWriteStream } from "node:fs";

const stripe = new Stripe(process.env.STRIPE_KEY);
const since = process.argv[2] ? Math.floor(Date.parse(process.argv[2]) / 1000) : null;

const COLUMNS = ["id", "created", "amount", "amount_refunded", "currency", "status", "customer", "email", "description", "payment_intent", "metadata"];
const cell = (v) => {
  const s = v == null ? "" : String(v);
  return /[",\r\n]/.test(s) ? `"${s.replaceAll('"', '""')}"` : s;
};

const out = createWriteStream("charges.csv");
out.write(COLUMNS.join(",") + "\n");
let count = 0;
const params = { limit: 100, ...(since && { created: { gte: since } }) };
for await (const c of stripe.charges.list(params)) {
  const row = [
    c.id,
    new Date(c.created * 1000).toISOString(),
    c.amount, // smallest currency unit: cents for USD
    c.amount_refunded,
    c.currency,
    c.status, // succeeded, pending or failed
    c.customer,
    c.billing_details?.email,
    c.description,
    c.payment_intent,
    JSON.stringify(c.metadata),
  ];
  out.write(row.map(cell).join(",") + "\n");
  count++;
}
out.end();
console.log(`${count} charges written to charges.csv`);

Give the key Read on charges only. If it is missing a permission, the error names it.

The same pattern works for any list: stripe.customers.list, stripe.subscriptions.list (pass status: "all", or canceled subscriptions are left out), stripe.invoices.list, stripe.refunds.list. Copy the file, change the call and the columns.

Load it into SQLite and ask

SQLite’s command-line tool imports a CSV into a table in one line, using the header row for column names:

sqlite3 stripe.db ".import --csv charges.csv charges"

Money in per month, after refunds, per currency:

SELECT substr(created, 1, 7) AS month,
       currency,
       COUNT(*)                              AS payments,
       SUM(amount - amount_refunded) / 100.0 AS net
  FROM charges
 WHERE status = 'succeeded'
 GROUP BY month, currency
 ORDER BY month;

Your ten largest customers in one currency:

SELECT customer, COUNT(*) AS payments, SUM(amount - amount_refunded) / 100.0 AS net
  FROM charges
 WHERE status = 'succeeded' AND currency = 'usd'
 GROUP BY customer
 ORDER BY net DESC
 LIMIT 10;

Payments per value of a metadata key you set yourself:

SELECT json_extract(metadata, '$.utm_source') AS source, COUNT(*) AS payments
  FROM charges
 WHERE status = 'succeeded'
 GROUP BY source;

Three things to keep in mind. Amounts are in the smallest currency unit, so dividing by 100 is wrong for zero-decimal currencies such as JPY. Never add one currency to another. To refresh, delete the table and import again, or export only since your last run and add it with .import --csv --skip 1 charges.csv charges, which leaves out the header row that would otherwise land in the table as data.

Option 4: Data Pipeline, if you already have a warehouse

Stripe Data Pipeline sends all of your Stripe data, without code, to a warehouse or to cloud storage you own. Its requirements, from Stripe’s docs:

Data arrives within 12 hours of accepting the share and is refreshed every three hours. It is billed as its own plan, which you turn off with Manage plan in the Data Pipeline settings of the Dashboard. If you do not already run one of those warehouses, setting one up to answer a few questions about a small account is the long way round.

Which one to use

Your questionUse
A one-off number, or a file for your accountantDashboard filters and CSV export
MRR, subscriber counts and churn by monthBilling analytics downloadable reports
”Find the payments or customers that match this”Search API
The same few questions every week or monthA script to CSV, queried in SQLite
New questions every day, written by several peopleSigma
Stripe data joined to a warehouse you already runData Pipeline

If churn is the question, the churn guide has a script for it that works on subscriptions directly.

Who should not use Launch for this

If you want free-form SQL over every Stripe object, Launch is not that: use a script, Sigma or Data Pipeline. If your accountant needs balance and payout reports, those come from Stripe. And if you bill through something other than Stripe, Launch cannot read it.

The faster way: Nordva Launch

Most of the questions above come down to three: how much came in, who is paying, and where they came from. Launch answers those without an export. You connect Stripe in the dashboard with a restricted key, and Launch reads it with GET requests only; disconnecting deletes every synced row. Every plan can connect Stripe: the Free plan reads 30 days of history and syncs every six hours, Indie reads 90 days and Builder 730 days, both syncing hourly.

The part a CSV cannot give you is the source. Launch traces each paying customer to a first visit through nordva_visitor_id in the customer’s or subscription’s metadata, identify() with a user id or email, or the email on your waitlist, first touch only. The Revenue API page lists what it reports. Start free: no time limit, no card.

Questions

Is Stripe Sigma free?
It is free in sandboxes, with no usage limits on test data. In live mode it is a paid subscription, which you manage and cancel under Sigma in your Dashboard settings.
Can I run SQL on Stripe data without Sigma?
Yes, on a copy. Export with the Dashboard or a script, load the file into SQLite, DuckDB or any database, and query it there. The copy is as fresh as your last export, and you decide which fields it keeps.
How fresh is the Search API?
Stripe says data is usually searchable within a minute, and can take longer during an outage. Do not use search right after writing something you need to read back; use the list endpoints for that.
Is it safe to run a script against my live Stripe account?
Use a restricted key with read permission only. It can list and retrieve, and every write it tries fails. Keep it out of your repository and out of anything that runs in a browser.
Related

Try it in your project

npx nordva@latest init

Free plan, no card, no invite.

Start free