---
title: "Create chat completion"
method: POST
path: "/chat/completions"
tags: ["Chat"]
---

# Create chat completion

`POST /chat/completions`

OpenAI-compatible hosted chat completion. See the chat completions reference for the exact forwarding contract.

## Request body

- ChatCompletionRequest
  - `model` string, required — Model id returned by GET /v1/models.
  - `messages` ChatMessage[], required
    - `role` string, required
    - `content` string, nullable
    - `tool_calls` unknown[]
      - unknown
    - `tool_call_id` string
  - `stream` boolean — When true, the response is a server-sent event stream.
  - `temperature` number
  - `max_tokens` integer
  - `max_completion_tokens` integer
  - `top_p` number
  - `n` integer
  - `best_of` integer
  - `stop` union
    - string
    - string[]
  - `tools` unknown[]
    - unknown
  - `tool_choice` unknown
  - `reasoning_effort` 'none' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' — Reasoning effort for this request. Which of these values a model honors, and which it rejects, is model specific and is stated on that model's page; deepseek-v4-flash applies max when the field is omitted and sends high and xhigh upstream as max. On a model that cannot enforce a response format while it is reasoning, a request carrying response_format is refused with 400 hosted_parameter_not_supported and param response_format unless it also sends reasoning_effort none.
  - `response_format` unknown

## Response `200`

Chat completion (or SSE stream if stream=true)

- ChatCompletion
  - `id` string, required
  - `object` string, required
  - `created` integer, required
  - `model` string, required
  - `choices` object[], required
    - `index` integer
    - `message` ChatMessage — Assistant messages require content or a non-empty tool_calls array. Tool messages require content and tool_call_id. Other roles require content.
      - `role` string, required
      - `content` string, nullable
      - `tool_calls` unknown[]
        - unknown
      - `tool_call_id` string
    - `finish_reason` 'stop' | 'length' | 'tool_calls' | 'content_filter'
    - `runinfra` RunInfraChoiceMetadata — RunInfra-owned choice metadata. Present when the gateway must distinguish a completed response from a response that produced no final answer.
      - `output_status` RunInfraOutputStatus
        - `code` 'generation_limit_reached_before_answer' | 'no_answer_content', required — The generation-limit code is used for finish_reason length. Other terminal empty choices use no_answer_content.
        - `message` string, required
  - `usage` Usage
    - `cost` number — The calculated cost of this request in US dollars, to eight decimals: the settlement formula over the tokens the provider reported. Present on hosted models; absent on workspace deployments. 0 during a promotional free window and for a response with no billable output. runinfra.cost_microcents is the canonical integer.
    - `prompt_tokens` integer
    - `completion_tokens` integer
    - `total_tokens` integer
    - `prompt_tokens_details` object — Present on every hosted model response. cached_tokens is the count of input tokens billed at the cached input rate, the figure the cost was computed with; 0 when nothing was billed as cached, including a response that settled at zero and a model whose cache is shared across tenants. runinfra.cached_input_tokens carries the same number.
      - `cached_tokens` integer
    - `runinfra` RunInfraUsageMetadata
      - `cost_microcents` integer — The calculated cost of this request in microcents (one cent is 1,000,000 microcents), the ledger unit settlement uses; the canonical figure. usage.cost is this value in dollars. The balance is debited in whole cents with sub-cent carry, so a single debit can differ from this by less than a cent.
      - `cached_input_tokens` integer — The count of input tokens billed at the cached input rate on this request, the same number as usage.prompt_tokens_details.cached_tokens. Present on every hosted model response; 0 when nothing was billed as cached.
      - `output_token_accounting` RunInfraOutputTokenAccounting
        - `visible_answer_tokens` 0, required — Final-answer token count classified by the RunInfra proxy for an all-empty generation-limit outcome.
        - `non_answer_completion_tokens` integer, required — Provider-reported completion tokens when the response produced no final answer.
        - `sources` object, required
          - `visible_answer_tokens` 'proxy_classified', required
          - `non_answer_completion_tokens` 'provider_reported', required

## Other responses

- `400` — Malformed request
- `401` — Missing or invalid API key
- `402` — Insufficient credits
- `403` — Key scope mismatch or plan limit exceeded
- `404` — Model or deployment not found
- `409` — Idempotency conflict
- `413` — Request body exceeds 3.5 MB (payload_too_large)
- `422` — Request cannot be replayed or processed safely
- `429` — Rate limit exceeded
- `500` — Unexpected gateway error
- `502` — Upstream serving backend transient failure
- `503` — Endpoint stopped, provisioning, or at capacity
- `504` — Gateway timeout

---

[API](https://skmtc.dev/runinfra/apis/runinfra-api.md) · [All operations](https://skmtc.dev/runinfra/apis/runinfra-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/runinfra/runinfra-api/revisions/dbd314122f80/schema)
