Chat Completions

Chat Completions API — route to 10,000+ LLMs via /v1/chat/completions with 12ms median overhead, intelligent routing, and semantic caching.

Create completions with OpenAI-compatible request/response shapes plus optional Xantly orchestration controls.

Recommended rollout: start with standard fields only (model, messages, temperature, max_tokens), then add orchestration controls incrementally.


Quick start example

curl -sS https://api.xantly.com/v1/chat/completions \
  -H "Authorization: Bearer $XANTLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "auto",
    "messages": [
      {"role": "user", "content": "Explain vector databases in 2 bullets."}
    ]
  }'

Request body

Standard parameters (OpenAI-compatible)

FieldTypeRequiredDefaultValidation / behavior
modelstringYes,A routing alias (auto, xantly/auto-speed, xantly/auto-value, xantly/auto-quality, xantly/auto-safety) or a catalog model id from GET /v1/models. See Choosing how the router picks. Unknown ids are rejected.
messagesarray<ChatMessage>Yes,Must contain at least 1 message.
modelsarray<string>NonullOrdered fallback chain, OpenRouter semantics. If the model in model cannot serve the request, the gateway tries these in order before its own routing. Each entry is a catalog slug.
streambooleanNofalseEnables SSE output.
nintegerNo1Allowed range: 1..=8.
max_tokensintegerNoprovider/model dependentAlias supported: max_completion_tokens.
temperaturenumberNoprovider/model dependentValidated range: 0.0..=2.0.
top_pnumberNoprovider/model dependentPassed through to provider.
frequency_penaltynumberNoprovider/model dependentValidated range: -2.0..=2.0.
presence_penaltynumberNoprovider/model dependentValidated range: -2.0..=2.0.
stopstring | array<string>NonullPassed through to provider.
toolsarray<object>NonullTool definitions for function-calling workflows.
tool_choicestring | objectNoprovider dependentPassed through to provider.
parallel_tool_callsbooleanNoprovider dependentPassed through to provider.
response_formatobjectNonullSupports {"type":"json_object"} and {"type":"json_schema", "json_schema": {...}}.
seedinteger (u64)NonullDeterminism hint.
userstringNonullEnd-user identifier, forwarded to provider.
logprobsbooleanNonullForwarded to provider.
top_logprobsinteger (u8)NonullValidated max: 20.
stream_options.include_usagebooleanNofalseForwarded to provider where supported.
reasoning_effortstringNonullAccepted values: minimal, low, medium, high. Maps to each provider's native reasoning mechanism and selects the routing tier/price (low→cheap, high→premium). It outranks an xantly/auto-* alias: the most specific thing you said wins. The effort actually applied comes back in x-xantly-reasoning-effort. See Reasoning & Thinking.
reasoningobjectNonullUnified reasoning controls: { effort, max_tokens, summary, exclude, enabled }. Returns the model's reasoning text. See Reasoning & Thinking.
service_tierstringNonull"batch" is accepted and treated as a cost-oriented routing hint.
metadataobject<string,string>NonullFree-form metadata map used for tracing/routing context.

ChatMessage object

FieldTypeRequiredNotes
rolestringYesCommon values: system, user, assistant, tool.
contentstring | arrayYesString for text, array for multimodal content parts.
namestringNoOptional participant name.
tool_callsarray<object>NoAssistant tool call payloads.
tool_call_idstringNoCorrelates tool output to a prior tool call.
refusalstringNoOptional refusal text.

Proprietary parameters (Xantly)

These are optional. If omitted, the gateway uses defaults and automatic policy.

routing_hints (soft preferences)

FieldTypeValue range / valuesBackend statusUsage guidance
modestringfast, balanced, quality, cost_optimized, free_models_onlyActiveCoarse routing preset when explicit preference knobs are not set.
preference_dialnumberBest used in 0.0..1.0 (values are clamped)ActiveLower biases cost/speed; higher biases quality.
prefer_latencybooleantrue/falseActivetrue strongly biases low-latency execution.
prefer_qualitybooleantrue/falsePartialAccepted; currently primarily suppresses mode preset behavior when explicit knobs are present.
max_cost_per_tokennumber--RejectedReturns 400. It was never enforced, and accepting a cost ceiling that does nothing is worse than refusing it. Use preference_dial, mode: "cost_optimized", or an organization spend limit instead.
max_latency_msintegerpositive integerActiveSets latency budget; very low budgets bias faster lanes.
max_tierinteger1, 2, 3ActiveTier guardrail hint.
required_capabilitiesarray<string>tools, tool_use, vision, json, structured_outputActiveEnforced as a hard pre-routing filter. Any other member returns 400 rather than being silently ignored.
task_complexitystringtrivial, standard, complex, expertActiveInfluences tier floor/ceiling behavior.
chain_routingstringsticky, mixedActivemixed disables sticky-route continuation behavior.
allow_free_fallbackbooleantrue/falseActivePassed into metadata as an explicit fallback preference signal.

