Rate limits & errors
Understand rate-limit policies, retries, and the gateway error contract.
OneHop applies its own rate-limit policy on top of upstream provider limits. The policy governs requests per minute and concurrent streams per account, and is resolved per request — your key's policy first, then your account's, then the platform default.
Handling 429
When you exceed a limit, the gateway returns RATE_LIMITED with HTTP 429 in
the error shape of the entry protocol.
{
"error": {
"code": "RATE_LIMITED",
"message": "Rate limit exceeded"
}
}Back off and retry
Treat 429 as transient. Retry with exponential backoff and jitter rather than
hammering the endpoint. If you consistently hit limits, contact support about a
higher policy tier.
Error shape per protocol
Errors are returned in the shape of the family you called, so your existing SDK error handling keeps working:
/v1/*and/responses— OpenAI error shape./anthropic/*and/v1/messages— Anthropic error shape./vertex-ai/*— Gemini / Google error shape.
Gateway error reference
| Error | HTTP | Meaning |
|---|---|---|
API_KEY_REQUIRED | 401 | No API key was sent. |
INVALID_API_KEY | 401 | Key does not exist or was revoked. |
AMBIGUOUS_API_KEY | 400 | More than one key header was sent. |
USER_BLOCKED | 403 | The owning account is disabled. |
INSUFFICIENT_CREDITS | 422 | Wallet balance is below the floor. |
RATE_LIMITED | 429 | RPM, concurrency, or policy limit hit. |
MODEL_NOT_FOUND | 404 | No such model in the catalog. |
MODEL_PROTOCOL_NOT_SUPPORTED | 400 | Model doesn't support that protocol. |
MODEL_TEMPORARILY_UNAVAILABLE | 503 | Published model is paused, not removed. |
SUB2API_POOL_UNAVAILABLE | 503 | No upstream capacity available. |
UPSTREAM_TIMEOUT | 504 | Upstream timed out. |
UPSTREAM_ERROR | 502 | Upstream returned a 5xx. |
Idempotency
Send an X-Idempotency-Key header to make a request safe to retry:
curl https://api.onehop.ai/v1/chat/completions \
-H "Authorization: Bearer $ONEHOP_API_KEY" \
-H "X-Idempotency-Key: idem_2026_06_19_001" \
-H "Content-Type: application/json" \
-d '{ "model": "openai/gpt-4o-mini", "messages": [{ "role": "user", "content": "hi" }] }'- If a request with the same key is still in flight, you get
IDEMPOTENCY_IN_PROGRESS(409) and the upstream is not called again. - If it already completed, you get
IDEMPOTENCY_REPLAY_UNAVAILABLE(409) — the request is not re-billed, but the original response body is not replayed.
Idempotency keys are scoped to your account and prevent double-billing across retries and reconciliation.