Migrating from OpenRouter

Replace model IDs and review provider preferences, fallback, and costs.

Keep the OpenAI SDK, replace the connection settings and model ID, then review every OpenRouter-specific option before switching traffic.

 client = OpenAI(
-    base_url="https://openrouter.ai/api/v1",
-    api_key=os.environ["OPENROUTER_API_KEY"],
+    base_url="https://api.deepraxis.com/openai/v1",
+    api_key=os.environ["PRAXIS_API_KEY"],
 )
-model = "openai/gpt-4o"
+model = "deepseek-flash"

1. Prepare

You need Python 3.10+, uv, and a Praxis key. Create one in Console → API Keys and securely inject it into the current terminal as PRAXIS_API_KEY. Never put the key in code or logs. Keep your original service configuration and key for rollback. Run the commands below in Bash on macOS or Linux.

test -n "${PRAXIS_API_KEY:-}"

Expected: exit code 0. Exit code 1 means the variable is missing; set it before continuing.

2. Replace model IDs

OpenRouter selectionPraxis selection
openai/gpt-4oStart with deepseek-flash; this is a different model, not an alias
vendor/modelCopy the exact ID from the Praxis catalog; do not assume removing the prefix is sufficient
An ID ending in :nitroSelect a catalog ID without the suffix; the suffix is unsupported
openrouter/autoChoose a specific model, or configure a models fallback list

Expected: client.models.list() includes your chosen ID. All entries in a fallback list must be valid Praxis IDs offering the operation you call.

Behavior differences

OpenRouter optionMigration action
provider.order, provider.only, provider.ignoreAvailable only with your own upstream key (BYOK). With platform credentials, remove them or receive 400 provider_selection_not_allowed
provider.allow_fallbacks, provider.sortHave no effect; remove them and reassess any routing assumptions
provider.data_collection, provider.zdrHave no effect; do not treat accepted requests as enforcement of these policies
modelsA model fallback list is available; replace every ID and verify the returned model
provider.require_parameters: trueChecks support for tool parameters and declared sampling parameters; returns 400 when a requested parameter is not declared as supported. Unsupported sampling parameters are otherwise ignored by default

The parameter check covers tool parameters and declared sampling parameters, not arbitrary provider features. See Chat Completions field support for the precise scope. If your application requires a data policy controlled by an ignored option, keep it on the original service until you have separately confirmed the required policy.

Chat's usage.cost is the amount charged; Responses and Messages currently omit it. When X-Praxis-Generation-Id is present, use GET /model/v1/generation?id=GENERATION_ID as described in the generation record API. Records may take a few seconds to appear. If the header is absent, check Console → Usage and costs. Neither the response body's id nor X-Request-Id is a substitute for a generation ID. Missing cost does not mean zero cost.

Unsupported operations and alternatives

vendor/model, :nitro, and openrouter/auto are not supported model selectors. There is no automatic mapping. For absent OpenAI endpoints, use the unsupported endpoint table and alternatives. The API reference owns operation and field details; do not assume OpenRouter extensions apply to Responses.

3. Verify one request

First prove the simplest Chat request, with no provider preferences:

unset HTTP_PROXY HTTPS_PROXY ALL_PROXY http_proxy https_proxy all_proxy
uv run -q --no-project --with openai --with anthropic python - <<'PY'
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.deepraxis.com/openai/v1",
    api_key=os.environ["PRAXIS_API_KEY"],
    timeout=90.0,
    max_retries=0,
)
models = client.models.list()
assert "deepseek-flash" in {m.id for m in models.data}
raw = client.chat.completions.with_raw_response.create(
    model="deepseek-flash",
    messages=[{"role": "user", "content": "Reply OK."}],
    max_tokens=1024,
)
reply = raw.parse()
text = reply.choices[0].message.content
print("HTTP", raw.status_code)
print("X-Request-Id:", raw.headers.get("x-request-id"))
print("X-Praxis-Generation-Id:", raw.headers.get("x-praxis-generation-id"))
print(text)
assert raw.status_code == 200 and text and text.strip()
assert raw.headers.get("x-request-id")
PY

Expected: exit code 0, HTTP 200, nonempty text (usually OK.), and an X-Request-Id. Assertions check both model availability and a real reply, not just connectivity. Keep the request ID for troubleshooting, never the key. The example incurs a small usage charge.

Then add back only the options your application needs, one at a time. Expected: each request succeeds and returns the intended model; an ignored field is not proof that a policy was applied.

Failures

Observed errorAction
400 provider_selection_not_allowedRemove provider selection when using platform credentials, or configure BYOK before selecting an upstream
404 with does not existReplace the namespaced ID, suffix, or automatic selector with a catalog ID
404 model_protocol_not_offeredChoose a model offering the requested operation

4. Roll back

Restore https://openrouter.ai/api/v1, the original OPENROUTER_API_KEY, your original model ID, and your saved OpenRouter options. Restart the client and run the original smoke request. Do not send the Praxis key to OpenRouter.

Expected: the original request returns usable text with the intended model. Any calls already charged on Praxis remain charged.

API reference → · Cookbook: OpenAI SDK →

Export

On this page