Developer Documentation

API Documentation

One gateway, three protocols: OpenAI Chat Completions, OpenAI Responses and Anthropic Messages (including Anthropic token counting). Point any OpenAI-compatible SDK or coding agent (Claude Code, Codex CLI, OpenCode…) at this domain, authenticate with one of your API keys, and request any enabled model. All URLs on this page are generated from the host and install path serving it.

Quick start

1 · Create an API key

Sign in, open API Keys and generate a key. It starts with sk- — copy it when it is created, or use Show key on the same page later (revoked keys can no longer be displayed).

2 · Point your client here

Use the base URLs below. OpenAI-style clients need the /v1 suffix; Claude Code and the official Anthropic SDKs use the root URL without it.

3 · Pick a model & call

Choose a Model ID from the catalog at the bottom of this page and send your first request.

# Replace YOUR_API_KEY — the model below is your first enabled model curl https://cheapaapi.com/v1/chat/completions \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "abliterated-hacker", "messages": [{"role": "user", "content": "Hello!"}]}'

Base URL & authentication

These URLs are generated from the host and install path serving this page, so they work unchanged on any host, sub-folder, port or HTTPS setup this application is installed under. Hosts are validated against the operator's allowlist; on an unrecognised host they fall back to localhost.

Client typeBase URL
OpenAI-compatible
OpenAI SDKs, Codex CLI, OpenCode, LangChain, curl, anything speaking /v1/chat/completions
https://cheapaapi.com/v1
Anthropic-compatible
Claude Code and Anthropic SDKs — they append /v1/messages themselves
https://cheapaapi.com

Why two URLs? OpenAI SDKs treat the base URL as a prefix for /chat/completions, so it includes /v1. Claude Code and the official Anthropic SDK append /v1/messages to the base URL themselves, so their base URL must not include /v1. AI SDK's @ai-sdk/anthropic (used by OpenCode) appends only /messages, so its baseURL does include /v1 — see Connect OpenCode.

Authentication

Every endpoint accepts your key as Authorization: Bearer YOUR_API_KEY. Anthropic-style clients may instead send x-api-key: YOUR_API_KEY — both are accepted on every endpoint.

Environment variables

# OpenAI-style clients (Codex CLI, OpenCode, OpenAI SDKs…) OPENAI_BASE_URL=https://cheapaapi.com/v1 OPENAI_API_KEY=YOUR_API_KEY # Anthropic-style clients (Claude Code, Anthropic SDKs — no /v1!) ANTHROPIC_BASE_URL=https://cheapaapi.com ANTHROPIC_API_KEY=YOUR_API_KEY

Connect Claude Code

CheapaAPI exposes an Anthropic Messages-compatible endpoint for Claude Code. Use the base URL without /v1: https://cheapaapi.com — Claude Code adds the Messages path itself.

Temporary setup session only

Windows — PowerShell
$env:ANTHROPIC_BASE_URL = "https://cheapaapi.com" $env:ANTHROPIC_AUTH_TOKEN = "sk-your-api-key" $env:ANTHROPIC_MODEL = "claude-opus-5.5" claude
Windows — Command Prompt
:: no quotes, no spaces around the = set ANTHROPIC_BASE_URL=https://cheapaapi.com set ANTHROPIC_AUTH_TOKEN=sk-your-api-key set ANTHROPIC_MODEL=claude-opus-5.5 claude
macOS / Linux
export ANTHROPIC_BASE_URL="https://cheapaapi.com" export ANTHROPIC_AUTH_TOKEN="sk-your-api-key" export ANTHROPIC_MODEL="claude-opus-5.5" claude

Persistent setup

On Windows, save the variables for your user account, then open a new terminal:

[Environment]::SetEnvironmentVariable("ANTHROPIC_BASE_URL", "https://cheapaapi.com", "User") [Environment]::SetEnvironmentVariable("ANTHROPIC_AUTH_TOKEN", "sk-your-api-key", "User") [Environment]::SetEnvironmentVariable("ANTHROPIC_MODEL", "claude-opus-5.5", "User")

On macOS or Linux, add the three export lines to ~/.zshrc or ~/.bashrc, then open a new terminal.

Start Claude Code

cd your-project claude
  • ANTHROPIC_MODEL is optional — replace claude-opus-5.5 with any Model ID from the Available models list, or leave it unset and pick models inside Claude Code.
  • ANTHROPIC_API_KEY also works on this gateway — it sends the same key via the x-api-key header.
  • This gateway accepts every enabled model over the Messages endpoint, including OpenAI-compatible ones — the request is converted automatically.
  • Claude Code's pre-flight count_tokens calls are answered locally — no upstream request, no charge (see POST /v1/messages/count_tokens).
  • Verify the connection with /status inside the REPL.

