Skip to main content

Claude Code BYOS

Responses Proxy exposes an Anthropic Messages-compatible gateway for Claude Code:

POST /v1/messages
POST /v1/messages/count_tokens
GET /v1/models

These routes share the org-scoped proxy keys, provider registry, model aliases, routing, metrics, and telemetry used by /v1/responses. Registered aliases can use anthropic_messages, responses, or chat_completions providers.

Connect Claude Code

Claude Code may already use Authorization or x-api-key for Anthropic credentials, so the gateway reads the Responses Proxy key from X-Responses-Proxy-Key by default.

export RESPONSES_PROXY_KEY="rprx-..."
export ANTHROPIC_BASE_URL="https://agent-responses-proxy.svc.cloud.morph.so/v1"
export ANTHROPIC_CUSTOM_HEADERS="X-Responses-Proxy-Key: $RESPONSES_PROXY_KEY"
export CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=1

claude --model "openai/gpt-mini"

GET /v1/models returns only enabled, Claude Code-compatible aliases in the proxy key's org, plus deployment-configured direct models. An alias with capabilities.claude_code.enabled=false, an invalid capability profile, or a Chat Completions provider disabled by deployment does not appear.

Supported alias profiles

The profile can be inferred from the provider wire_api or set explicitly on each alias:

ProfileProvider wire_apiBehavior
anthropic_nativeanthropic_messagesPreserves first-party Messages formatting and provider-native behavior.
openai_responsesresponsesConverts Messages input to Responses and converts Responses JSON or SSE back to Messages.
openai_chatchat_completionsConverts Messages to canonical Responses input, then through the Chat Completions adapter; output follows the reverse path.
autoAny supported value aboveResolves to the profile matching the provider wire_api. This is the default.

An explicit profile must match the provider protocol. For example, profile="openai_chat" is valid only for a chat_completions provider.

Capability schema and defaults

Claude Code compatibility is declared under the model alias capabilities object:

{
"claude_code": {
"enabled": true,
"profile": "auto",
"images": true,
"documents": true,
"client_tools": true,
"parallel_tools": true,
"hosted_tools": []
}
}

Defaults apply when capabilities.claude_code or one of its fields is omitted:

FieldDefaultMeaning
enabledtrueInclude the alias in model discovery and accept Claude Code traffic.
profileautoInfer the compatibility profile from wire_api.
imagestrueAccept portable base64 and URL image blocks.
documentstrueAccept portable base64, text, and URL document blocks, subject to profile limits.
client_toolstrueTranslate Claude function definitions, tool_use, and tool_result.
parallel_toolstrueAllow parallel tool calls when requested by the client.
hosted_tools[]Do not enable any hosted/server tool implicitly.

Unknown fields, non-Boolean values for Boolean fields, unknown profiles, and unknown hosted-tool names are rejected when an alias is created or updated. Provider-less aliases cannot declare a Claude Code profile.

Existing provider-bound aliases with no claude_code object receive these defaults. Disable or narrow an alias explicitly when its upstream model does not support images, documents, or tools.

Content mapping

anthropic_native aliases send Messages content to the Anthropic provider after model rewriting and normalization. Translated openai_responses and openai_chat aliases use these mappings:

Claude Messages inputCanonical Responses mappingChat Completions mapping
System textinstructionsSystem message.
User text blockinput_textText content part.
Base64 imageinput_image.image_url data URLimage_url.url data URL.
URL imageinput_image.image_urlimage_url.url.
Base64 documentinput_file.file_data data URLfile.file_data.
Text documentUTF-8 text encoded as base64 input_file.file_datafile.file_data.
URL documentinput_file.file_urlNot portable; rejected for Chat Completions.
search_result blockJSON serialized into input_textText content.
Assistant tool_usefunction_call with JSON argumentsAssistant function call.
User tool_resultfunction_call_outputTool message; returned image/file parts become a following user media message.

Image detail values auto, low, and high are preserved. Document title or source filename is preserved when present. Provider-scoped Claude file IDs are rejected because they cannot be used with another provider; send base64 data instead.

The proxy validates base64 before contacting the provider, accepts Claude's portable PNG, JPEG, GIF, and WebP image MIME types, and requires absolute HTTP or HTTPS media URLs. Invalid media returns 400 at the gateway boundary.

Thinking and redacted-thinking blocks are not sent to translated providers. Unsupported Anthropic-only request fields are normalized instead of being forwarded blindly. Successful translated responses can include X-Responses-Proxy-Normalized-Fields listing fields such as cache_control, context_management, top_k, and tool-level cache or eager-streaming hints that were removed.

