Kimi api
★★★★★ 4.5 CE

Kimi API: Access, Rate Limits & SDKs 2026

Kimi K3 answers in the OpenAI chat format, so most teams reach it with a base-URL swap and a key. What decides the bill is automatic prompt caching, always-on reasoning, and rate tiers shared across every Kimi model.

Kimi API verdict

Verified today·7 sources checked

Kimi K3 speaks the OpenAI chat-completions format, so if you already call OpenAI or a compatible model.

Moving over is mostly pointing the SDK at Moonshot and setting a key. Everything runs through one chat call: tool use, JSON-schema output, streaming, prefill, and native image and video input all ride on the same request.

How to build on it

Treat adoption as a config change, not a rewrite. Point the OpenAI SDK at Moonshot, set your key, and keep the model id as kimi-k3. After that, three habits keep the bill sane. Put the long, unchanging part of your prompt first so automatic caching can turn repeat input into the cache-hit rate of $0.30 per 1M tokens. Set the completion-length cap yourself instead of leaning on the high default, because the rate limits count that cap even when the model writes less. And send bulk, non-urgent jobs to a cheaper Kimi model, since K3 has no Batch discount at launch.

Honest limits
  • Reasoning is always on and the effort level only accepts max at launch, so you cannot turn thinking down to save output tokens. Artificial Analysis clocked 130M output tokens against a 63M average, and output runs $15.00 per 1M.
  • The completion-length cap defaults to 131,072 tokens and can go to 1,048,576. Rate limits count your request tokens plus that cap, not the tokens actually generated, so a high cap quietly eats your per-minute budget.
  • The 60% Batch discount does not cover K3 at launch. It applies to kimi-k2.7-code, kimi-k2.6 and kimi-k2.5, so bulk work on the flagship pays full rate.
  • Rate limits are set per account and shared across every Kimi model. A burst of kimi-k2.6 traffic spends the same requests-per-minute budget as K3.
Compatibility
OpenAI chat format
Cache-hit input
$0.30 / 1M (-90%)
Context window
1M tokens
Rate tiers
6, recharge-gated
Batch on K3
Not yet
View sources

Kimi K3 API calls, task by task

Step 1 of 9 · Get connected

Access and OpenAI compatibility

Access is deliberately boring, which is the point. Kimi runs an OpenAI-compatible HTTP API, so the official OpenAI Python and Node SDKs, along with tools like LangChain, Dify and Coze, work once you change two settings: the base URL and the key. If you are wiring this up for the first time, the exact base URL, header, model id and SDK versions are in the reference below. The one choice that is not obvious is which platform you sign up on, because the global and China platforms bill in different currencies at independently set rates.

Connection reference

AspectDetailNotes
Base URLhttps://api.moonshot.ai/v1Direct HTTP, or the SDK base_url
AuthAuthorization: Bearer $MOONSHOT_API_KEYSingle bearer scheme; keys from the console
CompatibilityOpenAI Chat CompletionsOpenAI Python/Node SDKs, LangChain, Dify, Coze
Model idkimi-k3GET /v1/models lists the capability flags
SDK versionsPython 3.8+, Node 18+, openai 1.0+pip install --upgrade 'openai>=1.0'
Global vs ChinaUSD platform (Singapore) or RMB platform (China)Independently set rates; do not convert

Who needs this: anyone doing the first integration. Copy the base URL and header into your SDK config, keep the model id as kimi-k3, and pick the platform that matches your billing currency.

With the base URL and key set, the next move is to fire one real request and read what comes back.

Step 2 of 9 · Your first call

The first request, and what each line does

Time for one real request. Pick a language below and send the same chat call; each tab prints the reply and the cached-token count. By the end you have a working round trip and know where to read the answer.

The raw HTTP call: one POST with a bearer key, the model id kimi-k3, a messages array, and a cap on how long the reply may run. Handy for a smoke test or a language the SDK does not cover.

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": "Summarize the architecture of this repository."}],
    "max_completion_tokens": 4096
  }'

