> ## Documentation Index
> Fetch the complete documentation index at: https://mifr.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Create chat completion

> OpenAI-compatible Chat Completions, including streaming and the signed receipt.

This is the OpenAI-compatible Chat Completions endpoint, for both stream and non-stream calls. A non-stream 200 is a `chat.completion` with `usage` and `mifr_receipt`. Stream is SSE (`text/event-stream`): a role chunk, content deltas, keepalives every 10 seconds (`: keepalive`), a stop chunk, then `data: [DONE]`.

The JSON `model` field echoes the request. The alias actually served is `x-mifr-model` / `mifr_receipt.model_id`.

<ParamField header="Authorization" type="string" required>
  Bearer product key. Format: `Bearer sk-mifr_…`. See [Authentication](/authentication).
</ParamField>

<ParamField body="model" type="string" required>
  Catalog alias or Hugging Face id. An empty value is 400. An unknown name is 404 `model_not_found`. Default alias: `qwen3-4b`.
</ParamField>

<ParamField body="messages" type="object[]" required>
  Non-empty. Each item needs `role`. Max 100 messages, 256 KiB total content chars.

  <Expandable title="message fields">
    <ParamField body="role" type="string" required>
      Message role (`user`, `assistant`, `system`, and so on).
    </ParamField>

    <ParamField body="content" type="string | object[]" required>
      A string, or parts `{"type":"text"|"input_text", "text":"…"}`. Other part types (for example `image_url`) return 400.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="max_tokens" type="number" default="512">
  Integer. Fractional values are rejected. Qwen3 is a thinking model, so a tiny cap often fills with `<think>…` and never reaches a visible answer.
</ParamField>

<ParamField body="max_completion_tokens" type="number">
  Alias for `max_tokens`. `max_tokens` wins if both are set.
</ParamField>

<ParamField body="temperature" type="number" default="0.7">
  Number. Bools and string numbers are rejected.
</ParamField>

<ParamField body="stream" type="boolean" default="false">
  If true, respond as SSE. The receipt and `x_mifr_*` verdicts are on the final chunk, not on the SSE HTTP head.
</ParamField>

<ParamField body="provider" type="string">
  Pin one Mac: exact provider id, or a unique prefix of at least 8 characters. A pin does not hop or hedge. If that Mac is offline or below the floor, the call returns 503 `provider_unavailable`.
</ParamField>

<ParamField body="provider_key_id" type="string">
  Alias for `provider`.
</ParamField>

<ParamField body="stream_options" type="object">
  Extra keys are ignored. `include_usage` still appears on the stop chunk.
</ParamField>

## Response

<ResponseField name="id" type="string">
  Completion id.
</ResponseField>

<ResponseField name="object" type="string">
  `chat.completion` (non-stream) or `chat.completion.chunk` (stream).
</ResponseField>

<ResponseField name="model" type="string">
  Echo of the request `model` field.
</ResponseField>

<ResponseField name="choices" type="object[]">
  Standard OpenAI choices. A stream sends a role chunk, then content deltas, then a stop chunk.
</ResponseField>

<ResponseField name="usage" type="object">
  Token counts from the verified receipt. Present on non-stream 200 and on the terminal SSE chunk.
</ResponseField>

<ResponseField name="mifr_receipt" type="object">
  Signed, request-bound receipt. This is the proof; HTTP `x-mifr-*` headers are the gateway's report of the same facts.
</ResponseField>

Failure after the first streamed token puts the same error object in `data:` and omits `[DONE]`. Do not splice a retry onto those bytes. If the caller hangs up, the gateway aborts the seal (`aborted`) and sends no body.

See [Errors and headers](/errors) for the full `mifr_action` table and verdict header list.

<RequestExample>
  ```bash cURL theme={null}
  curl https://mifr-gateway-production.up.railway.app/v1/chat/completions \
    -H "Authorization: Bearer $MIFR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "qwen3-4b",
      "messages": [{"role": "user", "content": "Reply with the single word pong."}]
    }'
  ```

  ```python Python theme={null}
  from openai import OpenAI

  client = OpenAI(
      base_url="https://mifr-gateway-production.up.railway.app/v1",
      api_key="YOUR_MIFR_API_KEY",
  )

  r = client.chat.completions.create(
      model="qwen3-4b",
      messages=[{"role": "user", "content": "Reply with the single word pong."}],
  )
  print(r.choices[0].message.content)
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch(
    "https://mifr-gateway-production.up.railway.app/v1/chat/completions",
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.MIFR_API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        model: "qwen3-4b",
        messages: [{ role: "user", content: "Reply with the single word pong." }],
      }),
    },
  );
  const json = await res.json();
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "id": "chatcmpl-…",
    "object": "chat.completion",
    "model": "qwen3-4b",
    "choices": [
      {
        "index": 0,
        "message": { "role": "assistant", "content": "pong" },
        "finish_reason": "stop"
      }
    ],
    "usage": {
      "prompt_tokens": 12,
      "completion_tokens": 1,
      "total_tokens": 13
    },
    "mifr_receipt": {
      "trust_level": "hardware",
      "model_id": "qwen3-4b"
    }
  }
  ```

  ```json 401 theme={null}
  {
    "error": {
      "message": "missing or invalid API key (Authorization: Bearer <key>)",
      "type": "invalid_request_error",
      "code": "invalid_api_key",
      "param": null,
      "mifr_action": "fix_key"
    }
  }
  ```
</ResponseExample>
