Anthropic Messages API Documentation: Endpoints, Requests, Vision, and Agent Backends

Anthropic Messages API Documentation: Endpoints, Requests, Vision, and Agent Backends

The Anthropic Messages API is the main HTTP interface for sending prompts to Claude. The core endpoint is POST /v1/messages: you provide a model, a list of typed message content blocks, and a token limit, then receive an assistant message containing one or more output blocks.

This guide turns the Anthropic API documentation into an implementation checklist. It covers the request contract, multi-turn state, streaming, vision, the Files API, tool use, and the choices involved when an agent backend needs to support both Anthropic-native and OpenAI-compatible model providers.

Messages API Endpoint and Required Headers

Anthropic’s native Messages API uses this endpoint:

POST https://api.anthropic.com/v1/messages

Direct HTTP requests normally include these headers:

HeaderPurpose
x-api-keyAuthenticates the Anthropic account
anthropic-versionSelects the documented API version contract
content-type: application/jsonDeclares a JSON request body

The API version header is not a model version. It controls the HTTP API behavior, while the model field selects the Claude model used for inference. Keep both values in configuration instead of scattering them through application code.

The Request and Response Structure

A basic request contains three fields:

{
  "model": "YOUR_CLAUDE_MODEL_ID",
  "max_tokens": 1024,
  "messages": [
    {
      "role": "user",
      "content": "Explain idempotency keys in two paragraphs."
    }
  ]
}

The response is an assistant message rather than a bare string. Its content property is an array of typed blocks, so production code should inspect each block’s type before reading its fields.

{
  "type": "message",
  "role": "assistant",
  "content": [
    {
      "type": "text",
      "text": "An idempotency key..."
    }
  ],
  "stop_reason": "end_turn",
  "usage": {
    "input_tokens": 18,
    "output_tokens": 126
  }
}

This block-based design matters once you add images or tools. A single assistant turn can contain text and a tool request, and a user turn can contain text alongside image or document blocks.

A Minimal curl Request

Store credentials in an environment variable and use a model ID currently available to your Anthropic account:

export ANTHROPIC_API_KEY="your-api-key"
export ANTHROPIC_MODEL="your-claude-model-id"

curl https://api.anthropic.com/v1/messages \
  --header "x-api-key: $ANTHROPIC_API_KEY" \
  --header "anthropic-version: 2023-06-01" \
  --header "content-type: application/json" \
  --data '{
    "model": "'"$ANTHROPIC_MODEL"'",
    "max_tokens": 512,
    "messages": [
      {
        "role": "user",
        "content": "Return three practical ways to reduce API latency."
      }
    ]
  }'

Do not hard-code a model name copied from an old tutorial. Model availability and aliases can change, so deployment configuration should use a model ID verified in the provider’s current model documentation or console.

Python Usage With the Anthropic SDK

The official Python SDK handles authentication headers and converts the response into typed objects:

import os

from anthropic import Anthropic

client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])

message = client.messages.create(
    model=os.environ["ANTHROPIC_MODEL"],
    max_tokens=512,
    messages=[
        {
            "role": "user",
            "content": "Write a Python function that validates a UUID string.",
        }
    ],
)

for block in message.content:
    if block.type == "text":
        print(block.text)

Iterating over content blocks is safer than assuming message.content[0] is always text. Agent applications may receive tool-use blocks, and multimodal features can add other block types to the conversation.

Multi-Turn Conversations and System Prompts

The Messages API is stateless. Your application sends the relevant conversation history again with each request:

{
  "model": "YOUR_CLAUDE_MODEL_ID",
  "max_tokens": 512,
  "system": "You are a concise API documentation assistant.",
  "messages": [
    {"role": "user", "content": "What does HTTP 429 mean?"},
    {"role": "assistant", "content": "It indicates rate limiting."},
    {"role": "user", "content": "How should my client retry?"}
  ]
}

Anthropic places the system instruction in the top-level system field rather than in a message with role: "system". That is one of the important differences to account for when translating requests from OpenAI-compatible schemas.

For long-running sessions, do not resend an unlimited transcript. Keep the latest turns, preserve decisions and tool results that still affect the task, and summarize older context before the prompt approaches the selected model’s context limit.

Streaming Responses

Set stream: true when the interface should display output incrementally:

import os

