Documentation

The API is OpenAI-compatible. If a client speaks the OpenAI protocol, it works here by changing the base URL.

Quickstart

Set two values — your base URL and your key — and send a request. Your key is created when you register and can be rotated from the console.

shell
export ICEBERG_BASE_URL="https://iceberg-inference.pages.dev/v1"
export ICEBERG_API_KEY="sk-router-…"

curl "$ICEBERG_BASE_URL/chat/completions" \
  -H "Authorization: Bearer $ICEBERG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "glm-5.3-flash",
    "messages": [{ "role": "user", "content": "Hello" }]
  }'

Python

python
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://iceberg-inference.pages.dev/v1",
    api_key=os.environ["ICEBERG_API_KEY"],
)

completion = client.chat.completions.create(
    model="glm-5.3-flash",
    messages=[{"role": "user", "content": "Hello"}],
)

print(completion.choices[0].message.content)

Authentication

Send your key as a Bearer token in the Authorization header, or as x-api-key. Keys are account-scoped; each request counts against the plan shared by the account.

HeaderValue
AuthorizationBearer sk-router-…
x-api-keysk-router-…

Never ship a key in client-side code. Proxy requests through your own server and keep the key in an environment variable.

Chat completions

POST /v1/chat/completions accepts the standard OpenAI chat body — model, messages, temperature, max_tokens, tools, stream and the rest — and returns the same response shape.

FieldTypeNotes
modelstringAny id from the catalogue.
messagesarrayStandard role/content objects.
temperaturenumberPassed through to the provider.
max_tokensintegerUpper bound on the completion.
streambooleanServer-sent events when true.

Streaming

Send "stream": true and read the response as server-sent events. Failover is preserved mid-stream where the provider supports it; if the first provider drops before any token is sent, the router retries transparently.

node
const stream = await client.chat.completions.create({
  model: "glm-5.3-flash",
  messages: [{ role: "user", content: "Tell me a story." }],
  stream: true,
});

for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}

Embeddings

POST /v1/embeddings mirrors the OpenAI embeddings request and returns vectors from the first embedding-capable provider for the model.

Images

POST /v1/images/generations and POST /v1/images/edits are supported. Edits accept multipart/form-data and are passed through untouched.

Audio

POST /v1/audio/speech returns generated audio, and POST /v1/audio/transcriptions accepts an uploaded file for transcription. Both keep the OpenAI request shape.

List models

GET /v1/models returns the catalogue in the OpenAI list format. GET /v1/models/:id returns one model with its capabilities.

json
{
  "object": "list",
  "data": [
    { "id": "glm-5.3-flash", "object": "model", "owned_by": "router" }
  ]
}

Errors

Errors use the OpenAI envelope. The type and code fields tell you what happened, and limit errors add limit, used and an upgrade_url.

json
{
  "error": {
    "message": "Monthly request limit reached (2000 on the Free plan).",
    "type": "rate_limit_error",
    "code": "monthly_request_limit",
    "limit": 2000,
    "used": 2000,
    "upgrade_url": "https://iceberg-inference.pages.dev/pricing"
  }
}
StatusMeaning
401Missing, invalid or disabled key.
404Unknown model, or no provider available for it.
429Plan or per-minute limit reached. Honour retry-after.
502/503Every provider for the model failed. Retry shortly.

Rate limits

Every plan carries a monthly request allowance, a monthly token allowance and a per-minute request rate. See pricing for the numbers, and your console for live usage against them.