Errors
HPP Router returns standard HTTP status codes and a JSON error envelope. Handle these in your client to distinguish auth, payment, quota, and upstream failures.
Status codes
| Code | Meaning | Typical cause |
|---|---|---|
400 | Bad Request | Malformed body, or an unroutable/unsupported model. |
401 | Unauthorized | Missing or invalid API key; or Agent (keyless) called a free/zero-price model (keyless_free_model_not_allowed). See Authentication and x402 Agent. |
402 | Payment Required | Wallet rail (X-Payment-Rail: wallet) or Agent (keyless) needs an x402 signature. Response includes PAYMENT-REQUIRED (and aliases) plus a JSON body with accepts. Sign and retry with PAYMENT-SIGNATURE (or X-PAYMENT). See Authentication — x402 Wallet and x402 Agent. |
429 | Too Many Requests / Quota exhausted | Rate limit hit, or prepaid quota insufficient. This is not the normal wallet-rail payment challenge (that is 402). |
500 | Internal Server Error | Unexpected gateway or upstream error. |
503 | Service Unavailable | Wallet rail / facilitator not configured, or settlement could not proceed (fail-closed). |
Error envelope
Errors are returned as JSON. Two shapes are possible.
Simple form
{
"error": "unauthorized",
"message": "Invalid API key"
}
Structured form (upstream/provider errors)
{
"error": {
"message": "The model is overloaded.",
"type": "upstream_error",
"code": "overloaded",
"provider": "openai",
"upstream_status": 503,
"retryable": true
}
}
| Field | Meaning |
|---|---|
error.message | Human-readable description. |
error.type | Error category. |
error.code | Machine-readable code. |
error.provider | Upstream provider, when the error originated there. |
error.upstream_status | The provider's HTTP status, when applicable. |
error.retryable | Whether the request can be safely retried. |
Wallet / Agent 402 challenge
On the keyed wallet rail or the Agent (keyless) path, a missing or unsigned payment typically returns 402 with:
- Headers:
PAYMENT-REQUIRED(primary), pluspayment-required/x-payment-required/WWW-Authenticatealiases - Body:
{ "x402Version": 2, "accepts": [ { "scheme": "upto", "asset", "amount", "payTo", "network", ... } ], ... }
Retry the same request once with:
- Keyed wallet:
X-Payment-Rail: walletand your API key - Agent: no API key (still omit
Authorization/apikey) - Either path:
PAYMENT-SIGNATURE: <base64 payload>(the gateway also acceptsX-PAYMENT)
@hpprouter/sdk runs the keyed loop automatically when you pass paymentRail: 'wallet' and a paymentSigner. For keyless Agent calls, use raw HTTP or hpp-x402 (see also x402 Agent).
Smart-routing errors
When using hpprouter/auto, you may encounter:
| Error | Cause |
|---|---|
400 smart_routing_failed | Baskets/tiers/streaming-fallback not configured, or the provider is not allowed. |
400 unsupported_model | The resolved model has no registered pricing. |
Handling guidance
401— fix your API key; do not retry blindly.402— sign the x402 challenge and retry once; ensure the paying wallet holds the payment asset on the challenged network (commonly USDC.e on HPP — see Networks & token). Prefer@hpprouter/sdkover hand-rolling the loop in the OpenAI SDK.429— back off and retry for rate limits; for quota exhaustion, top up prepaid credit or switch to the wallet rail.5xxwithretryable: true— retry with exponential backoff.5xxwithretryable: false— surface the error; retrying will not help.