What comes back, and the defaults worth setting yourself

  • The reply is standard OpenAI shape: choices[0].message.content holds the text, and finish_reason is stop on a normal finish, tool_calls when the model wants a function, or length when it hit the token cap.
  • usage.cached_tokens is how a cache hit surfaces to you: the count of input tokens served from the automatic prefix cache and billed at $0.30 per 1M instead of $3.00.
  • max_completion_tokens defaults to 131,072 and can be set up to 1,048,576. Set it to what you actually need: rate limits count request tokens plus this number, so an unset default can burn per-minute budget on tokens you never generate.
  • Reasoning is always on. K3 reads the top-level reasoning_effort, which only accepts max for now, so do not send the K2-style thinking parameter.
  • The sampling knobs are fixed on K3: temperature 1.0, top_p 0.95, n 1, presence_penalty 0 and frequency_penalty 0. Leave them out of the request rather than trying to override them.
  • The API keeps no server-side conversation state. Each turn you resend the whole history, and for multi-turn or tool calls you return the assistant message unchanged, including its reasoning_content.

The endpoint surface

  • The chat completions endpoint (POST) is the one call that does the work: chat, tools, JSON output, streaming, prefill and vision all travel through it.
  • The models endpoint (GET) lists every model with capability flags: context_length, supports_image_in, supports_video_in, supports_reasoning and owned_by. Query it to confirm access before a call, since a 404 means no such model or no access.
  • The token-estimate endpoint (POST) sizes a request before you send it, which matters for vision, where image and video token counts are dynamic.
  • The balance endpoint (GET) reads remaining credit; the files endpoints upload, list, fetch and delete files used for vision and batch jobs.
  • Errors come back as JSON with error.type and error.message. Expect 400 for a bad request, 401 for a bad key, 429 at a rate limit, 500 on a server fault, and 504 if a single request runs past about two hours.

One endpoint carries the work and you can read its output. The first thing worth tuning is the bill, so start with caching.

Step 3 of 9 · Make it cheap

How automatic caching works, and how to earn a hit

Repeated input is where a K3 bill grows without anyone noticing. This step covers what earns a cache hit and how the discount is priced. Get the prompt structure right and the fixed part of every call bills at a tenth of the normal rate.

  • Prompt caching is fully automatic. There is no cache id to create, no TTL to manage, and no separate storage or per-minute fee; every request gets it without asking.
  • A hit is billed as the gap between two input rates: cache-miss input is $3.00 per 1M tokens, cache-hit input is $0.30 per 1M, a 90% discount.
  • To earn hits, keep the long, fixed part of the prompt (a system prompt, a handbook, a schema) at the very start of messages and identical between calls, so later requests match and reuse that prefix.
  • The hit surfaces in the response as usage.cached_tokens, so you can measure your real hit rate. OpenRouter's launch-week traffic averaged a 93% hit rate, which pulled effective input to about $0.488 per 1M.
  • Setting response_format, or loading tools dynamically, does not invalidate the prefix cache, so structured output and large tool inventories still benefit.

Structuring a prompt so it hits the cache

Reuse a long system prefix across questions. The first call has nothing to reuse (cached_tokens is 0); the second, with the same prefix first, bills those shared tokens at the cache-hit rate of $0.30 per 1M.

import os
from openai import OpenAI

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

# A long, unchanging block: a handbook, a schema, a system prompt. Load it once.
HANDBOOK = open("handbook.md").read()

def ask(question: str):
    return client.chat.completions.create(
        model="kimi-k3",
        messages=[
            {"role": "system", "content": HANDBOOK},  # first and byte-for-byte identical
            {"role": "user", "content": question},
        ],
        max_completion_tokens=2048,
    )

cold = ask("What does chapter 3 cover?")
print(cold.usage.cached_tokens)   # 0: nothing to reuse yet

