Can You Point the Anthropic SDK at the Aggregator, or Do You Need a Shim?
Compare using the Anthropic SDK directly versus an OpenAI-compatible aggregator to call Claude models. For teams already using the Anthropic client, we show a thin translation shim that maps requests and responses, preserving existing code while adding multi-model flexibility and USDC payments.
Overview
If you're already using the Anthropic SDK, you might wonder whether you can point it at an aggregator's endpoint to call Claude models. The short answer: not without a translation layer. The Anthropic SDK expects Anthropic's native API format, while the aggregator exposes an OpenAI-compatible interface. In this article, we compare both approaches and show how to build a thin shim to bridge the gap.
Native Anthropic SDK
The Anthropic SDK is designed to communicate with Anthropic's API using their proprietary request and response structures. Key characteristics:
- Endpoint: Typically
https://api.anthropic.com/v1/messages - Authentication: Uses an
x-api-keyheader with an Anthropic API key. - Request body: Includes fields like
model,max_tokens,messages,system, andtemperature. Themessagesarray usesrole(e.g.,user,assistant) andcontent. - Response: Returns an object with
content(an array of text blocks),stop_reason, andusage.
This format is specific to Anthropic and is not compatible with OpenAI-style APIs.
Aggregator's OpenAI-Compatible Route
Aggregators often provide an OpenAI-compatible API to allow developers to use existing OpenAI SDKs and tools. For Claude models, the aggregator translates Claude's native format to OpenAI's format. Key points:
- Endpoint: Typically
https://api.aggregator.com/v1/chat/completions - Authentication: Uses an API key via
Authorization: Bearer <key>. - Request body: Follows OpenAI's chat completion format, with
model,messages(each withroleandcontent), and parameters liketemperatureandmax_tokens. - Response: OpenAI-style
choicesarray withmessage.content.
Since the aggregator supports multiple models (Claude, GPT, DeepSeek, Qwen, GLM, Kimi) under one API key, using this route simplifies multi-model access.
Why the Anthropic SDK Doesn't Work Out-of-the-Box
The Anthropic SDK is hardcoded to send requests in Anthropic's format and parse Anthropic's responses. Pointing it at an OpenAI-compatible endpoint would result in errors because:
- The request body structure differs (e.g.,
systemas a top-level parameter vs. a system message in themessagesarray). - The authentication header differs (
x-api-keyvs.Authorization: Bearer). - The response schema is incompatible (
contentblocks vs.choices).
Thus, you need a translation layer (shim) to convert between the two formats.
Building a Thin Translation Shim
A shim intercepts calls from the Anthropic SDK, transforms them to OpenAI format, sends them to the aggregator, and converts the response back to Anthropic format. Here's a conceptual implementation in Python:
from anthropic import Anthropic
import requests
class AggregatorClient:
def __init__(self, api_key, base_url):
self.api_key = api_key
self.base_url = base_url
self.anthropic = Anthropic(api_key="dummy") # Not used directly
def messages_create(self, **kwargs):
# Convert Anthropic request to OpenAI format
openai_payload = {
"model": kwargs["model"],
"max_tokens": kwargs.get("max_tokens"),
"temperature": kwargs.get("temperature"),
"messages": []
}
if "system" in kwargs:
openai_payload["messages"].append({"role": "system", "content": kwargs["system"]})
for msg in kwargs["messages"]:
openai_payload["messages"].append({
"role": msg["role"],
"content": msg["content"]
})
# Send to aggregator
headers = {"Authorization": f"Bearer {self.api_key}"}
response = requests.post(
f"{self.base_url}/v1/chat/completions",
json=openai_payload,
headers=headers
)
response.raise_for_status()
openai_resp = response.json()
# Convert back to Anthropic format
anthropic_resp = {
"id": openai_resp["id"],
"type": "message",
"role": "assistant",
"content": [{"type": "text", "text": openai_resp["choices"][0]["message"]["content"]}],
"model": openai_resp["model"],
"stop_reason": openai_resp["choices"][0].get("finish_reason"),
"usage": {
"input_tokens": openai_resp["usage"]["prompt_tokens"],
"output_tokens": openai_resp["usage"]["completion_tokens"]
}
}
return anthropic_resp
# Usage
client = AggregatorClient(api_key="your_aggregator_key", base_url="https://api.aggregator.com")
response = client.messages_create(
model="claude-3-opus-20240229",
max_tokens=1000,
messages=[{"role": "user", "content": "Hello, Claude!"}]
)
print(response["content"][0]["text"])
This shim allows you to keep using the Anthropic SDK's interface while routing through the aggregator. Note that it's a simplified example; production use should handle errors, streaming, and other parameters.
When to Use Each Approach
- Direct Anthropic SDK: Best if you only use Claude models, need the latest features immediately, and don't mind managing separate API keys.
- Aggregator with Shim: Ideal if you want to access multiple models (Claude, GPT, DeepSeek, etc.) with one API key, pay with USDC, and avoid KYC. The shim lets you reuse existing Anthropic-based code.
Payment and Cost Considerations
With the aggregator, you top up using USDC on Base without KYC. You pay the official price multiplied by 1.3. If you contribute keys, you're credited the official price multiplied by 1.1 (or 1.2 for premium) in USDC. This model can be beneficial for teams wanting to consolidate billing and access multiple models.
Conclusion
While you can't point the Anthropic SDK directly at an aggregator's OpenAI-compatible endpoint, a thin translation shim makes it possible with minimal changes. This approach combines the familiarity of the Anthropic SDK with the flexibility and payment benefits of the aggregator.