Kimi K3 — Moonshot's 2.8-trillion-parameter open model, with a 1-million-token context window and multimodal input — speaks the OpenAI Chat Completions API. That means you don't learn a new SDK or rewrite your agent. You change two lines: the base URL and the model name. Here's the whole thing in three languages.
1. Get a key, set it once#
Create a key in the Moonshot console and export it. Everything below reads it from the environment — never hard-code it:
export MOONSHOT_API_KEY="sk-..."
2. The call — Python#
Reuse the official openai SDK. The only K3-specific edits are base_url and model:
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["MOONSHOT_API_KEY"],
base_url="https://api.moonshot.ai/v1", # ← change 1
)
resp = client.chat.completions.create(
model="kimi-k3", # ← change 2
reasoning_effort="high", # low | medium | high | max
max_completion_tokens=4096,
messages=[
{"role": "system", "content": "You are a terse senior engineer."},
{"role": "user", "content": "Review this migration plan and name the 3 riskiest assumptions."},
],
)
print(resp.choices[0].message.content)
If your codebase already talks to OpenAI, this is your codebase — same client.chat.completions.create, same message shape, same resp.choices[0].message.content. Tool-calling and streaming come along unchanged.
3. The same call — Node#
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.MOONSHOT_API_KEY,
baseURL: "https://api.moonshot.ai/v1",
});
const resp = await client.chat.completions.create({
model: "kimi-k3",
reasoning_effort: "high",
max_completion_tokens: 4096,
messages: [
{ role: "user", content: "Summarize this 200-page RFP into 5 decisions I have to make." },
],
});
console.log(resp.choices[0].message.content);
4. The same call — curl#
For a smoke test with no SDK at all:
curl https://api.moonshot.ai/v1/chat/completions \
-H "Authorization: Bearer $MOONSHOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "kimi-k3",
"reasoning_effort": "medium",
"messages": [{"role": "user", "content": "One sentence: what is an MoE model?"}]
}'
The two knobs that matter#
reasoning_effort is the lever most people miss. K3 will spend more internal reasoning at high/max — worth it for planning, debugging, and code, wasteful for classification or extraction. Dial it per call type, not globally.
The output column is your bill. K3 runs about $3 per million input / $15 per million output — frontier-tier pricing, not budget-workhorse pricing, because it competes on agentic benchmarks rather than on being the cheapest token. Agents spend most of their tokens on output, so that $15 is the number to watch. The 1M-token context tempts you to stuff whole codebases into input; that's the cheap half — the generated tokens are where cost accumulates.
If you don't want a second vendor#
Point the exact same code at OpenRouter — change the base URL and prefix the model slug, nothing else:
client = OpenAI(
api_key=os.environ["OPENROUTER_API_KEY"],
base_url="https://openrouter.ai/api/v1",
)
# model="moonshotai/kimi-k3"
That's the payoff of an OpenAI-shaped API: the direct endpoint, a gateway, and — once its open weights land this weekend — your own self-hosted /v1 are all the same three lines of code. If you go the self-host route, don't skip the provenance check on those weights before they touch a GPU, and if you're still deciding between hosted and self-hosted, we ran the rent-vs-self-host economics on exactly this model.



