Anthropic Messages API ("Anthropic Skin")
> For Claude Code / Anthropic SDK users: see the step-by-step Claude Code Setup guide.
Surplus speaks Anthropic's Messages API natively, so tools built for Anthropic — Claude Code and the Anthropic Agent SDK — can route through the marketplace with nothing but environment variables. No local proxy, no client-side translation.
This is the same idea as OpenRouter's "Anthropic skin": point the Anthropic client's base URL at Surplus, authenticate with a Surplus buyer key, and every request is routed to the cheapest healthy seller and settled on-chain like any other marketplace call.
It is model-agnostic. Routing is by the model string, not by family — so you can run Claude Code on Claude or GPT, GLM, Llama, Gemini, DeepSeek, or any other catalog model, all through the Anthropic wire.
Base URL
https://api.surplusintelligence.ai/anthropic
This is what you set as ANTHROPIC_BASE_URL. The Anthropic client appends /v1/messages (and the other paths below) to it. The skin lives under a dedicated /anthropic prefix so it never collides with the OpenAI-compatible surface at /v1/....
Authentication
Use a Surplus buyer API key (inf_…), sent either way the Anthropic ecosystem sends it:
| Header | Set via | Notes |
|---|---|---|
Authorization: Bearer inf_xxx | ANTHROPIC_AUTH_TOKEN | What Claude Code uses |
x-api-key: inf_xxx | ANTHROPIC_API_KEY | The Anthropic SDK default |
Always set ANTHROPIC_API_KEY="" when using ANTHROPIC_AUTH_TOKEN, or the cached Anthropic credential can take precedence. An unauthenticated or non-buyer request returns an Anthropic-shaped 401 authentication_error (the skin does not issue x402/MPP 402 challenges — Claude Code can't satisfy them; use a buyer key with credits or an on-chain allowance).
Endpoints (under /anthropic)
| Method | Path | Description |
|---|---|---|
| POST | /anthropic/v1/messages | Send a message; non-streaming or streaming (SSE) |
| POST | /anthropic/min{N}/v1/messages | Same, but only route to sellers ≥ N% cheaper than reference |
| POST | /anthropic/v1/messages/count_tokens | Estimate input tokens for a request |
| GET | /anthropic/v1/models | List models (Anthropic shape) |
| GET | /anthropic/v1/models/{id} | Retrieve one model |
POST /anthropic/v1/messages
curl https://api.surplusintelligence.ai/anthropic/v1/messages \
-H "x-api-key: inf_xxx" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-opus-4.8",
"max_tokens": 1024,
"system": "You are concise.",
"messages": [{"role": "user", "content": "Hello!"}]
}'
Parameters
| Parameter | Required | Description | |
|---|---|---|---|
model | Yes | Any catalog model (canonical, -latest alias, dated Anthropic ID, or ~anthropic/…) | |
max_tokens | Yes | Maximum output tokens (required by the Anthropic API) | |
messages | Yes | Array of messages; content is a string or content blocks (text, image, tool_use, tool_result, thinking) | |
system | No | System prompt — a string, or an array of text blocks (with cache_control) | |
temperature, top_p, top_k | No | Sampling controls | |
stop_sequences | No | Custom stop sequences | |
stream | No | true for SSE streaming | |
tools | No | Tool definitions (name, description, input_schema) | |
tool_choice | No | auto / any / {type:"tool",name} / none | |
thinking | No | {type:"enabled", budget_tokens} (or adaptive) — extended thinking | |
metadata | No | {user_id} — passed through as the OpenAI user field | |
provider | No | Provider pin / allow-list — a string, string[], or the OpenRouter {order | only:[...]} object |
provider_base_url | No | Pin to a specific provider host (matched against the marketplace allowlist) | |
max_price_per_1m | No | Price cap in USD per 1M input tokens — offers above it are excluded |
Request and version/beta headers (anthropic-version, anthropic-beta) are accepted; version/beta are tolerated and ignored (never required).
Response (non-streaming)
A standard Anthropic Message:
{
"id": "msg_…",
"type": "message",
"role": "assistant",
"model": "claude-opus-4.8",
"content": [{"type": "text", "text": "Hello!"}],
"stop_reason": "end_turn",
"stop_sequence": null,
"usage": {"input_tokens": 12, "output_tokens": 3}
}
content blocks may be text, tool_use, or thinking. stop_reason is tool_use if and only if a tool_use block is present. usage.input_tokens is net of cache (cache_read_input_tokens / cache_creation_input_tokens are reported separately when the provider supplies them).
Streaming
With "stream": true, the response is the standard Anthropic SSE event sequence:
event: message_start → the Message skeleton
event: content_block_start → per content block (text / thinking / tool_use)
event: content_block_delta → text_delta / thinking_delta / signature_delta / input_json_delta
event: content_block_stop
event: message_delta → stop_reason + cumulative usage
event: message_stop
POST /anthropic/v1/messages/count_tokens
curl https://api.surplusintelligence.ai/anthropic/v1/messages/count_tokens \
-H "x-api-key: inf_xxx" -H "Content-Type: application/json" \
-d '{"model":"claude-opus-4.8","messages":[{"role":"user","content":"Hello"}]}'
Returns an estimate (includes the system prompt and tool schemas):
{ "input_tokens": 14 }
This is a heuristic estimate (no upstream round-trip); it is sufficient for context-budget sizing.
GET /anthropic/v1/models
Anthropic-shaped model list, served from the Surplus catalog (lists all marketplace models, not just Claude):
{
"data": [{"id": "claude-opus-4.8", "type": "model", "display_name": "Claude Opus 4.8", "created_at": "2025-01-01T00:00:00.000Z"}],
"has_more": false,
"first_id": "…",
"last_id": "…"
}
Errors
Errors on /anthropic/* use the Anthropic envelope:
{ "type": "error", "error": { "type": "invalid_request_error", "message": "…" }, "request_id": "…" }
| HTTP | error.type | When |
|---|---|---|
| 400 | invalid_request_error | Bad request / malformed JSON / out-of-credit |
| 401 | authentication_error | Missing or invalid buyer key |
| 404 | not_found_error | Unknown model id, or no sellers under your price threshold |
| 429 | rate_limit_error | Rate limited |
| 413 | request_too_large | Body exceeds the size limit |
| 5xx | api_error / overloaded_error | Upstream/provider error, or no healthy sellers |
There is no Anthropic 402 — an out-of-credit buyer gets a 400 invalid_request_error (mirroring Anthropic's "credit balance too low" behavior).
Model names & aliases
Send any catalog model id. The skin additionally resolves:
-latesttags:claude-opus-latest,claude-sonnet-latest,claude-haiku-latest, plus cross-familygpt-latest,glm-latest,deepseek-latest,gemini-latest, and more.- Dated Anthropic IDs (e.g.
claude-sonnet-4-5-20250929) → canonical. - The OpenRouter
~anthropic/…floating-tag prefix.
A model must exist in the catalog and have a healthy offer to route; otherwise you get an Anthropic-shaped 404/overloaded_error. Call GET /anthropic/v1/models for the catalog and GET /api/markets for models with live seller liquidity.
Feature fidelity on non-Claude models
The wire is fully translated, but some Anthropic features are model-dependent:
- Works on every model: text, system prompt, multi-turn, streaming, tool use (
tool_use/tool_result), images, stop reasons, usage/billing. - Best-effort: extended thinking — non-Claude models don't emit Anthropic
thinkingblocks; the field is accepted and the request still works, but no reasoning blocks are returned. Thinking-signature continuity across multi-turn tool loops is preserved on providers that echo signatures and degrades gracefully elsewhere.
Routing controls
Everything the marketplace offers applies here too: provider pinning / allow-lists, provider_base_url, max_price_per_1m price caps, the /anthropic/min{N}/v1/messages minimum-discount mirror, and the buyer's trusted-only / allow-untrusted preference. See Minimum-Discount Routing and BYOK / Priority Provider.