from anthropic import Anthropic

client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])

with client.messages.stream(
    model=os.environ["ANTHROPIC_MODEL"],
    max_tokens=1024,
    messages=[
        {"role": "user", "content": "Explain database connection pooling."}
    ],
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)

Streaming improves perceived latency, but it adds state-management work. Your application must handle a connection that closes early, partial text, event ordering, and final usage metadata. For tool-using agents, buffer the complete tool-input block before parsing or executing it.

Claude Vision API Requests

The Claude Vision API uses the same Messages endpoint. Add an image content block before the related text question. Images can be provided as supported base64 data or through an allowed source type described in the current vision documentation.

import base64
import os

from anthropic import Anthropic

client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])

with open("architecture.png", "rb") as image_file:
    image_data = base64.b64encode(image_file.read()).decode("utf-8")

message = client.messages.create(
    model=os.environ["ANTHROPIC_VISION_MODEL"],
    max_tokens=700,
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "image",
                    "source": {
                        "type": "base64",
                        "media_type": "image/png",
                        "data": image_data,
                    },
                },
                {
                    "type": "text",
                    "text": "Identify two reliability risks in this architecture diagram.",
                },
            ],
        }
    ],
)

Resize oversized images before sending them. Large images increase transfer time and token usage without necessarily improving the answer. Also validate the MIME type; declaring JPEG data as PNG is a common cause of rejected requests.

Anthropic Files API Usage

The Anthropic Files API is useful when a file should be uploaded once and referenced by later Messages API calls instead of being encoded and transmitted repeatedly. The exact availability, supported file types, and request fields can differ by feature status, so check the current Files API documentation before relying on it in production.

A typical integration has two stages:

  1. Upload the file and persist the returned file identifier with your application’s document record.
  2. Reference that identifier in a supported content block when creating a message.

Treat file IDs as provider-specific resources. Record which provider and account created each ID, apply your own access controls, and define a deletion policy. A file identifier should not be accepted directly from an untrusted user without authorization checks.

For occasional small images, base64 is straightforward. For documents used across many requests, a provider file resource can reduce repeated uploads. If your application must work across multiple providers, keep the original object in your own storage and create provider-specific file IDs as a cache.

Tool Use for Agent Backends

Tools allow Claude to request an application-defined function. Your backend describes each tool with a name, a purpose, and a JSON Schema input contract. The model can then return a tool_use block rather than pretending it executed the operation.

{
  "name": "get_order_status",
  "description": "Look up the current status of a customer order.",
  "input_schema": {
    "type": "object",
    "properties": {
      "order_id": {
        "type": "string",
        "description": "The order identifier shown to the customer."
      }
    },
    "required": ["order_id"]
  }
}

The safe execution loop is:

  1. Send messages and tool definitions to the model.
  2. Detect a tool_use content block.
  3. Validate its input against the schema and your authorization rules.
  4. Execute the tool in a controlled environment.
  5. Return a matching tool_result block in the next user turn.
  6. Continue until the model produces a normal answer or reaches your loop limit.

Never execute tool arguments as trusted shell, SQL, or file paths. For coding agents, run generated commands inside an isolated environment such as Novita Agent Sandbox, with explicit time, network, filesystem, and resource limits.

Anthropic-Native vs OpenAI-Compatible Requests

Anthropic-native and OpenAI-compatible APIs solve the same general problem, but their wire formats are not identical.

ConcernAnthropic Messages APIOpenAI-compatible chat API
Common endpoint/v1/messages/v1/chat/completions
System instructionTop-level system fieldCommonly a system or developer message
Output representationTyped content blocksCommonly choices[].message
Tool requesttool_use blockCommonly tool_calls
Tool resulttool_result content blockCommonly a tool role message

An OpenAI-compatible endpoint is valuable when your application already uses the OpenAI SDK or needs to switch among open-source models with minimal transport changes. Novita AI exposes an OpenAI-compatible LLM API, so the same client structure can target multiple available models by changing the base URL and model configuration.

import os

from openai import OpenAI

client = OpenAI(
    api_key=os.environ["NOVITA_API_KEY"],
    base_url="https://api.novita.ai/v3/openai",
)

response = client.chat.completions.create(
    model=os.environ["NOVITA_MODEL"],
    messages=[
        {
            "role": "user",
            "content": "Review this retry strategy for failure modes.",
        }
    ],
)

