Two values and you are done.
Shadr speaks the OpenAI chat API and the Anthropic Messages API. Keys start with shd_ and are shown once. Sign in with Privy using an email or wallet to create your account and first key. Manage keys and payments from your signed-in dashboard.
| Surface | Base URL |
|---|---|
| OpenAI-compatible | https://api.shadr.io/v1 |
| Anthropic-compatible | https://api.shadr.io/anthropic |
| Auth header | Authorization: Bearer shd_… |
curl
curl https://api.shadr.io/v1/chat/completions \
-H "Authorization: Bearer $SHADR_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"claude-sonnet-4.6","messages":[{"role":"user","content":"Hello"}],"stream":true}'Python
from openai import OpenAI client = OpenAI(api_key=SHADR_KEY, base_url="https://api.shadr.io/v1") r = client.chat.completions.create(model="gpt-5.5", messages=[{"role": "user", "content": "Hello"}]) print(r.choices[0].message.content)
JavaScript
import OpenAI from "openai";
const client = new OpenAI({ apiKey: process.env.SHADR_KEY, baseURL: "https://api.shadr.io/v1" });
const r = await client.chat.completions.create({ model: "deepseek-v4-pro", messages: [{ role: "user", content: "Hello" }] });Anthropic SDK users set baseURL to the Anthropic surface and pass the Shadr key as the auth token. Any model in the catalog works there, not only Claude.
Claude Code
Three variables. The third must be present and empty, or Claude Code prefers its cached key over yours.
export ANTHROPIC_BASE_URL="https://api.shadr.io/anthropic" export ANTHROPIC_AUTH_TOKEN="shd_your_key" export ANTHROPIC_API_KEY=""
Pin models if you want to control cost. Pin both slots or neither; the small slot handles the high-volume calls.
export ANTHROPIC_MODEL="claude-opus-4.8" export ANTHROPIC_SMALL_FAST_MODEL="claude-haiku-4.5" # or gpt-4o-mini
Non-Claude models answer but return no thinking blocks. Smaller models follow the tool protocol less reliably on long tasks.
Cursor, Aider, Continue, OpenCode
Each of these has an "OpenAI-compatible" provider setting. Enter the base URL and your key; the model field takes any catalog id.
| Tool | Where |
|---|---|
| Cursor | Settings › Models › OpenAI API key, then override the base URL with https://api.shadr.io/v1 |
| Aider | aider --openai-api-base https://api.shadr.io/v1 --model openai/claude-sonnet-4.6 with the key in OPENAI_API_KEY |
| Continue | Provider openai, apiBase set to the base URL |
| OpenCode | Provider openai with baseURL in opencode.json |
Models
The catalog is live. Ask for it rather than hard-coding ids.
curl https://api.shadr.io/v1/models -H "Authorization: Bearer $SHADR_KEY"
Ids are short and vendor-free: claude-opus-4.8, gpt-5.5, gemini-3.1-pro, deepseek-v4-pro, glm-4.7. Floating aliases such as claude-sonnet-latest and gpt-latest follow the newest release. Rates for the common ones are on the pricing page; everything else is priced at the same markup over its publisher's list.
Every request routes to a healthy provider for that model. If none is healthy you get a 503 with model_unavailable, never a silent substitution.
Budgets
Keys can carry a monthly ceiling in US dollars. Once spend plus pending reservations reaches it, new requests return 402 budget_exceeded until the next calendar month (UTC). A final request can exceed the remaining ceiling or balance; it is a limit on starting requests, not a guaranteed maximum charge.
Set a ceiling when issuing a key. On Pro and Sealed, use the dashboard to create or edit model and endpoint restrictions. Model IDs match exactly; include every alias your client sends. An endpoint allowlist must also include /v1/models if your client reads the catalog. Requests outside the policy return 403 key_restricted before reaching a provider.
Pay-as-you-go accounts have one live key. Existing restrictions remain enforced if a paid plan ends. Catalog responses contain model metadata and are not filtered by the model allowlist.
Usage and cost
Costs are in micro-dollars (1,000,000 = $1). Three places to read them:
| Where | What |
|---|---|
| x-shadr-cost-micro | Response header on non-streamed requests. The amount charged to your key. |
| x-shadr-request-id | Response header on every request. Quote it when you write to us. |
| GET /v1/usage | Account month-to-date spend and the last 100 requests with model, token counts and cost. Requires Privy sign-in. |
| GET /v1/account | Balance, plan and payment destination. Requires Privy sign-in. |
For streamed responses, send stream_options: {"include_usage": true} to get token counts in the final event, and read the charged cost from /v1/usage. Never infer a zero cost from a missing header.
curl https://api.shadr.io/v1/usage -H "Authorization: Bearer $PRIVY_ACCESS_TOKEN"
{ "month_spent_micro": 1834120,
"requests": [{ "id": "…", "model": "claude-sonnet-4.6", "cost_micro": 4212, "ts": 1792965983 }, …] }Funding
Sign in to your account, choose a USDC amount, and select Pay with wallet. Approve the payment through your connected or embedded Privy wallet on Base. Email users can create a payment wallet from the dashboard.
Or choose Add USDC to see your account's Base deposit address and send USDC on Base to it from any wallet or exchange. Only USDC on Base counts; it is credited six blocks after it lands. Paying from the wallet here needs ETH on Base for network fees.
Each payment transfers native USDC to the signed-in account's payment address. The gateway credits confirmed onchain funds; a submitted transaction is not yet a credited balance. The dashboard refreshes the balance automatically.
Plan credit arrives on your billing day and is spent before deposits. Requests are refused with 402 insufficient_credit when the balance reaches zero, so keep a buffer if you run agents unattended.
Limits
| Limit | Value |
|---|---|
| Requests per minute, per key | 300 on completion paths. Headers X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, and a Retry-After on 429. |
| Keys per account | 1, 25 or 200 by plan |
| Request body | 10 MB. Images and files go as URLs or base64 inside the body. |
| Sustained throughput | The same per-key limit applies to every plan. Contact us with expected volume if you need more. |
Errors
Branch on error.code. Messages are for humans and may change.
| Status | Code | Meaning |
|---|---|---|
| 401 | invalid_api_key | Missing, malformed or revoked key. With Claude Code, usually ANTHROPIC_API_KEY was not blanked. |
| 402 | insufficient_credit | Balance is empty. Sign in to the dashboard and pay with your wallet. |
| 402 | budget_exceeded | This key hit its ceiling. Funds remain. |
| 429 | rate_limit_exceeded | Back off for Retry-After seconds. |
| 503 | model_unavailable | No healthy provider for that model right now. Retry or pick another. |
Pro and Sealed include CSV export from the dashboard. Choose an inclusive UTC date range of up to 31 days. Exports contain request IDs, key IDs, models, endpoints, status, token counts, cost in micro-USD and Unix timestamps. No prompts or completions. If the range exceeds 10,000 requests, choose a shorter range; exports are never silently truncated.
What we store.
- Key id and account id
- Model and endpoint
- Input and output token counts
- Cost and timestamp
- Request id
- Prompts, system prompts, tool arguments
- Completions and tool results
- Your IP address
- User agent and client headers
Our gateway handles request bodies in memory and does not log or retain prompts and completions. Account and billing records are retained. Providers apply their own policies to the requests they receive.
What a provider sees
Requests use shared gateway credentials on every plan. We do not forward your Shadr key, login identity or client IP headers. We forward the request body and the protocol headers needed for inference. Information you include in the body can still identify you; secret masking does not remove all personal data.
Providers apply their own retention policies to the bodies they receive. Sealed accounts can restrict text requests to selected providers. This is routing control, not an independent privacy audit. See Providers.
Images and embeddings
The gateway supports image generation and embeddings. These requests are sent without text secret masking. Provider-restricted keys reject these endpoints because the network cannot enforce the provider selection there. Video, audio and asynchronous job APIs are not exposed by this gateway.
Payments
Account access uses Privy. We store your Privy user id to associate your account, keys and balance; your login identity is not forwarded to model providers. Wallet payments are public onchain. Pay with your connected or embedded Ethereum wallet, or use Add USDC to see your account's Base deposit address and send USDC from a wallet or exchange.
Secret masking
On every plan, our gateway requests secret masking from the model network for supported text endpoints. Recognised credentials can be replaced with placeholders before model inference and restored in the reply. This is not a guarantee that every secret will be detected or that every provider will apply masking.
Recognised
- API keys with known prefixes (OpenAI, Anthropic, GitHub, Stripe and others), AWS access key ids, JWTs
- PEM and WIF private keys, 12 to 25 word seed phrases
- Passwords, tokens and secrets in assignments, config, headers, connection strings and login shapes
Scanned fields: messages and history, system and developer instructions, tool descriptions, tool calls and results.
Not covered
- Personal data such as emails, names and phone numbers
- Content inside images, PDFs, audio or files
- Embeddings and media endpoints, which are sent as-is
- A secret the model is told to run or fetch: if a tool executes with a placeholder, the real value can reach whatever that tool calls
- A password repeated later with no identifying context
Text responses carry x-shadr-masking. A value of not_applied means masking was not applied. Image and embedding responses do not carry this header. Do not rely on masking to catch every secret.
Providers
The model network routes requests across model publishers, hosting providers and aggregators. We do not offer dedicated upstream accounts or an independently audited provider list. Review the policies of the providers you choose.
On Sealed, enable Restrict providers when creating or editing a key and choose from the current provider list. This applies to chat completions, completions, responses and Anthropic messages. A request can select a narrower set using provider, but cannot broaden the key's allowlist. A provider restriction does not guarantee that a model is available there; requests may fail when no selected provider serves it.
Security questions and disclosures: security@shadr.io.