Protocol Conversion Guide
RouteAPI, as a unified API gateway, automatically handles conversions between different protocol formats internally. When you call a Claude model using the OpenAI protocol, or call a Gemini model using the Claude Messages protocol, RouteAPI handles the differences in message structure, parameter mapping, and response format, so you don’t need to worry about underlying protocol details.
Conversion Mechanism Overview
Section titled “Conversion Mechanism Overview”RouteAPI as Protocol Adapter Layer
Section titled “RouteAPI as Protocol Adapter Layer”RouteAPI supports three mainstream protocol entry points:
- OpenAI-compatible protocol:
/v1/chat/completions,/v1/responses - Claude Messages protocol:
/v1/messages - Google Gemini protocol:
/v1beta/models/{model}:generateContent
When a request arrives, RouteAPI identifies the protocol type based on the path, determines the target upstream based on the model ID, and then performs necessary format conversions between them.
When Conversion is Needed
Section titled “When Conversion is Needed”| Scenario | Conversion? | Description |
|---|---|---|
| OpenAI protocol → OpenAI models | No | Pass-through |
| Claude Messages → Claude models | No | Pass-through |
| OpenAI protocol → Claude models | Yes | OpenAI → Claude Messages |
| OpenAI protocol → Gemini models | Yes | OpenAI → Gemini contents |
| Claude Messages → OpenAI models | Yes | Claude Messages → OpenAI |
| Claude Messages → Gemini models | Yes | Claude Messages → Gemini |
Conversion Transparency
Section titled “Conversion Transparency”Protocol conversion is transparent to clients. You send an OpenAI-format request and receive an OpenAI-format response, even if Claude or Gemini is called underneath.
However, conversion has limitations:
- Parameters not supported by the target protocol will be ignored or use default values.
- Some protocol-specific capabilities (like Claude’s extended thinking, prompt caching) may not be fully expressible after conversion.
- Conversion introduces slight latency (typically under 10ms).
Best Practice: Prioritize using the protocol natively supported by the target model for the most complete feature support and best performance.
Message Format Conversion
Section titled “Message Format Conversion”OpenAI messages ↔ Claude messages
Section titled “OpenAI messages ↔ Claude messages”system prompt Handling Differences
Section titled “system prompt Handling Differences”OpenAI places the system prompt as the first message in the messages array:
{ "messages": [ { "role": "system", "content": "You are a rigorous technical assistant." }, { "role": "user", "content": "Explain what an API gateway is" } ]}Claude places the system prompt in a top-level independent field:
{ "system": "You are a rigorous technical assistant.", "messages": [ { "role": "user", "content": "Explain what an API gateway is" } ]}Conversion Rules:
- OpenAI → Claude: Extract the first
role: "system"message and move it to thesystemfield. - Claude → OpenAI: Convert the
systemfield content to arole: "system"message and insert it at the beginning of themessagesarray.
role Mapping
Section titled “role Mapping”| OpenAI | Claude | Gemini | Description |
|---|---|---|---|
system | Top-level system field | systemInstruction | System prompt location differs |
user | user | user | User message, consistent |
assistant | assistant | model | Assistant/model reply, different names |
tool | tool_result within user | functionResponse within user | Tool result attribution differs |
Conversion Considerations:
- Claude doesn’t accept two consecutive messages with the same role; conversion requires merging or inserting placeholder messages.
- Gemini’s
modelrole is mapped toassistantwhen converting to OpenAI. - OpenAI’s
role: "tool"is merged intousermessages in both Claude and Gemini.
OpenAI messages ↔ Gemini contents
Section titled “OpenAI messages ↔ Gemini contents”Gemini’s message structure is called contents, with each message’s role called role and content in a parts array:
{ "contents": [ { "role": "user", "parts": [{ "text": "Explain what an API gateway is" }] } ]}Conversion Rules:
- OpenAI
messages↔ Geminicontents - OpenAI
content↔ Geminiparts - OpenAI
assistant↔ Geminimodel - system prompt converts to top-level
systemInstructionfield
Parameter Mapping Table
Section titled “Parameter Mapping Table”Sampling Parameters
Section titled “Sampling Parameters”| OpenAI | Claude | Gemini | Description |
|---|---|---|---|
temperature | temperature | temperature | Claude max 1, OpenAI max 2, Gemini max 2 |
top_p | top_p | topP | nucleus sampling, all three support |
| Not supported | top_k | topK | OpenAI doesn’t support, dropped in conversion |
max_tokens / max_completion_tokens | max_tokens (required) | maxOutputTokens | Claude requires explicit setting |
n | Not supported | candidateCount | Claude doesn’t support multiple candidates |
stop | stop_sequences | stopSequences | Different field names, same semantics |
Temperature Range Conversion:
When an OpenAI request’s temperature exceeds 1 and the target is Claude, RouteAPI automatically truncates it to 1 to avoid upstream rejection.
Output Control Parameters
Section titled “Output Control Parameters”| OpenAI | Claude | Gemini | Description |
|---|---|---|---|
response_format | Not supported | responseMimeType | OpenAI supports JSON mode and JSON Schema |
frequency_penalty | Not supported | frequencyPenalty | Claude doesn’t support penalty parameters |
presence_penalty | Not supported | presencePenalty | Claude doesn’t support penalty parameters |
stream | stream | stream | All three support, but event formats differ completely |
stream_options.include_usage | Always returned | Auto-returned when generateContentRequest.stream=true | Usage stats return method differs |
Conversion Behavior:
frequency_penaltyandpresence_penaltyare ignored when forwarded to Claude.response_format: { type: "json_object" }is simulated via tool calls when forwarded to Claude, or JSON output prompt added to system.n > 1is reset to 1 when forwarded to Claude, as Claude doesn’t support multi-candidate generation.
Metadata and Control
Section titled “Metadata and Control”| OpenAI | Claude | Gemini | Description |
|---|---|---|---|
user | metadata.user_id | Not supported | For abuse detection |
seed | Not supported | seed | Claude doesn’t support deterministic sampling |
logprobs / top_logprobs | Not supported | Not supported | Only OpenAI models support |
| Not supported | thinking | Not supported | Claude-specific extended thinking configuration |
Tool Calling Conversion
Section titled “Tool Calling Conversion”Tool Definition Format Differences
Section titled “Tool Definition Format Differences”OpenAI tools Format
Section titled “OpenAI tools Format”{ "tools": [ { "type": "function", "function": { "name": "get_weather", "description": "Query current weather for a specified city", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "City name" } }, "required": ["city"] } } } ]}Claude tools Format
Section titled “Claude tools Format”{ "tools": [ { "name": "get_weather", "description": "Query current weather for a specified city", "input_schema": { "type": "object", "properties": { "city": { "type": "string", "description": "City name" } }, "required": ["city"] } } ]}Gemini tools Format
Section titled “Gemini tools Format”{ "tools": [ { "functionDeclarations": [ { "name": "get_weather", "description": "Query current weather for a specified city", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "City name" } }, "required": ["city"] } } ] } ]}Tool Definition Conversion Rules
Section titled “Tool Definition Conversion Rules”| OpenAI | Claude | Gemini | Conversion Notes |
|---|---|---|---|
tools[].type: "function" | No such level | No such level | Remove type wrapper in conversion |
tools[].function | Flatten in tools[] | Place in functionDeclarations[] | Different hierarchy structure |
function.parameters | input_schema | parameters | Claude field name differs |
tool_choice Mapping
Section titled “tool_choice Mapping”| OpenAI | Claude | Gemini | Description |
|---|---|---|---|
"auto" | { "type": "auto" } | "AUTO" | Model decides automatically |
"none" | { "type": "none" } | "NONE" | Prohibit tool calls |
"required" | { "type": "any" } | "ANY" | Must call a tool |
{ "type": "function", "function": { "name": "get_weather" } } | { "type": "tool", "name": "get_weather" } | { "functionCallingConfig": { "allowedFunctionNames": ["get_weather"] } } | Force specific tool, structure differs greatly |
Tool Result Format Conversion
Section titled “Tool Result Format Conversion”OpenAI Tool Result
Section titled “OpenAI Tool Result”{ "role": "tool", "tool_call_id": "call_abc123", "content": "Beijing, sunny, 23°C"}Claude Tool Result
Section titled “Claude Tool Result”{ "role": "user", "content": [ { "type": "tool_result", "tool_use_id": "toolu_01A09q90qw90lq917835lq9", "content": "Beijing, sunny, 23°C" } ]}Gemini Tool Result
Section titled “Gemini Tool Result”{ "role": "user", "parts": [ { "functionResponse": { "name": "get_weather", "response": { "result": "Beijing, sunny, 23°C" } } } ]}Conversion Key Points:
- OpenAI’s
role: "tool"is merged intousermessages when converting to Claude/Gemini. - Tool call ID field names differ:
tool_call_idvstool_use_idvs Gemini’s function name identification. - Claude and Gemini require all tool results in the same
usermessage; OpenAI allows separatetoolmessages.
Multimodal Content Conversion
Section titled “Multimodal Content Conversion”Image URL Format Conversion
Section titled “Image URL Format Conversion”OpenAI Format
Section titled “OpenAI Format”{ "role": "user", "content": [ { "type": "image_url", "image_url": { "url": "https://example.com/image.jpg", "detail": "high" } }, { "type": "text", "text": "Describe this image" } ]}Claude Format
Section titled “Claude Format”{ "role": "user", "content": [ { "type": "image", "source": { "type": "url", "url": "https://example.com/image.jpg" } }, { "type": "text", "text": "Describe this image" } ]}Gemini Format
Section titled “Gemini Format”{ "role": "user", "parts": [ { "fileData": { "mimeType": "image/jpeg", "fileUri": "https://example.com/image.jpg" } }, { "text": "Describe this image" } ]}Base64 Encoding Handling
Section titled “Base64 Encoding Handling”OpenAI base64 Format
Section titled “OpenAI base64 Format”{ "type": "image_url", "image_url": { "url": "data:image/jpeg;base64,/9j/4AAQSkZJRg..." }}Claude base64 Format
Section titled “Claude base64 Format”{ "type": "image", "source": { "type": "base64", "media_type": "image/jpeg", "data": "/9j/4AAQSkZJRg..." }}Gemini base64 Format
Section titled “Gemini base64 Format”{ "inlineData": { "mimeType": "image/jpeg", "data": "/9j/4AAQSkZJRg..." }}Conversion Rules:
- OpenAI’s
data:URI is parsed,media_typeextracted from URI prefix, pure base64 part passed to target protocol. - Claude requires separate
media_typefield, doesn’t acceptdata:URI. - Gemini uses
inlineDatainstead offileDatafor base64 content. - OpenAI’s
detailparameter (low/high) is lost in conversion; Claude and Gemini have no equivalent concept.
Unsupported Parameter Handling
Section titled “Unsupported Parameter Handling”Which Parameters Cannot Be Converted
Section titled “Which Parameters Cannot Be Converted”| Parameter | Source Protocol | Cannot Convert To | Reason |
|---|---|---|---|
top_k | Claude, Gemini | OpenAI | OpenAI doesn’t support top-k sampling |
n | OpenAI, Gemini | Claude | Claude doesn’t support multi-candidate generation |
frequency_penalty / presence_penalty | OpenAI, Gemini | Claude | Claude has no penalty parameters |
logprobs | OpenAI | Claude, Gemini | Only OpenAI models return log probabilities |
thinking | Claude | OpenAI, Gemini | Claude-specific extended thinking configuration |
cache_control | Claude | OpenAI, Gemini | Claude-specific prompt caching control |
reasoning_effort | OpenAI | Claude, Gemini | OpenAI o1 series-specific parameter |
response_format (JSON Schema) | OpenAI | Claude, Gemini | Full JSON Schema constraints only OpenAI supports |
How Incompatible Parameters Are Handled
Section titled “How Incompatible Parameters Are Handled”RouteAPI uses the following strategies:
- Silent Ignore: Unsupported parameters are dropped during conversion without affecting request success (e.g.,
detail,logprobs). - Auto-Adjust: Out-of-range values are truncated to legal range (e.g.,
temperature > 1truncated to 1 when forwarding to Claude). - Conservative Degradation: Complex features simulated with simple methods (e.g., OpenAI’s JSON Schema degrades to tool calls or prompt constraints on Claude).
- Reject Request: Rarely, if core parameters cannot be converted and have no reasonable default, return 400 error (e.g., Claude protocol missing
max_tokens).
Warnings and Error Messages
Section titled “Warnings and Error Messages”RouteAPI provides conversion information in response headers and logs:
X-RouteAPI-Protocol-Conversion: openai-to-claudeX-RouteAPI-Dropped-Params: frequency_penalty,presence_penaltyIf conversion fails or parameters conflict, a standard error response is returned:
{ "error": { "message": "Parameter 'max_tokens' is required for Claude models", "type": "invalid_request_error", "param": "max_tokens", "code": "missing_required_parameter" }}Best Practices
Section titled “Best Practices”- Use Native Protocol: Use the model’s native protocol whenever possible to avoid conversion loss.
- Avoid Protocol-Specific Features: Don’t rely on capabilities unique to a single protocol like
logprobs,thinkingunless you’re certain to only use that protocol’s models. - Check Response Headers: Pay attention to
X-RouteAPI-Dropped-Paramsheader to know which parameters were ignored. - Test Cross-Protocol Compatibility: Validate the same request’s behavior across different protocol/model combinations in test environments.
- Log Model ID: Record the actual model ID and protocol type called in logs for troubleshooting differences.
Response Format Standardization
Section titled “Response Format Standardization”usage Field Standardization
Section titled “usage Field Standardization”| Protocol | input token field | output token field | total token field |
|---|---|---|---|
| OpenAI | prompt_tokens | completion_tokens | total_tokens |
| Claude | input_tokens | output_tokens | None (calculate yourself) |
| Gemini | promptTokenCount | candidatesTokenCount | totalTokenCount |
Conversion Rules:
- Claude → OpenAI:
input_tokens→prompt_tokens,output_tokens→completion_tokens, calculatetotal_tokens = input_tokens + output_tokens. - Gemini → OpenAI:
promptTokenCount→prompt_tokens,candidatesTokenCount→completion_tokens,totalTokenCount→total_tokens. - OpenAI → Claude:
prompt_tokens→input_tokens,completion_tokens→output_tokens, droptotal_tokens.
Claude’s prompt caching fields are also preserved:
{ "usage": { "prompt_tokens": 120, "completion_tokens": 45, "total_tokens": 165, "cache_creation_input_tokens": 80, "cache_read_input_tokens": 40 }}finish_reason Standardization
Section titled “finish_reason Standardization”| OpenAI | Claude | Gemini | Meaning |
|---|---|---|---|
stop | end_turn | STOP | Natural completion |
length | max_tokens | MAX_TOKENS | Reached length limit |
tool_calls | tool_use | STOP (with functionCall) | Requesting tool call |
content_filter | No equivalent | SAFETY | Blocked by content filter |
stop | stop_sequence | STOP | Hit stop sequence |
Conversion Rules:
- Claude
end_turn→ OpenAIstop - Claude
max_tokens→ OpenAIlength - Claude
tool_use→ OpenAItool_calls - Gemini
STOPmapped tostoportool_callsbased on presence offunctionCall - Gemini
SAFETY→ OpenAIcontent_filter
Error Response Standardization
Section titled “Error Response Standardization”All protocol error responses are converted to OpenAI format (when client uses OpenAI protocol):
{ "error": { "message": "Invalid API key", "type": "invalid_request_error", "param": null, "code": "invalid_api_key" }}Claude original error:
{ "type": "error", "error": { "type": "authentication_error", "message": "invalid x-api-key" }}After conversion to OpenAI format, type maps to invalid_request_error, code set to invalid_api_key.
Conversion Examples
Section titled “Conversion Examples”Example 1: OpenAI Request → Claude Format
Section titled “Example 1: OpenAI Request → Claude Format”Original OpenAI Request:
{ "model": "claude-sonnet-4-5", "messages": [ { "role": "system", "content": "You are a rigorous technical assistant, keep answers concise." }, { "role": "user", "content": "Explain what an API gateway is" } ], "temperature": 0.7, "max_tokens": 150, "stream": false}Converted Claude Request:
{ "model": "claude-sonnet-4-5", "system": "You are a rigorous technical assistant, keep answers concise.", "messages": [ { "role": "user", "content": "Explain what an API gateway is" } ], "temperature": 0.7, "max_tokens": 150, "stream": false}Key Changes:
- system message extracted from
messagesarray to top-levelsystemfield. messagesnow only containsuserandassistantmessages.
Example 2: Claude Tool Call → OpenAI Format
Section titled “Example 2: Claude Tool Call → OpenAI Format”Claude Tool Call Response:
{ "id": "msg_01XFDUDYJgAACzvnptvVoYEL", "type": "message", "role": "assistant", "model": "claude-sonnet-4-5", "content": [ { "type": "text", "text": "Let me check Beijing's weather." }, { "type": "tool_use", "id": "toolu_01A09q90qw90lq917835lq9", "name": "get_weather", "input": { "city": "Beijing" } } ], "stop_reason": "tool_use", "usage": { "input_tokens": 120, "output_tokens": 45 }}Converted to OpenAI Format:
{ "id": "msg_01XFDUDYJgAACzvnptvVoYEL", "object": "chat.completion", "created": 1726567890, "model": "claude-sonnet-4-5", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Let me check Beijing's weather.", "tool_calls": [ { "id": "toolu_01A09q90qw90lq917835lq9", "type": "function", "function": { "name": "get_weather", "arguments": "{\"city\":\"Beijing\"}" } } ] }, "finish_reason": "tool_calls" } ], "usage": { "prompt_tokens": 120, "completion_tokens": 45, "total_tokens": 165 }}Key Changes:
contentarray split:textblock extracted ascontentfield,tool_useblock converted totool_callsarray.tool_use.inputobject serialized tofunction.argumentsJSON string.stop_reason: "tool_use"→finish_reason: "tool_calls".input_tokens→prompt_tokens,output_tokens→completion_tokens, addtotal_tokens.- Add OpenAI format top-level fields:
object,created,choicesarray.
Example 3: Gemini Multimodal → OpenAI Format
Section titled “Example 3: Gemini Multimodal → OpenAI Format”Gemini Response:
{ "candidates": [ { "content": { "parts": [ { "text": "This image shows a modern user interface with a navigation bar, content area, and sidebar." } ], "role": "model" }, "finishReason": "STOP", "index": 0 } ], "usageMetadata": { "promptTokenCount": 258, "candidatesTokenCount": 32, "totalTokenCount": 290 }}Converted to OpenAI Format:
{ "id": "chatcmpl-gemini-abc123", "object": "chat.completion", "created": 1726567890, "model": "gemini-2.0-flash-exp", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "This image shows a modern user interface with a navigation bar, content area, and sidebar." }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 258, "completion_tokens": 32, "total_tokens": 290 }}Key Changes:
candidates[0].content.parts[0].text→choices[0].message.content.role: "model"→role: "assistant".finishReason: "STOP"→finish_reason: "stop"(lowercase).usageMetadatafield names mapped to OpenAI’susagestructure.
Best Practices Summary
Section titled “Best Practices Summary”1. Choose Appropriate Protocol
Section titled “1. Choose Appropriate Protocol”Select protocol based on client and model type:
| Client Type | Target Model | Recommended Protocol | Reason |
|---|---|---|---|
| OpenAI SDK | OpenAI models | OpenAI | Native support, zero conversion |
| Claude Code | Claude models | Claude Messages | Native support, zero conversion |
| LangChain / LiteLLM | Any model | OpenAI | Best ecosystem compatibility |
| Anthropic SDK | Claude models | Claude Messages | Access extended thinking, prompt caching |
| Custom client | Any model | Depends on needs | Prefer target model’s native protocol |
2. Avoid Protocol-Specific Features
Section titled “2. Avoid Protocol-Specific Features”If business needs cross-model switching, avoid using these features:
- OpenAI-specific:
logprobs,seed, full JSON Schema constraints,reasoning_effort(o1 series) - Claude-specific:
thinking,cache_control,mcp_servers - Gemini-specific:
grounding,codeExecution
Universal feature set (all three support):
- Basic chat conversation (
messages/contents) - Streaming output (
stream) - Temperature control (
temperature, note range differences) - Tool calling (
tools, note format differences) - Multimodal input (images, note format differences)
- Stop sequences (
stop/stop_sequences/stopSequences)
3. Test Cross-Protocol Compatibility
Section titled “3. Test Cross-Protocol Compatibility”Validate these scenarios in test environments:
- Same protocol, different models: Ensure OpenAI protocol correctly calls Claude and Gemini models.
- Different protocols, same model: Verify result consistency when calling the same Claude model via Claude Messages and OpenAI protocols.
- Tool call round-trip: Test tool definition, invocation, and result passing across protocols.
- Boundary parameters: Test boundary cases like
temperature: 1.5(OpenAI valid, Claude needs truncation),n: 2(OpenAI supports, Claude doesn’t). - Error handling: Verify upstream errors are correctly converted to client protocol format.
4. Monitoring and Logging
Section titled “4. Monitoring and Logging”Record the following information for troubleshooting protocol conversion issues:
{ "request_id": "req_abc123", "client_protocol": "openai", "model_id": "claude-sonnet-4-5", "upstream_protocol": "claude", "conversion_required": true, "dropped_params": ["frequency_penalty", "logprobs"], "adjusted_params": {"temperature": {"original": 1.8, "adjusted": 1.0}}, "latency_ms": 856, "conversion_overhead_ms": 8}Key metrics:
- Conversion success rate: Percentage of 400 errors caused by protocol conversion failures.
- Conversion latency: Additional latency introduced by protocol conversion (typically 5-15ms).
- Parameter drop rate: Which parameters are most frequently dropped, whether it affects business.
- Cross-protocol error rate: Whether OpenAI → Claude calls have higher error rates than OpenAI → OpenAI.
5. Progressive Migration Strategy
Section titled “5. Progressive Migration Strategy”If migrating from one protocol to another:
- Phase 1: Dual-write testing: New protocol call results only used for comparison, doesn’t affect business.
- Phase 2: Gradual switchover: Small traffic switches to new protocol, monitor error rates and response quality.
- Phase 3: Full switchover: Switch all traffic after confirming no anomalies.
- Phase 4: Cleanup old code: Remove adapter code for old protocol.
Each phase requires validating:
- Functional correctness (tool calling, multimodal, streaming output)
- Response quality (output differences across protocol/model combinations)
- Performance metrics (latency, token usage, cost)
- Error handling (network anomalies, rate limits, upstream failures)
Protocol conversion lets you flexibly choose clients and models, but best practice is still to prioritize using the target model’s native protocol. If cross-protocol calling is necessary, thoroughly validate in test environments and monitor conversion-related errors and performance metrics in production.