POST /v1/chat/completions.
Create a model response for a chat conversation. OpenAI Chat Completions-compatible; Webel extensions ride in the usage and webel blocks and never break existing clients.
Authenticates with Authorization: Bearer wbl-… (see Authentication). The reply is computed by running one full turn through the Webel engine (routing, moderation, and durable conversation state included), then returned synchronously (or streamed; see Streaming).
Request body
| Field | Type | Notes |
|---|---|---|
| messages required | array | A list of messages comprising the conversation so far, each {"role", "content"}. Must include at least one user message: its last user entry becomes the new turn. System-role entries are accepted but not applied. System behavior comes from your room's persona. content is a string, or, for image and PDF input, an array of content parts (see Multimodal input). |
| model optional | string | ID of the model to use. Send a specific model id to pin it exactly, or omit / send "auto" to let Webel's router pick per request. If the API key has a pinned model, "auto" resolves to that pin; otherwise the router chooses. Default: "auto". |
| conversation optional | string | Webel conversation id to append this turn to. Omit to mint a fresh thread (id returned as webel.conversation). See Conversations & memory. |
| room optional | string | The room to run in. A key is scoped to exactly one room; if supplied, it must match that room. Usually safe to omit. |
| stream optional | boolean | If true, partial deltas are sent as server-sent events. Default false. See Streaming. |
| temperature optional | number | Accepted for wire compatibility. Not applied yet. |
| max_tokens optional | integer | Accepted for wire compatibility. Not applied yet. |
temperature, max_tokens, and client-supplied system prompts are accepted so existing SDK code runs unmodified, but they do not change generation yet. Pinning behavior-critical integrations should not rely on them.Multimodal input: images & documents
A user message's content may be an array of typed parts instead of a plain string. Image and document parts are routed into the same engine path as product attachments, so the model must be vision- or document-capable (see GET /v1/models's supports_images / supports_documents, which now describe a capability this endpoint actually accepts).
{
"messages": [
{"role": "user", "content": [
{"type": "text", "text": "What does this document say about refunds?"},
{"type": "image_url", "image_url": {"url": "data:image/png;base64,…"}},
{"type": "file", "file": {"filename": "policy.pdf", "file_data": "base64…"}}
]}
]
}- Images:
{"type":"image_url","image_url":{"url":"data:image/<type>;base64,…"}}. Inlinedata:URLs only (remotehttp(s)URLs are not fetched). Accepted types:image/png,image/jpeg,image/webp. Max 5 images, 6 MiB each. The OpenAIdetailhint is accepted and ignored. - Documents:
{"type":"file","file":{"filename":"…","file_data":"…"}}.file_datais bare base64 or adata:<type>;base64,…URL; the media type is taken from an explicitmedia_type, else the data URL, else the filename extension. Accepted types:application/pdf,text/plain,text/markdown. Max 10 documents, 10 MiB each. - Reclassification: a document type sent through
image_url(e.g. a PDF) is reclassified to a document; the media type is authoritative, never a rejection. - Refusals: an unsupported part type, an over-allowlist media type, or an over-limit attachment refuses the whole request with a
400naming the offending part/file.
Response body
{
"id": "chatcmpl-1834708065435648",
"object": "chat.completion",
"created": 1756051200,
"model": "claude-sonnet-5",
"choices": [{
"index": 0,
"message": { "role": "assistant", "content": "…" },
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": 120,
"completion_tokens": 80,
"total_tokens": 200,
"cost_microusd": 1250000,
"model_selected_by": "auto"
},
"webel": {
"conversation": "1834708065435648",
"turn": "1834708065441792",
"flavor": "api",
"limit_microusd": 10000000,
"limit_remaining_microusd": 8750000
}
}| Field | Type | Notes |
|---|---|---|
| id | string | Completion id, derived from the turn. |
| object | string | chat.completion (non-streaming) or chat.completion.chunk (streaming frames). |
| created | integer | Unix timestamp of response creation. |
| model | string | The model that actually ran. When you pinned, it echoes your pin; when auto-routed, it names the chosen model. |
| choices[].message | object | The assistant reply (role + content). |
| choices[].finish_reason | string | stop: natural completion or the reply wait timed out cleanly. |
| usage.prompt_tokens usage.completion_tokens usage.total_tokens | integers | Token accounting for the call. |
| usage.cost_microusd | integer | This call's cost in millionths of a dollar (1250000 = $1.25). Compute passes through at cost, with no markup. |
| usage.model_selected_by | string | pinned when you chose the model, auto when Webel's router did. |
| webel.conversation | string | The thread id. Pass it back as conversation to continue. |
| webel.turn | string | The reply turn's id within the thread. |
| webel.flavor | string | Always api for API-created threads. |
| webel.limit_microusd webel.limit_remaining_microusd | integers | Present only on capped keys: the cap and remaining headroom, in millionths of a dollar. |
Every response also carries rate-limit headers. See Rate limits & spend caps.
Model selection
- Pin:
"model": "<model-id>"runs exactly that model. Unknown or unavailable ids are refused with a bad-request error rather than silently substituted. - Auto:
"model": "auto"(or omitted) lets Webel route each request to the best fit across frontier and open-source models. If the API key has a pinned model,"auto"resolves to that pin instead; the pin is set on the key (not per request). The chosen model is returned inmodel, andusage.model_selected_byconfirms who chose. - Model ids follow the provider-prefixed convention used across the platform (e.g.
claude-sonnet-5). Available ids are those selectable in your room.
Moderation
Prompts and completions pass through content classification. A flagged input is refused before any spend accrues; a flagged completion is blocked and logged rather than returned (fail-closed). Refusals surface as errors. See Errors.
For multimodal input, the text parts, the extracted text of every document (PDFs included), and the content of every image are classified before posting, so a flagged input is refused before any spend accrues. Image screening covers the sexual, self-harm, and violence categories; child-safety (sexual/minors) in images is not covered by the classifier and relies on the separately-managed hash-match control (a roadmap item).