---
title: "Anthropic Messages — drop-in proxy for Claude Code"
method: POST
path: "/v1/messages"
tags: ["Anthropic"]
---

# Anthropic Messages — drop-in proxy for Claude Code

`POST /v1/messages`

## Request

- Base URL: `http://localhost:9998`
- URL: `http://localhost:9998/v1/messages`
- Auth: HTTP bearer

Anthropic-shape `Messages` endpoint. Translates the request into
OpenAI Chat Completions internally and dispatches to the resolved
`EndpointConfig` (token binding → global "Anthropic Proxy Backend"
→ `model: "toolpiper:tp-<id>"` prefix override).

Authenticated via `Authorization: Bearer tp_<64 hex>` (Claude
Code's `ANTHROPIC_AUTH_TOKEN` path), validated by the unified
middleware against the same token store as every other
authenticated route. Errors return Anthropic-shape envelopes
(`{type: "error", error: {type, message}}`), never the OpenAI
shape — middleware-emitted 401/403/421 responses are remapped to
Anthropic-shape via `authErrorResponse(forPath:...)`.

Streaming (`stream: true`) emits the canonical Anthropic SSE
sequence: `message_start` → (`content_block_start` →
`content_block_delta`+ → `content_block_stop`)+ → `message_delta`
→ `message_stop`, with `ping` keepalives every 15 s.

See `docs/features/anthropic-api-proxy.md` for the full Protocol
Coverage Matrix.

## Request body

- AnthropicMessagesRequest: Anthropic Messages API request shape. The `model` field is logged but does not select the provider — provider selection runs through the `EndpointConfig` resolution flow (see Architecture § "Provider Selection"). When `model` carries a `toolpiper:tp-<id>` prefix, that layer-1 override picks the endpoint for this request.
  - `model` string, required
  - `max_tokens` integer, required
  - `messages` AnthropicInputMessage[], required
    - `role` 'user' | 'assistant', required
    - `content` union, required
      - string
      - AnthropicContentBlock[]
        - union
          - AnthropicTextBlock
            - `type` 'text', required
            - `text` string, required
          - AnthropicImageBlock: Image content block (Phase 9). Translated to OpenAI's `image_url` content part on dispatch — base64 sources serialize as `data:<media_type>;base64,<data>` URLs; URL sources pass through verbatim.
            - `type` 'image', required
            - `source` union, required
              - …
          - AnthropicToolUseBlock
            - `type` 'tool_use', required
            - `id` string, required
            - `name` string, required
            - `input` object, required
          - AnthropicToolResultBlock
            - `type` 'tool_result', required
            - `tool_use_id` string, required
            - `content` union, required
              - …
            - `is_error` boolean
  - `system` union
    - string
    - AnthropicTextBlock[]
      - `type` 'text', required
      - `text` string, required
  - `tools` AnthropicToolDefinition[]
    - `name` string, required
    - `description` string
    - `input_schema` object: JSON Schema (canonical safe-subset).
  - `tool_choice` union
    - object
      - `type` 'auto', required
    - object
      - `type` 'any', required
    - object
      - `type` 'tool', required
      - `name` string, required
  - `temperature` number
  - `top_p` number
  - `top_k` integer
  - `stop_sequences` string[]
  - `stream` boolean
  - `metadata` object

## Response `200`

Buffered (`stream: false`): a single Anthropic `Message` JSON
object. Streaming (`stream: true`): `text/event-stream` with
the Anthropic SSE sequence.

- AnthropicMessage
  - `id` string, required: Synthesized: msg_<22-char-base62>
  - `type` 'message', required
  - `role` 'assistant', required
  - `model` string, required: The upstream model the EndpointConfig actually called (NOT the client's request string).
  - `content` union[], required
    - union
      - AnthropicTextBlock
        - `type` 'text', required
        - `text` string, required
      - AnthropicToolUseBlock
        - `type` 'tool_use', required
        - `id` string, required
        - `name` string, required
        - `input` object, required
  - `stop_reason` 'end_turn' | 'max_tokens' | 'stop_sequence' | 'tool_use', nullable, required
  - `stop_sequence` string, nullable, required
  - `usage` object, required
    - `input_tokens` integer, required
    - `output_tokens` integer, required
    - `cache_creation_input_tokens` integer
    - `cache_read_input_tokens` integer

## Other responses

- `400`: Validation failure (Anthropic envelope)
- `401`: Authentication failed
- `413`: Request body exceeds 10 MB
- `503`: No EndpointConfig resolves; misconfigured backend

---

[API](https://skmtc.dev/modelpiper/apis/toolpiper-api.md) · [All operations](https://skmtc.dev/modelpiper/apis/toolpiper-api/llms.txt) · [OpenAPI document](https://skmtc.dev/modelpiper/apis/toolpiper-api/revisions/6722bf56385c?raw)