Translated output currently maps model text and function/custom tool calls back to Claude text and tool_use blocks. Buffered and streaming tool arguments must be valid JSON objects; malformed upstream arguments return 502 rather than being silently changed.

Tool mapping and hosted-tool limits

Claude client tools map to OpenAI function tools. The proxy preserves name, description, input_schema, and Boolean strict; it maps tool_choice values auto, none, any, and named tool, including disable_parallel_tool_use.

Hosted tools are deliberately narrower:

  • web_search is the only accepted value in capabilities.claude_code.hosted_tools.
  • openai_responses maps Claude server-tool types beginning with web_search_ to the Responses web_search tool. user_location, allowed_domains, and blocked_domains are preserved.
  • anthropic_native keeps provider-native web search on the Messages path.
  • openai_chat requires hosted_tools=[]; Chat Completions has no portable hosted-tool mapping.
  • file_search, code execution, computer use, MCP, web fetch, and every other Claude server-tool type have no translated mapping. They are not dropped silently; translated aliases return an error.

Client tools such as Bash, Read, Edit, and other Claude Code tools are function tools executed by Claude Code. They are controlled by client_tools, not hosted_tools.

Register an alias through the console

In the Morph Cloud Responses console:

  1. Create or select a provider with wire_api set to responses, chat_completions, or anthropic_messages.
  2. Add and validate a provider credential.
  3. In Model aliases, enter the alias and upstream model id.
  4. Choose Auto or the matching Claude Code profile.
  5. Open Compatibility settings and disable features the upstream model does not support. Hosted web search is unavailable for Chat Completions.
  6. Use Test to run the alias against the claude_code surface, then save it.
  7. Confirm the alias appears in GET /v1/models, mint a proxy key, and run Claude Code with the alias.

The console's model test is a text smoke test. Test images, documents, tools, and streaming separately before enabling them for production traffic.

Register aliases through the API

Responses alias example:

{
"alias": "openai/gpt-mini",
"provider_id": "openai-main",
"upstream_id": "gpt-4.1-mini",
"capabilities": {
"claude_code": {
"profile": "openai_responses",
"hosted_tools": ["web_search"]
}
}
}

Chat Completions alias example:

{
"alias": "kimi/k2",
"provider_id": "kimi-main",
"upstream_id": "kimi-k2.6",
"capabilities": {
"claude_code": {
"profile": "openai_chat",
"documents": false,
"hosted_tools": []
}
}
}

Test the Claude Code surface before saving or rolling out the alias:

curl -sS -X POST "$RESPONSES_PROXY_BASE_URL/admin/models/test" \
-H "$ADMIN_HEADER" \
-H 'content-type: application/json' \
-d '{
"provider_id": "kimi-main",
"upstream_id": "kimi-k2.6",
"surface": "claude_code",
"capabilities": {
"claude_code": {"profile":"openai_chat","documents":false}
}
}'

Deployment settings

VariableDefaultPurpose
PROXY_CLAUDE_GATEWAY_CHAT_COMPLETIONS_ENABLEDtrueEnables Chat Completions aliases on model discovery and /v1/messages. Set false as a deployment-wide rollback switch.
PROXY_CLAUDE_GATEWAY_MAX_BODY_BYTES33554432Maximum Claude gateway request body, including base64 expansion. Requests over the limit return 413.
PROXY_CLAUDE_GATEWAY_PROXY_KEY_HEADERx-responses-proxy-keyHeader containing the org-scoped proxy key.
PROXY_CLAUDE_GATEWAY_DIRECT_MODELSunsetComma-separated model ids allowed for direct Anthropic passthrough.
PROXY_CLAUDE_GATEWAY_UPSTREAM_BASE_URLhttps://api.anthropic.com/v1Upstream base URL used only by direct passthrough.

The compatibility expansion does not require a database migration; it uses the existing alias capabilities JSON. When request-body capture is enabled, the proxy redacts base64 image and document data before persisting Claude gateway request telemetry.

Stored subscription setup

Stored subscription setup moves a consented Claude Code OAuth bearer credential into an encrypted, org-owned provider credential row. It applies only to first-party Anthropic routing, not OpenAI Responses or Chat Completions aliases.

Enable it in the proxy deployment:

PROXY_ENABLE_CLAUDE_CODE_TOKEN_ESCROW=true
PROXY_SECRET_ENCRYPTION_KEY=...
PROXY_CLAUDE_CODE_OAUTH_REFRESH_URL=...
PROXY_CLAUDE_CODE_OAUTH_CLIENT_ID=...

