Skip to content
kenari.

Chat completions

The kenari chat completions endpoint is compatible with OpenAI, so it can be used as a direct replacement for https://api.openai.com/v1. Point the base URL to https://kenari.id/v1 and use the kn-... API key. Tokens are still billed from the prepaid balance in Rupiah.

POST /v1/chat/completions

Two fields are required: model and messages.

The model field accepts a model id from GET /v1/models, a :free variant (for example step-3-7-flash:free), or a route name you created yourself (for example opus-hemat, see Routing).

Other supported fields:

FieldTypeDescription
streambooleanSend the response as an SSE stream. See Streaming.
max_tokensintegerOutput token limit.
temperaturenumberSampling randomness level.
top_pnumberNucleus sampling.
stopstring or arrayText sequences that stop generation.
frequency_penaltynumberToken frequency penalty.
presence_penaltynumberToken presence penalty.
toolsarrayTool definitions. See Tools.
tool_choicestring or objectHow the model chooses a tool.
response_formatobjectOutput format, for example JSON.
reasoning_effortstringFor reasoning models. See Reasoning.
pluginsarrayPre-dispatch plugins. Today only file-parser, for reading documents. See Read documents.

Fields not listed in the table above are forwarded as-is to the upstream model.

The messages field is an array of {role, content} objects. The role value is one of system, user, assistant, or tool. The content value can be a string, or an array of parts for multimodal input: text, image_url, and file. A file part carries a PDF or document image and needs the file-parser plugin, see Read documents.

{
"model": "step-3-7-flash",
"messages": [
{ "role": "system", "content": "Kamu asisten yang ringkas." },
{ "role": "user", "content": "Halo!" }
]
}

The response follows the OpenAI chat.completion shape: id, object, created, model, choices[], and usage. Each choices entry has index, message{role, content}, and finish_reason. The usage object contains prompt_tokens, completion_tokens, and total_tokens. The usage.prompt_tokens_details.cached_tokens field appears when the upstream reports a cache read.

{
"id": "chatcmpl-...",
"object": "chat.completion",
"created": 1717000000,
"model": "step-3-7-flash",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "Halo! Ada yang bisa dibantu?" },
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 12,
"completion_tokens": 9,
"total_tokens": 21
}
}

OpenAI SDK Python, set base_url to https://kenari.id/v1:

from openai import OpenAI
client = OpenAI(base_url="https://kenari.id/v1", api_key="kn-...")
response = client.chat.completions.create(model="step-3-7-flash", messages=[{"role": "user", "content": "Halo!"}])
print(response.choices[0].message.content)

OpenAI SDK TypeScript, set baseURL to https://kenari.id/v1:

import OpenAI from "openai";
const client = new OpenAI({ baseURL: "https://kenari.id/v1", apiKey: "kn-..." });
const res = await client.chat.completions.create({ model: "step-3-7-flash", messages: [{ role: "user", content: "Halo!" }] });
console.log(res.choices[0].message.content);

curl:

Terminal window
curl https://kenari.id/v1/chat/completions -H "Authorization: Bearer kn-..." -H "Content-Type: application/json" -d '{"model":"step-3-7-flash","messages":[{"role":"user","content":"Halo!"}]}'

Set "stream": true in the request to receive the response as an SSE stream token by token. Event format details and stream reading steps are in Streaming.