routing_override (harder overrides)

FieldTypeValuesBackend statusUsage guidance
force_tierstringT1, T2, T3 (also tier-1, tier1, etc.)ActiveForces selected tier mapping.
force_lanestringsmart, turboActiveForces lane.
force_modelstringmodel slug/upstream idActivePins model after routing.
force_providerstringprovider identifierReservedAccepted in schema; not directly applied in this chat handler flow today.
allow_fallbacksbooleantrue / falseActivefalse makes this request fail on its first pick instead of substituting another model. OpenRouter allow_fallbacks semantics. Default true.
max_retriesinteger0..=5ActiveTransport retries of the primary model only: 429, 5xx, timeouts, network. Never applied to an answer the model chose to give. Default is one bounded retry. A request may tighten the organization's setting, never loosen it.
max_fallbacksinteger0..=5ActiveHow many model substitutions the gateway may make. 0 is the same as allow_fallbacks: false. Defaults per request shape: 3 plain chat, 5 JSON, 6 tools, 2 voice. A request may tighten the organization's setting, never loosen it.
timeout_msinteger1..=900000ActiveWall-clock budget for the whole attempt chain, and the ceiling for a single attempt within it. The caller decides: this raises as well as lowers the gateway's own default, up to a 15 minute hard cap. Set it when you ask a reasoning model for a long answer. An organization-level timeout still applies as an administrator's ceiling.

xantly orchestration block

FieldTypeValues / rangeEffective defaultBackend statusUsage guidance
quality_tolerancenumber0.0 to 0.200.03, or your organization's settingActiveHow much measured accuracy you will trade for a cheaper model, in absolute points. 0 serves the best model the evidence knows; higher admits cheaper ones. A value outside the range returns 400. Overrides the organization setting, and the auto-quality / auto-value aliases are presets of the same dial.
workflow_typestringsingle_turn, execution_task, multi_step_conversational, long_horizon_autonomous, voice_simple, voice_complex, creativeauto-classifiedActiveExplicitly sets workflow class when recognized.
chain_idstringUUID recommendednullActiveSignals chain continuation; invalid UUID is ignored by classifier.
conversation_idstringfree-form idnullActiveUsed for memory/sticky context continuity.
planning_modestringpreact or planacttenant/default heuristicActiveControls planner style where planning layer is active.
max_chain_stepsinteger (u16)1..65535workflow-dependentActive (conditional)Applies when workflow is long_horizon_autonomous.
chain_timeout_secsinteger (u32)0..4294967295workflow-dependentActive (conditional)Applies when workflow is long_horizon_autonomous.
chain_routingstringe.g. sticky / mixednullReservedAccepted in payload; rely on routing_hints.chain_routing for current behavior.
reliability_levelstringstandard, high, criticalstandardActiveInfluences reliability/verification activation.
enable_memorybooleantrue/falsetrueActiveControls persistence into L1/L2 memory in this handler path.
enable_speculationbooleantrue/falserouter/tenant defaultActivePer-request override for speculation toggle.
enable_hedgingbooleantrue/falserouter/tenant defaultActivePer-request override for hedging toggle.
enable_cachebooleantrue/falsetrueActiveEnables/disables cache lookup path for this request.
cache_ttl_secsinteger1 to 2592000organization setting (7 days)ActiveLifetime, in seconds, of the response-cache entry this request writes; clamped to thirty days. The x-xantly-cache-ttl header does the same and wins when both are sent.
output_verificationstringnone, native, schema, cross_modelstrategy auto-selectionActivePer-request override for output verification strategy.
compress_contextbooleantrue/falsenullReservedAccepted for forward compatibility.
redact_piibooleantrue/falsefalseActiveSets request redaction signal (x-redact-pii=true metadata).
voice_modestringtypically "true" for voice pathnullActiveEnables voice-oriented handling when set.
enable_tool_rerankingbooleantrue/falsenullReservedAccepted for forward compatibility.
intelligence_modestringproxy, cache, fullfull (system default)ActivePipeline intelligence preset. See Intelligence Modes.

