Stripe tells you its events arrive out of order and sometimes twice. Believe it.
Stripe allows 100 requests a second live, signs every webhook with HMAC-SHA256 and a five-minute replay window, and retries for three days. It also states plainly that events are not ordered and can arrive more than once — which is the single most important thing to design around.
What Stripe publishes about its API
Documentation
Yes — docs.stripe.com, versioned, with the current release named on the page. Stripe API versioning, fetched 1 September 2026.
Authentication
API keys rather than OAuth for direct use: publishable, restricted and secret, plus organisation keys. Stripe now recommends restricted keys for most cases and advises migrating away from unrestricted secret keys. Connect platforms act for other accounts via the Stripe-Account header. Stripe API keys, fetched 1 September 2026.
Token lifetimes
Keys do not expire on a timer. Rotation keeps the old key working for up to 7 days. A key unused for transfers or payouts for over 180 days may have its access limited. Stripe API keys, fetched 1 September 2026.
Rate limits
100 requests per second in live mode, 25 in a sandbox, and 25 per second on individual endpoints. Plus specific ones: 1,000 updates per PaymentIntent per hour, 20 new invoices per subscription per day, 20 reads per second on search. Stripe rate limits, fetched 1 September 2026.
When you exceed one
HTTP 429 with a Stripe-Rate-Limited-Reason header naming which of global-rate, endpoint-rate, global-concurrency, endpoint-concurrency or resource-specific you hit. No Retry-After — Stripe asks for exponential backoff with jitter. Stripe rate limits, fetched 1 September 2026.
Pagination
Cursor-based: limit, starting_after, ending_before. Default 10, maximum 100, reverse chronological, with has_more on the list envelope. Stripe pagination, fetched 1 September 2026.
Webhooks
Yes — up to 16 endpoints, over HTTPS only, with separate registration for v1 snapshot events and v2 thin events. Stripe webhooks, fetched 1 September 2026.
Event verification
HMAC-SHA256 over timestamp plus a full stop plus the raw body, in a Stripe-Signature header. Default replay tolerance is 5 minutes. Ignore any scheme that is not v1, and never parse the body before verifying it. Stripe webhooks, fetched 1 September 2026.
Retry behaviour
Up to three days with exponential backoff in live mode, three times over a few hours in a sandbox. Redirects count as failures. Manual resend works for 15 days from the dashboard, 30 from the CLI. Stripe webhooks, fetched 1 September 2026.
Bulk operations
A file-based Batch Jobs API: JSONL only, POST and DELETE only, one endpoint per batch, 5 GB and 2 million lines per run, 24-hour processing ceiling, results downloadable for 7 days. Stripe batch API, fetched 1 September 2026.
Test environment
Free and fully isolated — objects in one mode are not reachable from the other. Rate limits are lower and webhook retries shorter than live. Stripe sandboxes, fetched 1 September 2026.
Data location
Stripe does not publish where the data is stored.
Cost of API access
No separate charge for API access is published.
Every line above is Stripe’s own documentation, fetched 1 September 2026, linked so you can check it yourself. 2 of the 13 fields are not published at all — those are marked, and they are the ones that cost you time. The full capability register puts this beside the other eight.
What the Stripe API does and does not allow
Card payments and the money side of everything else. The best-documented API in this register by a wide margin.
Everything in the strip above is Stripe’s own published documentation, fetched 1 September 2026 and linked to the page it came from. We have not paraphrased it into something friendlier, because the exact wording is what you need when a limit bites at four in the afternoon.
What follows is what those facts mean for a build — the constraints that change a design decision rather than the ones that are merely true. If you want the same treatment for the other eight systems side by side, that is the capability register. If you want to know whether we have built against both sides of a particular pairing, the integration checker answers that specific question.
Unordered, at-least-once, and why that is good news
Stripe does not guarantee event order. Distinct events can even share a created timestamp, so that field cannot be used to sequence them. Stripe also says endpoints might occasionally receive the same event more than once, and that in some cases two separate Event objects are generated for one thing that happened.
Most platforms have these properties. Stripe is unusual in writing them down, and writing them down is what lets you build correctly. The handler has to be idempotent — track event IDs, ignore ones you have seen — and it has to derive state from the object rather than from the sequence of notifications. A payment handler that says "if I see succeeded after refunded, something is wrong" is a handler built on an assumption Stripe never made.
The verification discipline matters just as much. Verify the raw body before parsing it, because any manipulation of the bytes breaks the signature. Ignore any signature scheme that is not v1 — Stripe deliberately sends a fake v0 in test to catch downgrade handling. And do not set the replay tolerance to zero, which Stripe explicitly warns against.
Idempotency has a 24-hour memory, and minimum charges are real
Stripe supports idempotency keys on every POST, and saves the status code and body of the first request — including failures. Retry with the same key and you get the same answer back rather than a second charge. It is the right mechanism and we use it on every write.
The limit is that keys are only guaranteed for 24 hours. After that a key may be pruned, and the same request executes again as new. Any retry queue that can be down for longer than a day needs its own duplicate protection on top of Stripe’s, because Stripe’s has expired.
The other one that bites in practice is the minimum charge amount: fifty cents in Australian dollars, and different in every currency. Automations that charge a computed remainder — a rounding adjustment, a small part-payment, a final balance of thirty cents — fail on the small ones. That failure is correct behaviour and it always arrives as a surprise, so put a floor check in the flow and decide up front what happens below it.
Idempotency key on every writeA V4 UUID, stored with the intent that produced it, so a retry is provably the same request rather than a similar one.
Floor check before charging0.50 AUD is the minimum. Decide whether a smaller balance is written off, rolled forward or flagged — before the first one appears.
Never search-then-confirmStripe’s search is eventually consistent and filters on a cached status. Read the object directly for anything a decision depends on.
Rate limits and what breaks at scale
One hundred requests a second in live mode, twenty-five in a sandbox, twenty-five a second on individual endpoints, plus targeted limits — a thousand updates per PaymentIntent per hour, twenty new invoices per subscription per day, twenty reads a second on search. When you hit one, the 429 carries a Stripe-Rate-Limited-Reason header naming exactly which, which is the most helpful rate-limit response in this register.
The limit almost nobody knows about is the read allocation: an average of 500 read requests per transaction over a rolling 30 days, with a floor of 10,000 reads a month. Write requests have no allocation at all. The shape that trips it is a reporting or reconciliation integration polling hard against an account that does not process many payments — which is exactly the shape a small business builds first.
Concurrency is counted separately from rate, and list requests and requests with expansions are what drive it. So the fix for a concurrency 429 is not to slow down, it is to stop expanding things you do not need. Two different problems that return the same status code, distinguished only by that header.
What Stripe’s documentation supports — and the caveat on each. Source: Stripe developer documentation, fetched 1 September 2026.
Stripe
Read records on demand
●Yes100 a second live, 25 per endpoint. Reads have a quota of 500 per transaction over 30 days; writes do not.
Write records in
●YesIdempotency keys on every POST, honoured for at least 24 hours. Minimum charge is 0.50 AUD.
Know the moment something changes
●YesUp to 16 endpoints, HTTPS only, with separate registration for v1 snapshot and v2 thin events.
Verify an event came from them
●YesHMAC-SHA256 over timestamp and raw body, 5-minute replay tolerance, plus a published IP list.
Recover after an outage
●YesThree days of retries live, manual resend for 15 days from the dashboard and 30 from the CLI.
Bulk load history
●YesA file-based Batch Jobs API: JSONL, 5 GB, 2 million lines, 24-hour ceiling, results kept 7 days.
Keep data in Australia
–Not assessedNot published in the API documentation.
What Stripe does not publish
2 of the thirteen fields we track are simply absent from Stripe’s documentation: where your client’s data physically sits and whether API access itself costs anything.
This is the part of an integration page that competitors leave out, and it is the part that costs money. An undocumented rate limit is not an academic gap — it means the first time you find the ceiling is in production, on someone else’s business, usually on the busiest day of their month.
We are not going to fill these in with figures from a forum thread. Numbers circulate for most of them, and some are probably right, but we cannot show you where they came from and neither can the person who posted them. When we have measured Stripe properly under load, those figures will appear here with the date we measured them and the conditions we measured them under. Not before.
What we have built, and what we have not measured
We have implemented against Stripe in production. That is a real fact and it is also a limited one — it tells you we have solved this system's problems before, and it does not tell you how fast, how reliably, or at what volume.
The honest position is this. Everything on this page above the line is the vendor's published documentation, which we fetched, dated and linked rather than paraphrased. Nothing on this page is a Kindra measurement, because our measured register is not finished and publishing half of it dressed up as all of it would make this page less useful, not more.
What we would do on an engagement is measure the specific things that matter for your build — the endpoints you depend on, at your volume, with your data — and hand you those numbers whether or not they suit us. If they say the integration is harder than we quoted, you get told that too. Start with a Leak Check, or read how we work first if you would rather know the shape of it before talking to anyone.
Objections
Isn’t Stripe enough on its own?
Very often, yes — and if it is, we will say so and there is no engagement. Stripe is a mature product that solves the problem it was built for. Integration work is only worth paying for when the cost sits between systems: the same information being typed into Stripe and then into something else, or a decision waiting because two systems disagree. If everything you need lives inside Stripe, buy the plan that fits and spend the money elsewhere.
What happens when they change their API?
They will. Three of the nine systems in our register shipped a breaking or cost-changing update in the last twelve months. What matters is not preventing that — nobody can — but whether the integration was built so the change is a contained fix rather than a rebuild, and whether anyone is watching for the deprecation notice. You own the code either way, so you are never stuck with us to get it fixed.
Book a free Leak Check
20 minutes. We find where the money's going. No pitch.