Create an Anthropic OAuth provider with provider_type="anthropic", base_url="https://api.anthropic.com/v1", wire_api="anthropic_messages", auth_type="bearer", and auth_header="authorization". Then create a setup session from the dashboard and run the one-time command on the machine where Claude Code is already logged in:

printf '%s\n' "$SETUP_TOKEN" | responses-proxy-claude-code teleport \
--base-url "$RESPONSES_PROXY_BASE_URL" \
--session-id "$SESSION_ID" \
--setup-token-stdin

teleport reads Claude Code OAuth state from CLAUDE_CONFIG_DIR or ~/.claude. On Linux it rejects group- or other-readable credential files by default. Fix permissions with chmod 600 ~/.claude/.credentials.json; use --allow-insecure-files only for local throwaway testing.

Refresh settings are deployment-owned. If refresh is unavailable or fails after expiry, the credential is marked needs_reauth and removed from routing until setup is completed again.

Direct passthrough

Direct passthrough is for Claude Code sessions that already hold a local Anthropic credential. The proxy still requires X-Responses-Proxy-Key for org scoping and telemetry, but forwards the caller's Anthropic credential upstream.

PROXY_CLAUDE_GATEWAY_DIRECT_MODELS=claude-sonnet-4-5,claude-haiku-4-5

Do not register an alias with the same name unless registered-alias mode should take precedence.

Rollout and testing

For a staged rollout:

  1. Deploy the backend and frontend with PROXY_CLAUDE_GATEWAY_CHAT_COMPLETIONS_ENABLED=false if Chat aliases should remain hidden initially.
  2. Review existing aliases. Because omitted Claude Code capabilities use permissive defaults, explicitly disable unsupported media or tools.
  3. Run surface="claude_code" model tests for Responses and Chat providers.
  4. Exercise GET /v1/models, buffered and streaming /v1/messages, /v1/messages/count_tokens, a complete client-tool round trip, and each enabled media type.
  5. Enable Chat Completions routing, reload routing or wait for the refresh interval, and monitor request status, latency, and provider-specific failures in the Responses console.
  6. Roll back Chat compatibility by setting PROXY_CLAUDE_GATEWAY_CHAT_COMPLETIONS_ENABLED=false; Responses and Anthropic aliases remain available.

Errors

  • 401: X-Responses-Proxy-Key is missing, invalid, or revoked.
  • 404 Unknown model: the model is neither an enabled org alias nor an allowed direct model.
  • 413 request_too_large: the JSON body exceeds PROXY_CLAUDE_GATEWAY_MAX_BODY_BYTES.
  • 422 ... disabled for alias: capabilities.claude_code.enabled is false.
  • 422 ... disabled by deployment: Chat Completions routing is turned off globally.
  • 400 ... profile ... requires wire_api: the explicit profile does not match its provider.
  • 422 Image inputs..., Document inputs..., or Client tools... disabled: the request exceeds the alias capability declaration.
  • 422 ... no exact provider mapping: a translated request uses an unsupported Claude server tool or content block.
  • 422 ... document URLs: a Chat Completions alias received a URL document; send base64 data.
  • 502 ... invalid JSON arguments: the upstream returned malformed function-call arguments.

Current limitations

  • custom providers remain unroutable. Claude Code aliases require anthropic_messages, responses, or enabled chat_completions resources.
  • openai_responses and openai_chat normalize Anthropic-only thinking, prompt-caching, context-management, and beta features. They do not provide bit-for-bit Messages semantics.
  • Chat Completions document support varies by provider. Base64 file input is the portable proxy shape; URL documents are rejected.
  • Provider-scoped file IDs do not cross provider boundaries.
  • Translated model output supports text and client tool calls. Model-generated image, document, audio, computer-use, and arbitrary provider-specific output blocks are not converted to Claude Messages blocks.
  • Only hosted web_search is portable to Responses. Chat Completions has no hosted-tool mapping.
  • /v1/messages/count_tokens uses a local conservative estimate for Responses and Chat aliases. Billing telemetry comes from completed upstream calls.
  • Local token estimates charge a fixed media allowance and do not count raw base64 bytes as prompt text.
  • Failed or truncated translated streams emit an Anthropic error event and degrade the selected resource; they are not closed as successful messages.
  • The dashboard model test covers text only; capability toggles are declarations, not provider feature detection.