warm = ask("And chapter 4?")
print(warm.usage.cached_tokens)   # shared prefix now bills at $0.30 / 1M, not $3.00

A cheap, repeatable call is a solid base. Next, let the model reach past its own text and run your functions.

Step 4 of 9 · Give it tools

Tool use: schemas, strict mode, and the K3-only required

A tool lets the model run your code instead of guessing an answer. Here you define one function, hand it over, and finish the round trip when the model asks to use it. Do it once and you have a full tool call, from the model's request to the final reply.

  • A tool is a function definition: a name, a description, and a JSON Schema for its parameters. The name must match the pattern ^[a-zA-Z_][a-zA-Z0-9-_]{2,63}$, and a plain English name gets picked more reliably.
  • strict defaults to true, which constrains the model's arguments to your schema. That schema must follow MFJS, Moonshot's JSON Schema dialect, and the walle CLI checks it before you ship. Pass strict false only when you want valid JSON without structural guarantees.
  • tool_choice is auto, none or required. required forces a call and is K3-only: kimi-k2.6 and kimi-k2.7-code error if you send it.
  • You can register up to 128 functions in one request. For a large inventory, load tools dynamically and lean on tool_choice; neither hurts the prefix cache.
  • The round-trip is standard: the model returns finish_reason tool_calls with an id and stringified arguments, you run the function, then append a role:tool message whose tool_call_id matches, and call again.

Calling a function, end to end

Define one tool, force a call with tool_choice required, read the arguments off tool_calls, run the function, then hand the result back as a role:tool message and call again for the final answer.

import json

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Look up the current weather for a city.",
        "parameters": {
            "type": "object",
            "properties": {"city": {"type": "string"}},
            "required": ["city"],
            "additionalProperties": False,
        },
        # strict defaults to true: arguments are constrained to this schema (MFJS)
    },
}]

messages = [{"role": "user", "content": "What is the weather in Beijing right now?"}]

first = client.chat.completions.create(
    model="kimi-k3",
    messages=messages,
    tools=tools,
    tool_choice="required",   # force a call; only K3 accepts "required"
    max_completion_tokens=1024,
)

call = first.choices[0].message.tool_calls[0]
args = json.loads(call.function.arguments)
# run get_weather(**args) yourself, then hand the result back:

messages.append(first.choices[0].message)          # return the assistant turn unchanged
messages.append({
    "role": "tool",
    "tool_call_id": call.id,                        # must match the call
    "content": json.dumps({"tempC": 29, "sky": "clear"}),
})

final = client.chat.completions.create(model="kimi-k3", messages=messages, tools=tools, max_completion_tokens=1024)
print(final.choices[0].message.content)

The model can call your code. It can also read what you show it, so the next step feeds it an image.

Step 5 of 9 · Show it an image

Vision input: base64 or an uploaded file, never a URL

K3 reads images and video inside the same chat call, with no separate endpoint to learn. This step covers how to attach a picture and the two rules that trip people up. Attach one image and you get an answer grounded in what it shows.

  • K3 reads images and video natively. Images come in two ways: base64 inlined as an image_url part, or a file you upload first and reference with an ms:// file id. Public image URLs are rejected.
  • message.content has to be an array of parts, for example an image_url part plus a text part. Serialize it into a plain string and it will not be treated as visual input.
  • Images may be png, jpeg, webp or gif; video may be mp4, mov, webm and a few others. Keep images at or below 4K and video at or below 1080p, since higher only costs processing time.
  • There is no cap on image count, but the whole request body must stay under 100 MB. For large or reused media, upload through the files endpoint instead of inlining.
  • Vision is billed as input tokens on the same model as moonshot-v1, with no separate per-image fee. Counts are dynamic (resolution and, for video, key frames drive them), so size a request with the token-estimate call first.

Sending an image inline

