Ragmux

Integrations

Using Claude through an OpenAI-compatible gateway

Point an existing OpenAI-SDK app at Claude through Ragmux — no Anthropic SDK, and the message, tool and image translation Ragmux does for you.

Updated: Verified against Ragmux 0.5.0

Claude is reached through Ragmux the same way every other provider is: your application keeps calling /v1/chat/completions in the OpenAI schema, and the gateway is the part that actually speaks Anthropic’s Messages API on the other side. That matters if you already have OpenAI-SDK code, a framework that only knows the OpenAI shape, or several providers behind one integration and no appetite for a second SDK just for one of them.

Adding the connection

POST /admin/api/models with provider_type: anthropic, an api_key, and a model_name such as claude-sonnet-4-5 creates the connection; base_url doesn’t need to be set — it defaults to https://api.anthropic.com, but can be pointed elsewhere if you front Anthropic with your own proxy — one on a private or local network still has to be allowlisted first, the same as any other connection (see Private upstreams). Once saved, the key is never returned by the API again — every later read shows api_key_masked instead, and rotating it means setting a new key on the same connection, not reading the old one back out. Before pointing a real project at it, POST /admin/api/models/{id}/test with {"mode": "chat"} sends one bounded completion — max_tokens: 256 — and returns latency and a sample reply, which is the cheap way to catch a bad key or a mistyped model name before a user does.

What the gateway translates for you

An OpenAI-shaped request doesn’t map onto Anthropic’s Messages API field-for-field, and this is the actual value a gateway adds over calling Claude directly with hand-rolled translation code:

  • System and developer messages become one field. OpenAI’s system and developer roles are merged, in order, into the single top-level system field Anthropic’s API expects, sent as text blocks — Claude has no system role inside the message array itself.
  • max_tokens is required, so Ragmux makes sure it’s always there. Anthropic rejects a request with no max_tokens; a caller that never set one (normal for OpenAI, where it’s optional) gets 4096 filled in rather than a provider error surfaced back.
  • Sampling parameters map directly. temperature, top_p and stop carry across; n, response_format and user have no Anthropic equivalent and are dropped rather than silently misapplied. A dropped response_format is the one that announces itself: the response carries a Warning: 299 ragmux "response_format is not supported for anthropic connections; ignored" header, streams included, and the event is logged at info level.
  • Consecutive same-role messages are merged. Anthropic’s API expects strict user/assistant alternation; a caller that appends two user messages back to back before ever seeing an assistant reply has them combined into one, rather than the request failing on Anthropic’s side for a shape the caller didn’t know was invalid there.
  • Tool calls translate both ways. OpenAI-shaped tools and tool_choice become Anthropic’s tools/tool_choice, and a Claude tool_use block comes back as an OpenAI-shaped tool_calls entry, so function-calling code written against OpenAI’s shape doesn’t need a Claude-specific branch.
  • Image URLs are handled the way Claude expects. Anthropic fetches an image URL itself rather than requiring the caller to inline it, so Ragmux passes the URL through as given.
  • Finish reasons map to OpenAI’s vocabulary. Claude’s own stop reasons come back as values OpenAI-SDK code already branches on: end_turn and stop_sequence become stop; max_tokens and model_context_window_exceeded become length; tool_use becomes tool_calls; refusal becomes content_filter. A stop reason Ragmux doesn’t know becomes stop and is logged as a warning.

None of this is configurable per request; it’s the fixed translation every Anthropic connection gets, streaming and non-streaming alike, so the same client code that works against a streamed OpenAI response works against a streamed Claude one too.

What doesn’t carry over

A couple of things are worth knowing before they show up as a surprise rather than a documented gap. Claude has no embeddings endpoint at all, so an Anthropic connection can only ever back the chat half of a project — a private document Q&A setup that wants Claude to answer still needs a separate openai, gemini, ollama or custom_openai connection for the embedding half of the same RAG store. And a handful of OpenAI-only parameters — response_format, n, user — are dropped rather than emulated. For response_format the response says so in a Warning: 299 header; a caller relying on OpenAI’s structured-output mode against a Claude connection needs to ask for the shape in the prompt itself, because there’s no equivalent flag to forward.

