# InferSpeed API: plug your agent in

InferSpeed is a pay-per-token model API with OpenAI- and Anthropic-compatible endpoints, billed from a
prepaid balance. Point your agent at the base URL, give it a key, pick the model. Nothing else changes.

Models on sale and live prices: https://inferspeed.ai/model-plaza (JSON: https://inferspeed.ai/api/v1/public/pricing).

Human-readable version: https://inferspeed.ai/docs

## The settings

| Setting                       | Value                                                                        |
| ----------------------------- | ---------------------------------------------------------------------------- |
| OpenAI-compatible base URL    | `https://api.inferspeed.ai/v1`                                                |
| Anthropic-compatible base URL | `https://api.inferspeed.ai` (clients add `/v1/messages`)                      |
| Authentication                | `Authorization: Bearer $INFERSPEED_API_KEY` (`x-api-key` also works)          |
| Model IDs                     | Every public model, from `GET https://inferspeed.ai/api/v1/public/pricing` (`data.models[].id`) |
| Models per key                | Every live model (`GET /v1/models` with your key lists them)                 |
| Context window                | At least 324,955 prompt tokens accepted                                       |
| Max output tokens             | 131,072 (`max_tokens` above this returns 400; reasoning tokens count toward it) |
| Default limits                | 30 requests per minute and 5 concurrent requests per account (see below)     |

`https://inferspeed.ai/v1` is the same gateway as `https://api.inferspeed.ai/v1`.

The context window and max output above were measured on `glm-5.3`; each model's page on
https://inferspeed.ai/model-plaza shows its own. The examples below use `glm-5.3`: put any public model
ID in its place.

**One key, every model.** An API key calls every live model: `glm-5.3`, `kimi-k3`, `MiniMax-M3` and
the rest of `GET /v1/models`. Put the model ID in the request; nothing else changes. Each request is
billed at the price of the model that served it, and the key's spend limit, rate limits and IP
allowlist apply to every model. A model that is not on sale returns 404 `model_coming_soon` or
`model_not_found` (or is routed, see Model routing below).

