Short answer
Check the Stripe-Rate-Limited-Reason header to see which limit you hit. Retry with exponential backoff and random jitter, make fewer calls at the same time, and replace polling with webhooks. For bulk jobs, queue the calls and run them at a steady rate.
Rather not fix it yourself? Stripe Billing Fix and Setup handles it at a fixed price, agreed before work starts.
Why Stripe rate limits you, and the fix
01
A loop calls the API once per item
“If you exceed the limits, you get 429 Too Many Requests HTTP status responses.” Stripe, Rate limits
A sync job, a migration or a page that fetches every customer or invoice one by one can pass the limit fast. Use list calls with a limit and auto-pagination, store what you need in your database, and run bulk jobs through a queue at a fixed rate.
02
The header says which limit you hit
“Concurrency limits restrict the number of simultaneously active requests, separate from rate limits.” Stripe, Rate limits
The 429 response has a Stripe-Rate-Limited-Reason header: global-rate, endpoint-rate, global-concurrency or endpoint-concurrency. A rate limit means too many calls per second. A concurrency limit means too many calls running at the same time, so send fewer in parallel.
03
Retries fire again straight away
“Follow an exponential backoff schedule to reduce request volume when necessary, and add randomness to the backoff schedule to avoid a thundering herd effect.” Stripe, Rate limits (Handle limiting)
Retrying at once adds to the load. Wait longer after each 429 and add a random delay so many workers don’t retry together. Unlike rate-limit errors, lock-timeout 429s are retried by the Stripe SDKs, so add your own backoff for rate limits. When you retry a create or update call, send an idempotency key so a retry that did go through can’t charge twice.
async function withBackoff(fn, tries = 5) { for (let i = 0; ; i++) { try { return await fn(); } catch (err) { if (err.statusCode !== 429 || i >= tries - 1) throw err; const wait = 2 ** i * 500 + Math.random() * 500; // backoff + jitter await new Promise((r) => setTimeout(r, wait)); } } } const invoice = await withBackoff(() => stripe.invoices.retrieve(invoiceId)); // POST calls: pass { idempotencyKey } so a retried create can't run twice const pi = await withBackoff(() => stripe.paymentIntents.create(params, { idempotencyKey: `order-${orderId}` }), );04
The app polls Stripe for status
Checking a payment or subscription every few seconds from each open browser adds up. Listen for webhooks such as payment_intent.succeeded or customer.subscription.updated, save the state in your database, and read it from there. In the webhook handler, use the object in the event instead of fetching it again for every event.
05
Search and tests have lower limits
“Consider Sigma or Data Pipeline for more efficient options for data-intensive analytics tasks.” Stripe, Rate limits
Sandbox allows 25 requests per second in total, and the Search API 20 reads per second, so a load test in sandbox or a search-heavy admin page can hit the limit even when live traffic doesn’t. For reporting, Stripe points to Sigma or Data Pipeline instead of the API.
06
lock_timeout is a different 429
“If you see this error intermittently, retry the request.” Stripe, Rate limits (Object lock timeouts)
A 429 with code lock_timeout means two requests touched the same object at once, such as two updates to one customer. Retry it, and make changes to one object one after another instead of in parallel.
Checked against the vendor’s docs on : Stripe docs: Rate limits; Stripe docs: Error codes.
Rather hand it over?
Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.
- $950Stripe Billing Fix and SetupSubscriptions, webhooks, customer portal and failed payments set up or fixed, tested in Stripe test mode.See scope and start
- from $450App Fix TicketOne reproducible bug in an existing mobile or web app, diagnosed and fixed.See scope and start
- from $450AI-Built App RescueA Lovable, Bolt or Cursor app checked end to end in 3 days, then its worst problems fixed at a fixed price.No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.See scope and start
“Working with Simon makes everything run so smoothly and better than I could ask for it. Amazingly communicative, extremely knowledgeable of coding and the backend processes. I strongly recommend.”
Related: Stripe idempotency key in use · Stripe webhook 200 but database not updated · Stripe processing_error · Stripe card_not_supported