Prompt caching works, but you have to ask for it

Claude bills cache writes as well as cache reads, and Ragmux relays a client’s cache_control marker verbatim rather than inventing one on your behalf. Put "cache_control": {"type": "ephemeral"} on a content part, a tool definition, or a system/developer message’s content, and it’s copied onto the matching block Anthropic’s API expects; leave it off, and a request against a Claude connection looks exactly like it did before caching existed. The response accounting folds Anthropic’s own cache_creation_input_tokens and cache_read_input_tokens into the OpenAI-shaped usage.prompt_tokens_details object: reads become cached_tokens, the field OpenAI, Gemini and DeepSeek connections populate too — custom_openai and ollama don’t report cache usage at all (see the capability table) — while cache_creation_tokens is Anthropic-specific: OpenAI doesn’t bill cache writes and Gemini doesn’t report a separate write counter, so there’s nothing to report on those connections. Both feed the per-request cost estimate when present. One gap worth knowing: the gateway doesn’t mark a cache breakpoint on the system prompt or RAG context block it injects itself — that’s a client-side decision today, not something a Claude connection does automatically.

After it’s connected

Everything else about the project is identical to any other provider: rate limits, token budgets, the audit log and the request log all key off the project, not the provider behind it, so tracking what a Claude-backed project actually spent works the same way it would for GPT or Gemini. Swapping the model later — moving to a newer Claude release, or to a different provider entirely — means updating the connection or the project’s model_connection_id, not touching the application code that calls /v1/chat/completions.

Full reference: /docs/providers/#anthropic.

Connect Claude to Ragmux

  1. Add an Anthropic model connection

    POST /admin/api/models with provider_type: anthropic, an api_key, and a model_name such as claude-sonnet-4-5. base_url doesn't need to be set — it defaults to https://api.anthropic.com, but can be pointed elsewhere if you front Anthropic with your own proxy, provided that proxy isn't on a private or local network without first being allowlisted.

  2. Test it before wiring it into a project

    POST /admin/api/models/{id}/test with {"mode": "chat"} sends one bounded completion (max_tokens 256) and returns latency and a sample reply, so a bad key or model name fails here, not in front of a user.

  3. Attach the connection to a project

    POST /admin/api/projects with model_connection_id set to the Anthropic connection. The project's sk-proj-… key is shown exactly once — save it.

  4. Call /v1/chat/completions exactly as you would against OpenAI

    Point the OpenAI SDK's base_url at your Ragmux instance and its api_key at the project key. The gateway translates the request to Anthropic's Messages API and translates the response back before your code ever sees it.

Frequently asked questions

Do I need the Anthropic SDK to call Claude through Ragmux?
No — a project backed by an Anthropic connection is still called through Ragmux's own /v1/chat/completions endpoint, so the standard OpenAI SDK, in any language, works unchanged; Ragmux is what speaks Anthropic's Messages API on the other side.
What happens if my request doesn't set max_tokens?
Anthropic's API rejects a request with no max_tokens, so Ragmux fills in 4096 whenever a caller omits it, rather than passing the omission through and getting a provider-side error back.
Can I use response_format: json_object with a Claude connection?
Not as a constraint — response_format has no Anthropic equivalent, so the request is still answered but the field is ignored, and the response carries a Warning: 299 header saying so (the event is also logged at info level). A caller relying on OpenAI's JSON mode needs to ask for JSON in the prompt itself when the connection is Anthropic.
Does Claude support embeddings through Ragmux?
No — Anthropic has no embeddings API, so an anthropic connection can back a project's chat model but never a RAG store's embedding model; pair it with an openai, gemini, ollama or custom_openai connection for that half.
How does Ragmux handle a system prompt when calling Claude?
OpenAI-style system and developer messages are merged, in the order they appeared, into the single top-level system field Anthropic's Messages API expects (sent as text blocks), rather than being sent as a message in the array.

Arrow keys to move, Enter to open.