Read a PNG, base64-encode it, and send it as an image_url part alongside a text part. The content is a list, not a string, which is what makes it a vision request. No cURL tab for this one: a base64 payload inside a shell body is unreadable, so the walkthrough sticks to the SDKs.

import base64

with open("chart.png", "rb") as f:
    b64 = base64.b64encode(f.read()).decode()

response = client.chat.completions.create(
    model="kimi-k3",
    messages=[{
        "role": "user",
        "content": [   # content MUST be a list of parts, not a string
            {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{b64}"}},
            {"type": "text", "text": "What trend does this chart show?"},
        ],
    }],
    max_completion_tokens=1024,
)
print(response.choices[0].message.content)

Prose is fine for a person to read. When another system consumes the reply, you want a fixed shape instead.

Step 6 of 9 · Lock the output shape

Structured output: JSON mode versus a strict schema

When another program has to parse the reply, you want a guaranteed shape, not prose. This step sets loose JSON against a strict schema the model cannot break. The reply then comes back matching your field names and types every time.

  • response_format has two modes. json_object guarantees valid JSON but leaves the fields up to the model; json_schema pins the field names, types and nesting to a schema you supply.
  • json_schema is enforced by token-level constrained decoding: the sampler drops any token that would break the schema, so with strict true and additionalProperties false you get exactly the shape you asked for.
  • The schema must comply with MFJS; validate it with the walle CLI first. K3 reliably handles nested objects, arrays and anyOf; kimi-k2.7-code is the most robust for oneOf, $ref and additionalProperties; kimi-k2.6 is shaky on complex schemas.
  • For fields that might be missing, use a nullable union such as string or null, so the model returns null instead of inventing a value or dropping the key.
  • Parse choices[0].message.content, never the whole response object, because thinking models also return reasoning_content. A truncated object comes back as finish_reason length; raise the token cap or simplify the schema. Setting response_format does not invalidate the cache.

Getting a schema-locked JSON reply

Force a strict JSON object with json_schema. The nullable email union tells the model to return null when the field is absent rather than guessing, and only content is parsed.

import json

schema = {
    "type": "object",
    "properties": {
        "name": {"type": "string"},
        "email": {"type": ["string", "null"]},   # nullable union: returns null, not a guess
    },
    "required": ["name", "email"],
    "additionalProperties": False,
}

response = client.chat.completions.create(
    model="kimi-k3",
    messages=[{"role": "user", "content": "Pull the name and email from: Dana Ko, [email protected]"}],
    response_format={
        "type": "json_schema",
        "json_schema": {"name": "contact", "strict": True, "schema": schema},
    },
    max_completion_tokens=512,
)

data = json.loads(response.choices[0].message.content)  # parse .content only, never the whole object
print(data["name"], data["email"])

That settles what comes back. The next lever is when it arrives, so turn on streaming.

Step 7 of 9 · Stream the reply

Streaming, usage on the wire, and prefill

Streaming sends the answer as it is written, which cuts the wait for the first token. This step shows how to read the stream and still recover the token totals at the end. You print the reply as it lands and still read what the call cost.

  • Set stream true to get Server-Sent Events: the reply arrives as data: lines where message is replaced by delta, and the stream ends with data: [DONE]. You read text from choices[0].delta.content.
  • Add stream_options include_usage to get a final usage chunk before [DONE] carrying the token totals, including cached_tokens. If the stream is cut short, that final chunk may not arrive.
  • Kimi also attaches usage to the end block of each choice, so you can read per-choice totals; across choices only completion and total tokens differ, not the prompt count.
  • Streaming pairs with Partial Mode, or prefill: append a trailing assistant message with partial true to force the reply to continue from a prefix such as an opening brace or a code fence. Do not combine prefill with json_object; use structured output for locked JSON.

Streaming a reply token by token

Iterate the stream, print each delta as it lands, and read the final usage chunk, which is the only one that carries cached_tokens. include_usage is what makes that last chunk appear.

stream = client.chat.completions.create(
    model="kimi-k3",
    messages=[{"role": "user", "content": "Explain B-trees in two short paragraphs."}],
    max_completion_tokens=1024,
    stream=True,
    stream_options={"include_usage": True},   # adds a final usage chunk with cached_tokens
)

for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)
    if chunk.usage:                            # only the final chunk carries usage
        print("\ncached:", chunk.usage.cached_tokens)

