Documentation
One request shape. One decision shape.
The request and decision shapes the CenovaGate gateway uses, with a worked example you can validate.
Open consoleEvery request you send and every decision we return follow the two shapes below. They borrow familiar chat-completion ideas — a model name, a list of messages and a few parameters — but they are our own shapes, not a drop-in replacement for another provider's API yet. The version above changes whenever a field changes meaning.
No credentials travel in these payloads
Drop-in chat completions
Already using an OpenAI-compatible client? Point its base URL at https://your-cenovagate-domain/api/public/gateway/v1 and use your CenovaGate key. Requests and replies keep the familiar shape, with an extra cenovagate block carrying the request id, the decision and the estimated cost. Streaming is not available on this endpoint yet, so send stream: false or leave it out.
cURL
curl https://your-cenovagate-domain/api/public/gateway/v1/chat/completions \
-H "Authorization: Bearer $CENOVAGATE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-4.1-mini","messages":[{"role":"system","content":"You are a concise assistant."},{"role":"user","content":"Summarise in one sentence: the invoice export stops at 500 rows."}],"temperature":0.2,"max_tokens":300}'JavaScript (fetch)
const response = await fetch("https://your-cenovagate-domain/api/public/gateway/v1/chat/completions", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CENOVAGATE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"model": "gpt-4.1-mini",
"messages": [
{
"role": "system",
"content": "You are a concise assistant."
},
{
"role": "user",
"content": "Summarise in one sentence: the invoice export stops at 500 rows."
}
],
"temperature": 0.2,
"max_tokens": 300
}),
});
const result = await response.json();
console.log(result.choices[0].message.content);
console.log(result.cenovagate); // request id, decision and estimated costOpenAI SDK
import OpenAI from "openai";
// Only the base URL and key change — the request stays the same.
const client = new OpenAI({
apiKey: process.env.CENOVAGATE_API_KEY,
baseURL: "https://your-cenovagate-domain/api/public/gateway/v1",
});
const completion = await client.chat.completions.create({
"model": "gpt-4.1-mini",
"messages": [
{
"role": "system",
"content": "You are a concise assistant."
},
{
"role": "user",
"content": "Summarise in one sentence: the invoice export stops at 500 rows."
}
],
"temperature": 0.2,
"max_tokens": 300
});Request fields
What you send to the gateway.
| Field | Type | Required | What it means |
|---|---|---|---|
| contractVersion | string | Required | Version of this contract the caller was built against. |
| organisationId | uuid | Required | The organisation the request belongs to. |
| applicationId | uuid | Required | The application sending the request. |
| environmentId | uuid | Required | The environment, for example Production. |
| apiKeyPrefix | string | Required | Short prefix of the API key. Never send the full key or any provider credential in the payload. |
| requestedModel | string | Required | The model the caller asked for. Routing may choose another one. |
| messages | array | Required | Chat messages with role and content, 1 to 200 entries. |
| parameters | object | Optional | temperature, topP, maxOutputTokens, stream, stop. Unknown parameters are rejected. |
| metadata | object | Optional | Your own labels, up to 20 entries and 4096 characters. |
| requestedAt | ISO 8601 | Required | When the caller created the request. |
Decision fields
What the gateway returns about the choice it made.
| Field | Type | Required | What it means |
|---|---|---|---|
| contractVersion | string | Required | Version of this contract the decision was produced with. |
| requestId | uuid | Required | Identifier for this request, used in the request log. |
| decision | enum | Required | One of BYPASS, CACHE, COMPRESS, CHEAP_MODEL, PREMIUM_MODEL, HUMAN_REVIEW, BLOCK. |
| selectedModel | string or null | Required | The model actually used, or null when nothing was sent to a provider. |
| cacheStatus | enum | Required | One of miss, exact_hit, semantic_hit, bypassed. |
| tokensRemoved | integer | Required | Tokens removed by compression before sending. |
| baselineCost | number | Required | Estimated cost of sending the request unchanged to the requested model. |
| estimatedCost | number | Required | Estimated cost after the decision was applied. |
| saving | number | Required | Baseline cost minus estimated cost. May be negative. |
| latencyMs | integer | Required | Total time the gateway took, in milliseconds. |
| reason | string | Required | Plain-language explanation of why this decision was made. |
| decidedAt | ISO 8601 | Required | When the decision was made. |
Try an example
Copy the example request, change anything you like, then check it. Valid payloads return an example decision; invalid ones list exactly which field is wrong.
Nothing is sent anywhere — the same rules that run on the gateway run here in your browser.
Key status responses
Send your key as Authorization: Bearer cg_…. The gateway answers with a stable code you can branch on. Full key values are never echoed back or written to logs — only the public prefix.
| Code | HTTP status | What it means |
|---|---|---|
| missing_authorization | 401 | Provide your API key as an Authorization: Bearer header. |
| malformed_authorization | 401 | The Authorization header must use the Bearer scheme. |
| malformed_key | 401 | The API key format is not valid. Keys look like cg_<environment>_<prefix>_<secret>. |
| invalid_key | 401 | This API key is not recognised. |
| revoked_key | 403 | This API key has been revoked. Create a new key to continue. |
| expired_key | 401 | This API key has expired. Create a new key to continue. |
| environment_mismatch | 403 | This API key belongs to a different environment than the one requested. |
| insufficient_permission | 403 | This API key does not have the permission required for this request. |
| too_many_failed_attempts | 429 | Too many failed authentication attempts. Wait a moment before trying again. |
