# ThinCompute

> The verified inference exchange. One API key, OpenAI- and Anthropic-compatible. Each call routes to the cheapest offer that passes Proof-of-Model verification and returns an Ed25519-signed receipt.

Base URL: http://localhost:8787

## Auth
- API keys look like `sk-thin-…`. Send `Authorization: Bearer <key>` or `x-api-key: <key>`.

## Inference
- `POST /v1/chat/completions` — OpenAI Chat Completions (stream, tools, images). Response adds a `thin` object: request_id, offer_id, seller, region, verification, attempts, rescued, hedged, cache, masked, usage, cost_micro, list_cost_micro, savings_micro, receipt.
- `POST /anthropic/v1/messages`, `POST /anthropic/v1/messages/count_tokens` — Anthropic Messages. Claude Code: ANTHROPIC_BASE_URL=http://localhost:8787/anthropic, ANTHROPIC_AUTH_TOKEN=sk-thin-…, ANTHROPIC_MODEL=<model id>.
- `POST /v1/route/preview` — dry-run the routing decision (eligible + rejected offers) without calling upstream.
- `GET /v1/models` — models with live offers (`?all=1` for the full catalog).
- `GET /v1/balance`, `GET /v1/requests`, `GET /v1/requests/{id}`.

- `POST /v1/responses` — stateless Responses adapter: text/image inputs, function tools, JSON formats, SSE; store:false. No hosted tools, background jobs, or response persistence.
- `GET /v1/media/offers` — schema-probed media listings and explicit billing units. Requires thin.verification:"probed"; chat verification is not implied.
- `POST /v1/embeddings` (per request), `POST /v1/images/generations` (per image), `POST /v1/audio/speech` (per 1,000 Unicode characters), `POST /v1/audio/transcriptions` (multipart, per request). All media accepts max_cost_micro. See /docs/protocols for limits.

## Units
- Money is integer microdollars in fields ending `_micro` (1 USD = 1,000,000). Chat prices are per 1M tokens; media offers specify their billing unit.

## Routing policy (only ever tightens; unknown tokens fail closed with 400)
1. Key policy (dashboard)
2. Policy path: `/p/{tokens}/v1/...`, tokens joined by `+`: min{N}, zdr, tee, eu|us|apac, verified, probed, fast, cheap, reliable, value, mask, cache, hedge{ms}, max{usd}. Example: http://localhost:8787/p/min60+zdr+eu+verified/v1
3. Headers: X-Thin-Min-Discount, X-Thin-Objective, X-Thin-Region, X-Thin-ZDR, X-Thin-Verification, X-Thin-Mask, X-Thin-Cache, X-Thin-Hedge-Ms, X-Thin-Max-Output-Price
4. Body: `"thin": { objective, price_tolerance_pct, min_discount, max_input_price_micro, max_output_price_micro, verification, zdr, tee, regions, sellers, sellers_blocked, max_latency_ms, hedge_after_ms, mask, cache, cache_ttl_s, rescue, max_attempts }`
Defaults: objective price, verification verified, rescue true, max_attempts 3.

## Spending
Maximum charges are atomically reserved before upstream work. Active holds count against balances and key budgets. Omitted chat output limits default to 4096 tokens. GET /v1/balance includes available_micro and reserved_micro.

## Limit batches
- `POST /v1/batches` { model, requests:[{custom_id, body}], limit:{max_input_price_micro, max_output_price_micro, min_discount}, deadline, on_deadline: expire|market }
- `GET /v1/batches`, `GET /v1/batches/{id}`, `GET /v1/batches/{id}/results`, `POST /v1/batches/{id}/cancel`

## Price locks
- `GET /v1/market/locks`, `POST /v1/locks/{lock_id}/purchase` { amount_micro }, `GET /v1/holdings`

## Receipts
- `GET /.well-known/thin-receipts.json` (Ed25519 JWKS), `GET /v1/receipts/{id}`, `POST /v1/receipts/verify`

## Market data (public)
- `GET /v1/market/stats`, `GET /v1/market`, `GET /v1/market/{model}`, `GET /v1/catalog`

## Errors
OpenAI envelope `{"error":{"message","type","code"}}`. Branch on code: invalid_request, unauthorized, forbidden, not_found, insufficient_balance, budget_exceeded, key_frozen, no_offers_for_model, no_eligible_offers, upstream_failed, rate_limited, not_configured, conflict. Failed requests are never charged.
