# Move from the Anthropic API

The exchange serves `POST /v1/messages` in the Anthropic format. The official clients work with a new base URL and a new key. Server tools and the batch and file endpoints need more work. For setup, see [Anthropic SDK](https://inference.ai.exchange/docs/connect-anthropic-sdk.md) and [Claude Code](https://inference.ai.exchange/docs/connect-claude-code.md).

## Change these three things

1. Issue a `spend` key on the **API keys** page. See [API keys](https://inference.ai.exchange/docs/keys.md).
2. Set the base URL to `https://router.inference.ai.exchange`, with no `/v1`. The client adds `/v1/messages`, so a URL that ends in `/v1` gets a 404.
3. Change each `model` to a name that `GET /v1/anthropic/models` lists. See [Model names](#model-names).

Then check these:

- Keep `max_tokens` in each request. The exchange requires it.
- Remove each server tool. See [Anthropic features](#anthropic-features).
- Run a [dry run](https://inference.ai.exchange/docs/move-from-openrouter.md#check-a-request-without-a-purchase).
- Read [What is different about money](https://inference.ai.exchange/docs/move-from-openrouter.md#what-is-different-about-money). The exchange never lowers `max_tokens` to fit your balance or cap.

## What differs

- **Model names.** The exchange does not forward a Claude name to one provider. An unknown name returns `404 model_not_found`.
- **Server tools.** `web_search_*`, `web_fetch`, `code_execution` and other hosted tools return `400 unsupported_parameter`. To search the web, add `:web` (beta) to the model name.
- **Documents.** A `document` block must have a `base64` source. A `url` source returns `400 unsupported_content`.
- **Not available.** The Message Batches API and the Files API.

## Example

An Anthropic request, then the same request for the exchange. The new request changes the client and model, removes the refused `web_search` tool and adds a cap. The model name is an illustration.

```python
import anthropic

client = anthropic.Anthropic()

message = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    system="Answer in one sentence.",
    messages=[{"role": "user", "content": "What is new in Rust?"}],
    tools=[{"type": "web_search_20260209", "name": "web_search"}],
    metadata={"user_id": "user-123"},
)
```

```python
import os
import anthropic

client = anthropic.Anthropic(
    base_url="https://router.inference.ai.exchange",
    api_key=os.environ["LIQUID_API_KEY"],
)

message = client.messages.create(
    model="liquid.auto",
    max_tokens=1024,
    system="Answer in one sentence.",
    messages=[{"role": "user", "content": "What is new in Rust?"}],
    metadata={"user_id": "user-123"},
    extra_body={"exchange": {"cap_usd": 0.05}},
)
```

## Reference

### Settings that change

- Both `x-api-key` and `Authorization: Bearer` work with an exchange key, `sk-liquid-…`.
- `anthropic-version` is accepted and not required. On `GET /v1/models`, it selects the Anthropic format.
- `anthropic-beta` is accepted and not read.
- `max_tokens` is required. The exchange can lower it to the limit of the offers that can take the job. See [Output limits](https://inference.ai.exchange/docs/errors.md#output-limits).

### Model names

Send a name that `GET /v1/anthropic/models` returns, a router model, a basket or a preset. See [Connect an app](https://inference.ai.exchange/docs/connect-overview.md). An unknown name returns `404 model_not_found`. The exchange never uses a different model. Send the `exchange` object in the body. See [Purchasing rules](https://inference.ai.exchange/docs/rules.md).

### Anthropic features

| Anthropic feature                                               | What the exchange does                                                                                                                                                           |
| --------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `system` (a string or a list of blocks)                         | Applied. It becomes the first message.                                                                                                                                           |
| `stream`                                                        | Applied, in the Anthropic event format. The final event has the `exchange` block.                                                                                                |
| `stop_sequences`, `temperature`                                 | Applied. An offer must support `stop_sequences` to compete.                                                                                                                      |
| `top_p`, `top_k`                                                | Passed to a provider that declares support. If no offer supports it, `unsupported_parameter`.                                                                                    |
| `metadata.user_id`                                              | Names the end user for the limits of a [guardrail](https://inference.ai.exchange/docs/guardrails.md#end-users).                                                                                                   |
| `service_tier`, `container`, any parameter not in this table    | Ignored or accepted and not sent. To label spend, send `x-liquid-tag`. See [Cost tags](https://inference.ai.exchange/docs/rules.md#cost-tags).                                                                    |
| `tools` with an `input_schema`, and `tool_choice`               | Applied. Types `auto`, `any`, `tool` and `none` work. `disable_parallel_tool_use` is not read. Only an offer that declares tool support can win.                                 |
| Typed client tools `bash`, `text_editor`, `computer`, `memory`  | Applied as functions. Your client runs the tool. A tool with no `input_schema` gets an empty object schema, so declare your own.                                                 |
| Server tool `web_search_*`                                      | `400 unsupported_parameter`, `param` such as `tools[0]`. Add `:web` (beta) to the model name instead. See [Quickstart](https://inference.ai.exchange/docs/quickstart.md#web-access).                              |
| Other typed tools: `web_fetch`, `code_execution`, `tool_search` | `400 unsupported_parameter`. The exchange runs no hosted tool. Run the work in your own code.                                                                                    |
| `thinking` with `budget_tokens`                                 | Applied as a reasoning budget. Only an offer that supports a budget can win. `max_tokens` is never lowered to or below the budget. Thinking blocks come back only when it is on. |
| `output_config.effort` and `output_config.format`               | Applied: a reasoning level, and a `json_schema` that the answer must follow. Other keys are accepted and not sent.                                                               |
| `cache_control` on a block, and at the top level                | Applied. See [Prompt caching](https://inference.ai.exchange/docs/caching.md).                                                                                                                                     |
| `image` blocks                                                  | Applied to offers that declare image input. The source can be `base64` or a `url`. See [Modalities](https://inference.ai.exchange/docs/modalities.md).                                                            |
| `document` blocks                                               | Applied to offers that declare file input. The source must be `base64`, because the exchange measures the file before it sets the cap.                                           |
| Any other content block in a user turn                          | `400 unsupported_content`. The message names the block.                                                                                                                          |
| `POST /v1/messages/count_tokens`                                | An estimate from the exchange, not a provider tokenizer. It counts the text of `system` and `messages`, not tools, images or documents.                                          |
| Message Batches API, Files API                                  | Not available. Send each request alone, and send a document as `base64`.                                                                                                         |

### Troubleshooting

For `402 insufficient_balance` and `400 no_eligible_offer`, see [What is different about money](https://inference.ai.exchange/docs/move-from-openrouter.md#what-is-different-about-money). `error.type` follows the HTTP status. Match on `code`.

| Error                                                             | Cause                                                              | Fix                                                                          |
| ----------------------------------------------------------------- | ------------------------------------------------------------------ | ---------------------------------------------------------------------------- |
| `404` for `/v1/v1/messages`                                       | The base URL ends in `/v1`.                                        | Remove `/v1`.                                                                |
| `401 authentication_error`                                        | The key is wrong, revoked or expired.                              | Send a current key in `x-api-key`. See [API keys](https://inference.ai.exchange/docs/keys.md).                |
| `404 not_found_error`, `code` is `model_not_found`                | The `model` is not on the exchange.                                | Pick a name from `GET /v1/anthropic/models`.                                 |
| `400`, `code` is `unsupported_parameter`, `param` is `tools[...]` | The request has a hosted tool.                                     | Remove the tool.                                                             |
| `400`, `code` is `unsupported_content`                            | A block type is unknown, or a `document` has a `url` source.       | Send the document as `base64`, or remove the block.                          |
| `stop_reason` is `max_tokens` and the answer has no text          | A model that thinks by default used the output limit for thinking. | Send a larger `max_tokens`.                                                  |
| `503 overloaded_error`                                            | The awarded provider failed, or no seller can serve the model now. | Try again later, or select another model. See [Errors](https://inference.ai.exchange/docs/errors.md#auction). |
