HTTP 402 is Payment Required, and RFC 9110 section 15.5.3 says only that it is “reserved for future use”. There’s no standard meaning, no header that goes with it, and no client behavior: a browser shows a 402 like any other error page. Services use it anyway, each in its own way, so the body has to say what is owed and where to pay.
Who sends it
- Stripe answers 402 when the parameters were valid but the request failed, most often a declined card: the error’s
typeiscard_error, with adecline_codesaying why. - Shopify’s Admin API answers 402 when the shop is frozen for an unpaid balance.
- SaaS APIs send it for an expired trial or a plan whose paid allowance is used up.
- x402, a protocol Coinbase published in 2025, builds pay-per-request access on it: the 402 describes the price and how to pay, and the client retries with proof of payment.
The exchange
Nothing standard to follow, so make the body explicit. RFC 9457 problem details work well:
HTTP/1.1 402 Payment Required
Content-Type: application/problem+json
{
"type": "https://example.com/problems/plan-limit",
"title": "Plan limit reached",
"status": 402,
"detail": "The Starter plan includes 10,000 calls a month.",
"billing": "https://example.com/account/billing"
}
402 or another code
payment would fix it 402 Payment Required
a limit that resets by itself; wait and retry 429 Too Many Requests, with Retry-After
signed in, but this account may not do it 403 Forbidden
not signed in 401 Unauthorized
A monthly quota that refills on the first of the month is closer to a 429 with Retry-After; one that only an upgrade lifts is a 402.
Gotchas
- Don’t retry it automatically. The same request fails until someone pays.
- Paywalled pages shouldn’t send it. Google treats every 4xx except 429 as content that doesn’t exist, so a paywall served as 402 drops out of the index. Serve the page with a 200 and mark the paywalled part with Google’s paywalled-content structured data.
- Caching. 402 isn’t heuristically cacheable; caches won’t keep it without explicit headers.
In your stack
res.status(402).json({ title: 'Plan limit reached', billing: '/account/billing' }); // Express
raise HTTPException(status_code=402, detail="Plan limit reached") # FastAPI
http.Error(w, "plan limit reached", http.StatusPaymentRequired)
Search payment in the tool below: 402 is the only code whose phrase or meaning mentions it.