CheapAI

Документация

Всё, что нужно для подключения CheapAI к вашим инструментам — гайды для популярных агентов, справочник API, FAQ.

Base URL

Адреса два, и отличаются они ровно одним: стоит ли перед ними CDN. Всё остальное — ключи, модели, цены, формат запроса — одинаковое.

Основной — за CDN
https://cheapai.io/v1
Прямой — без CDN
https://api.cheapai.io/v1
Прямой адрес нужен там, где запрос может долго молчать до первого токена — reasoning-модели на большом промпте, агентские прогоны. CDN рвёт соединение, которое около двух минут не отдало ни байта, и клиент получает 524, хотя ответ уже шёл. У прямого адреса такого предела нет. Он же выручает там, где недоступен сам CDN. Во всех остальных случаях лучше основной: быстрее маршрут и защита от атак.

Единственное исключение из правила про /v1 — Claude Code: он дописывает путь сам, поэтому ему указывают https://api.cheapai.io (или https://cheapai.io) без суффикса.

Аутентификация

Каждый запрос к /v1/* требует bearer-токен (для OpenAI-совместимых эндпоинтов) или заголовок x-api-key (для Anthropic). Один и тот же ключ работает в обоих случаях — это строка из раздела «Ключи», начинающаяся с sk-.

bash
# OpenAI-style
Authorization: Bearer sk-...

# Anthropic-style
x-api-key: sk-...
POST/v1/chat/completions

OpenAI-совместимый Chat Completions. Работает со всеми моделями каталога (Claude, GPT, Gemini, …). Стриминг через stream: true.

bash
curl https://cheapai.io/v1/chat/completions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4-6",
    "messages": [
      {"role": "user", "content": "Hi!"}
    ]
  }'
javascript
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.CHEAPAI_KEY,
  baseURL: "https://cheapai.io/v1",
});

const res = await client.chat.completions.create({
  model: "claude-sonnet-4-6",
  messages: [{ role: "user", content: "Hi!" }],
});
console.log(res.choices[0].message);
Структура ответа
{
  "id": "chatcmpl-...",
  "object": "chat.completion",
  "model": "claude-sonnet-4-6",
  "choices": [{
    "index": 0,
    "message": { "role": "assistant", "content": "..." },
    "finish_reason": "stop"
  }],
  "usage": {
    "prompt_tokens": 10,
    "completion_tokens": 42,
    "total_tokens": 52
  }
}
POST/v1/messages

Anthropic-нативный Messages API. Используйте для Claude-моделей, когда нужны extended thinking, нативные tool_use блоки, prompt caching или любые Claude-специфичные параметры.

bash
curl https://cheapai.io/v1/messages \
  -H "x-api-key: YOUR_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4-6",
    "max_tokens": 1024,
    "messages": [
      {"role": "user", "content": "Hi!"}
    ]
  }'
javascript
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic({
  apiKey: process.env.CHEAPAI_KEY,
  baseURL: "https://cheapai.io",
});

const res = await client.messages.create({
  model: "claude-sonnet-4-6",
  max_tokens: 1024,
  messages: [{ role: "user", content: "Hi!" }],
});
console.log(res.content);
Структура ответа
{
  "id": "msg_...",
  "type": "message",
  "role": "assistant",
  "content": [{ "type": "text", "text": "..." }],
  "model": "claude-sonnet-4-6",
  "stop_reason": "end_turn",
  "usage": {
    "input_tokens": 10,
    "output_tokens": 42,
    "cache_read_input_tokens": 0,
    "cache_creation_input_tokens": 0
  }
}
GET/v1/models

Список моделей, доступных под вашим ключом (envelope в стиле OpenAI).

bash
curl https://cheapai.io/v1/models \
  -H "Authorization: Bearer YOUR_API_KEY"
POST/v1/images/generations

Генерация картинок. Списывается за вызов, а не за токены — цена указана на странице моделей.

bash
curl https://cheapai.io/v1/images/generations \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "grok-imagine-image",
    "prompt": "a lighthouse at dusk, long exposure",
    "n": 1
  }'

Ответ — {"data":[{"url":…}]} либо b64_json, в зависимости от модели. Лишние параметры, которые шлют некоторые SDK (size, quality, style), принимаются и игнорируются.

Только текст → картинка. grok-imagine полностью игнорирует входное изображение: он не отредактирует и не перерисует присланное, а сгенерирует новое по промпту. Чтобы изменить существующую картинку, берите gemini-3.1-flash-image-preview через /v1/chat/completions, передав изображение частью мультимодального сообщения — вход сохраняется. Эндпоинт /v1/images/edits не поддерживается.
POST/v1beta/models/{model}:generateContent

Нативный Gemini API. Нужен для grounding через google_search — в OpenAI-совместимом пути аналога нет.

bash
curl https://cheapai.io/v1beta/models/gemini-3.1-pro-high:generateContent \
  -H "x-goog-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contents": [{"parts": [{"text": "What changed in the news today?"}]}],
    "tools": [{"google_search": {}}]
  }'

Аутентификация здесь через x-goog-api-key, как ждут Google-SDK — ключ тот же, что и везде. Стриминг — :streamGenerateContent. У ответов с grounding приходит блок groundingMetadata со списком источников.

Если сконвертировать этот tool в OpenAI-шные function_declarations, grounding отваливается — ради этого эндпоинт и существует отдельно. Если нужен просто чат, Gemini-модели прекрасно работают и через /v1/chat/completions.
GET/v1/dashboard/billing/subscription

Баланс и расход в OpenAI-совместимом формате — готовые инструменты читают его без переделок.

bash
# всего доступно (остаток + уже потрачено), USD
curl https://cheapai.io/v1/dashboard/billing/subscription \
  -H "Authorization: Bearer YOUR_API_KEY"
# → {"hard_limit_usd": 148.51, "access_until": 0, …}

# потрачено, в сотых долях доллара
curl https://cheapai.io/v1/dashboard/billing/usage \
  -H "Authorization: Bearer YOUR_API_KEY"
# → {"total_usage": 7639.53}   // = $76.40
hard_limit_usd — это НЕ остаток, а остаток плюс уже потраченное: так устроено поле в исходном формате OpenAI. Остаток считается как hard_limit_usd − total_usage / 100. В примере выше: 148.51 − 76.40 = $72.11.

Стриминг

Передайте "stream": true в теле запроса и ответ придёт server-sent-event потоком. Для /v1/chat/completions формат — OpenAI SSE (чанки data: {…}, терминатор data: [DONE]). Для /v1/messages формат — Anthropic SSE (типизированные события: message_start, content_block_delta, message_stop).

Ошибки

Ошибки следуют формату upstream-провайдера. HTTP-код отражает класс сбоя.

HTTPЗначение
400Неверный запрос — модель, параметры, схема.
401Нет ключа или ключ невалидный.
402Баланса не хватает — пополните, чтобы продолжить.
429Лимит upstream-провайдера. Повторите позже.
5xxСбой upstream — запрос автоматически ретраится по fallback-каналам.

Таймауты и стриминг

Единственный жёсткий лимит — сколько модель может молчать ДО начала ответа: около 90 секунд. Keepalive-пинги тут не помогают, они включаются только после ответа провайдера. Cloudflare перед нами режет по тому же признаку на ~125 секундах, так что первым вы упрётесь в лимит шлюза.

Передавайте stream: true — с ним длинный ответ не обрежется. Как только пошли токены, таймаут больше не действует, а на паузах посреди ответа шлюз каждые 60 секунд шлёт keepalive-пинги, поэтому соединение переживает и долгое молчание в середине. Десятиминутная генерация доходит до конца.

Поднимите таймаут и в своём клиенте — многие SDK по умолчанию ставят 30-60 секунд, то есть строже нашего. Для Claude Code это переменные API_TIMEOUT_MS и CLAUDE_STREAM_FIRST_BYTE_TIMEOUT_MS.

Длинное молчание чаще всего дают reasoning-модели: они думают, ничего не отдавая. Если вы регулярно упираетесь в потолок на какой-то из них, более лёгкая модель того же семейства обычно начинает отвечать заметно раньше.