Chat Completions
Minimum-discount routing: Prefix the path with a min{N} segment (e.g. /min30/v1/chat/completions) to require marketplace seller offers to meet a minimum estimated buyer discount before routing. Buyer-owned providers are not covered. See Minimum-Discount Routing.
The primary inference endpoint. OpenAI-compatible — works with any client that speaks the OpenAI format.
Request
Parameters
- Name
model- required
- Description
- Model name (canonical, OpenRouter, Venice, or alias format)
- Name
messages- required
- Description
- Array of message objects
- Name
stream- Description
truefor SSE streaming (default: false)
- Name
max_tokens- Description
- Maximum output tokens
- Name
max_completion_tokens- Description
- Alias for
max_tokens
- Name
temperature- Description
- Sampling temperature
- Name
top_p- Description
- Nucleus sampling
- Name
stop- Description
- Stop sequences
- Name
tools- Description
- Function calling tools (OpenAI format — auto-translated for Anthropic sellers)
- Name
tool_choice- Description
- Tool selection strategy (
auto,required, or specific function)
- Name
response_format- Description
- Structured output format
- Name
reasoning_effort- Description
- Reasoning effort as a string, on models whose
supported_parameterslists it. See Reasoning Controls
- Name
reasoning- Description
- Reasoning options as an object (e.g.
{"effort": "high"}). Not interchangeable withreasoning_effort; see Reasoning Controls
- Name
provider- Description
- Optional provider hint — a single provider or an array of providers (an allow-list). Narrows routing to offers from the matching provider(s) before cheapest-offer selection.
- Name
provider_url- Description
- Optional provider URL hint (single value). Equivalent to
provider, but matched by provider host.
- Name
provider_base_url- Description
- Optional provider base URL hint (single value). Equivalent to
provider_url.
- Name
providers_blocked- Description
- Providers to refuse for this request — a single provider or an array. The deny-list counterpart of
provider; matched on the same spellings. See Routing Controls
- Name
provider_order- Description
- Preferred attempt order by provider, most-preferred first. Ordering only — it never makes an offer eligible or ineligible. See Routing Controls
- Name
stream_options- Description
{"include_usage": true}(auto-injected)
Minimum Discount
Routes only to offers at least 30% below the go-direct reference price; otherwise the request fails with
minimum_discount_not_met, naming the best discount that was available. The same floor can be set once on the
API key (min_discount_pct) or in the URL (/min30/v1/chat/completions) — the strictest of the three applies.
Price ceilings (max_price_per_1m, X-Max-Price-Per-1M) are retired: a per-1M input rate ignored output
and cache rates, so it never described what a request actually cost.
See Parameter Compatibility for full model-specific support, and
Reasoning Controls for reasoning_effort / reasoning.
Provider Pinning, Blocking, and Ordering
By default, Surplus routes each request to the cheapest healthy seller for the requested model. If you need to restrict routing to one or more specific providers, pass a provider hint in the request body. It accepts a single provider or an array of providers (an allow-list).
With an array, the request routes to any offer whose provider is in the list — the router then applies normal selection within that set: it picks the cheapest healthy offer among the allowed providers and excludes everyone else (even a cheaper provider you didn't list). All the usual rules still apply inside the allow-list: health checks, spend caps, price thresholds, estimated-cost sorting, and failover among matching offers.
Accepted forms (each array element can be any of these):
- a provider id or name —
"zai"/"Z.ai","uncensored"/"Uncensored AI" - a provider host —
"api.z.ai" - a provider URL —
"provider_url": "https://api.z.ai/api/paas/v4"or"provider_base_url": "https://api.uncensored.com/api/v1"(these two aliases stay single-valued)
Unsupported providers. Each entry is matched against the supported provider list. Unrecognized entries are ignored, so a mix like ["zai", "not-a-provider"] simply routes on zai. If every entry is unrecognized, the request fails with 400 unsupported_provider (the error names the bad entries and lists the supported providers).
No offers vs unsupported. A supported provider that just has no active healthy offer for the requested model returns 404 no_sellers_for_model — distinct from 400 unsupported_provider. Provider hints are optional and advanced: pinning narrowly can fail even when another (unlisted) provider has liquidity for the same model.
providers_blocked — the deny-list
The counterpart of provider, and a sibling of it rather than a nested option: provider says who may serve the request, providers_blocked says who may not. Same accepted spellings (family, name, or host), single value or array.
Unlike an unrecognized provider entry, an unreadable providers_blocked is refused, not ignored — {"venice": true} fails with 400 invalid_request rather than silently applying no block. A block that quietly disappears would route the request to precisely the provider you refused, so it fails loudly instead. An empty array means "block nothing", never "block everything".
If the block leaves no eligible offer, the request fails with 503 no_healthy_sellers.
provider_order — the attempt order
Providers you name are tried first, in the order given; everything else follows in the router's own order. Ordering is not eligibility — it reorders offers that already passed every filter and can neither resurrect an excluded offer nor exclude one you did not name.
All three work on every text surface: /v1/chat/completions, /v1/completions, /v1/responses, and /anthropic/v1/messages. None of them are forwarded to the provider. See Routing Controls for the full semantics and the key-scoped blocklist they compose with.
Tool Calling
Current behavior:
- Send tools in OpenAI
tools/tool_choiceformat. - OpenAI-compatible sellers receive OpenAI-format tool calls after normalization. This is the path used by the active production Claude sellers today, mostly Venice and Bankr LLM Gateway.
- Native Anthropic sellers (
api.anthropic.com) are supported through an OpenAI ⇄ Anthropic translation layer:toolsbecome Anthropic tools, assistanttool_callsbecometool_useblocks,role: "tool"messages becometool_resultblocks, and streamingtool_usedeltas are converted back to OpenAItool_callsdeltas. - Tool support is still model-dependent. Check
GET /v1/models: ifsupported_parametersdoes not includetools, the marketplace stripstoolsandtool_choicebefore forwarding because the upstream model rejects them. - Non-function tools such as computer-use or text-editor tool types are not executed by the marketplace; unsupported tool definitions are stripped or normalized to function tools when possible.
Streaming function-tool calling is supported for providers/models that stream tool-call deltas. Anthropic SSE tool_use events are translated to OpenAI tool_calls deltas; OpenAI-compatible providers are passed through after normalization.
Multimodal Input
Images, documents, and other media travel inside messages[].content as typed parts, with no upload step:
{"type": "image_url", "image_url": {"url": "https://…"}}, or a data: URL for inline bytes.
messages is forwarded to the chosen seller whole. The marketplace does not fetch buyer URLs, re-encode
bytes, or validate the MIME type declared in a data URL. Two consequences follow. An unusual shape, such as
a video data URL in image_url, succeeds only if the provider that wins the route accepts it. An image
referenced only by file_id returns 400 unresolvable_file_reference, since no marketplace seller's key
can resolve another account's file id.
Model capability requires a lookup: check architecture.input_modalities and supported_features on
GET /v1/models. The two disagree on some rows and the router treats either as sufficient.
Full contract, including video, YouTube URLs, documents, limits, and errors: Media Inputs.
Message Roles
Response
Standard OpenAI format. Streaming returns SSE chunks with data: {...} lines.