# Create Chat Completion

`POST https://api.vultrinference.com/v1/chat/completions`

Create Chat Completion on a specified text generation model.

**Continuation:** If the final message has the `assistant` role, the model continues that message instead of starting a new turn (the same convention as Anthropic and OpenRouter). Send a response that ended with `finish_reason` `length` back as the final assistant message to resume it. The message must be non-empty text without `tool_calls`, trailing whitespace is trimmed, thinking is disabled for the continuation, and only the new text is returned.

**Response shape:** Responses follow OpenRouter's chat completion shape whichever engine serves the model. Reasoning is always in `reasoning` (never `reasoning_content`), usage always has `prompt_tokens_details.cached_tokens` and `completion_tokens_details.reasoning_tokens`, ids start with `chatcmpl-` and tool call ids with `call_`, `finish_reason` is one of `stop`, `length`, `tool_calls`, `content_filter` or `error` with the engine's own value in `native_finish_reason`, and engine-specific fields are removed. A `-normalize` model suffix is accepted for compatibility and ignored.

**Errors:** Errors use OpenRouter's envelope, `{"error": {"code", "message", "type", "metadata": {"error_type"}}}`. A streaming request that fails before the first token gets the real HTTP status; one that fails later receives a final chunk carrying `error`.

**Reasoning budget:** Set `reasoning.max_tokens` to limit thinking tokens. This limit must be below `max_completion_tokens` (or the effective context-clipped limit). Models with `reasoning.supports_max_tokens: true` in `/v1/models?format=openrouter` (a `max_tokens` property under the `reasoning` parameter in the default list) enforce the budget; other models accept the field without enforcing it. Requested effort maps through the model's `reasoning_config` when configured. The `:express` model variant derives a budget for models with enforced budget support when no budget is supplied.

## Body (application/json)

