Migrate from Anthropic Claude
Currency note: Epithre prices in IDR (Rupiah). Competitor prices left in USD for comparison reference.
Anthropic's Messages API uses a different wire format than OpenAI. Migration to Epithre means switching to OpenAI-compat shape. Conceptually 1:1 but requires more code changes than coming from OpenAI.
If you'd prefer minimal code change, you can use Anthropic's official client with our base URL, but the response shape won't match what you're parsing. The cleaner path is to switch to the openai SDK.
High-level model mapping
| Anthropic model | Epithre equivalent | Notes |
|---|---|---|
claude-opus-4-1, claude-opus-4-5 |
epithre-omni (or epithre-prme for very long context) |
Flagship multimodal. |
claude-sonnet-4-5 |
epithre-omni |
Same general tier. |
claude-haiku-4-5 |
epithre-lyt |
Fast, cheap, multimodal. |
claude-3-5-sonnet (deprecated) |
epithre-omni |
|
| Voyage embeddings | epithre-embed |
4000-dim, multimodal. |
| (Anthropic has no rerank model) | epithre-rerank |
Cohere-compat shape. |
| (Anthropic has no image model) | epithre-iris |
Image generation + editing. |
Wire format differences
Messages
Anthropic shape:
{
"model": "claude-sonnet-4-5",
"system": "You are helpful.",
"messages": [
{"role": "user", "content": "Halo"},
{"role": "assistant", "content": [{"type": "text", "text": "..."}]}
],
"max_tokens": 1024
}
Epithre / OpenAI shape:
{
"model": "epithre-omni",
"messages": [
{"role": "system", "content": "You are helpful."},
{"role": "user", "content": "Halo"},
{"role": "assistant", "content": "..."}
],
"max_tokens": 1024
}
Key differences:
- System prompt is part of
messagesin OpenAI shape (withrole: "system"), not a separate top-levelsystemfield. - Assistant content can be a string in OpenAI shape, not always a list of content blocks.
max_tokensis optional in OpenAI shape (model picks a sensible default). It's required in Anthropic.- Stop reasons are called
finish_reason(OpenAI) vsstop_reason(Anthropic), with different vocab ("stop"vs"end_turn","length"vs"max_tokens").
Response shape
Anthropic:
{
"id": "msg_01...",
"type": "message",
"role": "assistant",
"content": [{"type": "text", "text": "..."}],
"model": "claude-sonnet-4-5",
"stop_reason": "end_turn",
"usage": {"input_tokens": 12, "output_tokens": 8}
}
Epithre:
{
"id": "chatcmpl-...",
"object": "chat.completion",
"model": "epithre-omni",
"choices": [{
"index": 0,
"message": {"role": "assistant", "content": "..."},
"finish_reason": "stop"
}],
"usage": {"prompt_tokens": 12, "completion_tokens": 8, "total_tokens": 20}
}
To get the text reply: response.choices[0].message.content (Epithre) vs response.content[0].text (Anthropic).
Tool use
Anthropic's tool use is {"type": "tool_use", ...} and {"type": "tool_result", ...} content blocks. Epithre uses OpenAI's tool_calls field on the assistant message and role: "tool" messages for results. Shape differs but capability is the same.
Anthropic:
{"role": "assistant", "content": [
{"type": "tool_use", "id": "toolu_01", "name": "get_weather", "input": {"city": "Jakarta"}}
]}
{"role": "user", "content": [
{"type": "tool_result", "tool_use_id": "toolu_01", "content": "30C, sunny"}
]}
Epithre:
{"role": "assistant", "content": null, "tool_calls": [
{"id": "call_01", "type": "function",
"function": {"name": "get_weather", "arguments": "{\"city\":\"Jakarta\"}"}}
]}
{"role": "tool", "tool_call_id": "call_01", "content": "30C, sunny"}
See the tool use guide for full patterns.
Vision
Anthropic accepts image content blocks:
{"role": "user", "content": [
{"type": "image", "source": {"type": "base64", "media_type": "image/jpeg", "data": "..."}},
{"type": "text", "text": "What's in this?"}
]}
Epithre uses OpenAI's image_url content block:
{"role": "user", "content": [
{"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,..."}},
{"type": "text", "text": "What's in this?"}
]}
Same model behavior, different field naming.
Prompt caching
This is one of the cleaner migrations: Anthropic and Epithre use identical cache_control markers.
Both:
{"role": "system", "content": [
{"type": "text",
"text": "<long stable system prompt>",
"cache_control": {"type": "ephemeral"}}
]}
Same pricing model too (1.25x write, 0.1x read on input rate). Migration is zero-effort for prompt cache logic.
Extended thinking
Anthropic exposes thinking as a parameter:
{"thinking": {"type": "enabled", "budget_tokens": 16000}}
Epithre uses chat_template_kwargs:
{"chat_template_kwargs": {"enable_thinking": true}}
Both surface the chain in the response (Anthropic as a thinking content block, Epithre prefixed in the message content depending on model). Functional equivalent.
Streaming
Anthropic streams as a sequence of event types: message_start, content_block_start, content_block_delta, content_block_stop, message_stop. Epithre streams as OpenAI's simple data: {choices: [{delta: {...}}]} chunks.
Migration: switch from event-type dispatch to delta accumulation. The OpenAI SDK handles this for you.
# Anthropic stream handler
with anthropic_client.messages.stream(model=..., messages=...) as stream:
for text in stream.text_stream:
print(text, end="")
# Epithre stream handler (using openai SDK)
stream = client.chat.completions.create(
model="epithre-omni",
messages=...,
stream=True,
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")
Pricing comparison
Approximate, 2026-05:
| Workload | Anthropic typical | Epithre |
|---|---|---|
| Sonnet input | $3 / 1M tok | epithre-omni Rp7,000 / 1M tok |
| Sonnet output | $15 / 1M tok | epithre-omni Rp25,000 / 1M tok |
| Haiku input | $0.25 / 1M tok | epithre-lyt Rp1,000 / 1M tok |
| Voyage embed | $0.12 / 1M tok | epithre-embed Rp1,500 / 1M tok |
| Cache write | 1.25x input | Same 1.25x |
| Cache read | 0.1x input | Same 0.1x |
| Batch | 50% off | Same 50% off |
Roughly 80-90% cheaper on chat, equivalent ratio model on prompt cache and batch.
What Anthropic has that Epithre doesn't (yet)
- Computer Use / Tool Use beta: Anthropic's special tool that gives the model "screen" abilities. Not currently planned for Epithre.
- PDFs as direct message attachments: Anthropic accepts PDF bytes directly in messages. Epithre requires you to extract text first via
/v1/fileswithpurpose=knowledge, then use retrieval, OR pass extracted text inline. See retrieval reference. - Fine-tuning (Custom Models): managed enterprise service. Epithre offers similar via email for now; self-serve fine-tuning is on the roadmap.
What Epithre has that Anthropic doesn't
- Self-serve fine-tuning via email, fast turnaround for Indonesian customers.
- Built-in rerank model (
epithre-rerank, Cohere-compat). Anthropic users typically pair Claude with Voyage rerank as a separate vendor. - Image generation + editing (
epithre-iris). Anthropic doesn't offer image generation. - Indonesian-tuned models. Claude is excellent at Indonesian (Anthropic invests in multilingual), but Epithre is purpose-built for Indonesian-first workloads with native register handling.
- Data residency Jakarta. Critical for UU 27/2022 (PDP) compliance.
Working example: migrating a chat agent
# BEFORE (Anthropic)
import anthropic
client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
def chat(history, user_msg):
resp = client.messages.create(
model="claude-sonnet-4-5",
system="You are a helpful Indonesian-speaking assistant.",
messages=history + [{"role": "user", "content": user_msg}],
max_tokens=1024,
)
return resp.content[0].text
# AFTER (Epithre)
from openai import OpenAI
client = OpenAI(
api_key=os.environ["EPITHRE_KEY"],
base_url="https://api.epithre.com/v1",
)
def chat(history, user_msg):
resp = client.chat.completions.create(
model="epithre-omni",
messages=[
{"role": "system", "content": "You are a helpful Indonesian-speaking assistant."},
*history,
{"role": "user", "content": user_msg},
],
max_tokens=1024,
)
return resp.choices[0].message.content
Differences: switch SDK, move system into messages, parse choices[0].message.content instead of content[0].text.
Migration checklist
- [ ] Sign up at platform.epithre.com, verify email.
- [ ] Create production API key.
- [ ] Switch SDK from
anthropictoopenai(or use any HTTP client). - [ ] Move
systemparameter into themessagesarray asrole: "system". - [ ] Update response parsing:
choices[0].message.contentnotcontent[0].text. - [ ] Update streaming handler to OpenAI delta-accumulation pattern.
- [ ] If using tool use: rewrite content blocks as
tool_calls(assistant) androle: "tool"messages (results). - [ ] If using vision: rewrite image content blocks to
{type: "image_url", image_url: {url: "data:..."}}. - [ ]
cache_controlmarkers work without modification. - [ ] Re-embed your Indonesian corpus with
epithre-embedfor native-quality vectors.
Email hello@epithre.com with subject "Anthropic migration" if you hit unexpected differences. We track common gotchas and update this guide as we see them.