Skip to content

Messages API (Anthropic)

The server exposes POST /v1/messages — an Anthropic-compatible endpoint that applies your Mend guardrail policy before and after calling the upstream Claude model. Point the Anthropic SDK at the server with a single base_url change.

The endpoint requires the anthropic extra on the server:

pip install 'mend-guardrails[anthropic]'

Request format

The request body is the standard Anthropic Messages payload with one additional field: a guardrails object that selects the policy to apply.

{
  "model": "claude-3-5-sonnet-latest",
  "max_tokens": 1024,
  "system": "You are a helpful assistant.",
  "messages": [
    {"role": "user", "content": "Hello!"}
  ],
  "guardrails": {
    "config_id": "strict"
  }
}

guardrails object

Field Type Required Description
config_id string No (in api policy-source mode, always optional; in local mode, required unless MEND_GUARDRAILS_DEFAULT_CONFIG_ID is set) Policy ID to apply.

Standard Anthropic fields forwarded to upstream

Field Type Description
model string Claude model name (e.g. claude-3-5-sonnet-latest).
max_tokens integer Required. Maximum tokens to generate.
messages array Conversation history in Anthropic message format.
system string \| array Top-level system prompt.
temperature number Sampling temperature.
top_p / top_k number / integer Sampling parameters.
stop_sequences array Custom stop sequences.
tools / tool_choice array / object Tool-use definitions.
metadata object Opaque metadata forwarded to Anthropic.

Any other fields are forwarded to the upstream provider unchanged.

Default Anthropic headers

POST /v1/messages always forwards these inbound headers to upstream when present, even if MEND_GUARDRAILS_FORWARD_HEADERS is unset:

Header Why
x-api-key Anthropic API key (including a Docker Sandboxes sentinel).
anthropic-version Required by the Anthropic API.
anthropic-beta Claude Code / 1M-context and other beta features.
Authorization Bearer tokens, when sent.

Additional names can still be allowlisted with MEND_GUARDRAILS_FORWARD_HEADERS.

Streaming

Set "stream": true to receive an Anthropic Server-Sent Events (SSE) response with native event: frames (message_start, content_block_delta, …). Guardrails still run on both input and output. If an output-stage guardrail fires mid-stream, a terminal event: error frame with type guardrail_enforcement_triggered is emitted.


Upstream configuration

The /v1/messages route always builds an Anthropic upstream client. When no models config entry matches the request's model, the server uses the global environment fallback:

Variable Description
ANTHROPIC_API_KEY API key for the upstream Anthropic provider.
ANTHROPIC_BASE_URL Base URL of the upstream (defaults to Anthropic's API).

LLM-based guardrails (e.g. Jailbreak) run on an OpenAI-compatible guardrail_llm, so OPENAI_API_KEY may also be required on the server when your policy contains such guardrails.

To route a model explicitly, add an entry with "provider": "anthropic" to your models config:

[
  {
    "name": "claude-3-5-sonnet-latest",
    "provider": "anthropic",
    "parameters": {
      "base_url": "https://api.anthropic.com",
      "api_key": "sk-ant-..."
    }
  }
]

Response format

On success the response is a standard Anthropic Message object:

{
  "id": "msg_abc123",
  "type": "message",
  "role": "assistant",
  "model": "claude-3-5-sonnet-latest",
  "content": [{"type": "text", "text": "Hello! How can I help you today?"}],
  "stop_reason": "end_turn",
  "usage": {"input_tokens": 20, "output_tokens": 10}
}

Enforcement responses

When a guardrail blocks a request the server returns HTTP 400:

{
  "detail": {
    "error": "guardrail_enforcement_triggered",
    "message": "Guardrail PromptInjection triggered enforcement",
    "guardrail": "PromptInjection"
  }
}

The upstream LLM is never called when an input-stage guardrail blocks the request.

HTTP status codes

Code Meaning
200 Successful completion; guardrails passed.
400 A guardrail blocked the request or response, or the upstream provider rejected the payload.
422 Invalid request — no config_id and no default configured, the model is routed to a non-Anthropic provider, the anthropic package is not installed, or the SDK rejected a request keyword. Sampling fields (temperature, top_p, top_k) and unknown Claude Code extras are forwarded via extra_body when the SDK signature omits them.
502 / 504 Upstream provider unreachable or timed out.
500 Unexpected internal error.

Examples

curl

curl -X POST http://localhost:8000/v1/messages \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ANTHROPIC_API_KEY" \
  -d '{
    "model": "claude-3-5-sonnet-latest",
    "max_tokens": 1024,
    "messages": [{"role": "user", "content": "Hello!"}],
    "guardrails": {"config_id": "default"}
  }'

Anthropic Python SDK

Because the server speaks the native Messages API, point the official SDK at it with a single base_url change:

from anthropic import Anthropic

client = Anthropic(
    base_url="http://localhost:8000",  # the guardrail server (SDK appends /v1/messages)
    api_key="any",  # forwarded as-is to the upstream
)

response = client.messages.create(
    model="claude-3-5-sonnet-latest",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello!"}],
    extra_body={"guardrails": {"config_id": "default"}},
)
print(response.content[0].text)

For server-side upstream configuration — provider selection, custom headers and query parameters, and model routing — see Configure the upstream provider.