kimi-k3
Kimi K3 — Moonshot's open-weight flagship for long-horizon coding and knowledge work. OpenAI-compatible /api/v1/chat/completions on reapi.ai with a 1,048,576-token context window, output up to the whole window, always-on reasoning, and native image and video input.
Moonshot's Kimi K3 — the flagship for long-horizon coding and end-to-end
knowledge work — exposed through reAPI as a drop-in OpenAI-compatible
Chat Completions endpoint. A 1,048,576-token context window shared by
input and generated output, reasoning
that is always on with a three-rung reasoning_effort dial, native image
and video input, tool calling with a required tool choice, strict JSON
Schema output, and automatic context caching. The wire model id is
kimi-k3. Current rates live on the
model page.
Quick example
curl https://reapi.ai/api/v1/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "kimi-k3",
"messages": [
{ "role": "user", "content": "Refactor this module and add tests." }
],
"max_completion_tokens": 16384,
"reasoning_effort": "high",
"stream": true
}'from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://reapi.ai/api/v1",
)
stream = client.chat.completions.create(
model="kimi-k3",
messages=[{"role": "user", "content": "Refactor this module and add tests."}],
max_completion_tokens=16384,
reasoning_effort="high",
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta
reasoning = getattr(delta, "reasoning_content", None)
if reasoning:
print(reasoning, end="")
if delta.content:
print(delta.content, end="")import OpenAI from "openai";
const client = new OpenAI({
apiKey: "YOUR_API_KEY",
baseURL: "https://reapi.ai/api/v1",
});
const stream = await client.chat.completions.create({
model: "kimi-k3",
messages: [{ role: "user", content: "Refactor this module and add tests." }],
max_completion_tokens: 16384,
reasoning_effort: "high",
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
body, _ := json.Marshal(map[string]any{
"model": "kimi-k3",
"messages": []map[string]string{
{"role": "user", "content": "Refactor this module and add tests."},
},
"max_completion_tokens": 16384,
"reasoning_effort": "high",
})
req, _ := http.NewRequest("POST",
"https://reapi.ai/api/v1/chat/completions", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
fmt.Println(string(out))
}Authentication
Use your reAPI API key — the same key that calls the image, video and audio endpoints — as a bearer token:
Authorization: Bearer YOUR_API_KEYCreate one under API keys in your reAPI dashboard. Chat requests are billed from the same credit balance as every other model on the platform.
Endpoint
POST /api/v1/chat/completionsBase URL https://reapi.ai/api/v1. The wire format is OpenAI-compatible, so the
same SDKs (openai-python, openai-node, openai-go, …) work once you swap the
base URL, the key and the model string. Moonshot's own quickstart drives this
model through the OpenAI SDK, so the compatibility is the vendor's design rather
than a translation layer.
Request body
model — string, required
Must be kimi-k3 exactly — no date suffix, no version decimal.
messages — array, required
Conversation history, each entry an object with role and content. Text, image
and video parts are supported — see Visual input.
Echo the assistant message back unchanged. In multi-turn conversations and
tool-call loops, the complete assistant message returned by the API has to go
back into messages as-is, including reasoning_content and tool_calls.
Keeping only content — the habit most OpenAI-shaped code has — breaks this
model's Preserved Thinking.
max_completion_tokens — integer
Upper bound on generated tokens, including reasoning and the visible answer.
Moonshot's native API documents a
131,072 default and accepts parameter values up to 1,048,576. It also
rejects a request when input tokens plus max_completion_tokens exceed the
context window. The largest accepted parameter value is therefore not a promise
of a million-token answer alongside a nonempty prompt.
On this reAPI endpoint, omitting the field uses the configured model ceiling, not Moonshot's native default. Set an explicit output budget, such as the 16,384 in the examples, and leave room for the input, preserved history, and reasoning. Raise the budget only within the remaining context capacity.
reasoning_effort — string, default "max"
Top-level field controlling how hard the model thinks. See Reasoning.
stream — boolean, default false
When true, tokens arrive as server-sent events. Reasoning and answer come as
separate deltas — reasoning_content and content — so a client can render
the reasoning live and still parse the answer on its own.
tools / tool_choice — optional
Tool definitions and the strategy for picking among them. tool_choice accepts
auto, none and required. See Tool calling.
response_format — object, optional
A JSON Schema with strict: true constrains the answer field. Parse that
field, not reasoning_content, which is prose.
Reasoning
This model always reasons. Moonshot's own FAQ answers "how do I turn off the chain of thought" with a flat you can't. There is no thinking toggle; the lever is effort.
reasoning_effort takes three rungs and defaults to the most expensive one:
| Level | Use it for |
|---|---|
max | The default. The hardest reasoning, where correctness outweighs cost. |
high | A step down that still reasons hard. |
low | Short, scoped, latency-sensitive work — and the answer to "the reasoning is taking too long". |
There is no medium.
Pick the rung before the conversation starts. Moonshot documents that switching effort levels invalidates prefix-cache hits, so flipping it mid-session silently throws away your cache.
The K2-era thinking object is not a parameter on this model. If you are
migrating from kimi-k2.6 or kimi-k2.7-code, delete it and use top-level
reasoning_effort instead. Code that already sends OpenAI's reasoning_effort
needs no change beyond the accepted values.
Parameters that are fixed
Moonshot pins all five of these on this model. Passing any other value returns an error, so leave them out of the request entirely:
| Parameter | Fixed at |
|---|---|
temperature | 1.0 |
top_p | 0.95 |
n | 1 |
presence_penalty | 0 |
frequency_penalty | 0 |
Steer with prompting and the reasoning_effort rung instead.
Tool calling
Two controls are specific to this generation.
tool_choice: "required" forces at least one tool call on the turn — the way
to stop an agent answering from memory when it was supposed to look something up.
The K2 models reject this value; this one accepts it.
Dynamic tool loading introduces a tool partway through a conversation: put
its complete definition in a system message that carries tools and no
content. It becomes available from that position onward.
{
"role": "system",
"tools": [
{
"type": "function",
"function": {
"name": "calculate",
"description": "Evaluate an arithmetic expression",
"parameters": {
"type": "object",
"properties": { "expression": { "type": "string" } },
"required": ["expression"]
}
}
}
]
}The server does not retain a dynamically loaded tool. Keep that system
message in your request history or the tool disappears on the next turn.
Include the complete name, description and parameters in the definition,
and after executing calls, append one tool message per call with the matching
tool_call_id.
Visual input
| Modality | Supported |
|---|---|
| Text | ✅ |
| Image | ✅ |
| Video | ✅ |
Output is text only. Vision is native to this model rather than a separate variant, which is what makes screenshot-driven work — frontend layout, game development, CAD — practical: it can look at what it just produced.
Public image URLs are not accepted. Moonshot documents base64 data URIs, or a
file reference from its own upload API, as the two ways in. content must also
be an array of parts, not a serialized string.
{
"role": "user",
"content": [
{ "type": "image_url", "image_url": { "url": "data:image/png;base64,iVBORw0..." } },
{ "type": "text", "text": "Why does this layout break at 768px?" }
]
}Note that file references come from Moonshot's Files API, which the Chat Completions endpoint does not itself provide.
Context caching
Caching is automatic — no cache id, no TTL, no extra parameter. Keep a long prefix (system prompt, knowledge document, tool definitions) stable and repeat requests attempt a hit on their own. Two conditions decide whether that happens:
- The previous request's prompt tokens must exceed 256. Below that the request is not cached at all.
- The
reasoning_effortrung must not change — switching it invalidates the prefix cache.
Put the fixed bulk at the front of messages and append the varying question
after it.
Pricing dimensions
Billing is per token, from your reAPI credit balance, with separate input and output rates. Three things to keep in mind:
- Reasoning tokens bill as output. Since this model always reasons, that is the usual reason a bill exceeds an estimate built from visible answer length.
- The rate is flat across context length. Moonshot documents no long-context tier, so a million-token prompt costs the same per token as a short one.
- Effort moves the bill. It is the only reasoning lever, and it defaults to the most expensive rung — so it is the first thing to tune.
Both token rates sit below Moonshot's published per-token rate, output by a
full fifth. Current numbers are on the
model page — that table is the canonical
source, not this page. The platform constants are 1 credit = $0.001 and
$1 = 1,000 credits; a request's cost is its input and output tokens at the
per-million rates, converted at that ratio.
Response shape
Non-streaming (stream: false)
{
"id": "chatcmpl-...",
"object": "chat.completion",
"created": 1785000000,
"model": "kimi-k3",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"reasoning_content": "...",
"content": "..."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 1204,
"completion_tokens": 860,
"total_tokens": 2064
}
}reasoning_content is a sibling of content, not a replacement for it — and it
is the field you must carry into the next request.
Streaming (stream: true)
Server-sent events, each data: line carrying a chat.completion.chunk.
Reasoning arrives in choices[0].delta.reasoning_content and the answer in
choices[0].delta.content, terminated by data: [DONE].
Errors
Failures use reAPI's standard error envelope. See the errors catalog for the full code list. Common cases:
| Trigger | What to do |
|---|---|
| Missing or invalid API key | Create a key under API keys in the reAPI dashboard |
Unknown model value | Send kimi-k3 exactly |
temperature / top_p / n / penalty params present | Remove them; they are fixed on this model |
K2-era thinking object present | Remove it and use reasoning_effort |
reasoning_effort set to medium | Not a valid rung — use low, high or max |
A public image URL in an image_url part | Send a base64 data URI or an uploaded file reference |
content sent as a string for a multimodal turn | Make it an array of parts |
| Output budget exceeds the parameter ceiling or remaining context | Lower max_completion_tokens or shorten the input; Moonshot validates input plus the requested budget against the context window |
| Insufficient balance | Top up your reAPI credits |
| Upstream rate limit | Retry with backoff, or route through another model |
Moonshot flags its own web_search tool as being updated and does not
recommend using it in the near term. Treat web search as unavailable on this
model for now and supply fresh context yourself.
Tips
- Give the whole task up front. This model is built for long-horizon work under minimal supervision; a complete specification beats a drip-feed of short turns.
- Drop your sampling parameters first. The single most common migration error
here is a carried-over
temperature. - Tune effort before anything else. The default is
max;lowexists precisely for the case where reasoning is costing more than the answer is worth. - Budget for reasoning and input. Reasoning consumes part of the output
allowance. If
finish_reasonislength, check the requested cap and remaining context before raisingmax_completion_tokensor continuing in another call. - Stream anything interactive, and render
reasoning_contentseparately from the answer rather than concatenating them. - Keep the assistant message intact in history. Stripping
reasoning_contentis silent — it does not error, it just degrades multi-turn behaviour. - Front-load the stable bulk of your prompt so automatic caching can hit, and do not change the effort rung mid-conversation.
Related
- Kimi K3 model page — current rates
- Errors catalog
- Authentication
- Quickstart