> ## Documentation Index
> Fetch the complete documentation index at: https://docs.compute.prentis.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrating from OpenAI or Anthropic

> Two lines of config, and the short list of parameters that behave differently.

export const origin = 'https://compute.prentis.ai';

export const baseUrl = 'https://compute.prentis.ai/v1';

Both clients work. Which endpoint you use is a question of which SDK you already have, not
which models you can reach — they reach the same ones.

## From an OpenAI client

Two lines:

```python theme={null}
client = OpenAI(
    base_url="https://compute.prentis.ai/v1",   # was https://api.openai.com/v1
    api_key=os.environ["PRENTIS_API_KEY"],      # was your OpenAI key
)
```

`/v1/chat/completions`, `/v1/completions`, `/v1/models` and `/v1/models/{model}` all
behave as the SDK expects. The model name is the one thing that must change — ours are not
OpenAI's. See [Models and resource names](/models-and-resource-names).

## From an Anthropic client

Give the SDK the **origin**, not the `/v1` base — it appends `/v1/messages` itself:

```python theme={null}
client = anthropic.Anthropic(
    base_url="https://compute.prentis.ai",
    api_key=os.environ["PRENTIS_API_KEY"],
)
```

`x-api-key` is accepted, so the SDK's auth code is untouched. Claude Code works by
changing `base_url` alone.

Two differences from Anthropic's own API:

* **No `claude-*` aliasing.** Model names stay ours.
* **`max_tokens` is optional.** Anthropic requires it; here, omitting it falls back to the
  model's default rather than failing the call.

## Ignored, or rejected

A parameter this API does not implement is **ignored**, not rejected — your existing
request bodies will not start failing because they carry something extra.

The exceptions are the handful that would change the answer if ignored. Those return
`INVALID_REQUEST`:

| Parameter                     | Accepted value |
| ----------------------------- | -------------- |
| `n`                           | `1` only       |
| `logprobs`                    | `false` only   |
| `best_of`, `echo`, `suffix`   | not supported  |
| `output_config`, `raw_output` | not supported  |

<Note>
  The reasoning is the same one behind [tool calling](/tool-calling) and
  [structured outputs](/structured-outputs): silently ignoring a parameter that changes the
  shape of the answer produces a response that looks right and is not. An error you cannot
  miss is the better failure.
</Note>

A few more are accepted and then deliberately dropped — `top_k` on `/v1/messages` is
accepted so Anthropic clients do not break, and not passed to the model. The per-parameter
truth is on each endpoint page in the [API reference](/api-reference/introduction).

## What to check after switching

<CardGroup cols={2}>
  <Card title="Model names" icon="boxes" href="/models-and-resource-names">
    The only change that is not configuration. Look them up rather than translating.
  </Card>

  <Card title="Retry logic" icon="rotate" href="/reliability">
    Branch on `error.code`, not on the status — three codes share `429` and one never
    succeeds.
  </Card>

  <Card title="Usage parsing" icon="calculator" href="/usage-and-billing">
    Streaming carries `usage` on the last event without `include_usage`.
  </Card>

  <Card title="Provider assumptions" icon="route" href="/routing-and-providers">
    Nothing in a response names who served it. Code that branched on that has nothing to
    branch on.
  </Card>
</CardGroup>