`glm-5.3-flash` is the low-cost GLM model ($0.09 input / $0.30 output per 1M tokens at the time of
writing; live prices at https://inferspeed.ai/api/v1/public/pricing). It is served on
`POST /v1/chat/completions` only.

Get a key: sign in at https://inferspeed.ai and open API keys (https://inferspeed.ai/keys).
Keep it in an environment variable; anyone with the key can spend your balance.

```
export INFERSPEED_API_KEY="sk-..."
```

Reasoning models such as `glm-5.3` and `kimi-k3` think before they answer. The reasoning comes back separately (`reasoning_content` in Chat
Completions, a `reasoning` output item in Responses, a `thinking` block in Messages) and counts as
output tokens. Leave room in `max_tokens`: with a very small limit the answer itself can be empty
(`finish_reason: "length"`).

## Endpoints

| Endpoint                    | API shape                                              | Used by                                      |
| --------------------------- | ------------------------------------------------------ | -------------------------------------------- |
| `POST /v1/chat/completions` | OpenAI Chat Completions (stream with `"stream": true`) | OpenAI SDKs, OpenCode, Cline, Continue, curl |
| `POST /v1/responses`        | OpenAI Responses                                       | Codex CLI                                    |
| `POST /v1/messages`         | Anthropic Messages                                     | Claude Code, Claude Agent SDK, Anthropic SDKs |
| `POST /v1/messages/count_tokens` | Anthropic token counting                          | Claude Code, Claude Agent SDK, Anthropic SDKs |
| `GET /v1/models`            | Models your key can call (OpenAI or Anthropic list shape) | Any client                                |

## Model routing

Agents often send a model name of their own (Claude Code and the Claude Agent SDK default to `claude-*`
names, Codex and the OpenAI SDKs to `gpt-*` names). A request for a model that is not available on
your key (not on sale yet, or a name no live model answers to) is routed to an
available model instead of failing: `claude-*`, `gpt-*`, `codex-*`, `o*`, `gemini-*` and `grok-*`
names go to `glm-5.3`, and small `gpt-*-mini` / `gpt-*-nano` names on
`/v1/chat/completions` go to `glm-5.3-flash`.

- The response says which model served it: the `model` field and the `X-Served-Model` header (the
  name you sent is in `X-Model-Routed-From`).
- You are billed at the price of the model that served the request. Your usage lists the request
  under that model, with the name you sent shown as "Requested".
- A model that is available on your key is always served as written.
- Want an error instead? Send `X-Model-Strict: 1`: an unavailable model is then never routed and
  returns an error (404 `model_coming_soon` or `model_not_found`, or 400 `model_not_available`).

If a model is temporarily unavailable (its upstream fails or is too slow to start answering), the
request may be served by an equivalent model instead, before any output reaches you. The response
says so: the `model` field and `X-Served-Model` name the model that served it, and
`X-Model-Failover: 1` is set. You are never billed more than the price of the model you requested.
Output that has started streaming is never switched to another model. `X-Model-Strict: 1` turns
this off too.

Set the model explicitly (the examples below do) so you know what you get.

## Connect your agent

### Codex CLI

Uses the OpenAI Responses endpoint. Add to `~/.codex/config.toml`, export the key, run `codex`.
Codex may print a warning that it has no metadata for `glm-5.3`; it still works.

Codex sends `wire_api = "responses"` only (recent Codex versions no longer support `"chat"`). Without
`model = ...` Codex asks for its default `gpt-*` model, which is routed to `glm-5.3` (see Model routing).

Verified on 2026-10-14 with Codex CLI 0.162.1 (`npm i -g @openai/codex@0.162.1`) and this exact
config against `https://api.inferspeed.ai`: shell commands and `apply_patch` edits, a three-turn
session (`codex exec resume --last`) and a 17-minute build-and-test task (55 tests written and
passing). In scripts, run `codex exec "..." < /dev/null`: when stdin is not a terminal,
`codex exec` waits for more input.

```
model = "glm-5.3"
model_provider = "inferspeed"

[model_providers.inferspeed]
name = "InferSpeed"
base_url = "https://api.inferspeed.ai/v1"
wire_api = "responses"
env_key = "INFERSPEED_API_KEY"

[tools]
web_search = false  # hosted tools are not executed by the gateway

# then:  export INFERSPEED_API_KEY=<your key>  &&  codex
```

### Claude Code

Uses the Anthropic Messages endpoint. Set these in your shell, then run `claude`.

```
export ANTHROPIC_BASE_URL="https://api.inferspeed.ai"
export ANTHROPIC_AUTH_TOKEN="$INFERSPEED_API_KEY"
export ANTHROPIC_MODEL="glm-5.3"
export ANTHROPIC_DEFAULT_OPUS_MODEL="glm-5.3"
export ANTHROPIC_DEFAULT_SONNET_MODEL="glm-5.3"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="glm-5.3"
export ANTHROPIC_DEFAULT_FABLE_MODEL="glm-5.3"
export CLAUDE_CODE_SUBAGENT_MODEL="glm-5.3"
export CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1
claude
```

`ANTHROPIC_DEFAULT_HAIKU_MODEL` is the small fast model Claude Code uses for background calls
(titles, summaries); `ANTHROPIC_SMALL_FAST_MODEL` is its older name and still read. To use
Kimi, put `kimi-k3` in place of `glm-5.3` (the same key works). Keep `glm-5.3` (not `glm-5.3-flash`) for every
Claude Code variable: `glm-5.3-flash` is served on `/v1/chat/completions` only.

Responses and tool use work on `https://api.inferspeed.ai`, including the `"role": "system"`
messages that recent Claude Code versions send inside `messages`.

Verified on 2026-10-14 with Claude Code 2.1.296 and exactly these variables (also as written by
`setup.sh claude`): Bash, Read, Write and Edit tool calls, a three-turn session (`claude -p` then
`--continue`) and a seven-minute task whose longest single response streamed for 224 seconds.
Every response ended with `message_stop`. Keep the model variables: without them Claude Code asks for
its built-in `claude-*` model names, which are routed to `glm-5.3` (see Model routing) but show up
under the `claude-*` name in Claude Code's own cost display. In `-p` mode Claude Code may print
`unrecognized_model` for `glm-5.3` on stderr; it still works.

Re-verified on 2026-10-18 with Claude Code 2.1.302 (`claude -p ... --output-format json`), with and
without the model variables, with `ANTHROPIC_AUTH_TOKEN` and with `ANTHROPIC_API_KEY`.

### Claude Agent SDK

The Claude Agent SDK runs Claude Code underneath, so it takes the same variables. Pass them in
`env` (they are not read from `~/.claude/settings.json` unless you load settings).

TypeScript (`npm i @anthropic-ai/claude-agent-sdk`):

```
import { query } from "@anthropic-ai/claude-agent-sdk";

const model = "glm-5.3";
for await (const msg of query({
  prompt: "List the files in this directory.",
  options: {
    env: {
      ...process.env,
      ANTHROPIC_BASE_URL: "https://api.inferspeed.ai",
      ANTHROPIC_AUTH_TOKEN: process.env.INFERSPEED_API_KEY,
      ANTHROPIC_MODEL: model,
      ANTHROPIC_DEFAULT_OPUS_MODEL: model,
      ANTHROPIC_DEFAULT_SONNET_MODEL: model,
      ANTHROPIC_DEFAULT_HAIKU_MODEL: model,
      ANTHROPIC_DEFAULT_FABLE_MODEL: model,
      CLAUDE_CODE_SUBAGENT_MODEL: model,
      CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: "1",
    },
  },
})) {
  if (msg.type === "result") console.log(msg.result);
}
```

Python (`pip install claude-agent-sdk`):

```
import asyncio, os
from claude_agent_sdk import ClaudeAgentOptions, ResultMessage, query

model = "glm-5.3"
env = {
    "ANTHROPIC_BASE_URL": "https://api.inferspeed.ai",
    "ANTHROPIC_AUTH_TOKEN": os.environ["INFERSPEED_API_KEY"],
    "ANTHROPIC_MODEL": model,
    "ANTHROPIC_DEFAULT_OPUS_MODEL": model,
    "ANTHROPIC_DEFAULT_SONNET_MODEL": model,
    "ANTHROPIC_DEFAULT_HAIKU_MODEL": model,
    "ANTHROPIC_DEFAULT_FABLE_MODEL": model,
    "CLAUDE_CODE_SUBAGENT_MODEL": model,
    "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1",
}

async def main():
    async for msg in query(prompt="List the files in this directory.", options=ClaudeAgentOptions(env=env)):
        if isinstance(msg, ResultMessage):
            print(msg.result)

asyncio.run(main())
```

Tool calls (built-in tools and your own MCP tools), streaming, `count_tokens` and the `anthropic-beta`
headers the SDK sends all work. Verified on 2026-10-18 with `@anthropic-ai/claude-agent-sdk` 0.3.302
and `claude-agent-sdk` 0.2.168 (Python), each running a query that calls an MCP tool.

### OpenAI Agents SDK

Point the SDK's OpenAI client at InferSpeed and pick the model. Both the Responses and the Chat
Completions model classes work, including function tools.

```
# pip install openai-agents
import asyncio, os
from openai import AsyncOpenAI
from agents import Agent, OpenAIResponsesModel, Runner, function_tool, set_tracing_disabled

set_tracing_disabled(True)  # traces go to OpenAI otherwise, with a key InferSpeed does not issue
client = AsyncOpenAI(base_url="https://api.inferspeed.ai/v1", api_key=os.environ["INFERSPEED_API_KEY"])

@function_tool
def get_time() -> str:
    """Returns the current time."""
    return "12:00"

agent = Agent(name="assistant", model=OpenAIResponsesModel(model="glm-5.3", openai_client=client), tools=[get_time])
print(asyncio.run(Runner.run(agent, "What time is it?")).final_output)
```

Use `OpenAIChatCompletionsModel` in place of `OpenAIResponsesModel` for `/v1/chat/completions`.
Verified on 2026-10-18 with `openai-agents` 0.24.0.

### CC Switch

[CC Switch](https://github.com/farion1231/cc-switch) can hold InferSpeed as a provider for Claude
Code and Codex. We have not yet run CC Switch itself against InferSpeed; the values below are the
ones Claude Code and Codex were verified with directly.

| CC Switch field                   | Claude Code                | Codex                         |
| --------------------------------- | -------------------------- | ----------------------------- |
| Endpoint                          | `https://api.inferspeed.ai` | `https://api.inferspeed.ai/v1` |
| API key                           | your InferSpeed key         | your InferSpeed key            |
| API format                        | Anthropic (default)        | OpenAI Responses (default)    |
| Model                             | `glm-5.3`                  | `glm-5.3`                     |
| Haiku / Sonnet / Opus model       | `glm-5.3` each             | not used                      |

Or import Claude Code with a deep link (CC Switch 4.0.10 or later). Put your key in place of
`<your key>` (URL-encoded) and open the link on the computer that runs CC Switch; it shows a
confirmation dialog before it changes anything. Keep the finished link private: it contains your
key. The `config` value adds `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1`.

```
ccswitch://v1/import?resource=provider&app=claude&name=InferSpeed&endpoint=https%3A%2F%2Fapi.inferspeed.ai&apiKey=<your key>&model=glm-5.3&haikuModel=glm-5.3&sonnetModel=glm-5.3&opusModel=glm-5.3&configFormat=json&config=eyJlbnYiOnsiQ0xBVURFX0NPREVfRElTQUJMRV9OT05FU1NFTlRJQUxfVFJBRkZJQyI6IjEifX0%3D
```

For Codex, CC Switch writes its own template (`model_reasoning_effort = "high"`,
`disable_response_storage = true`, `requires_openai_auth = true`, key in `auth.json`), which is
not the config verified above. For the verified Codex setup, use the `config.toml` block in the
Codex CLI section instead of a CC Switch provider.

The balance on the CC Switch card comes from `GET https://api.inferspeed.ai/v1/usage` with your key as
`Authorization: Bearer`; pick CC Switch's built-in usage template that reads that endpoint, no custom script needed.

### OpenCode

Uses the OpenAI Chat Completions endpoint. Add a provider to `opencode.json` (project) or
`~/.config/opencode/opencode.json`, export the key, then pick `inferspeed/glm-5.3`
(`opencode run -m inferspeed/glm-5.3 "..."`).

```
{
  "$schema": "https://opencode.ai/config.json",
  "provider": {
    "inferspeed": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "InferSpeed",
      "options": {
        "baseURL": "https://api.inferspeed.ai/v1",
        "apiKey": "{env:INFERSPEED_API_KEY}"
      },
      "models": {
        "glm-5.3": {
          "name": "glm-5.3"
        }
      }
    }
  }
}
```

### OpenClaw

Uses the OpenAI Chat Completions endpoint. OpenClaw reads `~/.openclaw/openclaw.json` (JSON5). Add a
provider and make it the default model, merging with what is already there, then run
`openclaw doctor` to check the file. This block follows OpenClaw's configuration docs
(https://docs.openclaw.ai/gateway/configuration). OpenClaw substitutes `${INFERSPEED_API_KEY}` from
the environment when it loads the file, so the key is not written into it. Set
`OPENCLAW_CONFIG_PATH` if your config lives elsewhere.

Last verified: 2026-10-16, field by field against OpenClaw's custom-provider reference
(https://docs.openclaw.ai/gateway/config-tools/custom-providers: `models.mode` `merge`,
`providers.<id>.baseUrl` / `apiKey` / `api: "openai-completions"` for `/v1/chat/completions`
backends, `models[].id` / `name`) and its environment-variable rules (`${VAR}` substitution).

```
{
  models: {
    mode: "merge",
    providers: {
      inferspeed: {
        baseUrl: "https://api.inferspeed.ai/v1",
        apiKey: "${INFERSPEED_API_KEY}",
        api: "openai-completions",
        models: [{ id: "glm-5.3", name: "glm-5.3" }],
      },
    },
  },
  agents: { defaults: { model: { primary: "inferspeed/glm-5.3" } } },
}
```

### Installer

`setup.sh` writes the Claude Code, Codex CLI or OpenCode config shown above (for OpenClaw it only
prints the block). It reads the key from `INFERSPEED_API_KEY` and never takes it as an argument,
prints the one file it will change with a diff (secrets shown as `<hidden>`), copies the old file
to `<file>.bak-<timestamp>`, writes, then checks the key against `GET /v1/models`. `--dry-run`
prints and writes nothing. `--model <id>` picks the model; without it the installer uses the first
model your key can call (`GET /v1/models`). Read it first: https://inferspeed.ai/setup.sh

```
curl -fsSL https://inferspeed.ai/setup.sh | sh -s -- codex --dry-run
curl -fsSL https://inferspeed.ai/setup.sh | sh -s -- codex
curl -fsSL https://inferspeed.ai/setup.sh | sh -s -- codex --model kimi-k3
```

For Claude Code it writes the variables above into the `env` block of `~/.claude/settings.json`,
which then holds the key (written with mode 600). For an existing Codex `config.toml` it appends a
`inferspeed` provider and profile and leaves your other settings alone; run `codex --profile inferspeed`.

### One-click config scripts

One open-source script per tool, under https://inferspeed.ai/install/. Each reads the key only from
`INFERSPEED_API_KEY`, never takes it as an argument and never prints it, backs up the file it
changes (`<file>.bak-<timestamp>`), changes nothing when run again with the same options, sends
nothing over the network (no telemetry), and ends by printing a `curl` command that checks your
key. The key is never written to disk unless you pass `--persist` (PowerShell: `-Persist`), which
prints a warning and writes the file owner-only (mode 600; on Windows an ACL that grants only your
account). After you switch back from `--persist`, the script lists the backups that still hold the
key; `--purge-backups` (PowerShell: `-PurgeBackups`) deletes them. `--model <id>` picks the model
(default `glm-5.3`); `--dry-run` prints the change and writes nothing.

```
curl -fsSL https://inferspeed.ai/install/codex.sh | sh -s -- --dry-run
curl -fsSL https://inferspeed.ai/install/codex.sh | sh
curl -fsSL https://inferspeed.ai/install/claude-code.sh | sh
curl -fsSL https://inferspeed.ai/install/opencode.sh | sh
curl -fsSL https://inferspeed.ai/install/openclaw.sh | sh -s -- --model kimi-k3
```

Windows PowerShell (Codex CLI and Claude Code):

```
irm https://inferspeed.ai/install/codex.ps1 | iex
irm https://inferspeed.ai/install/claude-code.ps1 | iex
& ([scriptblock]::Create((irm https://inferspeed.ai/install/claude-code.ps1))) -Model kimi-k3 -DryRun
```

What each one writes:

- `codex.sh` / `codex.ps1`: the Codex CLI block above in `~/.codex/config.toml`. An existing file
  keeps its lines and gets a marked `inferspeed` provider and profile block (`codex --profile
  inferspeed`); re-running either script replaces only that block. Codex reads the key from
  `INFERSPEED_API_KEY`.
- `claude-code.sh` / `claude-code.ps1`: the Claude Code variables above in the `env` block of
  `~/.claude/settings.json`, plus `"apiKeyHelper": "printf %s \"$INFERSPEED_API_KEY\""`, so the key
  comes from your environment each time Claude Code starts. `--persist` writes
  `ANTHROPIC_AUTH_TOKEN` instead.
- `opencode.sh`: the OpenCode provider above in `~/.config/opencode/opencode.json`, and
  `"model": "inferspeed/<id>"` as the default. Models you added to the `inferspeed` provider are kept.
- `openclaw.sh`: the OpenClaw block above merged into `~/.openclaw/openclaw.json` when that file is
  plain JSON (models you added to the `inferspeed` provider are kept); a JSON5 file (comments,
  unquoted keys) is left untouched and the block is printed.

### Cline, Continue and other OpenAI-compatible tools

Choose the "OpenAI Compatible" provider (the name varies by tool) and fill in three fields. Field
names differ between tools.

```
Provider:  OpenAI Compatible
Base URL:  https://api.inferspeed.ai/v1
API key:   <your InferSpeed key>
Model ID:  glm-5.3
```

## Call it from code

### curl (OpenAI)

```
curl https://api.inferspeed.ai/v1/chat/completions \
  -H "Authorization: Bearer $INFERSPEED_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "glm-5.3",
    "messages": [{"role": "user", "content": "Say hello in one sentence."}]
  }'
```

### Python (OpenAI)

```
# pip install openai
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.inferspeed.ai/v1",
    api_key=os.environ["INFERSPEED_API_KEY"],
)

resp = client.chat.completions.create(
    model="glm-5.3",
    messages=[{"role": "user", "content": "Say hello in one sentence."}],
)
print(resp.choices[0].message.content)
```

### Python (Anthropic)

```
# pip install anthropic
import os
import anthropic

client = anthropic.Anthropic(
    base_url="https://api.inferspeed.ai",
    api_key=os.environ["INFERSPEED_API_KEY"],
)

msg = client.messages.create(
    model="glm-5.3",
    max_tokens=512,
    messages=[{"role": "user", "content": "Say hello in one sentence."}],
)
print(next(block.text for block in msg.content if block.type == "text"))
```

## Errors and retries

Branch on the HTTP status and the top-level `code`, not on the message text (wording is not stable).
Every error body has a top-level `code` and `message` on every endpoint. OpenAI-compatible endpoints
also carry an OpenAI-style `error` object (`type`, `code`, `message`, `param`), which OpenAI SDKs
read; `/v1/messages` carries `"type": "error"` and an Anthropic-style `error` object (`type`,
`message`). Every `error` object has a `docs_url`; 401s add `keys_url`, unknown models `models_url`,
balance errors `topup_url`.

```
HTTP/1.1 401 Unauthorized   (POST /v1/chat/completions)
{"code": "INVALID_API_KEY", "message": "Invalid API key", "keys_url": "https://inferspeed.ai/keys",
 "error": {"type": "invalid_request_error", "code": "invalid_api_key", "param": null,
           "message": "Invalid API key. Send your API key as ...",
           "docs_url": "https://inferspeed.ai/developers.md#errors-and-retries",
           "keys_url": "https://inferspeed.ai/keys"}}
```

`code` is the top-level field; `error.code` is the value on OpenAI-compatible endpoints when it differs.

| Status | `code` (`error.code`) | Meaning | Retry? |
| ------ | --------------------- | ------- | ------ |
| 400 | `invalid_request_error` | The body is invalid or does not match the endpoint. | No. Fix the request. |
| 401 | `API_KEY_REQUIRED`, `INVALID_API_KEY` (`invalid_api_key`) | Key missing or not recognised. | No. Ask your human. |
| 401 | `API_KEY_DISABLED`, `USER_INACTIVE` (`api_key_disabled`, `user_inactive`) | Key disabled or account not active. | No. Ask your human. |
| 403 | `INSUFFICIENT_BALANCE` (`insufficient_quota`), `permission_denied` (`error.type` `billing_error`) | Prepaid balance is used up. `INSUFFICIENT_BALANCE` has `topup_url` and `topup_api`; `permission_denied` (a billing check failed after the request was admitted, e.g. the balance ran out mid-wait or a subscription limit was hit) has neither. | No. Top up first. |
| 403 | `API_KEY_QUOTA_EXHAUSTED` (`insufficient_quota`) | The spend cap set on this key is reached (see below). | No. Raise the cap. |
| 403 | `API_KEY_EXPIRED`, `ACCESS_DENIED` | Key expired, or IP not allowed for this key. | No. Ask your human. |
| 404 | `model_not_found` | The model is not available to this key. `GET /v1/models` lists the ones it can use. | No. Check the model. |
| 404 | `model_coming_soon` | The model is not on sale yet and the request was sent with `X-Model-Strict: 1` (without it, the request is routed; see Model routing). | No. Pick a listed model. |
| 429 | `rate_limit_exceeded` | Requests-per-minute limit, or balance held by your other in-flight requests. `Retry-After` is set. | Yes, after Retry-After. |
| 429 | `rate_limit_exceeded`, `USAGE_LIMIT_EXCEEDED` | A key spend cap (5-hour, daily, 7-day) or an account or subscription allowance (daily, weekly, monthly) is used up. These carry `x-should-retry: false`; `Retry-After`, when set, is the time until the window resets. | Not until the window resets or the cap is raised. |
| 429 | `gateway_concurrency_limit`, `gateway_queue_full` | Too many of your requests in flight. | Yes, with backoff. |
| 429 | `rate_limit_exceeded` (`error.type` `rate_limit_error`) | The model is at capacity right now. | Yes, with backoff. |
| 503 | `service_unavailable`, `API_KEY_AUTH_OVERLOADED` | No capacity is free for this model, or billing or key checks are briefly unavailable. | Yes, with backoff. |
| 500 / 502 / 504 | `api_error` | The request failed or timed out. | Yes, with backoff. |
| 400 | `model_not_available` | The model is not sold on this key. `available_models` lists the ones it can call. | No. Pick a listed model. |
| 403 | `GROUP_NOT_ALLOWED` | The key is not allowed for this request. | No. Ask your human. |
| 524 | none (the body is not JSON) | A non-streaming response took longer than about 100 seconds and was cut off. | Yes, with `"stream": true`. |

Long responses: send `"stream": true` for anything that can take more than a minute (long
outputs, a high `max_tokens`, agent turns over large contexts). A streaming response receives
keepalives while the model works, so it is not cut off while waiting. A non-streaming response must
arrive in full within about 100 seconds end to end at the edge; past that the connection is closed
with HTTP 524 and a non-JSON body. Retrying the same non-streaming request usually runs into the
same limit, so retry it once with `"stream": true` (or with a lower `max_tokens`) instead. Set your
client's request timeout above 100 seconds so the 524 reaches you rather than a local timeout.

Key spend cap: the cap is checked before each request. A request that starts under the cap
runs to completion and is billed in full, so total spend can end above the cap by at most one
request's cost (for example $0.104 on a $0.10 cap). The next request is then rejected with 403
`API_KEY_QUOTA_EXHAUSTED`. Raise or remove the cap on the key in the console to continue.

Backoff: a 429 with `x-should-retry: false` means a window or spend cap is used up (the OpenAI
and Anthropic SDKs honour this header and do not retry). Do not retry; wait for the window to reset
(`Retry-After`, when set, is the seconds until then) or raise the cap. Retry with backoff only for
5xx and for other 429s: wait `Retry-After` seconds when present, otherwise 1, 2, 4 … up to 30
seconds with jitter. The 403 balance and spend-cap errors never clear by retrying. For support,
quote the `x-request-id` response header.

Limits for new accounts: 30 requests per minute and 5 concurrent requests, across all keys of the
account. A request over the concurrency limit waits briefly for a free slot before it gets a 429.
Details: https://inferspeed.ai/rate-limits

## Prices and balance

- Prices, USD per 1M tokens, no key needed: `GET https://inferspeed.ai/api/v1/public/pricing`
  (`data.models[]`: `id`, `price` and `list_price` with `input`, `output`, `cache_read`,
  `cache_write`).
- Balance and usage for your key: `GET https://api.inferspeed.ai/v1/usage` (`remaining`, `unit`,
  `usage.today` / `usage.total` with tokens and `actual_cost`).
- Top up from code or an agent, with the same key: `POST https://inferspeed.ai/api/v1/billing/topup`
  with `{"amount_usd": 10}` (optional `Idempotency-Key` header) returns `data.payment_url` (a
  Stripe page: card, Apple Pay, Google Pay), `data.qr_code_png`, `data.expires_at` and
  `data.status_url`. Give the URL to a person; poll `GET /api/v1/billing/topup/{id}` until
  `status` is `completed`. `GET https://inferspeed.ai/api/v1/billing/balance` returns
  `balance_usd`. Both work at zero balance.

## More

- Agent setup instructions: https://inferspeed.ai/agents.md
- Agent skill: https://inferspeed.ai/skill.md
- Installer: https://inferspeed.ai/setup.sh
- Site index for language models: https://inferspeed.ai/llms.txt
- Models and prices: https://inferspeed.ai/model-plaza
- Status: https://inferspeed.ai/status

