Behavry Integration — Anthropic API Proxy
For teams building custom Claude integrations using the Anthropic SDK directly (rather than Claude Code or Claude Desktop), Behavry can proxy all API calls for identity verification, policy enforcement, and audit logging.
How It Works
Your Code (anthropic SDK)
↓ ANTHROPIC_BASE_URL=http://localhost:8000/api/v1/anthropic
Behavry Proxy
↓ validates JWT | audits metadata | checks OPA policy
Anthropic API (api.anthropic.com)
↑ response streamed back
The proxy:
- Validates your Behavry agent JWT (
Authorization: Bearer <behavry-jwt>) - Extracts your Anthropic API key from
X-Anthropic-Keyheader (never logged) - Audits request metadata: model, system prompt presence (boolean only — not content), input/output tokens — not message content
- Forwards request to
https://api.anthropic.com/{path}with your key - Streams response back transparently
Prerequisites
- Behavry stack running (
make devordocker compose up) - A Behavry agent with
web:readandweb:writepermissions - Your Anthropic API key (
sk-ant-...)
Step 1 — Get a Behavry JWT
curl -s -X POST http://localhost:8000/api/v1/auth/token \
-H "Content-Type: application/json" \
-d '{"client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_SECRET", "grant_type": "client_credentials"}' \
| jq -r .access_token
Step 2 — Configure Your Code
Python (anthropic SDK)
import anthropic
BEHAVRY_JWT = "eyJhbGci..." # Behavry agent token
ANTHROPIC_KEY = "sk-ant-..." # your real Anthropic key
client = anthropic.Anthropic(
base_url="http://localhost:8000/api/v1/anthropic",
api_key=BEHAVRY_JWT, # Behavry validates this
default_headers={
"X-Anthropic-Key": ANTHROPIC_KEY, # forwarded to Anthropic, never logged
},
)
message = client.messages.create(
model="claude-opus-4-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello!"}],
)
print(message.content[0].text)
Environment Variables
export ANTHROPIC_BASE_URL=http://localhost:8000/api/v1/anthropic
export ANTHROPIC_API_KEY=<behavry-jwt>
export ANTHROPIC_REAL_KEY=sk-ant-...
import os
import anthropic
client = anthropic.Anthropic(
base_url=os.environ["ANTHROPIC_BASE_URL"],
api_key=os.environ["ANTHROPIC_API_KEY"],
default_headers={"X-Anthropic-Key": os.environ["ANTHROPIC_REAL_KEY"]},
)
LangChain
from langchain_anthropic import ChatAnthropic
llm = ChatAnthropic(
anthropic_api_url="http://localhost:8000/api/v1/anthropic",
anthropic_api_key=BEHAVRY_JWT,
model="claude-opus-4-5",
model_kwargs={"extra_headers": {"X-Anthropic-Key": ANTHROPIC_KEY}},
)
Step 3 — Verify
Make a request and check http://localhost:5173 → Live Activity.
You should see an event with:
tool_name:anthropic-apimcp_server:anthropic-proxyaction:POSTpolicy_result:allow
Audited Metadata
The proxy logs the following — message content and system prompt text are never stored:
| Field | Example |
|---|---|
| Model | claude-opus-4-5 |
| Has system prompt | true (boolean only) |
| Max tokens (requested) | 1024 |
| Input tokens (used) | 89 |
| Output tokens | 234 |
| Stop reason | end_turn |
anthropic-version Header
If your client doesn't set an anthropic-version header, the proxy defaults to 2023-06-01. You can override this in your SDK or by passing the header explicitly.
Policy Control
Example OPA policy to restrict model access:
package behavry.authz
# Only allow specific Claude models for API-level access
deny if {
input.mcp_server == "anthropic-proxy"
not startswith(input.model, "claude-3-")
not startswith(input.model, "claude-opus")
}
Streaming
Streaming (stream=True) is fully supported. The proxy passes SSE chunks through without buffering. Token counts are available from Anthropic's stream final message event when using stream_manager.
Difference from Claude Code / Claude Desktop
| Surface | Protocol | Setup |
|---|---|---|
| Claude Code CLI | MCP over HTTP | mcp_config.py --apply |
| Claude Desktop App | MCP over HTTP | mcp_config.py --apply-claude-desktop |
| Anthropic SDK (this guide) | Anthropic REST API proxy | ANTHROPIC_BASE_URL redirect |
All three produce audit events in the same dashboard — the difference is which monitoring surface applies.
Troubleshooting
401 from Behavry
JWT expired. Re-fetch using Step 1.
401 from Anthropic (passed through)
Your X-Anthropic-Key is invalid. Verify your Anthropic API key.
anthropic-version errors
The proxy sets a default version. If you need a different version, pass anthropic-version as a header in your SDK client.