You have now touched the whole request surface. If you are arriving from OpenAI, a few specifics differ, so line them up before the switch.

Step 8 of 9 · Move off OpenAI

Coming from OpenAI: what actually differs

Most of this already runs on the OpenAI SDK, so the move is small. This step lists the handful of real differences to check before you point the base URL at Moonshot. Check them and the switch is two lines, with no surprises after.

  • Migration from OpenAI is a base-URL and key swap on the same SDK; the compatible surface covers the chat and files endpoints.
  • temperature runs on a 0 to 1 scale here, against 0 to 2 on OpenAI. Setting temperature 0 with n greater than 1 is an error, and near 0 the API returns a single choice.
  • The deprecated functions and function_call fields are not supported. Use tools and tool_calls, which also do parallel calls.
  • Three Kimi-only extensions have no OpenAI equivalent: the K2-style thinking parameter (passed through the SDK's extra_body), the assistant-message partial flag for prefill, and K3's top-level reasoning_effort, which maps to OpenAI's own field but only accepts max.

The last thing to plan for is scale, because the rate tiers decide how hard you can push on day one.

Step 9 of 9 · Stay inside the limits

How the rate tiers work

Rate limits are worth reading before you launch, because they are not per-key and they are not per-model. Every limit sits on the account and is shared across every Kimi model you call, and the tier you land in is bought, not requested: it rises with your cumulative recharge. The ladder below lays out all six tiers, so you can see where a launch-day spike needs a bigger deposit set aside in advance.

Rate-limit tiers, Tier 0 to Tier 5

Tier (cumulative recharge)Concurrency / RPM / TPM / TPDNotes
Tier 0 ($1)1 / 3 / 500K / 1.5MThrottled floor; $1 minimum to start
Tier 1 ($10)50 / 200 / 2M / UnlimitedFirst real working tier
Tier 2 ($20)100 / 500 / 3M / Unlimited
Tier 3 ($100)200 / 5,000 / 3M / Unlimited
Tier 4 ($1,000)400 / 5,000 / 4M / Unlimited
Tier 5 ($3,000)1,000 / 10,000 / 5M / UnlimitedHigher ceilings on request

Set per account and shared across every model. Limits count request tokens plus your completion-length cap, not the tokens actually generated, and overflow returns a 429. RPM is requests per minute; TPM tokens per minute; TPD tokens per day.

Limits sit on the account and cover every Kimi model, which is the cue to pick the right one for each job.

Reference · Pick the right model

Which Kimi model for which job

Kimi K3 is the flagship, but it shares an account and an API with the rest of the family, and picking the right model per job is the cheapest optimization there is. K3 is the only 1M-context model and the only one that accepts tool_choice required. The K2.7 Code line is built for programming agents and has the steadiest structured output. K2.6 is the vendor's cost-saver, and K2.5 with the old moonshot-v1 series are on their way out. The table sets the capabilities and rates side by side so you can route work down when the flagship is overkill.

The full Kimi model lineup

ModelContextInput / output (per 1M)Best for / status
kimi-k31,048,576$3.00 miss / $0.30 hit in, $15.00 outFlagship. Text plus image and video in, reasoning always on, tool_choice required, reliable structured output. Not on Batch.
kimi-k2.7-code262,144$0.95 miss / $0.19 hit in, $4.00 outDedicated coding, image and video in, thinking always on. Most stable structured output. Highspeed variant priced 2x.
kimi-k2.6262,144$0.95 miss / $0.16 hit in, $4.00 outGeneral multimodal, thinking optional. Vendor's cost-saver; shaky on complex schemas; no required tool_choice.
kimi-k2.5262,144$0.60 miss / $0.10 hit in, $3.00 outOpen general model, image in only. Blocked for new users; full sunset expected around August 31, 2026.
moonshot-v1 (8k/32k/128k)8K to 128K$0.20 to $2.00 in, $2.00 to $5.00 outLegacy series, differ only by context; vision-preview variants read images. Sunsetting.

Global USD, per 1M tokens. The Batch API runs at 60% of these rates but covers only kimi-k2.7-code, kimi-k2.6 and kimi-k2.5, not K3. The China platform bills the same models in RMB at independently set rates.

Kimi API FAQ

How hard is it to move an OpenAI integration to Kimi K3?

For most code it is a base-URL and key change. Kimi speaks the OpenAI chat-completions format, so the official OpenAI Python and Node SDKs work once you point them at Moonshot and set your key, with the model id kimi-k3. A few things differ: temperature runs on a 0 to 1 scale rather than 0 to 2, the old functions and function_call fields are gone in favour of tools, and K3 fixes its sampling settings so you leave temperature, top_p and n out of the request.

What does a Kimi K3 call cost, and how much does caching save?

Input is $3.00 per 1M tokens and output is $15.00 per 1M. Prompt caching is automatic, with no cache id, TTL or storage fee, and a cache hit drops input to $0.30 per 1M, a 90% cut. You earn hits by keeping the long, fixed part of the prompt at the start so later requests match it; the hit shows up in the response as cached_tokens.

What are Kimi K3's rate limits?

They are recharge-gated tiers from 0 to 5, set per account and shared across every Kimi model. Tier 0 ($1 recharge) is a throttle at 1 concurrent request, 3 per minute and 1.5M tokens a day. Tier 1 ($10) opens it to 50 concurrent, 200 per minute and 2M tokens per minute with no daily cap, and Tier 5 ($3,000) reaches 1,000 concurrent and 10,000 per minute. Limits count request tokens plus your completion-length cap, so an oversized cap costs you headroom.

Can I make Kimi K3 cheaper with the Batch API?

Not for K3 yet. The Batch API runs at 60% of standard price but only covers kimi-k2.7-code, kimi-k2.6 and kimi-k2.5, so the flagship has no async discount. K3 also keeps reasoning at full effort, which lifts output tokens, so the real levers are automatic caching, a deliberate completion-length cap, and routing bulk non-frontier work to a cheaper model.

How do I send an image to Kimi K3?

As base64 inside the message, or by uploading the file first and referencing its id; public image links are rejected. The message content has to be a list of parts, one for the image and one for your text. Keep images at or below 4K and the whole request body under 100 MB. Vision is billed as input tokens at the normal rate, not as a separate per-image fee, and you can size it in advance with the token-estimate call.

Sources & verification

Verified by ComparEdgeMethod: Vendor docs, official pages, and selected independent sources
SourceWhat was checkedLast checked
Artificial AnalysisOfficial product pageJuly 17, 2026
Kimi Api Chat.MdAPI Chat.mdJuly 17, 2026
Kimi Api Models Overview.MdAPI Models Overview.mdJuly 17, 2026
Kimi Api Overview.MdAPI Overview.mdJuly 17, 2026
Kimi Api Tool Use.MdAPI Tool Use.mdJuly 17, 2026
Kimi Guide Kimi K3 Quickstart.MdKimi K3 Quickstart.mdJuly 17, 2026
Kimi Guide Migrating From Openai To Kimi.MdMigrating From Openai To Kimi.mdJuly 17, 2026

Every fact on this Kimi page is tied to a named source and a verification date. Freshness-sensitive figures trace to the sources above; verify against the vendor before relying on them.