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 |
Authorization: Bearer inf_xxxSet via · ANTHROPIC_AUTH_TOKENNotes · What Claude Code usesx-api-key: inf_xxxSet via · ANTHROPIC_API_KEYNotes · The Anthropic SDK defaultAlways 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 402 challenges - Claude Code can't satisfy them; use a buyer key with credits).
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 |
/anthropic/v1/messagesDescription · Send a message; non-streaming or streaming (SSE)/anthropic/min{N}/v1/messagesDescription · Same, but only route to sellers ≥ N% cheaper than reference/anthropic/v1/messages/count_tokensDescription · Estimate input tokens for a request/anthropic/v1/modelsDescription · List models (Anthropic shape)/anthropic/v1/models/{id}Description · Retrieve one modelSend a Message
Parameters
modelrequiredAny catalog model (canonical,-latestalias, dated Anthropic ID, or~anthropic/…)max_tokensrequiredMaximum output tokens (required by the Anthropic API)messagesrequiredArray of messages;contentis a string or content blocks (text, image, tool_use, tool_result, thinking)systemSystem prompt - a string, or an array of text blocks (withcache_control)temperature, top_p, top_kSampling controlsstop_sequencesCustom stop sequencesstreamtruefor SSE streamingtoolsTool definitions (name,description,input_schema)tool_choiceauto/any/{type:"tool",name}/nonethinking{type:"enabled", budget_tokens}(oradaptive) - extended thinkingmetadata{user_id}- passed through as the OpenAIuserfieldproviderProvider pin / allow-list - a string,string[], or the OpenRouter{order|only:[...]}objectprovider_base_urlPin to a specific provider host (matched against the marketplace allowlist)providers_blockedProviders to refuse - a string orstring[], matched on family or host. The deny-list counterpart ofprovider. An unreadable value is refused with400, never silently ignored. See Routing Controlsprovider_orderPreferred attempt order by provider, most-preferred first. Ordering only, never eligibility. See Routing Controlsmin_discount_pctMinimum discount (0-100) below the go-direct reference price - offers under it are excluded. Also settable per key, or via theX-Min-Discountheader.
Request and version/beta headers (anthropic-version, anthropic-beta) are accepted; version/beta are tolerated and ignored (never required).
The non-streaming response is a standard Anthropic Message. 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).
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!"}] }'
{
"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}
}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
Count Tokens
Returns an estimate (includes the system prompt and tool schemas). This is a heuristic estimate (no upstream round-trip); it is sufficient for context-budget sizing.
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"}]}'
{ "input_tokens": 14 }List 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 |
error.type · invalid_request_errorWhen · Bad request / malformed JSON / out-of-crediterror.type · authentication_errorWhen · Missing or invalid buyer keyerror.type · not_found_errorWhen · Unknown model id, or no sellers under your price thresholderror.type · rate_limit_errorWhen · Rate limitederror.type · request_too_largeWhen · Body exceeds the size limiterror.type · api_error / overloaded_errorWhen · Upstream/provider error, or no healthy sellersThere is no Anthropic 402 - an out-of-credit buyer gets a 400 invalid_request_error (mirroring Anthropic's "credit balance too low" behavior).
A long-running non-streaming request is the exception to this table: its status is committed before the outcome
is known, so it always returns 200 with the Anthropic error envelope in the body. Branch on type: "error" in the
body rather than on the status alone. See
Long-running responses.
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, the minimum-discount floor (per key, X-Min-Discount, or the /anthropic/min{N}/v1/messages mirror), and the buyer's trusted-only / allow-untrusted preference. See Minimum-Discount Routing and BYOK / Priority Provider.