Skip to content
Skip to Content
Batchwell Docs

Chat completions

POST /v1/chat/completions, the fields we accept, and what we reject.

HTTP
POST /v1/chat/completions

The request and response follow the OpenAI Chat Completions format. Batchwell is strict: every field is checked against an allowlist, and anything we do not support is rejected with a 400 rather than silently dropped.

FieldNotes
modelRequired. A model id from GET /v1/models.
modelsOptional fallback list, up to 5 ids. See routing.
messagesRequired. Text only (see below).
max_tokens / max_completion_tokensOutput cap. Defaults to the model's default maximum.
temperature, top_p, stopSampling controls.
stream, stream_optionsSee streaming.
tools, tool_choiceFunction calling, where the model supports it.
reasoning_effortFor reasoning models.
providerRouting preferences. See routing.

Message content must be a string or an array of parts of type text. Parts of type image_url, input_audio or file are rejected with 400 unsupported_content.

  • n greater than 1, logprobs and top_logprobs → 400.
  • Any field not in the table above → 400 unsupported_parameter. The error message names the field.

A normal OpenAI response, plus:

  • usage.cost_micro: the amount charged for this request, in micro-USD (1,000,000 = $1).
  • choices[].message.batchwell: { "generation_id", "model", "provider", "ai_generated": true }, a machine-readable marker that the content is AI-generated.
  • Headers x-batchwell-generation-id and x-batchwell-model (the model that actually answered).
Response · 200 OK · application/json
{
  "id": "gen_0193...",
  "object": "chat.completion",
  "model": "batchwell/deepseek-v4.1-flash-uncensored",
  "choices": [
    {
      "index": 0,
      "finish_reason": "stop",
      "message": {
        "role": "assistant",
        "content": "...",
        "batchwell": {
          "generation_id": "gen_0193...",
          "model": "batchwell/deepseek-v4.1-flash-uncensored",
          "provider": "lyber",
          "ai_generated": true
        }
      }
    }
  ],
  "usage": { "prompt_tokens": 412, "completion_tokens": 288, "total_tokens": 700, "cost_micro": 470 }
}

Before a model runs we hold enough credit for your input plus the full output cap at the price of the dearest model in model + models. When the request ends we charge only what was used and release the rest. If the hold cannot be placed you get 402 insufficient_credit and nothing runs.