Claude proxy
A transparent passthrough proxy to the Anthropic Claude API at https://ai.hep.gg/anthropic/<proxy_token>/..., so Claude Code calls can be metered and analyzed. You supply your own Anthropic key.
Claude proxy
The Claude proxy is a transparent reverse proxy in front of the Anthropic API. You send a normal Anthropic request to https://ai.hep.gg/anthropic/<proxy_token>/... and everything after the proxy token is forwarded verbatim to https://api.anthropic.com. The point is metering and analytics: each call is logged (token usage, stop reason, tool names) against the machine that owns the proxy token. This is what ccas points Claude Code at.
How auth works here
This endpoint uses two credentials at once, and they belong to different parties:
- The
pt_proxy token sits in the URL path as the first segment. It identifies your machine to the gateway. Get one from POST /sync/machines (or letccas initdo it). It is matched against your registered machines. - Your own Anthropic credentials (the
x-api-keyheader,anthropic-version, and so on) ride in the request as usual and are forwarded to Anthropic unchanged. The gateway does not supply an Anthropic key for you.
An unknown proxy token returns 401 in Anthropic's error shape:
{ "type": "error", "error": { "type": "authentication_error", "message": "Unknown proxy token" } }https://ai.hep.gg/anthropic/{proxy_token}/v1/messagesAuth requiredThe proxy accepts any HTTP method. The path shown is the common case (the Messages API), but anything after /{proxy_token}/ is forwarded as-is, so /anthropic/{proxy_token}/v1/messages, /anthropic/{proxy_token}/v1/models, and any other Anthropic path all work. Query strings are preserved. The raw body is forwarded as bytes up to 32 MB with no JSON re-encoding.
proxy_tokenpt_ proxy token. First path segment.Headers are forwarded except host, content-length, connection, and accept-encoding. The x-session-id header (or metadata.userID in the body) is captured for analytics grouping. The response is Anthropic's, passed through with its status and headers (minus content-length, connection, transfer-encoding, and content-encoding). Streaming SSE is piped through and parsed for usage (input, output, cache_creation, cache_read tokens), stop_reason, and any tool_use names.
If Anthropic is unreachable, the proxy returns 502 in the Anthropic error shape:
{ "type": "error", "error": { "type": "upstream_error", "message": "Upstream unreachable" } }Example
Construct the URL by prefixing your normal Anthropic call with https://ai.hep.gg/anthropic/<proxy_token>. Send your Anthropic key exactly as you would to api.anthropic.com.
curl https://ai.hep.gg/anthropic/$PROXY_TOKEN/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-3-5-sonnet-latest",
"max_tokens": 256,
"messages": [{ "role": "user", "content": "Hello, Claude." }]
}'const proxyToken = process.env.PROXY_TOKEN; // pt_...
const res = await fetch(
`https://ai.hep.gg/anthropic/${proxyToken}/v1/messages`,
{
method: "POST",
headers: {
"x-api-key": process.env.ANTHROPIC_API_KEY,
"anthropic-version": "2023-06-01",
"content-type": "application/json",
},
body: JSON.stringify({
model: "claude-3-5-sonnet-latest",
max_tokens: 256,
messages: [{ role: "user", content: "Hello, Claude." }],
}),
},
);
console.log(await res.json());Using it with the Anthropic SDK
Point the SDK's base URL at the proxy prefix (including your proxy token) and pass your real Anthropic key. The SDK appends /v1/messages to the base URL.
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
baseURL: `https://ai.hep.gg/anthropic/${process.env.PROXY_TOKEN}`,
});
const msg = await client.messages.create({
model: "claude-3-5-sonnet-latest",
max_tokens: 256,
messages: [{ role: "user", content: "Hello, Claude." }],
});
console.log(msg);