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
$ 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
  }'
Python
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
$ 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]
Python
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:

Python
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
$ 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}
  }'
Python
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
$ 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..."}}
      ]
    }]
  }'
Python
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 window65,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
ReasoningBilled as output tokens

More on how prices are set: Models & pricing and the pricing page. Concurrency and error behavior: Errors & limits.

© 2026 AxForge · EU-hosted AI infrastructure Pricing Docs Trust Privacy Terms