Troubleshooting: 401 → wrong key · 404 / model not found → the ANTHROPIC_MODEL ID is not in your catalog · connection refused → wrong base URL (must be the root, without /v1).

Connect Codex CLI

CheapaAPI supports the Responses API used by Codex CLI. A separate profile keeps your normal Codex settings unchanged.

Create a profile persistent

Edit (or create) your Codex config file and add the profile below:

  • macOS / Linux: ~/.codex/config.toml
  • Windows: %USERPROFILE%\.codex\config.toml
[profiles.cheapaapi] model = "abliterated-hacker" model_provider = "cheapaapi" model_reasoning_effort = "medium" [model_providers.cheapaapi] name = "CheapaAPI" base_url = "https://cheapaapi.com/v1" env_key = "CHEAPAAPI_API_KEY" wire_api = "responses" request_max_retries = 1 stream_max_retries = 1 stream_idle_timeout_ms = 300000

If your config.toml already defines model / model_provider at the top, leave them as they are — the profile only overrides them when you start Codex with --profile.

Set your API key

Windows — PowerShell
$env:CHEAPAAPI_API_KEY = "sk-your-api-key"

Persist for your user account, then reopen the terminal:

[Environment]::SetEnvironmentVariable("CHEAPAAPI_API_KEY", "sk-your-api-key", "User")
macOS / Linux
export CHEAPAAPI_API_KEY="sk-your-api-key"

Add the export line to ~/.zshrc / ~/.bashrc to keep the key across sessions.

Start Codex

codex --profile cheapaapi

To use another CheapaAPI model for one session:

codex --profile cheapaapi --model MODEL_ID
  • The profile calls POST https://cheapaapi.com/v1/responses — see POST /v1/responses for current compatibility.
  • env_key is just a name — it must match the environment variable you set. Keep the key out of the TOML file itself.
  • Verify inside Codex with /status — it shows the active provider, base URL and model.

Connect OpenCode

OpenCode uses two CheapaAPI provider adapters. GPT, Grok and other OpenAI-compatible models use @ai-sdk/openai-compatible. Claude-protocol models must use @ai-sdk/anthropic so OpenCode calls CheapaAPI's Anthropic Messages endpoint.

Create the config persistent

Open or create:

  • macOS / Linux: ~/.config/opencode/opencode.jsonc
  • Windows: %USERPROFILE%\.config\opencode\opencode.jsonc
  • Project-level alternative: an opencode.jsonc in the project root
{ "$schema": "https://opencode.ai/config.json", "provider": { "cheapaapi": { "name": "CheapaAPI", "npm": "@ai-sdk/openai-compatible", "options": { "baseURL": "https://cheapaapi.com/v1", "headers": { "Authorization": "Bearer {env:CHEAPAAPI_API_KEY}" } }, "models": { "abliterated-hacker": { "name": "abliterated-hacker" }, "deepseek-v4-free": { "name": "deepseek-v4-free" }, "deepseek-v4.1-hacker": { "name": "DeepSeek-V4.1-Hacker" }, "ling-3.0": { "name": "ling-3.0-tiny" }, "glm-5.3-hacker": { "name": "glm-5.3-hacker" }, "mimo-v2.6-flash-hacker": { "name": "mimo-v2.6-flash-hacker" } } }, "cheapaapi-anthropic": { "name": "CheapaAPI Anthropic", "npm": "@ai-sdk/anthropic", "options": { "baseURL": "https://cheapaapi.com/v1", "apiKey": "{env:CHEAPAAPI_API_KEY}" }, "models": { "claude-opus-5.5": { "name": "claude-opus-5.5" }, "claude-opus-4.8": { "name": "claude-opus-4.8" }, "claude-fable-5.1": { "name": "claude-fable-5.1" } } } } }

You can replace or extend the lists with IDs from the Available models section below. Keep Claude-protocol models under cheapaapi-anthropic — putting them under the OpenAI-compatible provider produces a Messages endpoint error.

Add your API key

Windows — PowerShell
$env:CHEAPAAPI_API_KEY = "sk-your-api-key"

Persist: [Environment]::SetEnvironmentVariable("CHEAPAAPI_API_KEY", "sk-your-api-key", "User"), then open a new terminal.

macOS / Linux
export CHEAPAAPI_API_KEY="sk-your-api-key"

