The Kimi K3.1 Pro API runs at https://api.moonshot.ai/v1 with model IDs kimi-k3.1-pro and kimi-k3.1-pro-highspeed. It speaks three wire formats: OpenAI Chat Completions, the Responses API and Anthropic Messages, so the SDKs you already use work with a changed base URL. The model unlocks after a $1 minimum top-up.
This is the reference for production code. For your first call, streaming and the Codex or Claude Code setups, read how to use Kimi K3.1 Pro; for costs, see Kimi K3.1 Pro pricing. Facts come from Moonshot's K3.1 Pro quickstart and linked docs, read October 24, 2026.
Kimi K3.1 Pro Responses API, Anthropic API and Chat Completions
Moonshot exposes K3.1 Pro through three API surfaces. Pick the one your client library or agent already speaks; the model, key and billing are the same on all three.
| Surface | Format | Endpoint | Typical client |
|---|---|---|---|
| Chat Completions | OpenAI | https://api.moonshot.ai/v1/chat/completions |
openai SDK, most frameworks |
| Responses API | OpenAI Responses | https://api.moonshot.ai/v1/responses |
Codex (wire_api = "responses") |
| Messages API | Anthropic | https://api.moonshot.ai/anthropic/v1/messages |
Anthropic SDK, Claude Code |
They differ in how you set the cache TTL and where usage lands (see caching below). Coming from K3? Our Kimi K3 API guide still applies; K3.1 Pro is a post-trained K3 with the same 1,048,576-token context.
Kimi K3.1 Pro API key: unlock and check access
You need a funded account and a key from the right product. Four steps:
- Top up at least $1 on the Kimi API platform. K3.1 Pro is a flagship model and unlocks only after a successful top-up.
- Create a key in the API keys console and export it as
MOONSHOT_API_KEY. - Confirm the model is visible to that key with
GET /v1/models. - Call
kimi-k3.1-profrom code.
curl https://api.moonshot.ai/v1/models \
--header "Authorization: Bearer $MOONSHOT_API_KEY" | grep -o '"kimi-k3.1-pro[^"]*"'
If the model isn't listed, fix that first. Kimi API, Kimi Code and Kimi Membership are separate products: a Kimi Code key won't work on the API endpoint, and a membership doesn't become API balance.
Request parameters that matter for K3.1 Pro
Most OpenAI parameters behave as you'd expect. These are the ones that differ or catch people out:
| Parameter | What to know |
|---|---|
reasoning_effort |
Top-level field: "low", "high" or "max" (default "max"). Thinking is always on. |
thinking |
Don't send it. K3.1 Pro doesn't support it; use reasoning_effort instead. |
max_completion_tokens |
Defaults to 131072. Maximum output is 1,048,576 minus your prompt tokens. |
response_format |
json_schema with strict: true. Parse message.content only, never reasoning_content. |
partial |
Put "partial": true on a final assistant message to continue from a prefix. |
tool_choice |
"required" forces at least one tool call; "auto" lets the model decide. |
prompt_cache_options |
{"mode": "implicit", "ttl": "5m" or "1h"} on Chat Completions and Responses. |
Reasoning tokens count toward your usage, so use "low" for classification and extraction. Preserved Thinking is always on, so every assistant message goes back with its reasoning_content intact (thinking models guide).
Kimi K3.1 Pro tool calling: a complete loop in Python
A production tool loop on K3.1 Pro follows four rules from Moonshot's docs:
- Force a tool call on the first turn with
tool_choice="required", then switch to"auto". - Append the complete assistant message,
reasoning_contentandtool_callsincluded. - Send one
toolmessage pertool_call_id. - Cap the number of turns so a confused model can't loop forever.
import json, os
from openai import OpenAI
client = OpenAI([REDACTED CREDENTIAL],
base_url="https://api.moonshot.ai/v1")
TOOLS = [{"type": "function", "function": {
"name": "get_order_status",
"description": "Look up an order's shipping status by ID",
"parameters": {"type": "object",
"properties": {"order_id": {"type": "string"}},
"required": ["order_id"]}}}]
def get_order_status(order_id):
return {"order_id": order_id, "status": "shipped"}
messages = [{"role": "user", "content": "Where is order A-1042?"}]
tool_choice = "required"
for _ in range(8): # hard cap on turns
resp = client.chat.completions.create(
model="kimi-k3.1-pro", reasoning_effort="high",
messages=messages, tools=TOOLS, tool_choice=tool_choice)
msg = resp.choices[0].message
messages.append(msg) # whole message, not msg.content
if not msg.tool_calls:
print(msg.content)
break
for call in msg.tool_calls:
result = get_order_status(**json.loads(call.function.arguments))
messages.append({"role": "tool", "tool_call_id": call.id,
"content": json.dumps(result)})
tool_choice = "auto"
The classic bug is appending msg.content instead of msg, which drops tool_calls and reasoning_content.
Tool calling at scale with search_tools
When your agent has dozens or hundreds of tools, don't send every definition on every request. Moonshot's K3 tool calling best practice recommends this flow:
- Declare one
search_toolsfunction (your backend implements it) plus a few core tools. - Set
tool_choice: "required"on the first turn so the model retrieves before answering. - Inject the matching tool definitions through a
systemmessage that carries atoolsfield. - Let the model call the loaded tools on later turns, with
tool_choiceback on"auto".
# after search_tools returns ["create_github_pr"]
messages.append({"role": "system",
"tools": [CATALOG["create_github_pr"]]})
Injected definitions use the top-level tools format and apply from that message onward. The server doesn't retain them, so keep the message in later requests. Neither changing tool_choice nor appending a definition breaks the prefix cache.
Vision and video input
K3.1 Pro accepts images and video alongside text and returns text. Make content an array of parts: an image_url part (the quickstart example sends a base64 data URL, and notes public image URLs aren't supported) or a video_url part that points at an uploaded file with an ms:// ID.
from pathlib import Path
video = client.files.create(file=Path("demo.mp4"), purpose="video")
content = [{"type": "video_url", "video_url": {"url": f"ms://{video.id}"}},
{"type": "text", "text": "Summarize this video."}]
Pass content as the user message, and delete the file with client.files.delete(video.id) when you're done.
Context caching in code
Caching is automatic for repeated prefixes with a 5-minute default TTL. Cache hits bill at $0.20 per million tokens against $2.00 for uncached input, and a 1-hour write costs $4.00 against $2.00 for 5 minutes. On a 1M-token prefix, the 1-hour TTL pays for itself after two hits.
Put stable content first (system prompt, tool definitions, docs), changing content last, and no timestamps in the prefix. With the openai SDK, pass the TTL through extra_body:
resp = client.chat.completions.create(
model="kimi-k3.1-pro",
messages=[{"role": "system", "content": DOCS},
{"role": "user", "content": question}],
extra_body={"prompt_cache_options": {"mode": "implicit", "ttl": "1h"}},
)
d = resp.usage.prompt_tokens_details
print(resp.usage.prompt_tokens, d.cached_tokens,
getattr(d, "cache_write_tokens", 0))
The Anthropic API sets the TTL with a top-level cache_control field; markers inside messages are ignored:
curl https://api.moonshot.ai/anthropic/v1/messages \
--header "Content-Type: application/json" \
--header "Authorization: Bearer $MOONSHOT_API_KEY" \
--data '{"model": "kimi-k3.1-pro", "max_tokens": 256,
"cache_control": {"type": "ephemeral", "ttl": "1h"},
"messages": [{"role": "user", "content": "Hello"}]}'
Where cache usage shows up depends on the surface:
| Surface | Cache read | Cache write |
|---|---|---|
| Chat Completions | usage.prompt_tokens_details.cached_tokens |
usage.prompt_tokens_details.cache_write_tokens |
| Responses | usage.input_tokens_details.cached_tokens |
usage.input_tokens_details.cache_write_tokens |
| Messages | usage.cache_read_input_tokens |
usage.cache_creation_input_tokens |
When streaming Chat Completions, set stream_options.include_usage=true to get usage in the final chunk. Each hit renews the TTL, which is locked at first write. Full rules: the context caching guide.
Kimi K3.1 Pro API errors and fixes
Most failures fall into six patterns. Check error.type on every 429, because the fix depends on it.
| Symptom | Cause | Fix |
|---|---|---|
| 401 or 404 | Wrong product key, region mismatch, no balance, or wrong model name | Use a Kimi API key, check balance, confirm the model in GET /v1/models, clear stale env vars and proxies |
429 engine_overloaded_error
|
Server capacity | Wait per Retry-After, back off, lower concurrency. Topping up won't help. |
429 rate_limit_reached_error
|
Your org hit concurrency, RPM, TPM or TPD | Slow down or move up a tier |
429 exceeded_current_quota_error
|
Low balance, overdue account or expired voucher | Check the balance API and top up |
finish_reason: "length" |
Output hit max_completion_tokens
|
Raise the limit or continue with partial mode |
| Same tool called again and again | Broken message layout | Append the message as-is, match every tool_call_id, assemble streamed tool_calls fully, then add client-side repeat detection |
Watch retries. The OpenAI SDK retries 2 times by default on connection errors, 408, 409, 429 and 5xx, so one call can become three requests against your RPM. On a low tier, lower the client's max_retries and back off on error.type yourself. Requests interrupted by a 429 aren't charged.
If a third-party agent fails, call the API directly with the same key, endpoint and model. If that works, the tool is the problem. See the troubleshooting page and error codes.
Kimi K3.1 Pro rate limits by tier
Your cumulative top-up sets your tier on the limits page:
| Tier | Cumulative top-up | Concurrency | RPM | TPM |
|---|---|---|---|---|
| Tier0 | $1 | 1 | 3 | 500,000 (1.5M per day) |
| Tier1 | $10 | 15 | 100 | 2,000,000 |
| Tier2 | $20 | 40 | 100 | 3,000,000 |
| Tier3 | $100 | 50 | 200 | 3,000,000 |
| Tier4 | $1,000 | 60 | 200 | 4,000,000 |
| Tier5 | $3,000 | 100 | 300 | 5,000,000 |
Tier0 allows 3 requests per minute, and every turn of a tool loop is a request. A five-turn agent run already spills past one minute at that tier, so budget $10 cumulative before you test agents seriously.
Contract-test the Kimi API with Apidog CLI
A contract test catches the day your tool loop stops getting tool_calls back. Let your coding agent build it with Apidog CLI. Install and log in once:
npm install -g apidog-cli@latest
apidog login --with-token <YOUR_TOKEN>
apidog skill install
Then prompt Claude Code, Codex or whichever agent you use:
In Apidog project <projectId>, create an environment for https://api.moonshot.ai/v1
and an endpoint for POST /chat/completions. Add a test case that sends model
kimi-k3.1-pro, reasoning_effort "low", one get_order_status tool and
tool_choice "required". Assert status 200 and that choices[0].message.tool_calls
is non-empty. Run it and report failures.
The agent reads the schema, validates its payload and runs the case:
apidog environment create kimi-prod --project <projectId> --base-url https://api.moonshot.ai/v1
apidog endpoint create --project <projectId> --file ./endpoint.json
apidog cli-schema get test-case-create
apidog cli-schema validate test-case-create --file case.json
apidog test-case create --project <projectId> --file case.json
apidog run --test-case <caseId> --project <projectId> -e <envId> -r cli,json
Test cases need a valid category; apidog test-case category --project <projectId> lists them. Once the run passes, swap -r cli,json for -r junit with --out-dir and the same check gates your CI, as our Apidog CLI CI/CD guide shows. Agent setup lives in Apidog CLI in Claude Code. Apidog's Free plan covers up to 4 users.
FAQ
What is the base URL for the Kimi K3.1 Pro API?
https://api.moonshot.ai/v1 for Chat Completions and the Responses API, and https://api.moonshot.ai/anthropic for the Anthropic-compatible Messages API.
Does the Kimi K3.1 Pro API support the thinking parameter?
No. Thinking is always on. Control it with the top-level reasoning_effort field ("low", "high" or "max").
Why do I get 429 right after topping up?
Read error.type. engine_overloaded_error is server capacity and a top-up won't fix it. rate_limit_reached_error means your tier's limits, and Tier0 allows only 3 RPM.
How do I know whether caching is working?
A non-zero cache read field in usage means a hit: prompt_tokens_details.cached_tokens on Chat Completions or cache_read_input_tokens on Messages.
Is there a free Kimi K3.1 Pro API tier?
No. The API needs a $1 minimum top-up. Free chat in the Kimi app is the $0 route, covered in how to use Kimi K3.1 Pro for free. For model background, see what Kimi K3.1 Pro is.
Top comments (0)