# Anthropic-compatible API (/en/docs/developers/model/guides/anthropic-compatible)



Use the Anthropic SDK at `https://api.deepraxis.com/anthropic`. The SDK adds `/v1/messages`; do not append `/v1` to its base URL. Requests are forwarded using the same protocol, subject to the model's declared capabilities.

## What compatibility covers [#what-compatibility-covers]

`/anthropic/v1/models` lists Anthropic-compatible models. Do not assume an ID from another protocol's catalog works here. An undeclared operation returns `404` with `anthropic.messages is not offered for …`; switching the URL does not translate unsupported model capabilities.

## Field differences: where to check [#field-differences-where-to-check]

| Your application uses                                      | Difference to check                                                                                                                                         |
| ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `thinking` and `output_config.effort`                      | Model-dependent reasoning options; some models cannot disable thinking. See [Messages](/en/docs/api/compatible/anthropic/createMessage)                     |
| Cache controls, tools, metadata, beta or workspace headers | [Messages field support](/en/docs/api/compatible/anthropic/createMessage); do not assume every official extension is available                              |
| `count_tokens`                                             | A calibrated estimate, marked by `x-praxis-token-count: estimated`; see [Count tokens](/en/docs/api/compatible/anthropic/countTokens)                       |
| Model limits and capabilities                              | [List models](/en/docs/api/compatible/anthropic/listModels); unknown limits can be `null`                                                                   |
| File uploads and expiration                                | [Upload a file](/en/docs/api/compatible/anthropic/createFile)                                                                                               |
| Costs                                                      | [Messages cost handling](/en/docs/cookbook/migration/from-anthropic#behavior-differences) and [generation records](/en/docs/api/native/model/getGeneration) |

Unknown top-level fields can reach the same-protocol upstream, which decides whether to accept them. Declared fields are validated; a successful response alone does not establish that every option was applied. See the [operation list](/en/docs/api/compatible/anthropic) for support and [migration alternatives](/en/docs/cookbook/migration/from-anthropic#unsupported-operations-and-alternatives) for missing operations.

## 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. Verify Messages and token counting [#2-verify-messages-and-token-counting]

```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 anthropic import Anthropic

client = Anthropic(
    base_url="https://api.deepraxis.com/anthropic",
    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.messages.with_raw_response.create(
    model="deepseek-flash",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Reply OK."}],
)
reply = raw.parse()
text = "".join(block.text for block in reply.content if block.type == "text")
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")
count = client.messages.with_raw_response.count_tokens(
    model="deepseek-flash",
    messages=[{"role": "user", "content": "Reply OK."}],
)
print("count_tokens:", count.parse().input_tokens)
print("X-Request-Id:", count.headers.get("x-request-id"))
print("x-praxis-token-count:", count.headers.get("x-praxis-token-count"))
assert count.status_code == 200
assert count.headers.get("x-praxis-token-count") == "estimated"
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.

Expected: text is extracted from `type == "text"` blocks, even if a thinking block comes first. The second call prints a token estimate and `estimated`; do not use that estimate as billed usage.

If you receive `400` with `cannot disable thinking`, remove the request to disable thinking or choose a model that permits it. For `anthropic.messages is not offered for …`, choose an Anthropic-compatible model offering the operation. To roll back an existing application, restore its original URL, key, model, and thinking options, then rerun the original Messages request.

[API reference →](/en/docs/api/compatible/anthropic) · [Cookbook: migrate from Anthropic →](/en/docs/cookbook/migration/from-anthropic)
