For AI agents
Everything an AI agent needs to make its first call, on one page.
This page is the whole bootstrap for a program or AI agent. The same facts are at /llms.txt, and the API is described in /openapi.json.
Every docs page also answers as Markdown: add .md to its URL, or send Accept: text/markdown. All pages in one file: /llms-full.txt.
Facts
| Fact | Value |
|---|---|
| Base URL, OpenAI-compatible | https://api.plaingateway.com/api/v1 (also https://api.plaingateway.com/v1) |
| Base URL, Anthropic SDK | https://api.plaingateway.com/api |
| Auth | Authorization: Bearer <key>, or X-Api-Key: <key> |
| Key format | sk-pg-v1- followed by 64 hex characters |
| Model id format | author/slug, for example openai/gpt-5.6-luna; append :floor (cheapest host first) or :nitro (fastest host first) |
| Model list | GET https://api.plaingateway.com/api/v1/models, no key needed; data[].id is the model id |
| Endpoints | /chat/completions, /completions, /messages, /responses, /models, /models/{author}/{slug}/endpoints, /generation, /credits, /auth/key |
| Health | GET https://api.plaingateway.com/healthz returns {"status": "ok"} or {"status": "degraded"} |
The site host, plaingateway.com, serves no API.
First call
curl https://api.plaingateway.com/api/v1/chat/completions \
-H "Authorization: Bearer $PLAINGATEWAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "openai/gpt-5.6-luna", "messages": [{"role": "user", "content": "Say hello in five words."}], "max_tokens": 32}'A success is HTTP 200 with this shape (values vary):
{
"id": "gen-6f2d0c5e9a1b4c7d8e3f2a10",
"object": "chat.completion",
"model": "openai/gpt-5.6-luna",
"provider": "OpenAI",
"choices": [{ "index": 0, "finish_reason": "stop", "message": { "role": "assistant", "content": "Hello! How are you today?" } }],
"usage": { "prompt_tokens": 12, "completion_tokens": 11, "total_tokens": 23, "cost": 0.0000156 }
}usage.cost and the X-PG-Cost-USD header are the charge in USD. X-PG-Host names the serving host.
Errors
Errors are JSON. error.code is the HTTP status:
{ "error": { "message": "account balance is too low for this request; top up to continue", "code": 402 } }| Status | Meaning | Agent action |
|---|---|---|
| 400 | Bad request or unknown model id | Fix the request; read GET /models for ids |
| 401 | Missing or bad key | Ask the human for a key (below) |
| 402 | Balance too low, or the key's spend limit reached | Ask the human to top up; do not retry |
| 404 | No host left after provider filters, or unknown path |
Relax the filters or fix the path |
| 408, 502 | The host timed out or failed | Retry with backoff |
| 413 | Body over 32 MiB | Send less |
| 429 | The host rate limited the request | Wait Retry-After seconds when present, then retry |
| 503 | A gateway store is briefly unavailable | Retry after a few seconds |
/messages answers errors in Anthropic's shape: {"type": "error", "error": {"type": "...", "message": "..."}}.
Rate limits
The gateway sets no request rate limit of its own.
Each request first reserves its largest possible cost from the balance, so many large requests at once can get 402 before the balance is really spent; a lower max_tokens reserves less.
A 429 comes from a host. Before answering 429, 408 or 5xx, the gateway tries the model's next eligible host. You get the 429 only when the last host also refused, with that host's Retry-After. When the account turned Allow fallbacks off, or the request sets provider.allow_fallbacks: false, only one host per model is tried.
The one human step
A key needs a person: sign-up confirms an email address and the first top-up needs a card. There is no free tier and no API that creates keys. If you have no key, show your human this text:
I need a plaingateway API key to continue. 1. Sign up at https://plaingateway.com/signup and click the link in the confirmation email. 2. Add at least $5 USD of credit by card. 3. Open https://plaingateway.com/settings/keys, press "New key", and copy the key (it starts with sk-pg-v1-). 4. Give me the key, or set it as the environment variable PLAINGATEWAY_API_KEY.