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.