# Migrating from OpenAI (/en/docs/cookbook/migration/from-openai)



Keep the OpenAI SDK and migrate one Chat Completions request by changing the base URL, key, and model ID. This changes the model producing the answer; it does not make DeepSeek behave like GPT-4o.

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

## 1. Prepare [#1-prepare]

You need Python 3.10+, [uv](https://docs.astral.sh/uv/getting-started/installation/), and a Praxis key. Create one in [Console → API Keys](https://console.deepraxis.ai/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.

```bash
test -n "${PRAXIS_API_KEY:-}"
```

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

## 2. Choose a model ID [#2-choose-a-model-id]

These are migration choices, not aliases or promises of equivalent quality. Availability was checked on October 12, 2026; confirm it in the [model catalog](https://console.deepraxis.ai/models) before switching traffic.

| Existing ID                        | Praxis choice                       | What changes                                                                 |
| ---------------------------------- | ----------------------------------- | ---------------------------------------------------------------------------- |
| `gpt-4o`, `gpt-4o-mini`            | `deepseek-flash`                    | These original IDs do not exist; reassess prompts, tools, and output quality |
| `gpt-4.1`, `o3-mini`, `gpt-5`      | `deepseek-flash`                    | No automatic mapping; the original IDs return 404                            |
| An OpenAI-family model is required | `gpt-5.6-sol`                       | Chat Completions is available; Responses is not                              |
| Existing Responses code            | `deepseek-flash` or `glm-5.3-flash` | These are the currently available Responses choices                          |

For Responses, check that your selected ID appears in `GET /openai/v1/models?api=responses` (Python: `client.models.list(extra_query={"api": "responses"})`). Alternatively, inspect `supported_apis` in `GET /model/v1/models` or `GET /model/v1/models/{id}` and confirm it includes `openai.responses`. Other OpenAI filters are `chat`, `embeddings`, `images`, `audio`, and `videos`; comma-separated values match any selected API.

## Behavior differences [#behavior-differences]

* A protocol-compatible request keeps its protocol when forwarded. This does not guarantee every official model, endpoint, or field is available.
* A listed model can still reject a particular operation with `404 model_protocol_not_offered`. Keep Chat and Responses capability checks separate.
* Recheck streaming, tool execution, structured output, and reasoning on your own prompts before shifting traffic. Field differences live in [Chat Completions](/en/docs/api/compatible/openai/createChatCompletion) and [Responses](/en/docs/api/compatible/openai/createResponse).
* Files, conversations, and response IDs from the original service do not move with a URL change. Retain source data and rebuild the resources your application needs.
* 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](/en/docs/api/native/model/getGeneration). Records may take a few seconds to appear. If the header is absent, check [Console → Usage and costs](https://console.deepraxis.ai/usage). 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 endpoints and alternatives [#unsupported-endpoints-and-alternatives]

Paths below are relative to `/openai/v1` and return 404. Alternatives are not equivalent replacements. If your application depends on these operations, split the calls and keep the original service.

| Original endpoint    | Migration option                                                                 |
| -------------------- | -------------------------------------------------------------------------------- |
| `moderations`        | No direct replacement; keep your moderation service                              |
| `batches`            | Send individual requests with application-controlled concurrency                 |
| `fine_tuning`        | Choose an existing model; retain your fine-tuning workflow                       |
| `assistants`         | Rebuild with Responses / Conversations and an application tool loop              |
| `completions`        | Use `chat/completions` with `messages`                                           |
| `audio/translations` | Transcribe first, then translate through chat                                    |
| `uploads`            | Use `files`; check size and purpose limits                                       |
| `images/variations`  | Submit the image and editing instructions to `images/edits`; evaluate the result |

Available endpoints include `chat/completions`, `responses`, `embeddings`, `images/generations`, `images/edits`, `audio/speech`, `audio/transcriptions`, `videos`, `files`, and `models`. Endpoint availability does not mean every model supports that capability. See the [OpenAI API reference](/en/docs/api/compatible/openai) for individual operations and limits.

## 3. Verify one request [#3-verify-one-request]

Run this complete example after setting `PRAXIS_API_KEY`:

```bash
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(extra_query={"api": "chat"})
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.

## Failures [#failures]

| Observed error                              | Action                                                                                                    |
| ------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `404` with `Model "gpt-4o" does not exist.` | Change the model as well as the URL and key; use the exact catalog ID                                     |
| `404 model_protocol_not_offered`            | Use a model that offers the requested operation; for Responses choose `deepseek-flash` or `glm-5.3-flash` |
| `404 Not Found` on an endpoint above        | Use its alternative or leave that request on the original service                                         |

## 4. Roll back [#4-roll-back]

Restore all three original values: `https://api.openai.com/v1`, the key from `OPENAI_API_KEY`, and your original model ID. Remove Praxis-only request fields and restore original resource IDs. Restart the application so its client uses the restored configuration, then run your original smoke test. Keep its request ID.

Expected: the original endpoint returns a successful response with usable text. Rolling back configuration does not refund calls already made or copy conversation state between services.

[API reference →](/en/docs/api/compatible/openai) · [Compatibility guide →](/en/docs/developers/model/guides/openai-compatible)
