Highlights
Quota-exceeded responses now return HTTP 429 with a Retry-After header, matching what OpenAI, GitHub, and Cloudflare send. The pricing page grew a Bandwidth row (every public plan is Unlimited). And requests that ask for exitCountries on a plan without geo-targeting now get a clean 403 that names the parameter and the fix.
What's New
Quota limits speak HTTP 429 now, not 402
If you hit a plan limit (credits or bandwidth), the response is 429 Too Many Requests with Retry-After on every reply and resets_at in the body pointing at your billing-period end. The reason field tells you which limit you hit (plan_limit_credits or plan_limit_bandwidth) so it doesn't collide with per-minute rate limits.
Why the change? 402 sounds right ("Payment Required") but in practice it's how Stripe reports failed charges, and several HTTP clients and proxies mishandle it. OpenAI, GitHub, Twilio, and Cloudflare all reject exceeded quotas with 429 and a distinct error code. Following the herd here is the right move: every retry library on the planet already knows what to do with our responses.
The Retry-After value is capped at 24 hours for the sleep-and-retry crowd. If you want the real reset time, read resets_at from the JSON body.
Bandwidth on the pricing page: Unlimited
/prices grew a Bandwidth row in the compare matrix. Every public plan ships uncapped bandwidth, and the matrix now says so out loud. It's the kind of thing you don't need until a prospect asks and you can't find the number. Now it's on the page.
Custom plans that cap bandwidth show their GB figure in the same row.
geo-targeting gates itself with a proper error
If a request sends exitCountries while the plan doesn't include the geo-targeting feature, the response is 403 with a message naming the parameter and how to fix it. Before, the request went through as if geo-targeting was allowed. Now it fails loudly at the door.
Requests without exitCountries are untouched. This only kicks in when you're actually asking for the feature.
Small Dashboard fixes on Limits and Billing
Three quality-of-life fixes:
- Limits tab. The saved sub-tab (Overview / API keys / Limits & Features) restores before paint, so you no longer see a wrong-tab flash on reload.
- API Keys. The search box uses the canonical search pattern instead of a naked input.
- Billing. The meta lines under Payment Method now render with the right styling (they were falling through unstyled before).
Under the Hood
Plan-limit enforcement modes are now live-flippable. Each of the six data-plane limits (per-product concurrency, per-minute rate, browser-per-day, credits, bandwidth, features) plus the management-plane key-create check can be switched between off, signal, and enforce from a settings panel our team controls. No redeploy. A background refresher polls the setting every 60 seconds and the hot path stays synchronous.
Why does this matter to you? When a limit misbehaves in production, we can dial it back in a minute instead of shipping new code. It also lets us bring enforcement on gradually, per limit, watching what real traffic does at each step. Signal mode records the event without blocking; enforce switches on the 429 or 403 response. We wanted the intermediate step to be first-class rather than an emergency toggle.
Numbers
Retry-Aftercap on quota rejections: 24 hours (real reset time inresets_at)- Runtime settings poll interval: 60 seconds
- Public plans with uncapped bandwidth: all of them
The plan limiter has been the through-line for a month. Next up: enforcement on the first limits (credits and per-product concurrency look like the natural first pair), plus email warnings once the mailing phase ships.