Completions

API reference for the chat completions endpoint

Creates a model response for the given chat conversation. Compatible with any OpenAI SDK. Sansa can route each request to the best model ("sansa-auto") or call a specific model directly; see Models.

POST /v1/chat/completions

See the code panel for request and response examples.


Body Parameters

On sansa-auto, some fields return 400; see What sansa-auto accepts.

messages

Required. An array of messages comprising the conversation so far. Sansa supports text, image, and audio inputs. Messages can include image_url (URL or base64) and input_audio (base64) content parts. On sansa-auto, they go to a model that can read them.

To transcribe a standalone audio file, use the Transcriptions endpoint instead.

interface Message {
  // One of "system", "user", "assistant", "tool".
  // The legacy "developer" role is also accepted and treated as "system".
  role: "system" | "user" | "assistant" | "tool";

  // The text content of the message.
  // Can be a plain string or an array of content parts.
  // Set to null on assistant messages that contain tool_calls.
  content: string | ContentPart[] | null;

  // An array of tool calls the model wants to make.
  // Present when the model decides to call tools instead of generating text.
  tool_calls?: ToolCall[];

  // Must match an id from a prior tool_calls entry.
  // Required for tool messages.
  tool_call_id?: string;
  
  // The model's reasoning text (assistant messages only).
  reasoning?: string;

  // Structured reasoning blocks (assistant messages only).
  // When echoing back assistant messages, pass these unmodified
  // to maintain reasoning continuity. See the Reasoning docs.
  reasoning_details?: ReasoningDetail[];
}

interface ContentPart {
  type: "text" | "image_url" | "input_audio";

  // For type "text".
  text?: string;

  // For type "image_url". Accepts a public URL or a base64 data URI.
  // data URI format: "data:<mime>;base64,<data>"
  image_url?: {
    url: string;
  };

  // For type "input_audio". Base64-encoded audio bytes.
  input_audio?: {
    // Base64-encoded audio bytes.
    data: string;
    // Audio format: "mp3", "wav", "m4a", "webm", "ogg", "flac", or "opus".
    format: string;
  };
}

model

Optional. Controls how the request is dispatched.

  • "sansa-auto", null, or omitted: the router picks the model. The response's model is the model that was used.
  • A catalog model ID (e.g. "openai/gpt-5.4", "anthropic/claude-sonnet-4.6"): calls that model directly.
  • An unknown ID: 400 invalid_model.

Model IDs are listed on the Models page. See Models for how each mode works.

stream

Default: false. If true, the response is delivered as Server-Sent Events (SSE), compatible with OpenAI SDK streaming. See Streaming.

temperature

Optional. Sampling temperature between 0 and 2. Higher values produce more random output; lower values produce more deterministic output. When omitted, the model's default applies.

max_completion_tokens

Optional. Upper bound on the number of tokens that can be generated for a completion, including visible output tokens and reasoning tokens. Must be at least 1 if provided. Takes precedence over max_tokens.

max_tokens

Optional. Legacy alias for max_completion_tokens, used when that isn't set.

tools

Optional. A list of tools the model may call.

interface Tool {
  type: "function";
  function: {
    name: string;
    description?: string;
    // A JSON Schema object
    parameters: object;
  };
}

tool_choice

Default: "auto". Controls which tool (if any) the model calls.

// Model decides whether to call a tool or generate text.
"auto"

// Model will not call any tool.
"none"

// Model must call at least one tool.
"required"

// Forces the model to call the named function.
{ type: "function", function: { name: "my_function" } }

parallel_tool_calls

Default: true. Whether to allow the model to make multiple tool calls in a single response.

response_format

Optional. Forces the model to produce output in a specific format.

// Default. Unstructured text output.
{ type: "text" }

// Model output is guaranteed to be valid JSON.
{ type: "json_object" }

// Structured outputs. The response conforms to the provided JSON Schema.
{
  type: "json_schema",
  json_schema: {
    name: "...",
    strict: true,
    schema: { ... }
  }
}

reasoning

Optional. Reasoning (extended thinking) configuration.

{
  // One of "xhigh", "high", "medium", "low", "minimal", "none".
  effort: "medium",

  // Token budget for reasoning, instead of effort.
  max_tokens: 1000,

  // If true, reasoning is used internally but not returned in the response.
  exclude: false,

  // Optional. false disables reasoning.
  enabled: true
}

If both reasoning and reasoning_effort are provided, reasoning takes precedence.

On sansa-auto, omitting both defaults to effort: "high"; see Smart Routing.

reasoning_effort

Optional. Top-level OpenAI-style reasoning effort. Accepted values: "xhigh", "high", "medium", "low", "minimal", "none".

Equivalent to reasoning: { effort: ... }; reasoning wins if both are sent.

top_p

Optional. Nucleus sampling. Value between 0 and 1. The model considers only the tokens comprising the top top_p probability mass.

stop

