Migrating from the OpenAI API to the Claude API
The request shape is close enough to migrate in an afternoon — and different enough that a blind cutover breaks in three predictable places: the system message, the required token limit, and tool calling.
https://aicomp.ai/v1).
Create one free →
Side-by-side request
OpenAI style:
resp = client.chat.completions.create(
model="gpt-5.6-luna",
messages=[
{"role": "system", "content": "You are a careful editor."},
{"role": "user", "content": "Proofread this."},
],
)
Claude style:
resp = client.messages.create(
model="claude-sonnet-5",
system="You are a careful editor.", # top-level, not a message
max_tokens=1024, # required
messages=[{"role": "user", "content": "Proofread this."}],
)
print(resp.content[0].text)
The mapping table
| Concept | OpenAI | Claude |
|---|---|---|
| System prompt | {"role":"system"} inside messages | Top-level system parameter |
| Token limit | max_tokens, optional | max_tokens, required |
| Text output | choices[0].message.content | content[0].text |
| Input usage | prompt_tokens | input_tokens |
| Output usage | completion_tokens | output_tokens |
| Stop sequences | stop | stop_sequences |
| Tool calling | functions / tools | tools with input_schema |
| JSON mode | response_format | Prefill or tool-based extraction |
| Auth header | Authorization: Bearer | x-api-key + anthropic-version |
Tool calling: the part that needs real rewriting
OpenAI puts arguments in function.arguments as a JSON string. Claude returns a tool_use content block with an already-parsed input object, and you return results as a tool_result block rather than a message with a role. Budget most of your migration time here.
tools = [{
"name": "get_weather",
"description": "Current weather for a city",
"input_schema": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
}]
What it costs after you move
| Model | Gateway rate in / out per 1M tokens | Official list in / out per 1M tokens | Diff |
|---|---|---|---|
| gpt-5.6-luna | $0.1 / $0.6 | $0.2 / $1.2 | 50% |
| claude-sonnet-5 | $1 / $5 | $2 / $10 | 50% |
| claude-opus-5 | $2.5 / $12.5 | $5 / $25 | 50% |
Rates checked 2026-09-16. Gateway rates move with upstream promotions — verify the current number in your dashboard before committing to a budget.
Do not assume the migration saves money. Compare tokens per task on real traffic, not list price per million — models differ in how verbose they are, and output is the expensive side.
A cutover plan that does not hurt
- Shadow mode. Send the same prompts to both, store both outputs, ship the OpenAI one.
- Diff quality. Review where they disagree; those are your risk areas.
- Route 10%. Real traffic, real latency, real cost.
- Compare cost per task. Not per token — per completed task.
- Ramp. Increase only after a week of clean metrics.
Common errors during migration
| Error | Cause |
|---|---|
| max_tokens is required | Claude requires it; OpenAI made it optional |
| Invalid system message position | System prompt left inside messages |
| 401 / authentication_error | Using Authorization: Bearer instead of x-api-key |
| Tools ignored | Schema passed as parameters rather than input_schema |
FAQ
Can I reuse my OpenAI code with Claude?
Partly. If you went through an OpenAI-compatible layer, changing the base URL and key may be enough. If you called the OpenAI API directly, you need the changes in the mapping table above — mostly the system field, max_tokens, and tool calling.
What is the biggest gotcha in the migration?
max_tokens is required on Claude and optional on OpenAI. Requests that worked for months will fail with a validation error until you set it.
Does the response format change?
Yes. Instead of choices[0].message.content you read content[0].text, and usage is reported as input_tokens and output_tokens rather than prompt_tokens and completion_tokens.
How do I keep costs under control during migration?
Run both in parallel on a sample first, measure tokens per task on each, then cut over. Migrating blind is how teams double their bill on day one.
Can I migrate gradually?
Yes, and you should. Route a percentage of traffic, compare quality and cost for a week, then increase. The per-task cost difference is usually visible within a day of real traffic.