Home / Docs / API reference
/v1/chat/completions
POST /v1/chat/completions
Authentication relay key (bearer)
Request body
| Field | Type | Description |
|---|---|---|
model | string | A model id or an alias from GET /v1/models. Optional: the key's routing decides when absent. |
messages required | array of object | Required and non-empty; an empty or missing list is a 400. |
messages[].role | string | Who wrote the message: system, user, assistant or tool. |
messages[].content | string or array | Text; the gateway reads the text of a message. |
max_completion_tokens | number | Upper bound on the generated tokens, the newer OpenAI name for max_tokens. Send one of the two. |
max_tokens | number | Upper bound on the tokens the model may generate for this answer. Send this or max_completion_tokens, not both. |
temperature | number | Sampling temperature: lower is more deterministic, higher more varied. Usually between 0 and 2. |
stream | boolean | Default false. |
tools | array | Carried and forwarded verbatim upstream; never validated here. |
response_format | object | Carried and forwarded verbatim upstream. |
reasoning_effort | string | The o-series field; read as the request's effort. |
Example request
curl
curl -X POST https://api.massrelay.ai/v1/chat/completions \
-H "Authorization: Bearer $RELAY_KEY" \
-H "Content-Type: application/json" \
-d '{"messages":[{"role":"user","content":"Say hello in one sentence."}]}'Python
import os, requests
r = requests.post(
"https://api.massrelay.ai/v1/chat/completions",
headers={"Authorization": f"Bearer {os.environ['RELAY_KEY']}"},
json={
"messages": [
{
"role": "user",
"content": "Say hello in one sentence."
}
]
},
)
r.raise_for_status()
print(r.json())TypeScript
const r = await fetch("https://api.massrelay.ai/v1/chat/completions", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.RELAY_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({"messages":[{"role":"user","content":"Say hello in one sentence."}]}),
});
if (!r.ok) throw new Error(`${r.status} ${await r.text()}`);
console.log(await r.json());Response
| Field | Type | Description |
|---|---|---|
id required | string | chatcmpl-<decisionId>; the decision id is the key of GET /v1/route/explain/{decisionId}. |
object required | string | The kind of object returned, for example chat.completion. Always "chat.completion". |
created required | integer | When the answer was created, in Unix seconds. |
model required | string | The model id. In a request it is optional: without it the key's routing chooses. |
choices required | array of object | The generated answers; one unless n asks for more. |
choices[].index | integer | The position of this choice in the list. |
choices[].message | object | The generated message: its role and content. |
choices[].message.role | string | Who wrote the message: system, user, assistant or tool. Always "assistant". |
choices[].message.content | string | The text of the message. |
choices[].finish_reason | string | Why generation stopped, for example stop or length. |
usage required | object | Tokens counted for this call. |
usage.prompt_tokens | number | Tokens in the input. |
usage.completion_tokens | number | Tokens generated. |
usage.total_tokens | number | Input plus generated tokens. |
Example response (shape)
{
"id": "chatcmpl-1f2e3d4c",
"object": "chat.completion",
"created": 1761400000,
"model": "provider/model-id",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Hello there."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 12,
"completion_tokens": 6,
"total_tokens": 18
}
}Common errors
401invalid_api_key400the body is not usable402out of credit or over a budget413the body is over the limit403insufficient_scope429over the request rate; read Retry-After
Every error has the same JSON shape; see Errors and Limits.
Full schema (JSON)
Request schema
{
"description": "Every other field is accepted and not read (for example n, stop, top_p, seed are ignored). Fields the gateway does not read are not documented as honoured.",
"type": "object",
"required": [
"messages"
],
"additionalProperties": true,
"properties": {
"model": {
"type": "string",
"description": "A model id or an alias from GET /v1/models. Optional: the key's routing decides when absent."
},
"messages": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"additionalProperties": true,
"properties": {
"role": {
"type": "string"
},
"content": {
"description": "Text; the gateway reads the text of a message.",
"type": [
"string",
"array"
]
}
}
},
"description": "Required and non-empty; an empty or missing list is a 400."
},
"max_completion_tokens": {
"type": "number"
},
"max_tokens": {
"type": "number"
},
"temperature": {
"type": "number"
},
"stream": {
"type": "boolean",
"description": "Default false."
},
"tools": {
"description": "Carried and forwarded verbatim upstream; never validated here.",
"type": "array"
},
"response_format": {
"description": "Carried and forwarded verbatim upstream.",
"type": "object",
"additionalProperties": true
},
"reasoning_effort": {
"type": "string",
"description": "The o-series field; read as the request's effort."
}
}
}Response schema
{
"description": "Every other field is accepted and not read (streaming responses are server-sent events and are not described here). Fields the gateway does not read are not documented as honoured.",
"type": "object",
"additionalProperties": true,
"required": [
"id",
"object",
"created",
"model",
"choices",
"usage"
],
"properties": {
"id": {
"type": "string",
"description": "chatcmpl-<decisionId>; the decision id is the key of GET /v1/route/explain/{decisionId}."
},
"object": {
"const": "chat.completion"
},
"created": {
"type": "integer"
},
"model": {
"type": "string"
},
"choices": {
"type": "array",
"items": {
"type": "object",
"properties": {
"index": {
"type": "integer"
},
"message": {
"type": "object",
"properties": {
"role": {
"const": "assistant"
},
"content": {
"type": "string"
}
}
},
"finish_reason": {
"type": "string"
}
}
}
},
"usage": {
"type": "object",
"properties": {
"prompt_tokens": {
"type": "number"
},
"completion_tokens": {
"type": "number"
},
"total_tokens": {
"type": "number"
}
}
}
}
}Every answer carries a decision id; the explain endpoint returns why that model was chosen.