# Chat Completions

Source: https://convergingthought.com/docs/api-reference/chat-completions

> OpenAI-compatible text and function calls, backed by durable inference jobs.



`POST /v1/chat/completions` requires `inference` scope. The same rate, reservations, adapter ownership checks, and settlement rules apply as [native inference](/docs/api-reference/inferences).

## Customer scope [#customer-scope]

Supply optional `tenant_id` in the body or `X-Internalize-Tenant` in the headers. If both are present they must match. A tenant-restricted key supplies its own tenant when omitted and rejects another tenant. Without either, an unrestricted key uses the separate project namespace. Use the same tenant for learning, inference, job reads, and version changes. See [Serve multiple customers](/docs/guides/multitenancy).

## Request [#request]

```json
{
  "model": "glm-5.3",
  "messages": [{ "role": "user", "content": "Hello!" }],
  "max_completion_tokens": 2048,
  "temperature": 0,
  "stream": false
}
```

| Field                          | Behavior                                                                       |
| ------------------------------ | ------------------------------------------------------------------------------ |
| `model`                        | Required; `glm-5.3` only                                                       |
| `messages`                     | 1–64 messages; text, assistant function calls, and completed tool-result turns |
| `subject_id`                   | Optional; routes through that subject's active adapter                         |
| `adapter_version`              | Optional retained version, or `base`; non-base pinning requires a subject      |
| `max_completion_tokens`        | 1–4,096, default 2,048; includes reasoning                                     |
| `max_tokens`                   | Legacy alias; do not send both limits                                          |
| `temperature`                  | 0–1, default 0                                                                 |
| `tools`                        | Up to 32 function definitions with unique names                                |
| `tool_choice`                  | `auto`, `none`, `required`, or a named function                                |
| `parallel_tool_calls`          | Boolean; false permits at most one returned call                               |
| `response_format`              | `text` or `json_object`; JSON is validated after generation                    |
| `stream`                       | False by default; true returns buffered SSE                                    |
| `stream_options.include_usage` | Adds a final usage chunk when streaming                                        |
| `n`                            | Only 1 is supported                                                            |

Unknown fields are rejected. `strict: true` tools, `json_schema`, images, audio, logprobs, and Responses-specific fields are unsupported. JSON validation is not constrained decoding; invalid JSON can yield a failed job with consumed inference tokens charged.

Each message's normalized text is bounded to 16,000 JavaScript string-length units. Serialized normalized messages plus tools must fit 64,000 units. The HTTP body limit is 100,000 bytes. Function argument strings have a 16,000-unit bound. The actual tokenizer context ceiling is also enforced before paid execution.

## Routing [#routing]

Omitting the subject always selects base, even if the project's `default` subject has learned versions. Use `subject_id` or `X-Internalize-Subject` for adapted inference. If both appear, their values must match. A missing or expired explicitly requested adapter fails; it does not silently fall back.

The subject comes from your server's authorization mapping. A key is project-scoped and can optionally be restricted to a tenant; it is not restricted to one subject. Pinned versions must belong to the key’s project, the selected tenant, and the supplied subject.

## Conversation and tools [#conversation-and-tools]

`system`, `developer`, `user`, `assistant`, and `tool` roles are accepted. Developer messages normalize to system messages. Content may be a string or an array of text blocks. Null assistant content is accepted when function calls are present.

Assistant calls need unique IDs and JSON-object argument strings. Every call must receive exactly one matching tool result before the next assistant generation. The final message must be a user message or the end of a completed tool-result block. The server emits function calls; your runtime authorizes and executes them.

## Response [#response]

A successful JSON response includes the standard `id`, `object`, `created`, `model`, `choices`, and `usage` fields. `choices[0].message` contains final text, `tool_calls`, or both. `finish_reason` is `stop`, `length`, or `tool_calls`.

The `internalize` extension contains `job_id`, `subject_id`, and the resolved `adapter_version`. Response headers include `X-Internalize-Job-Id`, `Idempotency-Key`, and `X-Request-Id`. Inference usage includes all generated reasoning tokens, but reasoning text is never returned.

## Stream behavior [#stream-behavior]

SSE sends keepalive comments while the durable job runs. After validation it emits a content/tool delta, a finish chunk, optional usage, and `[DONE]`. Tool deltas include their index, ID, function name, and complete argument string.

This stream is buffered until final validation, not token-live generation. Disconnecting or cancelling the client stream does not cancel the underlying job. The same job remains visible in Activity and through `/v1/jobs/{id}`.

## Recovery and deadlines [#recovery-and-deadlines]

A supplied `Idempotency-Key` is strongly recommended for paid operations. Reusing it with the same normalized payload and submitting credential returns the original job. A conflicting body or another key returns `409`. If omitted, the gateway generates an operation key and returns it in the response header.

The HTTP wait is bounded to about four minutes. A pending, failed, or reconciliation result after admission uses `409` and includes `error.job_id`, `error.status_url`, and `retryable: false`. Poll that existing job. A stream already admitted reports the same error envelope in a data frame before `[DONE]`.

Disable automatic framework retries unless they reuse a persisted operation key. If a connection fails before you save the generated key or job ID, a fresh request may create new paid work. Use [native asynchronous inference](/docs/api-reference/inferences) when your application needs a job receipt immediately.
