Run your first completion
This page sends one chat completion through the gateway, walks through what came back, and points at the things you’ll come back to.
Send the request
Set your key in an environment variable so it doesn’t end up in shell history:
export LOWROUTER_API_KEY="sk-lr-..."Then call the gateway:
curl https://api.lowrouter.ai/v1/chat/completions \
-H "Authorization: Bearer $LOWROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "auto/mistralai/mistral-large-2512",
"messages": [
{"role": "user", "content": "In one sentence, what is a vector database?"}
]
}'An auto/<creator>/<model> ID names the model you want and leaves the
route to us: among the providers and regions serving it, LowRouter
prefers EU-sovereign routes, then the lowest-carbon one (modeled from
annual grid averages — see the
methodology). You get the same model
either way — only where it runs is decided for you.
The model field is required. You can name the route yourself
instead, for example openai/openai/gpt-4.1/global or
anthropic/anthropic/claude-haiku-4.5/global, pinning a region with a
UN/LOCODE as the fourth segment (e.g.
vertex/anthropic/claude-opus-4.6/sg-sin), or call an alias you can
repoint later without changing code. See
routing. Custom auto-routing policies (like a
per-key carbon budget) are coming soon.
What comes back
The response is OpenAI-shaped. The fields you’ll use most are:
{
"id": "chatcmpl-01J9...",
"object": "chat.completion",
"created": 1714150000,
"model": "openai/openai/gpt-4.1",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "A vector database stores …"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 18,
"completion_tokens": 26,
"total_tokens": 44,
"cost": 0.000034,
"currency": "EUR",
"remaining_balance": 9.87
},
"lowrouter_metadata": {
"provider": "openai",
"region": "eu-west",
"energy_wh": 0.0021,
"carbon_gco2e": 0.00057,
"carbon_intensity_gco2_per_kwh": 45.0,
"estimation_methodology": "parameter-based",
"routing_mode": "auto",
"routing_reason": "lowest_carbon_intensity",
"fallback_occurred": false,
"providers_attempted": ["openai"]
}
}The OpenAI-compatible parts (id, choices, usage, …) follow the
standard OpenAI Chat Completions shape. LowRouter adds three billing
fields to usage:
cost— what this request cost, incurrency. This is the per-request figure: attribute it to a user, tenant, or workflow without scraping a dashboard or maintaining your own price table.currency— ISO-4217 code forcostandremaining_balance(EUR).remaining_balance— your credit balance after this request.
Costs are billed in integer micros (millionths of a euro) and rounded up to the next micro, so a request never bills below what it cost us. On very small requests that rounding is visible: the amount you are charged can exceed the exact computed cost by up to €0.000001.
The lowrouter_metadata block carries the LowRouter-specific fields:
provider— which upstream actually served the request.region— the region the upstream served from.energy_whandcarbon_gco2e— the energy and carbon estimate for this request. Read methodology before quoting these numbers anywhere.routing_mode,routing_reason,fallback_occurred, andproviders_attempted— the routing trace: how the model was picked and whether a fallback was used.
To look up the full record for a request later, open its transaction on the dashboard.
Stream the response
For interactive UIs, set "stream": true and read Server-Sent Events:
curl https://api.lowrouter.ai/v1/chat/completions \
-H "Authorization: Bearer $LOWROUTER_API_KEY" \
-H "Content-Type: application/json" \
-N \
-d '{
"model": "auto/mistralai/mistral-large-2512",
"stream": true,
"messages": [{"role": "user", "content": "Count to 5 slowly"}]
}'The stream is a Server-Sent Events stream in the same format the OpenAI streaming API uses, so any OpenAI-compatible SDK consumes it unchanged. See integrations for per-SDK snippets.
Streaming does not cost you cost attribution. The final chunk before
data: [DONE] carries lowrouter_metadata and a usage object with
the same cost, currency, and remaining_balance fields the
non-streaming response returns:
{
"object": "chat.completion.chunk",
"choices": [],
"usage": {
"cost": 0.000034,
"currency": "EUR",
"remaining_balance": 9.87
},
"lowrouter_metadata": { "provider": "openai", "...": "..." }
}Token counts appear exactly once across the stream. If the upstream
provider already sent a usage chunk with prompt_tokens /
completion_tokens / total_tokens, this final chunk carries the
money fields only rather than restating them — so read tokens from
whichever chunk carries them, and cost from the final one.
If a stream is cut short — you cancel it, your client times out, or
the connection drops — you are still billed for the tokens the
provider generated before the cut. Those requests are marked
interrupted on the dashboard, in the CSV export, and on the
generation record, so you can reconcile them against your own logs.
Things that might surprise you
- The
modelin the response is the resolved four-segment ID, not necessarily the string you sent. If you sent anauto/oralias/ID, the response tells you which route actually ran. usagereflects upstream tokens, which may include caching discounts (for providers that support them). The credits charged on your dashboard match thisusage.- The carbon estimate is absent on requests we couldn’t classify, e.g. a model whose parameter count is unknown. The dashboard shows the same record without an eco number rather than a fabricated one.
If it didn’t work
A 401, 402, or 404 here almost always means a key, balance, or model-id problem. The errors reference lists every payload the gateway returns, with the one-line fix for each.
