API reference
The Seligo API is OpenAI-compatible: any client that
speaks the OpenAI API can point at https://api.seligo.cloud/v1. Base URL is
https://api.seligo.cloud/v1.
Authentication
Send your key in the standard Authorization header:
Authorization: Bearer rk-…
Every request is authenticated with an API key scoped to your org & user. Unknown
keys get a 401; known keys blocked by a quota/balance/region rule get a
403 with a machine-readable code.
Chat completions
POST /v1/chat/completions
Body is the standard OpenAI chat request. stream:true returns
server-sent events (SSE); otherwise you get a JSON response.
# non-streaming
curl -s "$SELIGO_BASE/chat/completions" \
-H "authorization: Bearer rk-…" \
-H "content-type: application/json" \
-d '{"model":"scaleway/Meta-Llama-3-1-8B-Instruct",
"messages":[{"role":"user","content":"Explain EU data sovereignty in one line."}]}'
# streaming (SSE) — set the model to whatever you listed in /v1/models
curl -N -s "$SELIGO_BASE/chat/completions" \
-H "authorization: Bearer rk-…" \
-H "accept: text/event-stream" \
-H "content-type: application/json" \
-d '{"model":"scaleway/Meta-Llama-3-1-8B-Instruct",
"stream":true,
"messages":[{"role":"user","content":"Hello"}]}'
List models
GET /v1/models
Returns ids from the public catalogue. When called with a bearer key it also
lists your org’s registered endpoints and, if you have a live private GPU, the stable
seligo/gpu alias (see Private GPU). Without a
key it returns just the public catalogue.
curl -s "$SELIGO_BASE/models" -H "authorization: Bearer rk-…"
Session usage
Every request is attributed to a session — the unit your console reports tokens
and spend against. You do not have to send one: if the body omits session_id,
the router mints an id and keeps it sticky for that API key for 30 minutes
of idle time, so an agent run or a plugin conversation is attributed without any client
change. A client that already manages conversations should send its own id.
curl -s "$SELIGO_BASE/chat/completions" \
-H "authorization: Bearer $SELIGO_KEY" \
-H "content-type: application/json" \
-d '{"model":"scaleway/Meta-Llama-3-1-8B-Instruct",
"session_id":"conv-2026-10-21-a",
"messages":[{"role":"user","content":"Hello"}]}'
session_id is 1–200 characters of URL-safe printable ASCII
(A-Z a-z 0-9 . _ ~ : @ + -). A malformed id is refused with
400 invalid_session_id rather than silently rewritten: attribution is never
rearranged behind your back.
Reading the attribution back
| Where | What |
|---|---|
X-Seligo-Session-Id (header) | The session this turn belongs to — on streaming and non-streaming responses alike. |
seligo.session_id (body) | The same value, for clients that only parse JSON. |
usage.cost + usage.currency | What this turn cost, inside the standard OpenAI usage object (OpenRouter-compatible shape). Seligo bills in EUR, so the currency is always stated rather than left to assumption. |
seligo.cost_eur | The same number in Seligo’s own block. |
Streaming responses report tokens only: a streamed turn’s cost is known only after the stream closes, and the stream itself stays strictly OpenAI-shaped. Read spend from the session API below.
Session usage API (console)
These endpoints authenticate with a console session (a signed-in user), not an API key,
and are role-scoped: sysadmin sees the org, a manager their groups, a user
their own keys.
| Endpoint | Returns |
|---|---|
GET /api/usage/sessions?days=&limit=&kind= | Sessions in the window, newest activity first: turns, input / cached / output tokens, estimated-turn count, cost, models, first and last seen. |
GET /api/usage/sessions/{id}?live=0 | One session: the ledger rollup, its turns, and all_in_cost_eur — inference plus any private-GPU infrastructure charge. |
A private-GPU burst appears as a session whose id is gpu:<burst-session-id>.
Its cost_eur is the infrastructure line (node-hours × tier rate + session
fee) and it carries zero tokens; inference served on that GPU is listed
separately and folded into all_in_cost_eur, so the two figures are never
conflated.
The detail response carries the ledger answer plus a live reading written at
settle time: current to the last finished turn, with as_of stating when it was
taken. The ledger remains the record and may trail by a moment.
Errors
Errors are OpenAI-shaped with Seligo extensions: a top-level
{"error":{"message","type","code","param","request_id"}}. The
code is machine-readable and prefixed seligo_* for Seligo-native
conditions, while provider failures pass through untouched.
| HTTP | code | Meaning |
|---|---|---|
| 401 | invalid_key etc. | Unknown / expired / revoked key |
| 403 | insufficient_balance, budget_cap, region… | Key known but a rule blocked it |
| 429 | — | Ingress rate limit |
| 502 | provider_error | Upstream provider failed |
Regions
Keys and orgs carry a region pin. By default requests stay in your org’s EU region;
models are labelled with their zone (eu / us / apac
/ global).
seligo/gpu model alias — see Private GPU.