curl https://www.ninjachat.ai/api/v1/chat/completions \
-H "Authorization: Bearer $NINJACHAT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-3.8-flash",
"messages": [{ "role": "user", "content": "Hello!" }],
"stream": true
}'Each request below is generated from what Gemini 3.8 Flash 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": "gemini-3.8-flash",
"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": "gemini-3.8-flash",
"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"
}'Ask questions about a photo, screenshot, or chart in the same chat request.
# 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": "gemini-3.8-flash",
"messages": [{
"role": "user",
"content": [
{ "type": "text", "text": "What is wrong with this dashboard?" },
{ "type": "image_url", "image_url": { "url": "https://example.com/dashboard.png", "detail": "high" } }
]
}],
"max_completion_tokens": 400
}'content becomes an array of parts: text parts and image_url parts (up to 20 per message). The URL can be public HTTPS or a data:image/...;base64, URL of up to 7 MB.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": "gemini-3.8-flash",
"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
}
}
}
}'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\": \"gemini-3.8-flash\",
\"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.Gemini 3.8 Flash costs $1.5 per 1M input tokens and $7.5 per 1M output tokens on NinjaChat, billed per token with no subscription. Cached input is $0.15 per 1M tokens.
Gemini 3.8 Flash accepts up to 1M tokens of context per request and returns up to 66K output tokens.
Gemini 3.8 Flash is served through GMI Cloud. Requests use one NinjaChat key and one balance.
Gemini 3.8 Flash supports streaming, JSON mode, tool calling, image input, reasoning, long context, and multilingual use. It is suited to cost- and latency-sensitive applications, multi-step reasoning and analysis, tool-calling agents and workflows, and image and document understanding.
Send a POST to /api/v1/chat/completions with model "gemini-3.8-flash" in the body. The endpoint is OpenAI-compatible, so the official OpenAI SDKs work after changing the base URL and key.
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.detail: "low""high"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.routing.caching: "auto"usage