Search

Search HiAPI models, tools, and resources.

Back to blog
Tutorial

kimi-k3.1-pro API: curl, Python and a Working Request

hiapikimi-k3.1-proapi-guidechat-completionshiapi

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.3 is rejected. The model page says temperature and top_p are fixed (1 and 0.95), so omit them. If you are porting code from another provider's SDK with a default temperature, strip it.
  • reasoning_effort: "medium" is rejected. Only low, high, max are 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-k3kimi-k3.1-pro
PositioningGeneral reasoning modelPost-trained from K3 for coding, agent tool workflows, long documents
Context / max outputnot stated on its page1M tokens / 131,072
Parameters on model pagereasoning_effort, streamingadds structured output and function tools
Token priceslightly higherslightly 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.

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.

Generate it with HiAPI

Choose a model, enter your prompt, and see the result.

HiAPI Blog

Related articles

HiAPI

Generate it with HiAPI

Start generating