Build
Chat completions
Send OpenAI-format chat requests to every model with one key. Request fields, roles, the response and usage object, and what changes for Claude models.
POST /v1/chat/completions is the OpenAI Chat Completions API. It is the one request format that every model in the catalogue accepts, so it is the safest default for new code: switch models by changing one string.
https://api.oneaiapikey.com/v1/chat/completions (OpenAI format)Base URL https://api.oneaiapikey.com/v1
Send a request
Point any OpenAI SDK at the base URL above and use your key. Nothing else in your code changes.
curl https://api.oneaiapikey.com/v1/chat/completions \
-H "Authorization: Bearer $RELAYKIT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.6-terra",
"messages": [
{"role": "system", "content": "You are a concise assistant."},
{"role": "user", "content": "Explain what an API gateway does in two sentences."}
],
"max_tokens": 300
}'import os
from openai import OpenAI
client = OpenAI(base_url="https://api.oneaiapikey.com/v1", api_key=os.environ["RELAYKIT_API_KEY"])
reply = client.chat.completions.create(
model="gpt-5.6-terra",
messages=[
{"role": "system", "content": "You are a concise assistant."},
{"role": "user", "content": "Explain what an API gateway does in two sentences."},
],
max_tokens=300,
)
print(reply.choices[0].message.content)
print(reply.usage)import OpenAI from "openai";
const client = new OpenAI({ baseURL: "https://api.oneaiapikey.com/v1", apiKey: process.env.RELAYKIT_API_KEY });
const reply = await client.chat.completions.create({
model: "gpt-5.6-terra",
messages: [
{ role: "system", content: "You are a concise assistant." },
{ role: "user", content: "Explain what an API gateway does in two sentences." },
],
max_tokens: 300,
});
console.log(reply.choices[0].message.content);
console.log(reply.usage);Request fields
| Field | Type | Notes |
|---|---|---|
model |
string | Required. An exact id from the models table, for example gpt-5.6-terra. |
messages |
array | Required. The conversation so far, oldest first. See roles. |
max_tokens / max_completion_tokens |
integer | Upper limit for the reply. Set it: it caps cost and keeps long answers from timing out. |
temperature, top_p |
number | Sampling controls. Leave unset unless you need them; some reasoning models accept only the default. |
stop |
string or array | Stop sequences. |
stream |
boolean | true sends the reply as server-sent events. See Streaming. |
stream_options |
object | {"include_usage": true} adds a final chunk with token counts. |
tools, tool_choice, parallel_tool_calls |
Function calling. See Tool calling. | |
response_format |
object | JSON mode and JSON Schema. See Structured output for which models honour it. |
reasoning_effort |
string | low, medium or high on reasoning models. See Reasoning models. |
Other OpenAI fields (seed, n, logprobs, presence_penalty, frequency_penalty, user …) are passed to the provider as they are. Whether they have an effect depends on the model, as it would if you called the provider directly.
Roles
| Role | Use it for |
|---|---|
system |
Instructions that apply to the whole conversation. Put one at the start. (developer is accepted too.) |
user |
What the person or your app asks. Text, or a list of parts with images and files. |
assistant |
Earlier replies from the model, sent back so it remembers the conversation. Also carries tool_calls. |
tool |
The result of a tool the model asked you to run, with its tool_call_id. |
The API is stateless: it does not remember earlier requests. To continue a conversation, send the whole history again, with the model’s previous answers as assistant messages:
messages = [
{"role": "system", "content": "You are a helpful SQL tutor."},
{"role": "user", "content": "What is a LEFT JOIN?"},
{"role": "assistant", "content": "A LEFT JOIN returns every row from the left table …"},
{"role": "user", "content": "Show me an example with orders and customers."},
]Every request is billed for all the tokens it sends, so a long history costs more with each turn. Trim or summarise old turns, and see prompt caching for how repeated prefixes get cheaper.
Response
{
"id": "chatcmpl-…",
"object": "chat.completion",
"created": 1791420807,
"model": "gpt-5.6-terra",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "An API gateway is a single entry point …" },
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 31,
"completion_tokens": 42,
"total_tokens": 73,
"prompt_tokens_details": { "cached_tokens": 0 },
"completion_tokens_details": { "reasoning_tokens": 0 }
}
}choices[0].message.contentis the reply. With tools it may benullandtool_callsis set instead.finish_reasonisstop(finished),length(hitmax_tokens),tool_calls(wants a tool run) orcontent_filter.usagelists the tokens you are billed for.prompt_tokens_details.cached_tokensandcompletion_tokens_details.reasoning_tokensappear when the provider reports them. Reasoning tokens are already included incompletion_tokens.- The
X-Request-Idresponse header identifies the request. Quote it if you contact support.
The response carries token counts, not a price. The cost of each request is on the usage page; the rates are in the models table.
Claude models in this format
Claude models accept chat completions too: the gateway translates the request to Anthropic’s format and the answer back. Most code works unchanged. The differences:
- If you leave out
max_tokens, the gateway sends 8,192, because Anthropic’s API requires a limit. Set your own. response_formatis not forwarded to Claude. Use a forced tool or the Messages endpoint instead (see Structured output).n,seed,logprobs,presence_penalty,frequency_penaltyandlogit_biashave no Anthropic equivalent and are dropped.reasoning_effortturns on Claude’s extended thinking; the thinking text comes back asreasoning_content(see Reasoning models).- Images and PDFs given by URL are downloaded by the gateway and sent to Claude inline.
If you need Anthropic-only features such as cache_control breakpoints, use the Anthropic Messages endpoint with claude-sonnet-5-5 instead.
Related
- Streaming: show the reply as it is written.
- Errors: every status code and what to do about it.
- API reference: the full endpoint list.