Tencent's HY4 Preview mixture-of-experts model for coding agents, tool use, and long-context work.
curl https://www.ninjachat.ai/api/v1/chat/completions \
-H "Authorization: Bearer $NINJACHAT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "hy4-preview",
"messages": [{ "role": "user", "content": "Hello!" }],
"stream": true
}'Each request below is generated from what HY4 Preview serves on NinjaChat today — the same capabilities and parameters that GET /models reports — so it runs as written with your key.
Show text as it is generated instead of waiting for the whole completion.
# export NINJACHAT_API_KEY="nj_sk_..." (Developers → Keys)
curl -N https://www.ninjachat.ai/api/v1/chat/completions \
-H "Authorization: Bearer $NINJACHAT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "hy4-preview",
"messages": [{ "role": "user", "content": "Write a haiku about deploy day." }],
"stream": true,
"stream_options": { "include_usage": true }
}'data: line carries one chat.completion.chunk and the stream ends with data: [DONE]. Both SDKs parse that for you and stop at the sentinel.stream_options.include_usage the last chunk before [DONE] has an empty choices array and a usage object with the billed token counts, so guard on choices.length before reading a delta.curl -N so the buffer is not held back; the final usage chunk also carries cost_usd for this request.Let the model decide when to call your function and hand you typed arguments.
# export NINJACHAT_API_KEY="nj_sk_..." (Developers → Keys)
curl https://www.ninjachat.ai/api/v1/chat/completions \
-H "Authorization: Bearer $NINJACHAT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "hy4-preview",
"messages": [{ "role": "user", "content": "Do I need an umbrella in Lisbon today?" }],
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Current weather for a city",
"parameters": {
"type": "object",
"properties": { "city": { "type": "string" } },
"required": ["city"]
}
}
}],
"tool_choice": "auto"
}'tool_choice: "auto" lets the model answer directly when no tool is needed; "required" forces at least one call, and { "type": "function", "function": { "name": "get_weather" } } pins a specific one.function.arguments, never as an object — parse before use. Send your result back as a tool message with the same tool_call_id, then call again for the natural-language answer.parallel_tool_calls: false when your functions must run one at a time.Have the model return an object that matches your schema, so you can parse it without cleanup.
# export NINJACHAT_API_KEY="nj_sk_..." (Developers → Keys)
curl https://www.ninjachat.ai/api/v1/chat/completions \
-H "Authorization: Bearer $NINJACHAT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "hy4-preview",
"messages": [{ "role": "user", "content": "Extract the invoice: ACME Ltd billed 1,240.50 EUR." }],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "invoice",
"strict": true,
"schema": {
"type": "object",
"properties": {
"vendor": { "type": "string" },
"total": { "type": "number" },
"currency": { "type": "string" }
},
"required": ["vendor", "total", "currency"],
"additionalProperties": false
}
}
}
}'json_schema with strict: true constrains the output to your schema; mark every property required and set additionalProperties: false so the object is exactly what you parse.{ "type": "json_object" } is the looser form — valid JSON with no schema. Whichever you use, message.content is the JSON string; parse it, do not regex it.Put a whole document in the prompt — the window is 1,048,576 tokens — and cap the answer.
# export NINJACHAT_API_KEY="nj_sk_..." (Developers → Keys)
DOC=$(jq -Rs . < contract.txt) # the whole file as one JSON string
curl https://www.ninjachat.ai/api/v1/chat/completions \
-H "Authorization: Bearer $NINJACHAT_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"model\": \"hy4-preview\",
\"messages\": [
{ \"role\": \"system\", \"content\": \"Answer only from the document.\" },
{ \"role\": \"user\", \"content\": $DOC },
{ \"role\": \"user\", \"content\": \"List every termination clause with its section number.\" }
],
\"max_completion_tokens\": 1200,
\"routing\": { \"caching\": \"auto\" }
}"max_completion_tokens so a long input cannot run up an unbounded output.routing.caching: "auto" turns on provider-native prompt caching for a stable prefix. When you ask several questions over the same document, cache reads are billed at this model's cached-input rate and show up separately in usage.HY4 Preview costs $0.84 per 1M input tokens and $2.51 per 1M output tokens on NinjaChat, billed per token with no subscription. Cached input is $0.042 per 1M tokens.
HY4 Preview accepts up to 1M tokens of context per request and returns up to 64K output tokens.
HY4 Preview is served through Tencent Cloud TokenHub and GMI Cloud. NinjaChat routes each request to a healthy provider and fails over automatically, on one key and one balance.
HY4 Preview supports streaming, JSON mode, tool calling, reasoning, long context, and multilingual use. It is suited to multi-step reasoning and analysis, tool-calling agents and workflows, large-document and repository analysis, and structured extraction and JSON output.
Send a POST to /api/v1/chat/completions with model "hy4-preview" in the body. The endpoint is OpenAI-compatible, so the official OpenAI SDKs work after changing the base URL and key.