Legacy request headers (still supported)

The gateway maps selected request headers into metadata for backward compatibility.

HeaderMapped metadata key
x-xantly-workflowx-xantly-workflow
x-xantly-voicex-xantly-voice
x-xantly-planning-modex-xantly-planning-mode
x-xantly-preferencex-xantly-preference
x-xantly-chain-routingx-xantly-chain-routing
x-xantly-lanex-xantly-lane
x-xantly-tierx-xantly-tier
x-xantly-run-idrun_id
x-xantly-conversation-idconversation_id
x-intelligence-modex-intelligence-mode

Choosing how the router picks

model accepts a routing alias instead of a model id. This is the normal way to use Xantly: you state what matters and the router picks per request, rather than you maintaining a model list that goes stale.

AliasWhat it optimises for
auto or xantly/autoBalanced. The router weighs quality, cost and latency per request. Start here.
xantly/auto-speedLowest latency.
xantly/auto-valueLowest cost that still answers the request.
xantly/auto-qualityStrongest answer.
xantly/auto-safetySafety-critical work.

An objective reorders the models that can serve your request; it never lowers the bar for what the request needs. Ask for speed on a hard question and you get the fastest model that can still answer it, not a cheap one that cannot. That is why xantly/auto-quality may return a mid-priced model on an easy question: it was the best answer available for the work, and paying more would have bought nothing.

Every response tells you what happened: x-xantly-objective echoes the objective in force, and x-xantly-model-used names the model that answered.