print(response.choices[0].message.content)

This is not a drop-in translation of every Anthropic feature. If your application depends on Anthropic-specific content blocks, tool semantics, citations, or beta features, keep an Anthropic-native adapter. Use the shared OpenAI-compatible path for workloads that fit its common request model.

Building a Provider-Neutral Agent Backend

A provider-neutral backend should normalize application concepts without pretending all providers are identical. A practical design has four layers:

  1. Conversation model: store roles, text, images, tool calls, and tool results in an internal schema.
  2. Provider adapter: translate the internal schema into Anthropic Messages or OpenAI-compatible payloads.
  3. Capability registry: track whether the selected model supports vision, tools, structured output, or other required behavior.
  4. Execution layer: run tools and code separately from the inference provider.

This separation lets a team use Claude where Anthropic-native behavior is important while routing compatible workloads to an open-source model through Novita AI. The open-source path can be useful for cost control, model experimentation, data-location requirements, or avoiding a single-provider dependency. Test output quality and tool reliability on your own tasks rather than assuming two models are interchangeable because both accept chat messages.

For agent workloads, the execution layer deserves equal attention. Model switching does not protect your infrastructure from unsafe commands. Use an isolated sandbox, enforce tool allowlists, cap iterations, and log each model decision and tool result with secrets removed.

Common Errors and Debugging

400 Bad Request

Check the JSON shape, content-block types, required fields, and whether the selected model supports the requested feature. Log the provider’s request ID and structured error body, but redact credentials and base64 file data.

401 Authentication Error

Confirm the API key is present in the runtime environment and belongs to the intended provider. Anthropic uses x-api-key for direct HTTP requests; an OpenAI-compatible client usually sends a bearer token automatically.

404 Model or Resource Not Found

Verify the model ID against the current provider documentation or console. For Files API resources, also verify that the file belongs to the same account and environment used by the request.

429 Rate Limit

Retry with exponential backoff and jitter, but cap the number of attempts. Queue background work, limit concurrency per provider, and avoid immediately retrying every failed request at the same interval.

Context or Token Limit Errors

Reduce conversation history, image size, file content, or requested output length. Count the entire request, including system instructions, tool schemas, prior tool results, and multimodal content.

Implementation Checklist

  • Keep API keys, model IDs, base URLs, and API versions in runtime configuration.
  • Parse typed content blocks instead of assuming a single text string.
  • Store enough conversation state to reconstruct each stateless request.
  • Validate tool inputs and execute them outside the model process.
  • Add timeouts, retry limits, request IDs, and redacted observability.
  • Gate provider routing by model capability, not just price or name.
  • Recheck model IDs, feature status, limits, and pricing before deployment.

The Messages API is straightforward at the HTTP layer. The harder engineering work appears when an application adds streaming, multimodal input, tools, persistent files, or multiple model providers. Keep those concerns behind explicit adapters, and your agent backend can evolve without tying business logic to one request format.

FAQ

What is the Anthropic Messages API endpoint?

The native endpoint is POST https://api.anthropic.com/v1/messages. Requests require authentication, an Anthropic API version header, a model ID, a token limit, and a messages array.

Is the Anthropic Messages API OpenAI-compatible?

No. The concepts overlap, but system prompts, content blocks, response objects, and tool-use messages differ. Use a provider adapter if one application needs to support both formats.

Does the Claude Vision API use a separate endpoint?

No. Vision requests use the Messages API with image and text content blocks. The selected Claude model must support image input.

When should I use the Anthropic Files API?

Use it when supported files need to be referenced across requests and repeated base64 uploads would be wasteful. Keep your own source file and authorization record because provider file IDs are account-specific resources.

Can Claude Code use a custom API backend?

Claude Code integration depends on the authentication and provider configuration supported by the current Claude Code release. Do not assume an OpenAI-compatible endpoint implements Anthropic’s Messages API. For a custom agent, a provider-neutral adapter is usually clearer than attempting to make different protocols appear identical.

When should I choose an open-source model through Novita AI?

Consider it when you want OpenAI-compatible model switching, open-model experimentation, or a second provider for compatible workloads. Keep Anthropic-native requests for features that require Claude-specific API behavior, and evaluate both paths on your own prompts and tools.