- `model` (string): The [model](#operation/list-models) to use. If omitted, the gateway resolves its default model. A `-normalize` suffix is accepted for compatibility and ignored; every response is normalized. A `:<variant>` suffix is parsed separately from the model ID; `:express` derives a thinking budget when the model supports enforced budgets and no explicit budget is supplied.
- `messages` (array of objects, required): The message context to use for the chat completion request, separated by system, user, assistant, tool, and developer roles. A final `assistant` message is treated as a prefill and continued (see `continue_final_message`). [at least 1 items]
  - `role` (string): The role of the author of this message. [system, assistant, user, tool, developer]
  - `content` (string or array of objects): The contents of the message: a string, or an array of content parts (text, images, audio, video and documents). Media parts are accepted on `user` messages. See `chat-content-part` for documents: they are converted to text, which becomes part of the prompt.
- `continue_final_message` (boolean): Continue the final message instead of starting a new assistant turn. Implied whenever the final message has the `assistant` role, so it only makes the intent explicit. The final message must carry non-empty text and no `tool_calls`; trailing whitespace is trimmed, thinking is disabled for the continuation, and only the newly generated text is returned. Use it to resume a response that ended with `finish_reason` `length`. [default false]
- `stream` (boolean): Indicates whether the response should be streamed.
- `max_tokens` (integer): Deprecated name for `max_completion_tokens`. If both are sent, `max_completion_tokens` takes precedence. A value below 1 returns 400. [at least 1]
- `max_completion_tokens` (integer): Maximum completion tokens, including reasoning and visible output. A value below 1 returns 400; omit the field to get the default. A value that does not fit the model's context window with the prompt is not refused. It is cut to the window less the prompt and a 32 token margin, and `finish_reason` reports `length` if the answer reaches the cut. A prompt that alone fills the window returns 400. [default 32768, at least 1]
- `reasoning_effort` (string): Shorthand for `reasoning.effort`. When both are supplied, `reasoning.effort` takes precedence. Configured models map this level to their supported reasoning control; unsupported levels return 400. [ultra, max, xhigh, high, medium, low, minimal, none]
- `reasoning` (object): Reasoning controls. Configured models map effort through their database profile. Models advertising `reasoning.supports_max_tokens: true` in `/v1/models?format=openrouter` (a `max_tokens` property under the `reasoning` parameter in the default list) enforce the budget; other models accept it without enforcing it.
  - `effort` (string) [ultra, max, xhigh, high, medium, low, minimal, none]
  - `enabled` (boolean): When false, sets effort to `none`.
  - `summary` (string): Accepted but not supported by the current engines. [auto, concise, detailed]
  - `max_tokens` (integer): Thinking-token budget. Must be below the effective completion limit so the model has room to answer. Ignored when thinking is disabled or a final assistant message is being continued. [at least 1]
- `n` (integer): The number of chat completion choices to generate for each input message. [default 1, at least 1]
- `seed` (integer): If you would like a different response from the same message, changing the seed will change the response. A null value generates a random seed.
- `top_k` (integer): Sample only from the k most likely tokens at each step. 0 disables it. Passed to the engine; a model's default is the `top_k` in `default_parameters` of the public model list. [at least 0]
- `repetition_penalty` (number (float)): Penalises tokens already in the prompt or the answer. 1.0 is no penalty and above 1.0 discourages repetition. Passed to the engine, which also reads it as a model default. [range 0–2]
- `response_format` (object): Constrains the answer's format. `json_object` makes the model answer with a JSON object; `json_schema` makes it answer with JSON that matches the schema. `text` is the default.
  - `type` (string, required) [text, json_object, json_schema]
  - `json_schema` (object): Required when `type` is `json_schema`.
    - `name` (string)
    - `strict` (boolean)
    - `schema` (object): A JSON Schema.
- `temperature` (number (float)): A value between 0.0 and 2.0 that controls the randomness of the model's output. When set closer to 1, such as 0.8, the outcome is more unpredictable and creative. Values nearing 0, like 0.2, produce more predictable and less creative results. A temperature of zero requests greedy decoding; exact reproducibility depends on the model engine. [default 1, range 0–2]
- `top_p` (number (float)): A value between 0.0 and 1.0 that controls the probability of the model generating a particular token. A higher value will result in more diverse outputs, while a lower value will result in more repetitive outputs. [default 1, range 0–1]
- `frequency_penalty` (number (float)): A value between -2.0 and 2.0 that controls how much the model penalizes generating repetitive responses. [default 0, range -2–2]
- `presence_penalty` (number (float)): A value between -2.0 and 2.0 that controls how much the model penalizes generating responses that contain certain words or phrases. [default 0, range -2–2]
- `stop` (string or array of strings): The strings the model stops generating at, up to 4. A single string is accepted as shorthand for a one-item array.
- `logprobs` (boolean): Whether to return log probabilities of the output tokens or not. If true, returns the log probabilities of each output token returned in the content of message.
- `top_logprobs` (integer): An integer between 0 and 20 specifying the number of most likely tokens to return at each token position, each with an associated log probability. Optional: `logprobs: true` alone returns the sampled token's log probability. Requires `logprobs` to be true. [range 0–20]
- `tool_choice` (string or object): Controls which (if any) tool is called by the model. A tool choice other than `none` requires `tools`.
- `tools` (array of objects): A list of function tools the model may call.
  - `type` (string): The type of the tool. Currently, only `function` is supported.
  - `function` (object): An object representing a function for use with chat completion tool calling.
    - `name` (string): The name of the function to be called. Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length of 64
    - `description` (string): A description of what the function does, used by the model to choose when and how to call the function.
    - `parameters` (object): The parameters the functions accepts, described as a JSON Schema object.
    - `strict` (boolean): Whether to enable strict schema adherence when generating the function call. If set to true, the model will follow the exact schema defined in the `parameters` field. Only a subset of JSON Schema is supported when `strict` is `true`.

## Responses

- `200`: OK (chat-completion-response-payload)
- `400`: Bad Request, including context_length_exceeded (error-payload)
- `401`: The API key is missing, unknown or not active. Send it as Authorization: Bearer <key>. (error-payload)
- `429`: Rate limit exceeded (error-payload)
- `502`: The model could not be reached (error-payload)
- `504`: The model timed out (error-payload)
- `404`: No model by that name exists, or its row is missing (error-payload)
- `503`: The list of models being served could not be read, so the request's model could not be resolved. Retry shortly. (error-payload)

## Example

```bash
curl https://api.vultrinference.com/v1/chat/completions \
  -H "Authorization: Bearer $VULTR_INFERENCE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-v4.1-flash",
    "messages": [
      {
        "role": "system",
        "content": "Answer in one sentence."
      },
      {
        "role": "user",
        "content": "Why is the sky blue?"
      }
    ],
    "max_completion_tokens": 512
  }'
```

```python
import os
import requests

response = requests.post(
    "https://api.vultrinference.com/v1/chat/completions",
    headers={"Authorization": f"Bearer {os.environ['VULTR_INFERENCE_API_KEY']}"},
    json={
        "model": "deepseek-v4.1-flash",
        "messages": [
            {
                "role": "system",
                "content": "Answer in one sentence.",
            },
            {
                "role": "user",
                "content": "Why is the sky blue?",
            },
        ],
        "max_completion_tokens": 512,
    },
)
print(response.json())
```

```javascript
const response = await fetch("https://api.vultrinference.com/v1/chat/completions", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.VULTR_INFERENCE_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "model": "deepseek-v4.1-flash",
    "messages": [
      {
        "role": "system",
        "content": "Answer in one sentence."
      },
      {
        "role": "user",
        "content": "Why is the sky blue?"
      }
    ],
    "max_completion_tokens": 512
  }),
});
console.log(await response.json());
```