Any xantly/* id that is not in this table is rejected with a 400, so a typo fails loudly instead of silently routing somewhere you did not intend.

Response body

Non-stream (200 OK)

{
  "id": "chatcmpl-...",
  "object": "chat.completion",
  "created": 1741400000,
  "model": "bedrock/v3.2/us-east-1",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "..."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 31,
    "completion_tokens": 18,
    "total_tokens": 49
  },
  "xantly_metadata": {
    "request_id": "req_01abc...",
    "routing_decision": "Lane: Turbo (Source: BarpRouter)",
    "provider": "deepseek",
    "tier": "T2",
    "provider_tier": "T2",
    "latency_ms": 142,
    "requested_model": "auto",
    "decision_source": "BarpRouter",
    "task_family": "analysis",
    "cost_usd": 0.00032,
    "baseline_cost_usd": 0.00120,
    "savings_usd": 0.00088,
    "savings_pct": 73.3,
    "cost_attribution": "xantly",
    "estimated_cost_usd": 0.00032,
    "healer_report": null
  }
}

xantly_metadata fields

FieldTypeAlways presentDescription
request_idstringYesCorrelation ID for support and audit.
routing_decisionstringYesHuman-readable routing summary (lane + source).
providerstringYesProvider that served the request (e.g. "deepseek", "anthropic").
tierstringYesEffective execution tier ("T1", "T2", "T3").
provider_tierstring?NoProvider-level tier when different from effective tier.
latency_msintegerYesEnd-to-end gateway latency in milliseconds.
requested_modelstringYesThe model string you sent (e.g. "auto", "gpt-4o"). Useful for debugging routing decisions when using "auto".
decision_sourcestring?NoMachine-readable routing engine source (e.g. "BarpRouter", "Pinned", "CacheHit").
task_familystring?NoTask category detected by the smart router (e.g. "code", "writing", "analysis").
cost_usdnumber?NoActual cost for this specific request in USD. Present when usage data is available.
baseline_cost_usdnumber?NoGPT-4o reference cost for the same token counts (input $2.50/M, output $10/M). Lets you compute savings without a separate analytics call.
savings_usdnumber?Nobaseline_cost_usd - cost_usd. Positive value means Xantly saved money vs. GPT-4o.
savings_pctnumber?NoSavings as a percentage of baseline (0-100+).
cost_attributionstringYes"xantly" when routed via Xantly-managed provider keys; "byok" when routed via your own API key.
estimated_cost_usdnumber?NoLegacy alias for cost_usd. Kept for backward compatibility.
healer_reportobject?NoPresent when JSON repair was applied. Contains original, healed, stage, confidence, healing_time_ms.

Notes

Stream (text/event-stream)


Response headers

Common observability headers

HeaderPresent whenDescription
x-xantly-request-idalwaysRequest correlation id. Quote it in support requests.
x-xantly-model-usednon-streamThe model that actually answered, which is the one you are billed for. This is the header to read when you want to know what auto chose.
x-xantly-provideralwaysFull catalog slug of the serving deployment, for example vertex/gemini-3.5-flash/global.
x-xantly-objectivealwaysThe routing objective in force: auto, speed, value, quality.
x-xantly-tier-usedalwaysEffective execution tier (T1 to T3).
x-xantly-lane-usedalwaysEffective lane (smart / turbo).
x-xantly-cache-hitalwaystrue / false.
x-xantly-cache-statusalwaysHIT or MISS.
x-xantly-stream-modestreamingincremental or buffered. Some contracts (tools, strict JSON) are answered buffered.
x-xantly-cost-usdnon-streamWhat this request costs you.
x-xantly-input-tokens, x-xantly-output-tokensnon-streamToken counts as billed.
x-xantly-latency-breakdownnon-streamJSON string with stage-level latency, including gateway overhead.
x-xantly-routing-confidencenon-streamThe router's confidence in the pick, 0.0 to 1.0.
x-xantly-escalation-count, x-xantly-wasted-attemptsnon-streamHow many substitutions the request needed, and how many attempts produced nothing. 0 on a clean request.
x-xantly-audit-idnon-streamCorrelation id for the audit trail.
x-ratelimit-limit, x-ratelimit-remainingalwaysYour organization's per-minute request budget, and what is left of it.
ratelimit-resetalwaysSeconds from now until the window resets. This is the one to sleep on.
x-ratelimit-resetalwaysThe same moment as a Unix epoch timestamp. Near-identical name, different unit: sleeping on this value waits decades.
x-ratelimit-concurrency-limit, x-ratelimit-concurrency-scopealwaysThe in-flight request ceiling and what it applies to. The scope is gateway, meaning platform-wide and shared, not per organization and not raised by any plan.
x-xantly-tool-capablealwaysWhether the model that served this request can emit tool calls at all. Absent rather than false when we have no measurement, so it never guesses. This is what separates "the model ignored your tools" from "the model chose not to call one".
x-xantly-reasoning-effortwhen reasoning was requestedThe effort the request actually resolved to and was served under. Absent when none applied.
x-xantly-ignored-parameterswhen non-emptyComma-separated reserved fields you sent that nothing acted on. Emitted on buffered and streamed responses. The same list appears in xantly_metadata.ignored_parameters on the non-streamed body.
x-xantly-provider-cost-usdalwaysWhat the upstream provider charged for this request, so "we bill routed usage at provider cost" is checkable rather than merely asserted.
x-xantly-cache-read-tokens, x-xantly-cache-write-tokenswhen the provider reported themInput tokens served from, and written to, the provider's prompt cache. See Prompt Caching.
x-xantly-alignmentxantly/auto-safety, when the response proposed tool callschecked;aligned=true;confidence=..;judge=.. when the calls serve your task, blocked;aligned=false;.. when they were stripped (the assistant message says why), unchecked;reason=.. when the judge could not answer and the calls were left in place. A streamed safety-mode request with tools is answered buffered (x-xantly-stream-mode: buffered) so the calls are judged whole.
x-xantly-injection-guardwhen the request carried tool resultsmode=<mode>;scanned=<chunks>;flagged=<n>;confirmed=<n>;redacted=<n>;spotlighted=<n>: what the tool-result injection guard did to this request (flagged is the classifier; confirmed is the second check, which runs in redact mode only, and only a confirmed piece is removed). Send the same header name on the request, x-xantly-injection-guard: spotlight or redact, to tighten the mode for that request; it can never loosen it. Emitted on buffered and streamed responses. See Security & Compliance.

Every response also carries the standard OpenAI fields, so a client that reads response.model and response.usage needs no Xantly-specific code at all.

Cache-path headers

HeaderValue
x-xantly-cache-typeexact or semantic
x-xantly-latency-msend-to-end latency (cache path)
x-xantly-semantic-similaritysimilarity score (semantic cache only)

Usage / cost headers

These are included when usage is available:


Timeouts

The gateway gives a request a budget for one attempt and a budget for the whole attempt chain. Both are derived from the shape of your request, because a tool call and a reasoning turn are not the same kind of wait.

Request shapeOne attemptWhole chain
Plain chat25s52s
Plain chat asking for 2048 output tokens or moremax_tokens divided by 40 tokens a second, at least 25stwice the attempt plus 2s
Reasoning (reasoning or reasoning_effort set)850s900s
Tools present10s20s
response_format JSON8s15s
Pinned model (allow_fallbacks: false)8s52s
Voice5s8s

Two ceilings apply to the scaled row. A buffered answer is capped at 90s per attempt and 95s for the chain, because the edge in front of the API closes a connection that has sent no bytes for 100 seconds. A streamed answer is not subject to that, since bytes are already flowing, so it runs up to the 15 minute hard cap. If you ask for a long answer, stream it.

Deciding for yourself

routing_override.timeout_ms sets the chain budget and raises the per-attempt ceiling with it, from 1ms to 900000ms (15 minutes). It raises as well as lowers: the gateway's own default is a starting point, not a limit you must live under.

curl -sS https://api.xantly.com/v1/chat/completions \
  -H "Authorization: Bearer $XANTLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "auto",
    "messages": [{"role": "user", "content": "Prove it, showing every step."}],
    "max_tokens": 8192,
    "stream": true,
    "routing_override": {"timeout_ms": 600000}
  }'

An organization-level timeout, if an administrator has set one, still applies as a ceiling over whatever a request asks for.

What happens when an attempt runs out

A timeout is a failed attempt, not a failed request: the gateway substitutes another model and keeps going, until max_fallbacks or the chain budget is spent. Set allow_fallbacks: false to fail on the first attempt instead. x-xantly-escalation-count on the response tells you how many substitutions it took, and x-xantly-wasted-attempts how many produced nothing.

Errors

Error payloads use OpenAI-style shape:

{
  "error": {
    "message": "temperature (2.5) must be between 0 and 2",
    "type": "invalid_request_error",
    "code": "validation_error",
    "param": null
  }
}
HTTPerror.typeerror.code (examples)Typical trigger
400invalid_request_errorvalidation_errorInvalid parameter range, unknown model, empty messages.
401authentication_errorinvalid_api_key, expired_api_key, revoked_api_keyMissing/invalid API key.
403authorization_errorforbidden, insufficient_scopes, tenant_violationScope/policy denial.
404not_found_error or governance_errorresource_not_found, tool_not_registeredMissing referenced resource or unregistered tool.
422governance_errortool_call_blockedGovernance blocked a tool call.
429rate_limit_errorrate_limit_exceeded, upsteam_rate_limitTenant or upstream rate limiting.
502upstream_errorprovider_errorUpstream provider error.
503governance_errorcircuit_breaker_openCircuit breaker open.
504upstream_errorprovider_timeoutUpstream timeout.
500internal_errorinternal_errorInternal platform failure.

Error headers


Edge cases and implementation notes

  1. Model validation is catalog-aware

    • model validation is strict when the model catalog is loaded.
    • During catalog cold-start/empty states, strict rejection may be relaxed.
  2. top_logprobs validation

    • Server enforces top_logprobs <= 20.
    • Provider-specific logprobs behavior may vary.
  3. Chain limit overrides are conditional

    • xantly.max_chain_steps and xantly.chain_timeout_secs apply only when workflow resolves to long_horizon_autonomous.
  4. Streaming semantics

    • Non-voice stream mode is SSE-compatible but not guaranteed token-by-token.
  5. Reserved fields

    • Some accepted proprietary fields are reserved for compatibility (force_provider, compress_context, enable_tool_reranking, and certain routing_hints fields); they come back in x-xantly-ignored-parameters.

Practical rollout checklist

  1. Start with model: "auto" + standard fields.
  2. Enable response_format for structured outputs.
  3. Add one routing/orchestration control at a time.
  4. Track x-xantly-* response headers in observability.
  5. Add override fields only for test/debug traffic.

See also