HelipodDocs

Limits and errors

Rate and concurrency limits, sizes and timeouts, every error the AI Gateway returns, and when to retry.

Rate limits

These limits are checked before every request, in this order. A refused request is not charged and takes no hold.

LimitScopeWhen reached
Key rate limitOne key, requests per minute. Only for keys that have their own limit.429 rate_limited, "Too many requests for this key (limit N per minute)"
Account rate limitAll keys of your account together, requests per minute. 600 by default.429 rate_limited, "Too many requests for this account (limit N per minute)"
Monthly spend limitOne key, Rupiah per calendar month (UTC). Only for keys created with one.403 key_spend_limit_reached
ConcurrencyAll keys of your account together, requests in progress at the same time. 20 by default.429 too_many_concurrent_requests

Good to know:

  • Fixed windows. Per-minute limits count requests in each calendar minute, so the count resets at the start of every minute.
  • Every attempt counts. A request counts toward the per-minute limits even when it is then refused.
  • The message has the number. The 429 message always states the limit that applies to you, so read it from there rather than assuming the defaults.
  • Streams hold a slot. A streaming request holds its concurrency slot until the stream ends, so close streams you no longer need.

Need higher limits? Contact Helipod support.

Sizes and timeouts

WhatLimit
Request body8 MB
Output cap when you send none16,384 tokens, or the model's output limit when lower
Output cap above the model's limitLowered to the model's limit
Context, input and output per modelSee Models & pricing in the dashboard
Total time for one request10 minutes
Stream keep-aliveAfter about 10 seconds without output, then every 15 seconds

Use streaming for long answers and reasoning models. A streamed request keeps the connection busy with output or keep-alive comments, so proxies and HTTP clients do not cut it. A long non-streaming request sends nothing until the whole answer is ready, and some clients and proxies give up on an idle connection long before 10 minutes. Set your client timeout to at least 10 minutes.

Error body

Errors use the error shape of the format you called, so the official SDKs raise their normal error types.

On /v1/chat/completions and /v1/models (OpenAI style):

{
  "error": {
    "message": "Insufficient balance. Top up your AI balance to continue.",
    "type": "billing_error",
    "code": "insufficient_balance"
  }
}

On /v1/messages and /v1/messages/count_tokens (Anthropic style):

{
  "type": "error",
  "error": {
    "type": "billing_error",
    "message": "Insufficient balance. Top up your AI balance to continue."
  }
}

The Anthropic shape has no code. Branch on the HTTP status and error.type, and on error.code in the OpenAI shape. The type follows the status:

Statustype
400invalid_request_error
401authentication_error
402billing_error
403permission_error
404, 410not_found_error
413request_too_large
429rate_limit_error
any otherapi_error

Every response from /v1/chat/completions and /v1/messages, errors included (except 401), carries an x-request-id header. Include it when you contact support.

Errors in a stream

When a streaming request is waiting for a slow model, the gateway has already answered 200 and is sending keep-alive comments. If the model then fails, the status can no longer change, so the error arrives as the last event of the stream:

OpenAI style:

data: {"error":{"message":"The AI provider is unreachable. Please retry.","type":"api_error","code":"upstream_unreachable"}}

data: [DONE]

Anthropic style:

event: error
data: {"type":"error","error":{"type":"api_error","message":"The AI provider is unreachable. Please retry."}}

Failures in the first seconds, before the gateway answers, come back as a normal error response with the real status.

If a stream breaks in the middle of the answer, the connection closes without the usual end (data: [DONE], or message_stop). Treat a stream that ends without it as failed.

Error codes

StatusCodeMeaningWhat to do
400invalid_requestThe body is not valid JSON, not a JSON object, has no model, or the model rejected the parameters (for example the message format or max_tokens).Fix the request. Do not retry as is.
400unsupported_formatThe model is not available in the format you called. The message names the right endpoint.Call the other endpoint.
401missing_api_keyNo key in Authorization or x-api-key.Send the key.
401invalid_api_keyUnknown or revoked key.Use a valid key. Do not retry.
401expired_api_keyThe key is past its expiry.Create a new key.
402insufficient_balanceYour available AI balance cannot cover the request's hold.Top up, turn on auto top-up, or lower the output cap. Do not retry in a loop.
403key_spend_limit_reachedThe key reached its monthly spend limit.Wait for next month or use another key.
404model_not_foundUnknown model, switched off, or not in this key's allowlist.Pick an id from GET /v1/models.
404not_foundUnknown endpoint, usually a wrong base URL.Use https://ai.helipod.io/v1 for OpenAI clients and https://ai.helipod.io for Anthropic clients.
404, 413, 422invalid_requestThe model refused the request with this status (for example the prompt is too long for it).Fix the request.
410model_retiredThe model was retired. The message names the replacement.Switch model.
413request_too_largeThe body is over 8 MB.Send less, or send images by URL.
429rate_limitedA per-minute limit (key or account), or the model is busy.Retry with backoff.
429too_many_concurrent_requestsToo many requests in progress for your account.Wait for some to finish, then retry.
500internal_errorUnexpected error in the gateway.Retry with backoff.
502upstream_errorThe model returned an error.Retry with backoff.
502upstream_unreachableThe model could not be reached or did not answer in time.Retry with backoff.
502upstream_auth_errorThe model is temporarily unavailable.Retry after a short wait.
503upstream_unavailableThe AI service is temporarily unavailable.Retry later, or try another model.
503model_unavailableThis model is temporarily unavailable.Try another model.
503server_busyThe gateway is busy. Sent with retry-after: 1.Retry after the given seconds.
503pricing_unavailablePrices could not be loaded.Retry shortly.
503service_unavailableThe model cannot be served right now.Retry later, or try another model.

Errors returned as an HTTP status (any 4xx or 5xx) are never charged. If a stream breaks after the model has started writing, what was generated up to then is charged, like a cancelled stream.

Retries

  • Retry: 429, 500, 502, 503. Use exponential backoff with jitter (for example 1 s, 2 s, 4 s, up to about 30 s) and a limit on attempts. Honour retry-after when it is present. The official OpenAI and Anthropic SDKs already retry these by default.
  • Do not retry unchanged: 400, 401, 403, 404, 410, 413. Fix the request, the key or the model first.
  • 402: stop and top up. Retrying only repeats the refusal.
  • Fall back: for model_unavailable, upstream_unavailable and repeated 5xx on one model, a second model from GET /v1/models keeps your app answering.

A retried request is a new request and is billed on its own if it succeeds. A failed attempt costs nothing.

On this page