Add the export line to ~/.zshrc / ~/.bashrc to keep the key across sessions.

Start OpenCode

opencode --model cheapaapi/abliterated-hacker

For Claude-protocol models:

opencode --model cheapaapi-anthropic/claude-opus-5.5

You can also run /models inside OpenCode and select a configured CheapaAPI model.

GET /v1/models

List the models enabled on this gateway with their context capacity, supported parameters and per-1M-token pricing. Requires a valid API key. Clients use the response to size requests before sending them. Listing still works while an account is awaiting email verification, so pre-configured clients can enumerate models before their first generation call.

curl https://cheapaapi.com/v1/models \ -H "Authorization: Bearer YOUR_API_KEY"
{ "object": "list", "data": [ { "id": "abliterated-hacker", "object": "model", "created": 1735689600, "owned_by": "ai-light-proxy", "type": "model", "display_name": "abliterated-hacker", "context_length": 128000, "max_output_tokens": 16384, "supported_parameters": ["temperature", "top_p", "tools", "reasoning_effort"], "pricing": { "currency": "USD", "unit": "1m_tokens", "input": 0.15, "output": 0.6, "cache_read": 0.075, "cache_write": 0, "long_context": { "threshold_input_tokens": 200000, "input": 0.3, "output": 1.2, "cache_read": 0.15, "cache_write": 0 } } } ] }

type and display_name mirror Anthropic's model-list fields (Claude clients read them); context_length, max_output_tokens, supported_parameters and pricing are OpenRouter-style extras. OpenAI SDKs ignore all of them. supported_parameters is null when the model accepts every parameter, max_output_tokens is null when unbounded, and pricing.long_context is present only when the operator configured a long-context tier.

POST /v1/chat/completions

OpenAI Chat Completions format — streaming and non-streaming. Only n=1 is supported; system/developer, user, assistant and tool roles are accepted.

curl https://cheapaapi.com/v1/chat/completions \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "abliterated-hacker", "messages": [ {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Hello!"} ], "stream": false }'

The response is a standard OpenAI chat.completion object including usage with prompt_tokens_details.cached_tokens and completion_tokens_details.reasoning_tokens (reported as 0 when the upstream does not provide them).

Streaming (SSE)

Set "stream": true. Chunks are forwarded to you incrementally as the upstream provider generates them — nothing is buffered server-side. The stream ends with a usage chunk and data: [DONE] — usage is always sent, so stream_options.include_usage is not required. The request ID is returned in the X-Request-Id response header.

curl https://cheapaapi.com/v1/chat/completions \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "abliterated-hacker", "messages": [{"role": "user", "content": "Count to 5"}], "stream": true}' # SSE frames: data: {"id":"...","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant","content":""}}]} data: {"id":"...","choices":[{"index":0,"delta":{"content":"1"}}]} data: {"id":"...","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]} data: {"id":"...","choices":[],"usage":{"prompt_tokens":12,"completion_tokens":34,"total_tokens":46,...}} data: [DONE]

Python example

from openai import OpenAI client = OpenAI(base_url="https://cheapaapi.com/v1", api_key="YOUR_API_KEY") stream = client.chat.completions.create( model="abliterated-hacker", messages=[{"role": "user", "content": "Hello!"}], stream=True, ) for chunk in stream: print(chunk.choices[0].delta.content or "", end="")

POST /v1/responses

OpenAI Responses API format (including streaming events like response.output_text.delta). Accepts input as a string or an array of message/function-call items. Top-level instructions is honored as the system prompt. Text and image parts are supported; audio input is not accepted here.

curl https://cheapaapi.com/v1/responses \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "abliterated-hacker", "input": "Tell me a haiku about proxies."}'

POST /v1/messages

Anthropic Messages format for Claude-style clients and agents. Requires max_tokens (1–200000). Authentication uses the same key via x-api-key (sent automatically by Anthropic SDKs) or the standard Bearer header. system, tool_use/tool_result blocks and thinking are supported.

curl https://cheapaapi.com/v1/messages \ -H "x-api-key: YOUR_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "Content-Type: application/json" \ -d '{ "model": "abliterated-hacker", "max_tokens": 1024, "messages": [{"role": "user", "content": "Hello, Claude!"}] }'

Remember: raw curl uses the full path above, but Claude Code and Anthropic SDKs want the base URL without /v1 — see Connect Claude Code.

POST /v1/messages/count_tokens

Anthropic-compatible token counting, used by Claude Code to size a conversation before sending it. The count is estimated by the gateway — no upstream request is made, nothing is billed and no rate-limit quota is used. The body takes the same model and messages shapes as POST /v1/messages; max_tokens is not required.