Optional. Up to 4 sequences where the model will stop generating further tokens. The returned text will not contain the stop sequence.

frequency_penalty

Optional. Number between -2.0 and 2.0. Positive values penalize tokens based on their existing frequency in the text so far, reducing repetition.

presence_penalty

Optional. Number between -2.0 and 2.0. Positive values penalize tokens based on whether they have already appeared in the text, encouraging the model to cover new topics.

metadata

Optional. A set of up to 16 key-value pairs attached to the request. Keys must be ≤ 64 characters; values must be ≤ 512 characters.

Use metadata["call_name"] to tag a request with a label. Tagged requests can be filtered in your dashboard.

  • call_name must be ≤ 64 characters and cannot be empty or whitespace-only.
  • Invalid call_name values return 400 with code invalid_call_name.
{
  "call_name": "summarize-email"
}

Currently, call_name is the only metadata key that Sansa reads. Other keys are accepted for OpenAI SDK compatibility but are not stored.

session_id

Optional. Keeps a sansa-auto conversation on one model so its prompt cache stays warm (max 256 characters), like prompt_cache_key. Also accepted as the x-session-id header; the body wins if both are sent. See Prompt Caching.


Returns

A ChatCompletion object.

interface ChatCompletion {
  // Unique identifier for the completion.
  id: string;

  // Always "chat.completion".
  object: "chat.completion";

  // Unix timestamp of when the completion was created.
  created: number;

  // The model that actually served the request.
  // For sansa-auto requests, this is the routed model.
  // For direct model requests, this is the model you requested.
  model: string;

  // Completion choices. Always length 1.
  choices: {
    // Always 0.
    index: number;

    message: {
      // Always "assistant".
      role: "assistant";
      
      // Text content. null when tool_calls is present.
      content: string | null;
      
      // Tool calls the model wants to make, if any.
      tool_calls: ToolCall[] | null;
      
      // Reasoning text, if reasoning was enabled and not excluded.
      reasoning: string | null;
      
      // Structured reasoning blocks.
      reasoning_details: ReasoningDetail[] | null;
    };
    
    // Reason why the generation stopped.
    // "stop": Natural completion or stop sequence hit.
    // "length": Hit max_tokens / max_completion_tokens limit.
    // "tool_calls": Model wants to call one or more tools.
    // "content_filter": Content was filtered.
    // "error": Error during generation.
    finish_reason: "stop" | "length" | "tool_calls" | "content_filter" | "error";
  }[];

  // Token usage statistics.
  usage: {
    // Number of tokens in the input.
    prompt_tokens: integer;
    
    // Number of tokens in the output.
    completion_tokens: integer;
    
    // Sum of prompt_tokens and completion_tokens.
    total_tokens: integer;

    // Total billed cost for this completion in USD.
    cost: number;
  };

  // Routing metadata. See the Models docs.
  sansa: SansaCompletionExtension;
}

Errors

All errors follow this format:

{
  "error": {
    "code": "error_code",
    "message": "Human-readable description."
  }
}
HTTP StatusCodeWhen
400invalid_modelThe model value isn't "sansa-auto", null, or a known model ID
400invalid_call_namemetadata["call_name"] is empty, whitespace-only, or exceeds 64 characters
400invalid_requestreasoning.effort isn't one of the values above, or it is "none" on sansa-auto and no model can serve the request without reasoning
400unsupported_parametern > 1, audio, web_search_options, functions, function_call, logprobs or top_logprobs provided, or a field sansa-auto doesn't take
401unauthorizedInvalid or missing API key
402insufficient_creditsAccount balance is zero or negative
429rate_limit_exceededToo many requests
500internal_errorUnexpected server error

See Errors for handling, including 402 with the OpenAI SDK.


Unsupported parameters

These return 400:

  • n > 1 (n=1 or omitting n is fine)
  • audio
  • modalities containing "audio" (omitting modalities or passing ["text"] is fine)
  • web_search_options
  • functions (deprecated, use tools)
  • function_call (deprecated, use tool_choice)
  • logprobs, top_logprobs (log probabilities aren't returned yet)

seed, logit_bias, prediction, store, service_tier, verbosity, user, safety_identifier and tools[].function.strict are passed to the model. stream_options is accepted and has no effect.


Prompt Caching

On sansa-auto, send a prompt_cache_key so a conversation stays on one model; see Prompt Caching. The fields:

  • prompt_cache_key (or session_id): one value per conversation.
  • Top-level cache_control (for example { "type": "ephemeral" } or { "type": "ephemeral", "ttl": "1h" }) for automatic cache breakpoints.
  • Per-block cache_control on text content parts for explicit breakpoints on large static content.
  • prompt_cache_retention on direct model IDs.

Cached tokens are reported in usage.prompt_tokens_details.cached_tokens.


Billing

  • Sansa holds the request's estimated cost while it runs, then charges for the tokens used. usage.cost is the billed amount in USD.
  • Failed requests are not charged.
  • See Pricing for rates.