how-tos

Kimi K3 API Guide: Python, Vision, Tools and 1M Context

Poyo.ai Team
8 min read
Share:

Kimi K3 API developer guide

Kimi K3 is available through Moonshot AI's OpenAI-compatible Chat Completions API with the model ID kimi-k3. The API supports always-on reasoning, streaming, images, uploaded video, strict JSON Schema, custom tools, dynamic tool loading, and a 1-million-token context window.

Compatibility does not mean identical behavior. K3 has fixed sampling values, requires complete assistant state in later tool and conversation turns, and handles reasoning separately from final content. This guide focuses on those details.

Availability and prices updated July 22, 2026. Kimi K3 is available on Poyo.ai as kimi-k3 through the OpenAI-compatible Chat Completions API. Pricing is $2.28 per 1M input tokens and $11.40 per 1M output tokens — 24% lower than official pricing.

Requirements

You need:

  • Python 3.9 or newer;
  • openai Python package version 1.0 or newer;
  • a Moonshot API key stored outside source control;
  • the base URL https://api.moonshot.ai/v1;
  • model ID kimi-k3.

Install the SDK:

python -m pip install --upgrade "openai>=1.0"

Set the key in your shell:

export MOONSHOT_API_KEY="your-key"

On PowerShell:

$env:MOONSHOT_API_KEY="your-key"

Never place a production key in a code example, client-side bundle, log, or repository.

Make your first Kimi K3 request

Python

import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["MOONSHOT_API_KEY"],
    base_url="https://api.moonshot.ai/v1",
)

response = client.chat.completions.create(
    model="kimi-k3",
    messages=[
        {"role": "user", "content": "Review this migration plan and list its three highest risks."}
    ],
)

print(response.choices[0].message.content)

cURL

curl https://api.moonshot.ai/v1/chat/completions \
  -H "Authorization: Bearer $MOONSHOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "kimi-k3",
    "messages": [
      {"role": "user", "content": "Explain Kimi Delta Attention in plain language."}
    ]
  }'

Configure reasoning effort

K3 always uses thinking mode. Configure its effort through the top-level reasoning_effort field:

response = client.chat.completions.create(
    model="kimi-k3",
    reasoning_effort="high",
    messages=[
        {"role": "user", "content": "Find the flaw in this distributed lock design."}
    ],
)

Supported values are:

ValueUse it for
lowEasier tasks where latency and output matter
highDifficult coding, analysis, and tool planning
maxThe hardest tasks and benchmark-style evaluation

The documented default is max. Do not assume it is the cheapest production setting. Evaluate success rate, latency, and generated tokens at each effort.

Stream reasoning and final content

Streaming responses expose reasoning and final text through different delta fields.

stream = client.chat.completions.create(
    model="kimi-k3",
    messages=[{"role": "user", "content": "Review this architecture for race conditions."}],
    stream=True,
)

for chunk in stream:
    delta = chunk.choices[0].delta
    reasoning = getattr(delta, "reasoning_content", None)
    if reasoning:
        # Store or process according to your product and provider policies.
        pass
    if delta.content:
        print(delta.content, end="", flush=True)

Keep user-facing final content separate from internal processing. Do not parse structured output from reasoning_content.

Send an image to Kimi K3

K3 vision messages use an array of content objects. Public image URLs are not supported in this flow; encode a local image as base64.

import base64
from pathlib import Path

image_data = base64.b64encode(Path("interface.png").read_bytes()).decode()

response = client.chat.completions.create(
    model="kimi-k3",
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "image_url",
                    "image_url": {"url": f"data:image/png;base64,{image_data}"},
                },
                {
                    "type": "text",
                    "text": "Identify the three largest accessibility problems in this interface.",
                },
            ],
        }
    ],
)

Validate file type and size before encoding user uploads. Avoid logging base64 payloads.

Send a video to Kimi K3

Upload video through the Files API, reference the returned ID with the ms:// scheme, and delete the file when it is no longer needed.

from pathlib import Path

video = client.files.create(file=Path("demo.mp4"), purpose="video")

try:
    response = client.chat.completions.create(
        model="kimi-k3",
        messages=[
            {
                "role": "user",
                "content": [
                    {
                        "type": "video_url",
                        "video_url": {"url": f"ms://{video.id}"},
                    },
                    {"type": "text", "text": "Summarize the workflow and identify failed steps."},
                ],
            }
        ],
    )
finally:
    client.files.delete(video.id)

Return strict JSON Schema output

Use strict: true when downstream code needs a predictable shape.

import json

