Anthropic SDK#

Base URL: http://127.0.0.1:8787/anthropic. Do not add /v1: the SDK adds /v1/messages itself. You can also set it with ANTHROPIC_BASE_URL.

Connect#

import anthropic

client = anthropic.Anthropic(
    base_url="http://127.0.0.1:8787/anthropic",
    # api_key defaults to ANTHROPIC_API_KEY; on a team server, pass your lp_... key
    default_headers={
        "X-Lockpin-Task": "fix-login-bug",
        "X-Lockpin-Budget-Usd": "0.50",
    },
)
msg = client.messages.create(
    model="claude-sonnet-5-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Fix the login bug"}],
)

To name the task per call instead of per client:

client.messages.create(..., extra_headers={"X-Lockpin-Task": "summarise-logs"})
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic({
  baseURL: "http://127.0.0.1:8787/anthropic",
  // apiKey defaults to ANTHROPIC_API_KEY; on a team server, pass your lp_... key
  defaultHeaders: { "X-Lockpin-Task": "fix-login-bug", "X-Lockpin-Budget-Usd": "0.50" },
});

The SDK sends the key as x-api-key. A Lockpin team server reads an lp_... key from that header, so nothing else changes on a team server.

The two headers:

Header

What it does

X-Lockpin-Task

Names the task. Calls with the same name share one budget.

X-Lockpin-Budget-Usd

The task’s budget in USD. It can only lower the budget below -default-budget.

Lockpin removes every X-Lockpin-* header before the call goes to Anthropic. See Budgets and tasks for the other headers.

Prompt cache#

Anthropic caches nothing unless a call asks for it. When a task’s previous call was less than 5 minutes ago, Lockpin adds the cache marker to calls that have none, and the reply carries X-Lockpin-Cache-Marker: added. -auto-cache-marker=false turns this off.

When the cap hits#

The SDK raises an error with status 402 and does not retry it. In Python it is anthropic.APIStatusError; in TypeScript it is Anthropic.APIError with status === 402. The response body has error.type == "budget_exceeded" and a lockpin object with the numbers:

try:
    msg = client.messages.create(...)
except anthropic.APIStatusError as e:
    if e.status_code == 402:      # budget reached: wrap up with what you have
        print(e.response.json()["lockpin"])   # {'task': ..., 'spent_usd': ..., 'budget_usd': ...}
        return partial_result
    raise

The call never reached Anthropic, so it cost nothing.

Models#

A model with no price is refused with HTTP 400 unknown_model. lockpin providers -models lists the priced ones. To add one, see Prices.

Verify#

After one call, the meter shows it under the task you named. Non-streaming replies carry X-Lockpin-Cost-Usd, X-Lockpin-Spent-Usd and X-Lockpin-Remaining-Usd.