Skip to main content
When you call Claude’s native format (/v1/messages), the response is completely different from OpenAI compatible mode: the answer is a typed content block array, and streaming uses Anthropic’s named-event SSE protocol. This page explains how to parse both modes.
The request side (endpoint, anthropic-version header, x-api-key auth, effort / thinking params) is covered in Claude API Basics and the Claude Effort & Thinking Guide. This page is purely about the response side. Examples use the lightweight model claude-haiku-4-5-20251001.

Non-streaming response

The top level is a message object, and the answer lives in the content array, split into blocks by type:
Getting the answer means iterating the content array — you can’t read a single string field like in OpenAI:
stop_reason values: end_turn (normal), max_tokens (cut off by max_tokens — the text may be empty; raise the limit), stop_sequence, tool_use (wants to call a tool). With thinking on, the content array gains a type: "thinking" block placed before the text block.

Streaming response (named-event SSE)

Claude streaming uses the Anthropic event protocol: each message has an event: name plus a data: payload, and you dispatch by event type rather than treating every chunk identically as in OpenAI.
The fixed event sequence and what each carries: The core is accumulating the text_delta inside content_block_delta:
The event type is present in both the event: line and the data: payload’s "type" field; dispatch on either. With the official anthropic SDK, point base_url at https://api.apiyi.com and the SDK handles the event stream for you — no hand-written loop needed.
With thinking (adaptive thinking) on, a type: "thinking" block appears first; its increments are thinking_delta, and a signature_delta (thinking-block signature) appears before the block closes. To display thinking, render thinking_delta and text_delta separately. See the Claude Effort & Thinking Guide.

Key differences from OpenAI compatible mode

The two easiest migration traps: (1) the answer is an array, not a string — iterate content for type=="text" blocks; (2) streaming has no [DONE] — detect the end via the message_stop event.

Usage and billing

  • Non-streaming: usage comes back with the result, including input_tokens, output_tokens, cache_creation_input_tokens, cache_read_input_tokens.
  • Streaming: input_tokens is in message_start, and the final output_tokens is in message_deltamerge both.
  • For the cache-hit field (cache_read_input_tokens) discount and usage, see Claude Cache Billing.