Relay365Multi-model API relay desk
← All desk bulletins
Wire & endpointsEN1 desk reads

Shift Note: Messages API Payloads and Adapter Verdicts

Two message envelopes on the same integration desk

Anthropic’s Messages API and OpenAI’s Chat Completions API both carry conversations, but their envelopes differ. Treating them as interchangeable JSON is where integration trouble starts. This comparison covers Chat Completions specifically, not OpenAI’s separate Responses API.

In plain words, a Messages request names a model, sets an output budget with max_tokens, and supplies a messages array. Each message has a role and content. Instructions that govern the conversation belong in the top-level system field. The response is an assistant message containing content blocks, plus metadata explaining usage and why generation stopped.

System instructions belong in different places

With Anthropic Messages, system instructions sit outside the messages array. Conversation turns use user and assistant roles. With Chat Completions, instructions generally travel inside the messages array using system or developer messages, depending on the model and interface.

This is more than a naming difference. An adapter must extract instruction messages and map them deliberately. Copying an OpenAI-style system message directly into Anthropic’s conversation array is not a valid native Messages request.

The verdict is straightforward: Messages makes the separation between instructions and conversation explicit. Chat Completions keeps more of the conversation envelope in one array. Neither removes the need to preserve instruction priority during conversion.

Content blocks beat the single-string assumption

Anthropic accepts a plain string for simple text input, but its richer structure is an array of typed content blocks. A text block contains text; other supported blocks can carry images, tool interactions, or additional model-specific output. Assistant responses use a content array, so reading one assumed string is insufficient.

Chat Completions also supports structured content for relevant inputs and models. Its tool calls, however, commonly appear in a separate tool_calls field rather than as Anthropic-style tool_use blocks inside content.

  • A Messages response parser should inspect block types and collect text blocks rather than assume the first block contains the complete answer.
  • An adapter should preserve supported non-text blocks or explicitly reject unsupported content instead of silently discarding it.

The verdict favors block-aware parsing on both sides. Anthropic makes that requirement especially visible in its response shape.

Tool execution needs a real round-trip adapter

In Messages, you declare tools with names, descriptions, and input_schema definitions. The assistant can return tool_use blocks containing tool names, IDs, and structured inputs. Your application executes the requested work, then sends tool_result blocks in a user message, linked through tool_use_id.

Chat Completions typically declares function tools using a parameters schema. The assistant returns tool_calls, and the application replies with tool-role messages linked by tool_call_id. Function arguments commonly arrive as a JSON string that the application must parse.

Both interfaces describe tool requests; neither means your application can skip execution, authorization, or validation. Preserve the assistant’s tool request in conversation history before returning results.

The verdict is to use native tool handling when possible. A compatibility layer is useful only if it translates the complete round trip, including multiple calls and error results.

Completion signals are not interchangeable

Anthropic reports stop_reason values such as end_turn, max_tokens, and tool_use. Chat Completions reports finish_reason values such as stop, length, and tool_calls. Similar intent does not make those fields identical.

Streaming also differs. Messages streams named events for message and content-block lifecycles, while Chat Completions streams chunks containing deltas. Neither stream should be parsed as a sequence of complete final responses.

The operational verdict is to normalize events deliberately. Distinguish completed answers, output-budget limits, and pending tool execution. Retry logic must also avoid repeating side-effecting tool actions after a partial failure.

Relay routing does not erase protocol differences

Relay365 fits teams that want pay-as-you-go access across model families through a shared relay desk. It works with Claude Code, Codex, Gemini CLI, and OpenAI SDKs. Its API base is https://api.api365relay.com; OpenAI clients add /v1.

A shared base URL is not proof that every native Messages feature maps losslessly to an OpenAI-compatible route. Check the selected route’s payload, tool, and streaming support before migration. If that routing model fits your workload, create a Relay365 account and test one representative conversation end to end.

The final verdict: choose native Messages for direct control over Anthropic’s structure. Choose an OpenAI-compatible route for client reuse when its supported mappings meet your needs. In either case, test blocks, tools, and stop signals—not just a successful text reply.

Further desk bulletins

Curious how it runs on your own code? Sign up →