Start with the exact endpoint, model ID, HTTP status, error body, and whether any output arrived. These details usually distinguish a configuration problem from a temporary model failure or an uncertain disconnected request.
The first request fails
| Symptom | Check | Fix |
|---|---|---|
| 401 | Key missing, invalid, revoked, or expired | Verify the server's environment and test the current key. Replace expired or revoked keys. |
| 403 trial message | Account has only trial credit | Add non-trial credit. The trial works in Chat, not the API. |
| 403 model permission | Key has a model allowlist | Use an allowed model or edit the key. |
| 404 | Wrong model ID or route | Copy an exact ID from GET /v1/models and use a documented API path. |
| 400 unsupported field | Client sends fields the endpoint does not implement | Inspect the request body and compatibility guide. Remove or translate the named field. |
| 400 model rejection | Context too large or another model-side request restriction | Shorten the history, lower output needs, and check the selected model's limits. |
| 413 | Serialized body exceeds 12 MB | Reduce messages or image payloads before retrying. |
When setting an OpenAI-style base URL, use https://redrouter.org/v1; the client's request path should produce /v1/chat/completions or /v1/responses exactly once. For Messages, verify that your client's base URL and route compose to /v1/messages. See Migration.
Credit is visible but admission fails
Compare available credit with the request's maximum hold, rather than its likely final cost. A large prompt and high output limit can require a hold larger than the remaining available credit. Other running or unresolved requests may also reserve credit.
Lower the output limit, reduce history, or let other requests settle. A key credit limit can stop one key even when the account has funds. A daily account ceiling is a separate restriction and considers reserved exposure; adding credit alone does not remove it. See Billing and Rate limits.
If a checkout finished but credit is missing, open Credits and check its state. A browser redirect is not proof of verified payment. Avoid making a second purchase solely to resolve a pending first one.
Requests become slow or return 429
Inspect Retry-After and the rate-limit headers. A request-rate limit needs less dispatch per minute; a concurrency limit needs fewer simultaneous generations. Long outputs hold slots longer even when request frequency is low. Read the actual effective limits in Settings; keys and Chat share them.
Bound queues, spread retries with jitter, and avoid retrying at multiple layers. If concurrency remains occupied after your client disconnects, allow time for generation to end and usage to settle. See Production use.
A stream starts and then stops
HTTP 200 does not establish completion. Check for an SSE error, an endpoint-specific terminal event, or an unexpected EOF. Make sure your parser handles events split across network chunks and multiple events in one chunk. Do not stop reading on the first finish reason; terminal usage can arrive later.
Check the application's timeout, reverse proxy buffering, idle timeouts, and response-body consumption. A non-streaming generation has a 110-second total deadline; use streaming for longer work. If a partial stream fails, check Usage before retrying because reported partial output can be charged. Follow the retry decision table.
The answer is incomplete or wrong for the task
| Symptom | Next step |
|---|---|
| Output stops at the token limit | Inspect the finish reason or incomplete status. Increase the output limit within the model's maximum, or reduce the task. |
| Tool call contains invalid arguments | Assemble the whole call, parse and validate it locally, then return a useful tool error or retry under your application's policy. |
| Model generated a malformed tool call | Treat the stopped response as a failed generation; do not execute partial arguments. Inspect Usage and retry if appropriate. |
| JSON parses but violates your schema | Check Structured output support and keep local schema validation. |
| Model cannot use an image | Check the exact model and encoding in Images; an omitted image is replaced with explanatory text. |
| Cache discount is missing | Inspect reported cached-input counts. A stable prefix can help, but requesting caching does not guarantee a cache hit. |
| Reasoning or usage is absent | Check the selected model and Reasoning. An absent reported count is not proof that zero tokens were used. |
Model capabilities vary. Changing only a client-side model alias does not make an unsupported feature available. Use Model selection to choose explicitly.
Usage looks incomplete or inconsistent
Use the request state, cost, and token counts together. In progress is a hold, Awaiting usage needs reconciliation, and Not charged is a released hold. A settled request can have zero cost even when its diagnostic outcome records a failure. Unknown token counts appear as missing values rather than fabricated actual usage.
A complete answer can arrive without reported usage. Keep the answer and inspect its billing outcome instead of retrying just to obtain counts. If a hold cannot be resolved by the configured reconciliation deadline, it is released uncharged. There is no fixed client-visible release duration to infer from the HTTP timeout. See failed-request billing.
Send a useful support report
Email support@redrouter.org with:
- The
x-request-idresponse header, if received, and the UTC time of the attempt. - Endpoint, exact model ID, client/SDK version, and whether streaming was enabled.
- HTTP status and sanitized error body, including
Retry-Afterwhen present. - Whether any output arrived, how the stream ended, and the Usage state or charge you are asking about.
- A minimal request shape or reproduction with sensitive content removed.
Never include API secrets, login links, full payment-card details, wallet secrets, or confidential prompts. If several attempts were made, identify each one so a retry is not confused with its original request.