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

WhereWhat
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.currencyWhat 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_eurThe 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.

Cost is omitted, never zeroed, when the request was served by something Seligo does not price — your own registered endpoint or a BYOK key.

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.

EndpointReturns
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=0One 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.

HTTPcodeMeaning
401invalid_key etc.Unknown / expired / revoked key
403insufficient_balance, budget_cap, region…Key known but a rule blocked it
429—Ingress rate limit
502provider_errorUpstream 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).

Private GPUs are served on the same OpenAI-compatible surface. The only differences are the self-serve lifecycle endpoints and the stable seligo/gpu model alias — see Private GPU.