What you'll build
kimi-k3 is a reasoning-capable chat model available on hiapi through the standard OpenAI-compatible /v1/chat/completions endpoint — no async task polling, no image upload. This guide gets you from zero to a working call in curl and Python, then covers the two things that trip people up in production: reasoning tokens eating your max_tokens budget, and streaming.
Prerequisites: an hiapi API key. Grab one from the dashboard if you don't have one yet — every request below authenticates with Authorization: Bearer sk-<your-key>.
Minimal working example
kimi-k3 is a text model, so it does not go through hiapi's /v1/tasks job queue used by image/video models — it's a direct, synchronous chat completion call.
curl
curl https://api.hiapi.ai/v1/chat/completions \
-H "Authorization: Bearer sk-<your-key>" \
-H "Content-Type: application/json" \
-d '{
"model": "kimi-k3",
"messages": [
{"role": "user", "content": "Explain what an API rate limit is in two sentences."}
],
"max_tokens": 300
}'
Python
import requests
resp = requests.post(
"https://api.hiapi.ai/v1/chat/completions",
headers={
"Authorization": "Bearer sk-<your-key>",
"Content-Type": "application/json",
},
json={
"model": "kimi-k3",
"messages": [
{"role": "user", "content": "Explain what an API rate limit is in two sentences."}
],
"max_tokens": 300,
},
timeout=60,
)
resp.raise_for_status()
data = resp.json()
print(data["choices"][0]["message"]["content"])
A successful response looks like this:
{
"id": "chatcmpl-fb762e7481bd4442abb1d8ed3892b4f5",
"model": "FW-Kimi-K3",
"object": "chat.completion",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "OK",
"reasoning_content": "We need answer user: \"Reply with exactly the word OK.\" ..."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 95,
"completion_tokens": 52,
"total_tokens": 147,
"completion_tokens_details": {"reasoning_tokens": 38}
}
}
The final answer is in choices[0].message.content. Model id in the request is the bare id, kimi-k3 — hiapi maps it internally (you'll see the underlying label, e.g. FW-Kimi-K3, echoed back in the response's model field, which is expected).
The one gotcha: reasoning tokens vs max_tokens
kimi-k3 is a reasoning model — it writes out chain-of-thought into message.reasoning_content before producing the final content, and both draw from the same max_tokens budget. If you set max_tokens too low, the model can burn the entire budget on reasoning and return finish_reason: "length" with an empty content field:
{
"choices": [{
"message": {"content": "", "reasoning_content": "The user is asking me to say \"OK\""},
"finish_reason": "length"
}]
}
That's not a bug — it's the reasoning running out of room before it reaches the final answer. Two ways to handle it:
- Give it headroom. For short factual answers, 200–300
max_tokensis usually enough to cover reasoning + answer. For longer generations, budget accordingly. - Check
finish_reason. If it comes back"length"andcontentis empty, retry with a highermax_tokensrather than treating an empty string as the final answer.
Streaming
Set "stream": true to get server-sent events instead of waiting for the full response. Chunks carry incremental delta.reasoning_content first, then delta.content once the model starts writing the final answer:
import requests
with requests.post(
"https://api.hiapi.ai/v1/chat/completions",
headers={
"Authorization": "Bearer sk-<your-key>",
"Content-Type": "application/json",
},
json={
"model": "kimi-k3",
"messages": [{"role": "user", "content": "Count to 3."}],
"max_tokens": 200,
"stream": True,
},
stream=True,
timeout=60,
) as resp:
for line in resp.iter_lines():
if line and line.startswith(b"data: ") and line != b"data: [DONE]":
print(line.decode("utf-8"))
If you're building a chat UI, stream and render delta.content only — most apps hide or collapse delta.reasoning_content behind a "thinking" toggle rather than showing it inline.
Production notes
- Errors. An invalid or missing key returns HTTP 401 with a structured body:
Log{"error": {"code": "permission_denied", "message": "This API key is invalid...", "request_id": "...", "type": "hiapi_error"}}request_id— it's what support needs if you open a ticket. - Retries. Chat completions are synchronous, so there's no task id to poll and no callback to register (that pattern is for hiapi's async image/video models, not text). On a timeout or 5xx, just retry the request; treat it as a normal idempotent GET-like retry since nothing is queued server-side.
- Pricing. kimi-k3 is billed per token like any other text model on the platform — check current rates on the pricing page before estimating cost at scale, since reasoning tokens count toward completion tokens.
FAQ
Does kimi-k3 support streaming?
Yes — pass "stream": true and read the text/event-stream response as shown above.
Why is content empty in my response?
finish_reason is almost certainly "length" — the model spent its entire max_tokens budget on reasoning_content before reaching a final answer. Raise max_tokens and retry.
Do I need to use hiapi's /v1/tasks endpoint for kimi-k3?
No. /v1/tasks is for asynchronous image, video, and music generation models. kimi-k3 is a synchronous text model served over the standard /v1/chat/completions endpoint.
Can I use the OpenAI Python SDK instead of raw requests?
Yes — point the SDK's base_url at https://api.hiapi.ai/v1 and pass your hiapi key as the API key; the request/response shape is OpenAI-compatible.
What model id do I pass in requests?
The bare id kimi-k3. You'll see an internal label like FW-Kimi-K3 echoed back in the response's model field — that's expected and doesn't affect billing or behavior.








