API reference

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.

POSThttps://api.webel.ai/v1/chat/completions

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

FieldTypeNotes
messages requiredarrayA 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 optionalstringID 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 optionalstringWebel conversation id to append this turn to. Omit to mint a fresh thread (id returned as webel.conversation). See Conversations & memory.
room optionalstringThe room to run in. A key is scoped to exactly one room; if supplied, it must match that room. Usually safe to omit.
stream optionalbooleanIf true, partial deltas are sent as server-sent events. Default false. See Streaming.
temperature optionalnumberAccepted for wire compatibility. Not applied yet.
max_tokens optionalintegerAccepted for wire compatibility. Not applied yet.
⚠️v1 note: 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,…"}}. Inline data: URLs only (remote http(s) URLs are not fetched). Accepted types: image/png, image/jpeg, image/webp. Max 5 images, 6 MiB each. The OpenAI detail hint is accepted and ignored.
  • Documents: {"type":"file","file":{"filename":"…","file_data":"…"}}. file_data is bare base64 or a data:<type>;base64,… URL; the media type is taken from an explicit media_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 400 naming 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
  }
}
FieldTypeNotes
idstringCompletion id, derived from the turn.
objectstringchat.completion (non-streaming) or chat.completion.chunk (streaming frames).
createdintegerUnix timestamp of response creation.
modelstringThe model that actually ran. When you pinned, it echoes your pin; when auto-routed, it names the chosen model.
choices[].messageobjectThe assistant reply (role + content).
choices[].finish_reasonstringstop: natural completion or the reply wait timed out cleanly.
usage.prompt_tokens
usage.completion_tokens
usage.total_tokens
integersToken accounting for the call.
usage.cost_microusdintegerThis call's cost in millionths of a dollar (1250000 = $1.25). Compute passes through at cost, with no markup.
usage.model_selected_bystringpinned when you chose the model, auto when Webel's router did.
webel.conversationstringThe thread id. Pass it back as conversation to continue.
webel.turnstringThe reply turn's id within the thread.
webel.flavorstringAlways api for API-created threads.
webel.limit_microusd
webel.limit_remaining_microusd
integersPresent 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 in model, and usage.model_selected_by confirms 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).