Responses
Create a model response with the OpenAI Responses format. This is a stateless subset built for coding agents such as Codex, and the official OpenAI SDKs work once you point the base URL at https://kenari.id/v1. For Codex configuration, see Codex.
POST /v1/responses
Authenticate with Authorization: Bearer kn-.... See Authentication and API keys.
Stateless by design
Section titled “Stateless by design”kenari stores nothing between requests, so send the whole conversation in input every time.
- A
previous_response_idother thannullreturns 400. storeis accepted and ignored.- There are no endpoints to retrieve, list or delete a response.
Request
Section titled “Request”| Field | Type | Required | Description |
|---|---|---|---|
model | string | Yes | A catalog id, a :free id, a route name or a byok/ id. The same values as in Chat completions. |
input | string or array | Yes | A string is one user message. An array holds input items. It must not be empty. |
instructions | string | No | System instructions. Merged with any leading developer items. |
tools | array | No | Flat function tools, each with type set to function, plus name, description and parameters. A function tool without name returns 400. kenari server tools such as {"type": "kenari:web_search"} also work. Every other tool type is dropped without an error. See Function calling and Server tools. |
tool_choice | string or object | No | auto, none, required or {"type": "function", "name": "get_weather"} to force one function. Anything else returns 400. |
reasoning | object or null | No | {"effort": "low"}. Levels are none, minimal, low, medium, high, xhigh and max. summary is accepted and ignored. See Reasoning. |
max_output_tokens | integer | No | Upper limit on generated tokens, reasoning included. Default 65,536. |
temperature | number | No | Sampling temperature. |
top_p | number | No | Nucleus sampling. |
stream | boolean | No | Set true to receive Server-Sent Events. See Streaming. |
text | object | No | Only {"format": {"type": "text"}} is accepted. Any other format returns 400. For JSON output, use Chat completions and see Structured output. |
prompt_cache_key | string | No | A stable id for one conversation, so follow-up requests reuse its cached prefix. Up to 512 bytes. Longer or blank values are ignored. See Prompt caching. |
previous_response_id | string or null | No | Must be absent or null. |
store | boolean | No | Accepted and ignored. |
include | array | No | Accepted and ignored. |
metadata | object | No | Accepted and ignored. |
parallel_tool_calls | boolean | No | Accepted and ignored. |
Input items
Section titled “Input items”| Item | Fields | Notes |
|---|---|---|
| Message | role, content | role is system, developer, user or assistant. type may be omitted. content is a string or an array of parts. |
| Function call | type set to function_call, call_id, name, arguments | A call the model made earlier. arguments is a JSON string. |
| Function result | type set to function_call_output, call_id, output | The result for a call. output is a string or an array of text parts. |
| Reasoning | type set to reasoning, summary (an array) | Earlier reasoning, handed back to the model. |
Leading system and developer messages merge into the system prompt. Unknown item types are dropped without an error, and any other role returns 400.
Message parts are input_text and output_text, plus input_image with an image_url string, which is accepted only in user and assistant messages (in a developer message it returns 400). An input_file part returns 400. For documents, use Chat completions: a file part works on any model. See Images and files as input and Read documents.
Response
Section titled “Response”The response is a response object. Its output array holds the items the model produced, in order.
{ "id": "resp_4f1c9a2e7b3d5a60", "object": "response", "created_at": 1790000000, "status": "completed", "model": "step-3-7-flash:free", "output": [ { "type": "message", "id": "msg_1", "role": "assistant", "content": [{ "type": "output_text", "text": "Hello! How can I help?" }] } ], "usage": { "input_tokens": 9, "output_tokens": 12, "total_tokens": 21, "input_tokens_details": { "cached_tokens": 0 } }}| Output item | Description |
|---|---|
reasoning | The model’s reasoning as one summary_text entry. First in the array, and only present when the model reasoned. |
message | The answer, in an output_text part. |
function_call | A function the model wants you to run: call_id, name and arguments as a JSON string. Run it and send a function_call_output item with the same call_id in the next request. |
status is completed, or incomplete with incomplete_details.reason set to max_output_tokens when the limit cut the answer short. usage.input_tokens_details.cached_tokens counts input served from cache and is part of input_tokens.
After you run a function, send a follow-up request that carries the earlier call and its result in input:
{ "model": "step-3-7-flash:free", "input": [ { "role": "user", "content": "What is the weather in Jakarta?" }, { "type": "function_call", "call_id": "call_1", "name": "get_weather", "arguments": "{\"city\": \"Jakarta\"}" }, { "type": "function_call_output", "call_id": "call_1", "output": "31 C and sunny" } ], "tools": [ { "type": "function", "name": "get_weather", "description": "Get the current weather for a city.", "parameters": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"] } } ]}Streaming
Section titled “Streaming”Set "stream": true to receive the response as Server-Sent Events. The event sequence is in Streaming.
Examples
Section titled “Examples”curl https://kenari.id/v1/responses \ -H "Authorization: Bearer $KENARI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "step-3-7-flash:free", "instructions": "You answer briefly.", "input": "Hello!" }'Python
Section titled “Python”import osfrom openai import OpenAI
client = OpenAI(base_url="https://kenari.id/v1", api_key=os.environ["KENARI_API_KEY"])
response = client.responses.create( model="step-3-7-flash:free", instructions="You answer briefly.", input="Hello!",)print(response.output_text)JavaScript
Section titled “JavaScript”import OpenAI from "openai";
const client = new OpenAI({ baseURL: "https://kenari.id/v1", apiKey: process.env.KENARI_API_KEY,});
const response = await client.responses.create({ model: "step-3-7-flash:free", instructions: "You answer briefly.", input: "Hello!",});console.log(response.output_text);Billing
Section titled “Billing”Each request is billed per token at the model’s Input, Output, Cache read and Cache write prices. :free models cost nothing. See How billing works.
Errors
Section titled “Errors”Errors use the OpenAI envelope: an error object with message, type, param and code. Only the errors specific to this endpoint are listed here. The rest, such as model_not_found, context_length_exceeded and subscribers_only, are in Errors.
| Status | Code | When |
|---|---|---|
| 400 | bad_request | input is missing or empty. previous_response_id is not null. text.format is not text. A message has an unknown role. An input_file part is present. A function tool has no name. tool_choice is not one of the supported forms. |
| 400 | bad_request | The model is not a chat model, such as an image or speech model. The message names the endpoint to use instead. |