What you'll build
kimi-k3.1-pro is Moonshot AI's K3.1-series model on hiapi, called through the OpenAI-compatible POST /v1/chat/completions endpoint, not the async /v1/tasks queue used for image and video models. This guide gives you a working curl and Python call, then covers streaming, tool calls, JSON mode, and the parameters this model rejects. Every request and response below was run against the live API on 2026-10-29.
Prerequisites: an hiapi API key from the dashboard. Requests authenticate with Authorization: Bearer sk-<your-key>.
Confirm the model id first
GET /v1/models lists three Kimi entries. The id uses a dot (3.1), not a hyphen:
kimi-k3
kimi-k3.1-pro
kimi-k3.1-pro-highspeed
Use kimi-k3.1-pro exactly. The URL slug of the model page is the same string. The model page lists a 1M-token context window and up to 131,072 output tokens.
Minimal working request
curl
curl https://api.hiapi.ai/v1/chat/completions \
-H "Authorization: Bearer sk-<your-key>" \
-H "Content-Type: application/json" \
-d '{
"model": "kimi-k3.1-pro",
"reasoning_effort": "low",
"max_tokens": 2000,
"messages": [{"role": "user", "content": "Reply with exactly: pong"}]
}'
Actual response:
{
"id": "chatcmpl-202610291406016130917698268d9d69wIjAYVY",
"object": "chat.completion",
"model": "kimi-k3.1-pro",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "pong",
"reasoning_content": "I'll respond exactly pong."
},
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": 91,
"completion_tokens": 23,
"total_tokens": 114,
"completion_tokens_details": {"reasoning_tokens": 6}
}
}
Python
import requests
resp = requests.post(
"https://api.hiapi.ai/v1/chat/completions",
headers={"Authorization": "Bearer sk-<your-key>"},
json={
"model": "kimi-k3.1-pro",
"reasoning_effort": "low", # low | high | max (default max)
"max_tokens": 2000,
"messages": [{"role": "user", "content": "Reply with exactly: pong"}],
},
timeout=180,
)
resp.raise_for_status()
choice = resp.json()["choices"][0]
if choice["finish_reason"] == "length" and not choice["message"]["content"]:
raise RuntimeError("reasoning used the whole max_tokens budget; raise max_tokens")
print(choice["message"]["content"])
Reasoning is always on, so budget for it
The model page states reasoning is always enabled, with reasoning_effort set to low, high or max (default max). Reasoning tokens are billed as output and count against max_tokens. Our request with max_tokens: 30 and no reasoning_effort (so max):
{
"choices": [{"message": {"content": "", "reasoning_content": "I need respond to user simple: \"Explain LRU cache in two sentences.\" I'll provide exactly two sentences likely. Should think concise accurate."}, "finish_reason": "length"}],
"usage": {"completion_tokens": 30, "completion_tokens_details": {"reasoning_tokens": 27}}
}
27 of the 30 tokens went to reasoning and content came back empty. Treat finish_reason: "length" with empty content as "retry with a bigger budget", not as an answer. Use a generous max_tokens (we used 2000-3000 for every call here), or reasoning_effort: "low" for simple tasks.
Streaming
Add "stream": true (and "stream_options": {"include_usage": true} if you want usage). The stream is standard SSE chat.completion.chunk events. Reasoning arrives first as delta.reasoning_content, token by token, and the answer follows as delta.content:
data: {"object":"chat.completion.chunk","model":"kimi-k3.1-pro","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
data: {"...","choices":[{"index":0,"delta":{"reasoning_content":"I"},"finish_reason":null}]}
data: {"...","choices":[{"index":0,"delta":{"reasoning_content":" should"},"finish_reason":null}]}
A UI that only reads delta.content shows nothing during the reasoning phase. Render reasoning_content as a "thinking" state, or the call looks hung.
Tool calls
Function tools use the standard OpenAI tools array. Request:
curl https://api.hiapi.ai/v1/chat/completions \
-H "Authorization: Bearer sk-<your-key>" \
-H "Content-Type: application/json" \
-d '{
"model": "kimi-k3.1-pro",
"reasoning_effort": "low",
"max_tokens": 3000,
"tools": [{"type": "function", "function": {
"name": "get_weather",
"description": "Get weather for a city",
"parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}
}}],
"messages": [{"role": "user", "content": "Weather in Paris?"}]
}'
Actual response (trimmed):
{
"choices": [{
"message": {
"role": "assistant",
"content": "",
"tool_calls": [{"index": 0, "id": "tool_BqQcDsdAJ91D6BEV7DNirvs4", "type": "function",
"function": {"name": "get_weather", "arguments": "{\"city\":\"Paris\"}"}}],
"reasoning_content": "I'll respond using the tool get weather Paris. Straight."
},
"finish_reason": "tool_calls"
}]
}
When you send the tool result back, append the whole assistant message (tool_calls and reasoning_content included), as the model page instructs, then add your role: "tool" message with the matching tool_call_id. We did not run that second turn, so we make no claim about what happens if you drop reasoning_content.
JSON mode
response_format: {"type": "json_object"} was accepted:
curl https://api.hiapi.ai/v1/chat/completions \
-H "Authorization: Bearer sk-<your-key>" \
-H "Content-Type: application/json" \
-d '{"model": "kimi-k3.1-pro", "reasoning_effort": "low", "max_tokens": 3000,
"response_format": {"type": "json_object"},
"messages": [{"role": "user", "content": "Return a JSON object with keys city and country for the capital of Japan."}]}'
message.content was exactly {"city":"Tokyo","country":"Japan"}. The model page also lists structured output; we only tested json_object, not a JSON-schema response_format.
What the API rejects
Two rejections we hit, both HTTP 400 with invalid_request_error:
{"error":{"code":"invalid_parameter","message":"temperature: is outside allowed values","type":"invalid_request_error"}}
{"error":{"code":"invalid_parameter","message":"reasoning_effort: is outside allowed values","type":"invalid_request_error"}}
temperature: 0.3is rejected. The model page saystemperatureandtop_pare fixed (1 and 0.95), so omit them. If you are porting code from another provider's SDK with a defaulttemperature, strip it.reasoning_effort: "medium"is rejected. Onlylow,high,maxare valid.
Stay on kimi-k3 or move to k3.1-pro?
Both ids are live and use the same endpoint and request shape. We ran the identical Reply with exactly: pong prompt on both with reasoning_effort: "low" and both returned pong, so migrating is a one-line change to model. We did not benchmark answer quality or latency between them, so we can't say one is better on your workload.
What the model pages and /api/pricing say, as of 2026-10-29:
| kimi-k3 | kimi-k3.1-pro | |
|---|---|---|
| Positioning | General reasoning model | Post-trained from K3 for coding, agent tool workflows, long documents |
| Context / max output | not stated on its page | 1M tokens / 131,072 |
| Parameters on model page | reasoning_effort, streaming | adds structured output and function tools |
| Token price | slightly higher | slightly lower on input, output and cached input |
A reasonable rule: if your workload is tool-using agents or long documents, test kimi-k3.1-pro on your own prompts first. It is aimed at those and is not more expensive per token. If you have a tuned prompt on kimi-k3 that works, the price gap is small, so switch only after your own A/B run. See /en/pricing for current rates. kimi-k3.1-pro-highspeed is a faster variant at a higher unit price; we did not time it.
Related pages
- kimi-k3.1-pro model page
- kimi-k3.1-pro-highspeed model page
- How to use kimi-k3 via the hiapi API
- hiapi pricing
FAQ
What is the exact model id? kimi-k3.1-pro, with a dot between 3 and 1. It appears in /v1/models.
Why is content empty? Reasoning tokens share the max_tokens budget. A finish_reason of length with empty content means the budget ran out during reasoning. Raise max_tokens or lower reasoning_effort.
Can I set temperature? No. A request with temperature: 0.3 returned HTTP 400. Omit it.
Does it use /v1/tasks? No. It is a text model on /v1/chat/completions.





