Chat completions
POST /v1/chat/completions — the OpenAI chat shape, served by
Qwen3.8 27B as
qwen3.8-27b-nvfp4. 65,536-token context. €0.29 / 1M input
tokens, €1.77 / 1M output tokens (launch pricing). Streaming, tool calls,
reasoning output and image input all work on this one endpoint.
Request & response
$ curl https://api.axforge.ai/v1/chat/completions \
-H "Authorization: Bearer $AXFORGE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3.8-27b-nvfp4",
"messages": [
{"role": "system", "content": "You answer in one sentence."},
{"role": "user", "content": "What is an embedding?"}
],
"max_tokens": 2048
}'
from openai import OpenAI
client = OpenAI(
base_url="https://api.axforge.ai/v1",
api_key="YOUR_AXFORGE_KEY",
)
r = client.chat.completions.create(
model="qwen3.8-27b-nvfp4",
messages=[{"role": "user", "content": "What is an embedding?"}],
)
print(r.choices[0].message.content)
The response is the standard OpenAI shape. Note
reasoning_content — the model's thinking, separate from the
answer (details below).
{
"id": "chatcmpl-...",
"object": "chat.completion",
"model": "qwen3.8-27b-nvfp4",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "An embedding is a vector that encodes meaning...",
"reasoning_content": "The user wants a one-line definition..."
},
"finish_reason": "stop"
}],
"usage": {"prompt_tokens": 21, "completion_tokens": 96, "total_tokens": 117}
}
Streaming
Set "stream": true and the response arrives as server-sent
events, one JSON chunk per data: line. Usage is included in
streaming mode too — the final chunk before [DONE] carries it.
$ curl -N https://api.axforge.ai/v1/chat/completions \
-H "Authorization: Bearer $AXFORGE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "qwen3.8-27b-nvfp4", "stream": true,
"messages": [{"role": "user", "content": "Count to three."}]}'
# the wire format:
data: {"choices":[{"delta":{"content":"One"}}]}
data: {"choices":[{"delta":{"content":", two"}}]}
data: {"choices":[{"delta":{},"finish_reason":"stop"}]}
data: {"choices":[],"usage":{"prompt_tokens":13,"completion_tokens":9,"total_tokens":22}}
data: [DONE]
r = client.chat.completions.create(
model="qwen3.8-27b-nvfp4",
stream=True,
messages=[{"role": "user", "content": "Count to three."}],
)
for chunk in r:
if chunk.choices:
print(chunk.choices[0].delta.content or "", end="")
if chunk.usage:
print("\ntokens:", chunk.usage.total_tokens)
Tool calls
The endpoint accepts the OpenAI tools schema. Declare
functions, let the model decide when to call one, run it yourself, and send
the result back as a tool message. One complete round trip:
import json
tools = [{
"type": "function",
"function": {
"name": "get_invoice",
"description": "Look up an invoice by its number",
"parameters": {
"type": "object",
"properties": {"number": {"type": "string"}},
"required": ["number"],
},
},
}]
messages = [{"role": "user", "content": "What is the total on invoice 2041?"}]
r = client.chat.completions.create(
model="qwen3.8-27b-nvfp4", messages=messages, tools=tools,
)
# the model asked for the tool instead of answering
call = r.choices[0].message.tool_calls[0]
args = json.loads(call.function.arguments) # {"number": "2041"}
# run it yourself, then send the result back
messages.append(r.choices[0].message)
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": json.dumps({"number": "2041", "total_eur": 1240.0}),
})
r = client.chat.completions.create(
model="qwen3.8-27b-nvfp4", messages=messages, tools=tools,
)
print(r.choices[0].message.content) # "Invoice 2041 totals EUR 1,240.00."
On the wire, the model's tool request looks like this — pass the same
tools array in a curl body to get it:
"message": {
"role": "assistant",
"content": null,
"tool_calls": [{
"id": "call_...",
"type": "function",
"function": {"name": "get_invoice", "arguments": "{\"number\": \"2041\"}"}
}]
},
"finish_reason": "tool_calls"
Reasoning output
The model thinks before it answers. The thinking arrives in
reasoning_content on the message (and in the delta when
streaming); content holds only the answer. Reasoning tokens are
output tokens and are billed as such.
To disable thinking, pass chat_template_kwargs:
$ curl https://api.axforge.ai/v1/chat/completions \
-H "Authorization: Bearer $AXFORGE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3.8-27b-nvfp4",
"messages": [{"role": "user", "content": "Classify: \"refund please\""}],
"chat_template_kwargs": {"enable_thinking": false}
}'
r = client.chat.completions.create(
model="qwen3.8-27b-nvfp4",
messages=[{"role": "user", "content": "Classify: \"refund please\""}],
extra_body={"chat_template_kwargs": {"enable_thinking": False}},
)
Tip — give thinking room. With thinking enabled, the
model spends output tokens on reasoning_content before it
writes the answer, so a small max_tokens can be used up by
reasoning and return an empty content. Raise
max_tokens, or disable thinking for short structured outputs.
Image input (vision)
Send images as content parts: content becomes an array
mixing text and image_url parts, with the image
as a base64 data URL. Each image adds roughly 1,000–1,600 prompt tokens,
billed as input tokens.
$ curl https://api.axforge.ai/v1/chat/completions \
-H "Authorization: Bearer $AXFORGE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3.8-27b-nvfp4",
"messages": [{
"role": "user",
"content": [
{"type": "text", "text": "What is the total on this receipt?"},
{"type": "image_url",
"image_url": {"url": "data:image/png;base64,iVBORw0KGgo..."}}
]
}]
}'
import base64
b64 = base64.b64encode(open("receipt.png", "rb").read()).decode()
r = client.chat.completions.create(
model="qwen3.8-27b-nvfp4",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "What is the total on this receipt?"},
{"type": "image_url",
"image_url": {"url": f"data:image/png;base64,{b64}"}},
],
}],
)
print(r.choices[0].message.content)
Context & pricing
| Context window | 65,536 tokens |
|---|---|
| Input | €0.29 / 1M tokens (launch pricing) |
| Output | €1.77 / 1M tokens (launch pricing) |
| Image input | ~1,000–1,600 prompt tokens per image, billed as input |
| Reasoning | Billed as output tokens |
More on how prices are set: Models & pricing and the pricing page. Concurrency and error behavior: Errors & limits.