Documentation
Frontière API reference
The Frontière API is an OpenAI-compatible gateway to a curated catalog of powerful open-source models hosted in Europe. Point your existing SDK or HTTP client at the base URL below, authenticate with an API key from your dashboard, and every live model is available through the same endpoint — each one labeled EU sovereign or fast access, so you always know which jurisdiction serves your data.
Overview
The API implements the OpenAI chat-completions contract. If your code already talks to OpenAI — through the official Python or JavaScript SDK, LangChain, or a plain HTTP client — you only change two things: the base URL and the key. One key unlocks the whole catalog.
https://getfrontiereai.eu/api/v1Two endpoints:
POST /chat/completions | Run a model (streaming supported) |
GET /models | List the catalog — public, no key required |
Authentication
Every call to the chat endpoint carries your API key in the Authorization header. Keys are created in the dashboard under API keys — the full value (sk-front-…) is shown once at creation, then only its prefix. Create one key per environment or app; each can be revoked independently without touching the others.
Authorization: Bearer sk-front-…Keep keys server-side (environment variables, a secret manager) — never in client-side code or a public repository. If a key leaks, revoke it from the dashboard and create a new one; the old one stops working immediately.
Quickstart
The same call in three languages. The Python and JavaScript examples use the official OpenAI SDK (pip install openai / npm install openai) — no Frontière-specific library needed.
curl https://getfrontiereai.eu/api/v1/chat/completions \
-H "Authorization: Bearer $FRONTIERE_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "glm-5.2",
"messages": [{"role": "user", "content": "Bonjour"}]
}'import os
from openai import OpenAI
client = OpenAI(
base_url="https://getfrontiereai.eu/api/v1",
api_key=os.environ["FRONTIERE_KEY"],
)
reply = client.chat.completions.create(
model="glm-5.2",
messages=[{"role": "user", "content": "Bonjour"}],
)
print(reply.choices[0].message.content)import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://getfrontiereai.eu/api/v1",
apiKey: process.env.FRONTIERE_KEY,
});
const reply = await client.chat.completions.create({
model: "glm-5.2",
messages: [{ role: "user", content: "Bonjour" }],
});
console.log(reply.choices[0].message.content);Chat completions
https://getfrontiereai.eu/api/v1/chat/completionsSend a conversation, get the model's reply. Request body fields:
| Field | Type | Description |
|---|---|---|
model | string — required | A live model ID from the catalog, e.g. glm-5.2 (see Models below). |
messages | array — required | The conversation so far: a list of {role, content} objects with roles system, user and assistant, in OpenAI format. |
stream | boolean | true streams the reply as server-sent events (see Streaming). |
max_tokens | integer | Cap on completion tokens. On reasoning models, thinking counts against it — omit it or allow at least ~1,000 (see Reasoning models). |
temperature, top_p, stop, … | various | Standard OpenAI sampling parameters, forwarded unchanged to the provider serving the model. |
The request body is forwarded to the provider hosting the model, so the standard OpenAI parameters behave exactly as documented by OpenAI. Fields a given provider does not support are ignored by that provider.
The response is a standard chat.completion object. The usage block is what your balance is billed against — token-exact, including reasoning tokens on reasoning models:
{
"id": "chatcmpl-…",
"object": "chat.completion",
"model": "glm-5.2",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "Bonjour ! Comment puis-je aider ?" },
"finish_reason": "stop"
}
],
"usage": { "prompt_tokens": 9, "completion_tokens": 42, "total_tokens": 51 }
}Streaming
Set "stream": true and the reply arrives as server-sent events — data: chunks with the incremental delta, terminated by data: [DONE]. This is the same wire format as OpenAI, so SDK streaming helpers work unchanged.
stream = client.chat.completions.create(
model="llama-3.3-70b",
messages=[{"role": "user", "content": "Bonjour"}],
stream=True,
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")Frontière always enables stream_options.include_usage upstream: the final data chunk before [DONE] carries the usage object (and an empty choices array). That chunk is how streamed calls are billed exactly — don't be surprised by it if you parse the stream by hand.
Models
https://getfrontiereai.eu/api/v1/modelsThe catalog is served live by GET /api/v1/models — public, no key required. Each entry carries the OpenAI fields (id, object) plus three Frontière-specific ones: status ("live" or "coming-soon"), sovereign (boolean) and note (usage caveat, when one applies).
{
"object": "list",
"data": [
{
"id": "glm-5.2",
"object": "model",
"label": "GLM-5.2 (Zhipu/Z.ai)",
"provider": "scaleway",
"status": "live",
"sovereign": true,
"note": "Reasoning model — thinks before answering. Omit max_tokens or allow at least ~1,000."
}
]
}sovereign: true means the company operating the infrastructure has no non-EU capital or jurisdictional control (the SecNumCloud principle) — OVHcloud, Scaleway, or dedicated EU servers. Models served through US infrastructure (even in an EU region) are labeled fast access, never sovereign, so you can filter per call with full information.
| Model | model ID | Hosting | Status |
|---|---|---|---|
| Qwen3 235B (instruct) | qwen3-235b | EU sovereign | live |
| Qwen3.5 397B (multimodal) | qwen3.5-397b | EU sovereign | live |
| GLM-5.2 (Zhipu/Z.ai) | glm-5.2 | EU sovereign | live |
| Llama 3.3 70B | llama-3.3-70b | EU sovereign | live |
| Qwen3.6 27B (multimodal) | qwen3.6-27b | EU sovereign | live |
| Qwen3.5 9B (fast, budget) | qwen3.5-9b | EU sovereign | live |
| Qwen3 32B | qwen3-32b | EU sovereign | live |
| Qwen3 Coder 30B | qwen3-coder-30b | EU sovereign | live |
| Qwen2.5-VL 72B (vision) | qwen2.5-vl-72b | EU sovereign | live |
| GPT-OSS 120B (OpenAI) | gpt-oss-120b | EU sovereign | live |
| GPT-OSS 20B (OpenAI) | gpt-oss-20b | EU sovereign | live |
| Mistral Small 3.2 24B | mistral-small-3.2-24b | EU sovereign | live |
| Kimi K3 (2.8T parameters, 1M context) | kimi-k3 | Fast access (US) | live |
| Kimi K3 — EU sovereign variant | kimi-k3-souverain | EU sovereign | Coming soon |
| DeepSeek V4 Flash (1M context) | deepseek-v4-flash | Fast access (US) | Coming soon |
| DeepSeek V4 Flash — EU sovereign variant | deepseek-v4-flash-souverain | EU sovereign | Coming soon |
Model notes
glm-5.2— Reasoning model — thinks before answering. Omit max_tokens or allow at least ~1,000.kimi-k3— Reasoning model. First call after a quiet period can take a few minutes to warm up — then it responds in seconds.
Per-token prices for every live model are listed on the model catalog. Calling a coming-soon model returns HTTP 409 — and records your interest: asking for a model is the best way to vote for its priority. Unknown model IDs return 404 with a pointer back to the catalog.
Errors
Errors are JSON, OpenAI-style — an error object with a human-readable message and a stable type you can branch on:
{
"error": {
"message": "Insufficient credit balance. Top up your account from the dashboard.",
"type": "insufficient_credit"
}
}| Status | type | Meaning |
|---|---|---|
| 400 | invalid_request | The body is not valid JSON or the model field is missing. |
| 401 | invalid_api_key | Missing, malformed or revoked API key in the Authorization header. |
| 402 | insufficient_credit | Your prepaid balance is at zero. Top up from the dashboard to resume. |
| 404 | model_not_found | The model ID is not in the catalog — list valid IDs via GET /api/v1/models. |
| 409 | model_not_live | The model exists but is still coming soon. Pick a live model. |
| 502 | upstream_error | The provider returned an unreadable response. Retry; report it if it persists. |
| 503 | provider_not_configured | No provider credentials for this model on this instance. |
Provider-side errors (rate limits, overloaded model, invalid parameter for that provider) are relayed as-is with their upstream status code and body — what you would get calling the provider directly.
Credit & billing
Frontière is prepaid: you top up a balance (from €20, via Stripe, in the dashboard) and every successful call draws it down. No subscription, no card on file, no invoice at the end of the month — when the balance reaches zero, calls return 402 and nothing else happens.
Billing is token-exact, computed from the usage object the provider reports for your call: prompt tokens at the model's input rate, completion tokens (including reasoning tokens) at the output rate. When a provider serves part of your prompt from its cache and reports it (usage.prompt_tokens_details.cached_tokens), those tokens are billed at the model's cheaper cache rate.
Your dashboard shows the balance, a per-call billing history (tokens in/out and price per call), and top-up history. The price of each call is charged at the moment the provider returns its usage — streamed calls included, via the final usage chunk.
Reasoning models
glm-5.2 and kimi-k3 think before they answer: the thinking consumes completion tokens (billed as output) before any visible text is produced. With a small max_tokens the entire budget can go to reasoning — the reply then comes back with content: null and finish_reason "length", which looks like an empty answer. Omit max_tokens or allow at least ~1,000.
kimi-k3 additionally scales to zero between uses: the first call after a quiet period can take a few minutes to warm up, then it answers in seconds. It is served through US infrastructure and labeled fast access — check the sovereign field if jurisdiction matters for your workload.
Reasoning also takes wall-clock time: on a substantial prompt, glm-5.2 can think for several minutes before the full reply is ready. Set your HTTP client's timeout generously (many tools default to well under a minute — Make.com's HTTP module, for instance, cuts at 40 seconds unless you raise it), or better, use streaming: the first chunk arrives in under a second and the connection stays active throughout.
FAQ
Can I use the official OpenAI SDK?
Yes. The API implements the OpenAI chat-completions contract: point base_url at the Frontière API and pass your key as api_key — the official Python and JavaScript SDKs, and tools built on them, work unchanged.
What happens when my credit reaches zero?
Calls return HTTP 402 (insufficient_credit) and stop being served. Nothing else happens — no overdraft, no automatic charge. Top up from the dashboard to resume.
How do I know whether a model is EU sovereign?
Every model carries a sovereign boolean in GET /api/v1/models and a badge on the catalog. sovereign: true means no non-EU capital or jurisdictional control over the operator (SecNumCloud principle); models served through US infrastructure are always labeled fast access, never sovereign.
Why did my reply come back empty?
You most likely called a reasoning model (glm-5.2, kimi-k3) with a small max_tokens: the whole budget went to thinking and content came back null with finish_reason "length". Omit max_tokens or allow at least ~1,000.
Ready to make your first call?
Create an account, top up from €20, paste two lines — the whole catalog behind one key.
Create an account