Move from the OpenAI API
The exchange serves Chat Completions and a stateless part of Responses. Most OpenAI code changes in two places: the base URL and the API key. Model names, and features that need OpenAI to keep state, need more work. For setup, see OpenAI SDK.
Change these three things
- Issue a
spendkey on the API keys page. See API keys. - Set the base URL to
https://router.inference.ai.exchange/v1(orOPENAI_BASE_URL). Send the key asAuthorization: Bearer sk-liquid-…(orOPENAI_API_KEY). - Change each
modelto a name thatGET /v1/modelslists. See Model names.
Then check these:
- Remove each parameter that the exchange refuses. See OpenAI features.
- Run a dry run. See Check a request without a purchase.
- Read What is different about money. The exchange never lowers an output limit that you set. See Output limits.
What differs
- Model names. An unknown name, or a fine-tuned model, returns
404 model_not_found. ngreater than 1. Refused. OpenAI bills every choice, and the exchange serves one.- State in Responses.
previous_response_id,conversationandbackground: trueare refused. Send the full conversation ininput. - Hosted tools. The exchange runs none. It removes
web_searchwith the headerx-liquid-notice: web_search_droppedand refuses the others. To search the web, add:web(beta) to the model name. - Not available. The Batch, Files, Assistants and Moderations APIs, and image edits.
- Retries. The SDK retries a
5xxresponse, and each try is a new request. To get the first response again, send the sameidempotency-keyheader. See Purchasing rules.
With with_raw_response, the SDK returns the headers, including x-liquid-cap-usd.
Example
An OpenAI request, then the same request for the exchange. The new request changes the client and the model, removes n=2 (refused) and store and service_tier (ignored), and adds a cap and a data rule. user stays, because it names the end user for guardrail limits. The model name is an illustration.
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Say hello."}],
max_completion_tokens=500,
n=2,
store=True,
service_tier="auto",
user="user-123",
)
import os
from openai import OpenAI
client = OpenAI(
base_url="https://router.inference.ai.exchange/v1",
api_key=os.environ["LIQUID_API_KEY"],
)
response = client.chat.completions.create(
model="gpt-oss-120b",
messages=[{"role": "user", "content": "Say hello."}],
max_completion_tokens=500,
user="user-123",
extra_body={"exchange": {"cap_usd": 0.05, "privacy": {"retention": "none"}}},
)
Reference
Model names
Send a name that GET /v1/models returns. The model field accepts a model, a router model, a basket or a preset. See Model names. The exchange never uses a different model.
max_completion_tokens, max_tokens and max_output_tokens (Responses) are all accepted. Reasoning tokens count toward the limit.
OpenAI features
| OpenAI feature | What the exchange does |
|---|---|
stream, stream_options |
Applied. Set stream_options: {"include_usage": true} to get token usage in a stream. |
tools, tool_choice |
Applied. Only an offer that declares tool support can win. |
parallel_tool_calls, service_tier, include, truncation, safety_identifier, metadata |
Ignored. For metadata, send x-liquid-tag to label spend. See Cost tags. An input too long for an offer excludes it. |
response_format |
Applies json_schema and json_object. Only an offer that declares support can win. See Structured output. |
reasoning_effort, reasoning.effort (Responses) |
Applied to offers that support the level, or unsupported_parameter. |
temperature |
Applied. |
top_p, top_k, min_p, repetition_penalty, stop, seed, logprobs, top_logprobs, logit_bias, frequency_penalty, presence_penalty |
Passed to a provider that declares support. If no offer supports one, unsupported_parameter. /v1/responses refuses logprobs and top_logprobs. |
n greater than 1 |
400 unsupported_parameter, param is n. |
store |
Ignored. The exchange keeps no response. To limit what a provider keeps, send exchange.privacy.retention: "none". See Data handling. |
user |
Names the end user for the limits of a guardrail. The X-Liquid-End-User header wins. |
prompt_cache_key |
Read into the cache plan of the job. See Prompt caching. |
previous_response_id, conversation, background: true (Responses) |
400 unsupported_parameter. Send the full conversation in input. |
Hosted tool web_search (Responses) |
Removed, with x-liquid-notice: web_search_dropped. No search runs. Add :web (beta) to the model name. See Quickstart. |
Other hosted tools: file_search, code_interpreter, mcp |
400 unsupported_parameter, param such as tools[1]. Declare your own function. |
| Embeddings, image generation, speech and video endpoints | Served. See Embeddings, Modalities and Move from the Sora API. |
Batch, Files, Assistants, Moderations, image edits, fine-tuning (ft: names) |
Not available. Send each request on its own. |
Troubleshooting
For 402 insufficient_balance and 400 no_eligible_offer with param set to exchange.cap_usd, see What is different about money.
| Error | Cause | Fix |
|---|---|---|
404 model_not_found |
The model is an OpenAI name that the exchange does not list. |
Pick a name from GET /v1/models. |
400 unsupported_parameter, param is n |
The request asks for more than one choice. | Remove n. |
400 unsupported_parameter, param is previous_response_id |
The Responses request asks the exchange to keep state. | Send the full conversation in input. |
400 unsupported_parameter, param is tools[...] |
The request has a hosted tool that the exchange does not run. | Remove the tool, or declare your own function. |
400 unsupported_parameter, param is another field |
No offer for the model supports that parameter. | Remove the parameter, or select another model. See Errors. |
402 insufficient_balance |
The cheapest eligible cap is more than the balance. | Add funds, or send a lower output limit. |
429 rate_limited |
Too many requests from the address, or a guardrail rate limit refused the call. | Wait for Retry-After. OpenAI limits do not apply here. See Guardrails. |
503 provider_failed or 503 model_unavailable |
The awarded provider failed, or no seller can serve the model now. | Set max_retries yourself, and send the same idempotency-key on a retry. See Purchasing rules. |