curl https://cheapaapi.com/v1/messages/count_tokens \ -H "x-api-key: YOUR_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "Content-Type: application/json" \ -d '{"model": "abliterated-hacker", "messages": [{"role": "user", "content": "Hello!"}]}'
{ "input_tokens": 8 }

The count covers the messages plus any tools definitions and ignores max_tokens, so it matches the gateway's own prompt estimate.

Tool / function calling

Send standard OpenAI tools definitions to any model with the tool_calling capability. Tool call deltas are streamed in OpenAI format (tool_calls in delta) and completed tool calls are returned in the message body for non-streaming requests. Anthropic-style tool_use/tool_result blocks are converted automatically on /v1/messages.

{ "model": "abliterated-hacker", "messages": [{ "role": "user", "content": "What is the weather in Paris?" }], "tools": [{ "type": "function", "function": { "name": "get_weather", "description": "Get current weather for a city", "parameters": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"] } } }] }

Images (vision) & audio input

Models with vision accept image input on every protocol. The gateway validates images before forwarding — unsupported input types, malformed images or oversized payloads return a clean 400 without consuming credits.

LimitValue
FormatsPNG, JPEG, WebP, GIF
Max size per image5 MB (decoded)
Max images per request8 via the API · 4 on the dashboard chat
Max total image payload20 MB (decoded)
Remote URLsMust be public https:// URLs (private/loopback hosts are blocked), or use base64 data URLs

OpenAI Chat Completions

{ "model": "abliterated-hacker", "messages": [{ "role": "user", "content": [ { "type": "text", "text": "Describe this image." }, { "type": "image_url", "image_url": { "url": "https://example.com/photo.jpg" } } ] }] }

A base64 data URL works in the same slot: {"type":"image_url","image_url":{"url":"data:image/png;base64,…"}}

OpenAI Responses

{ "model": "abliterated-hacker", "input": [{ "role": "user", "content": [ { "type": "input_text", "text": "Describe this image." }, { "type": "input_image", "image_url": "https://example.com/photo.jpg" } ] }] }

Anthropic Messages

{ "model": "abliterated-hacker", "max_tokens": 1024, "messages": [{ "role": "user", "content": [ { "type": "image", "source": { "type": "base64", "media_type": "image/png", "data": "iVBORw0KGgo..." } }, { "type": "text", "text": "Describe this image." } ] }] }

Audio input

Models whose Inputs include audio accept inline audio on Chat Completions (check the Available models table — most text/vision models do not). Send a base64 payload (no data: prefix) plus its container format:

{ "model": "YOUR_AUDIO_MODEL", "messages": [{ "role": "user", "content": [ { "type": "text", "text": "Transcribe and summarize this clip." }, { "type": "input_audio", "input_audio": { "data": "UklGRiQAAABXQVZF...", "format": "wav" } } ] }] }

Audio is forwarded only to OpenAI-compatible Chat Completions upstreams. /v1/responses does not accept input_audio, and Anthropic-protocol upstreams reject it with 400 unsupported_input — pick a chat-completions channel for audio models. Images, by contrast, are converted for every upstream protocol.

Billing

Images are billed as input tokens — exactly how OpenAI, Anthropic and Google charge for vision. The provider converts each image into input tokens (OpenAI: 512px tiles at 170 tokens each + 85 base; Anthropic ≈ width × height ÷ 750; Gemini: flat ~258) and reports them inside prompt_tokens / input_tokens in the usage. Your account is charged at the model's normal input price for those tokens — no separate image fee. Audio works the same way: it is billed as provider-reported input tokens with no separate fee (pre-authorization estimates each audio clip at roughly 1,600 tokens).

Reasoning models

For models with the reasoning capability the gateway applies a default thinking effort of low automatically — small tasks stay fast and cheap. Any reasoning parameter you send yourself always wins over the default, and the default is skipped when the model's parameter policy does not allow reasoning parameters.

  • Chat Completions: "reasoning_effort": "low" | "medium" | "high" (none, minimal and xhigh are also accepted and forwarded where the upstream supports them). OpenRouter-style "reasoning": {"effort": "..."} is accepted too.
  • Responses: "reasoning": {"effort": "low"}.
  • Anthropic Messages: send "thinking": {"type": "enabled", "budget_tokens": 2048} directly, or just "reasoning_effort": "low" and the gateway maps it to a thinking budget (low → 2048, medium → 8192, high → 16384, xhigh → 32768) that is always kept below your max_tokens. While thinking is enabled, temperature/top_p are dropped (Anthropic rejects them).

Reasoning deltas stream as reasoning_content (chat), reasoning summary items (responses) or thinking blocks (messages), and reasoning tokens are included in usage when the provider reports them.

Context limits & long-context pricing

Each model advertises its real capacity via GET /v1/models (context_length, max_output_tokens). How oversized requests are handled:

  • If the input alone fills the model's context window, the request is rejected up front with 400 context_length_exceeded (OpenAI wording) or prompt is too long (Anthropic wording on /v1/messages) — no credits are consumed. Coding agents treat these codes as a signal to compact their context.
  • If the requested max_tokens exceeds the model's maximum output or the remaining context room, it is capped (not rejected). The response's usage always reflects the tokens actually processed.
  • The token counts we validate are close estimates; if a request still overflows at the provider, the provider's own error is passed back (as an error event on streaming requests) and you are not charged.

Long-context (tiered) pricing

Some providers charge higher per-token rates once a request's input crosses a threshold (e.g. GPT-4.1 above 272K input tokens, Gemini 2.5 Pro above 200K). When an operator configures a threshold for a model, requests whose total input tokens exceed it are billed at the long-context rates, shown in pricing.long_context on GET /v1/models and in your dashboard pricing. Pre-authorization holds use the same tier, so the estimate matches the final charge.

Errors

Errors use OpenAI-compatible JSON (Anthropic shape on /v1/messages) with proper HTTP status codes:

HTTPtypeWhen
400invalid_request_errorMalformed body, unsupported input, context length exceeded
401authentication_errorMissing/invalid/expired API key
402insufficient_quotaNot enough credits for the pre-authorization estimate
403permission_errorEmail address not verified (only when the operator requires verification)
404not_found_errorUnknown or disabled model
413invalid_request_errorRequest body too large (operator limit, default 4 MB)
429rate_limit_error / insufficient_quotaRate limit or spend cap reached; repeated failed key checks (60 per 2 minutes per IP) return auth_rate_limited
500api_errorInternal server error — the hold is released and nothing is charged
502/503api_errorUpstream provider failure (after automatic failover)
503api_errormodel_not_priced — the model has no pricing configured and cannot be billed
{ "error": { "message": "Incorrect API key provided.", "type": "authentication_error", "param": null, "code": "invalid_api_key" } }

Rate limits & billing

Each request is pre-authorized against your credit balance (a hold equal to the estimated cost), then settled with the actual token usage when the response completes. Failed requests are never charged — holds are released automatically. Responses carry an X-Request-Id header you can quote in support requests (every endpoint except a successful GET /v1/models); the same ID appears in your usage history. Request bodies are capped by the operator (max_request_mb, default 4 MB) and larger bodies return 413 before any processing.

Per-key (default 60 req/min) and per-account (default 120 req/min) rate limits apply — a value of 0 means unlimited — along with optional daily/monthly spend caps, all as configured by the operator. The same limits cover the dashboard chat as well as the API.

Available models

Model IDTitleInputsCapabilitiesContextMax out$/1M in/out
abliterated-hacker abliterated-hacker text,image tool_calling,reasoning,web_search 1,048,576 262,144 $1.50 / $3.00
deepseek-v4-free deepseek-v4-free text,image tool_calling,reasoning,web_search 264,000 64,000 $0.00 / $0.00
deepseek-v4.1-hacker DeepSeek-V4.1-Hacker text,image tool_calling,web_search 512,000 128,000 $0.28 / $1.11
ling-3.0 ling-3.0-tiny text tool_calling,web_search 262,144 32,768 $0.02 / $0.07
glm-5.3-hacker glm-5.3-hacker text,image tool_calling,reasoning,web_search 1,048,576 131,072 $1.50 / $2.70
mimo-v2.6-flash-hacker mimo-v2.6-flash-hacker text,image tool_calling,reasoning,web_search 1,048,576 65,536 $0.60 / $1.80
claude-opus-5.5 claude-opus-5.5 text,image tool_calling,reasoning,web_search 1,048,576 131,072 $0.80 / $2.50
claude-opus-4.8 claude-opus-4.8 text,image tool_calling,reasoning,web_search 1,048,576 131,072 $0.80 / $2.50
claude-fable-5.1 claude-fable-5.1 text,image tool_calling,reasoning,web_search 1,048,576 131,072 $0.80 / $2.50
gpt-5.6-sol gpt-5.6-sol text,image tool_calling,reasoning,web_search 1,048,576 131,072 $0.60 / $1.88