response = client.chat.completions.create(
    model="kimi-k3",
    messages=[
        {"role": "user", "content": "Extract the risk, severity, and owner from this incident note."}
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "incident_risk",
            "strict": True,
            "schema": {
                "type": "object",
                "properties": {
                    "risk": {"type": "string"},
                    "severity": {"type": "string", "enum": ["low", "medium", "high"]},
                    "owner": {"type": ["string", "null"]},
                },
                "required": ["risk", "severity", "owner"],
                "additionalProperties": False,
            },
        },
    },
)

result = json.loads(response.choices[0].message.content or "{}")

Parse only the final message.content, then validate it again in application code.

Call custom tools

The first response can request one or more tools. Execute each allowed call, append the complete assistant message, then append one matching tool result for every tool_call_id.

import json

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_build_status",
            "description": "Return the current build status for an allowed project.",
            "parameters": {
                "type": "object",
                "properties": {"project": {"type": "string"}},
                "required": ["project"],
                "additionalProperties": False,
            },
        },
    }
]

messages = [{"role": "user", "content": "Check the web build and summarize any failure."}]

first = client.chat.completions.create(
    model="kimi-k3",
    messages=messages,
    tools=tools,
    tool_choice="required",
)

assistant_message = first.choices[0].message
messages.append(assistant_message)

for call in assistant_message.tool_calls or []:
    arguments = json.loads(call.function.arguments)
    # Authorize and validate before executing a real tool.
    tool_result = {"project": arguments["project"], "status": "passed"}
    messages.append(
        {
            "role": "tool",
            "tool_call_id": call.id,
            "content": json.dumps(tool_result),
        }
    )

final = client.chat.completions.create(
    model="kimi-k3",
    messages=messages,
    tools=tools,
)

Never execute arbitrary model-generated shell commands without a permission boundary, input validation, a scoped environment, and an audit trail.

Load tools dynamically

K3 supports placing a complete tool definition in a system message at the point where it becomes available. Keep that message in later history because the server does not retain it for you.

Dynamic loading helps large agent systems avoid sending every tool schema on every turn. It also creates new state-management requirements: the model must see the exact declaration when interpreting later tool results.

Use the 1M-token context window

Large contexts are most valuable when distant evidence must be reasoned over together. Use them deliberately:

  1. Keep stable repositories or document corpora at the beginning.
  2. Append questions and results rather than rewriting the prefix.
  3. Track cached and uncached input separately.
  4. Retrieve a smaller subset when the full corpus is unnecessary.
  5. Establish source identifiers so the final answer can be verified.
  6. Compact only when your client preserves all state required by K3.

Automatic caching has no cache ID or ordinary TTL parameter. Stable prefixes give the service the best opportunity to hit the cache.

Preserve complete multi-turn state

This is the most important K3-specific integration rule.

When continuing a conversation or returning tool results, append the complete assistant message returned by the API. Do not keep only content. Moonshot warns that K3 was trained with preserved thinking history and can become unstable if the harness drops required history or switches to K3 in the middle of a session.

Store conversation state securely, apply retention limits, and avoid exposing hidden state to users who should not see it.

Important Kimi K3 API limits

  • K3 always has thinking enabled.
  • reasoning_effort supports low, high, and max.
  • max_completion_tokens defaults to 131,072 and can be set up to 1,048,576.
  • temperature=1.0, top_p=0.95, n=1, presence_penalty=0, and frequency_penalty=0 are fixed; omit them.
  • Public image URLs are not supported for vision messages.
  • Multi-turn and tool requests must preserve the complete assistant message.
  • Moonshot says its web-search tool is being updated and is not currently recommended for production.

Production checklist

  • Keep API keys server side.
  • Add request timeouts and bounded retries.
  • Validate tool arguments and authorize every action.
  • Limit tool turns and completion length.
  • Preserve complete K3 assistant state.
  • Validate strict JSON after generation.
  • Record input, cached input, output, latency, and errors.
  • Avoid switching models in the middle of a K3 session.
  • Add explicit behavioral boundaries to reduce excessive proactiveness.
  • Test with broken tools, partial responses, and long histories.

Read Kimi K3 API Pricing before choosing context and output limits. Follow the Kimi K3 model page for Poyo.ai availability.

Frequently asked questions

Is the Kimi K3 API OpenAI compatible?

Yes. Moonshot exposes an OpenAI-compatible Chat Completions endpoint. K3-specific state, reasoning, sampling, and media rules still apply.

What is the Kimi K3 model ID?

The official Moonshot API model ID is kimi-k3.

Does Kimi K3 support function calling?

Yes. It supports custom tools, required tool choice, matching tool results, and dynamic tool loading.

Can Kimi K3 process video?

Yes. Upload the video through the Files API and reference its ms:// file ID in a video content object.

How do I use the 1M context window?

Send the required messages and content through the standard model request, keep stable prefixes unchanged for automatic caching, and set bounded completion limits.

Sources

Share: