# agent polled payment_intent status every second: hit stripe rate limits

## TL;DR
Stop polling in a tight loop; subscribe to the provider's webhook for status changes, and if you must poll, use exponential backoff starting at 5 seconds. A 429 means you already overdid it, so treat the rate-limit error as a signal to back off, not to retry faster. The webhook tells you the moment it changes; polling every second never adds information.

```text
agent polled payment_intent status every second: hit stripe rate limits
```

## Fix it

1. **Switch the primary path to webhooks.** Register for `payment_intent.succeeded` / `payment_intent.payment_failed` (or the provider equivalent) and let events drive state. Success check: a test payment flips your local status within seconds with zero polling.
2. **If you must poll, back off.** Start at 5s, double each attempt, cap at 60s, stop after ~10 minutes. Success check: staging logs show at most ~15 status calls for a slow payment, not 600.
3. **Handle 429 correctly.** On a rate-limit response, honor the `Retry-After` header and pause all polling for that account. Success check: a forced 429 in staging pauses the poller instead of erroring loudly.
4. **Audit existing pollers.** Search the codebase for status-retrieve loops and convert them. Success check: no retrieve loop runs faster than the backoff floor.

## When this applies

- An agent waits on a payment outcome and calls a status endpoint in a loop.
- You are seeing 429s or throttled status reads on payment intents, charges, or invoices.

## When it doesn't

- Webhooks are not arriving at all; that is a delivery/signature problem, not a polling problem.
- You need one status check right now, not a loop; a single retrieve is fine.

## Compatibility

- Pattern: agent harnesses and payment-orchestration scripts on Stripe, Adyen, Checkout.com, or any API with rate-limited reads.
- Stripe: live rate limits are per-account; test mode is more forgiving, so staging may not catch this.

### Variant: agent polled invoice status in a cron every minute for thousands of invoices

Same fix at scale: webhooks plus a daily reconciliation sweep, not per-invoice polling.

### Variant: 3DS redirect wait polling

The agent polls while the customer authenticates elsewhere. Same fix: pause polling during the redirect and resume on the return URL or webhook.

## Why it happens

Agents are written to be impatient: the simplest wait implementation is a tight loop. But status endpoints are read APIs with rate limits, and a 1-second loop against one payment is 60 reads a minute that add zero information between state changes.

## Edge cases

- Webhook delays: keep a bounded fallback poll (the backoff schedule) in case a webhook is delayed, but never let it become the primary path.
- Multiple pollers per account: two agents polling different payments still share the account's read budget; centralize status waiting in one helper.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_is5O4Qei-BYk44WRBhyxuA
