Caesar uses standard Bearer authentication. If you have a partner key, set it in the Authorization header:
curl -s https://search-api-staging-779189860552.europe-west1.run.app/v1/search \
-H "Authorization: Bearer $CAESAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "rust async runtime comparison", "max_results": 3}'
Drop the Authorization header and the same call still works — anonymously, at a lower rate limit. You do not need a key to evaluate Caesar.
Anonymous tier vs API keys
| Anonymous | API key |
|---|
| Setup | none | restricted to partners |
| Rate limit | 30 requests/second per client IP | per-key limit, default 100 requests/second |
access.tier in responses | anonymous | api_key |
| Search and feedback attribution | none | recorded to your account |
Document access by doc_id | any document | account-granted documents |
A key changes three things:
- A higher, dedicated rate limit. Keyed requests are counted per key, not per IP — your limit is yours regardless of where you call from. See rate limits.
- Account-scoped attribution. Keyed searches are recorded to your account, and
/v1/feedback referencing a search_id or doc_id is checked against that ownership. Your feedback provably belongs to your searches.
- Document grants. For keyed callers,
/v1/document lookups by doc_id resolve documents your account has been granted — by appearing in your search results or by a prior direct canonical_url lookup. Anonymous callers skip ownership checks entirely.
Keys start with sk_live_, followed by a 12-character key_prefix and a longer secret. The key_prefix is not secret — it is safe to display in dashboards and logs to identify a key. The full key is returned exactly once at creation and stored only as a hash; it cannot be retrieved again.
Scopes
| Scope | Grants |
|---|
search:read | POST /v1/search |
document:read | POST /v1/document |
feedback:write | POST /v1/feedback |
New keys get all three scopes by default. Calling an endpoint your key lacks the scope for returns 403:
{
"type": "error",
"request_id": "ee314ccd-dbcd-418f-9c6a-f2917c599c67",
"error": { "code": "insufficient_scope", "message": "API key is not allowed to call this endpoint" }
}
Getting a key
API keys are currently restricted to partners. Use anonymous access unless the Caesar team has issued you a partner key.
Invalid keys never fall back to anonymous
If a Bearer token is present, it is always validated. A malformed, unknown, expired, or revoked key returns 401 invalid_api_key — even on deployments where anonymous access is enabled. There is no silent downgrade:
{
"type": "error",
"request_id": "ee314ccd-dbcd-418f-9c6a-f2917c599c67",
"error": { "code": "invalid_api_key", "message": "missing or invalid API key" }
}
To call anonymously on purpose, omit the Authorization header entirely.
One environment variable everywhere
Every first-party client reads CAESAR_API_KEY:
# set in your shell profile, or inject it from your secret manager
export CAESAR_API_KEY="$(your-secret-manager get caesar-api-key)"
The Python SDK and TypeScript SDK pick it up automatically in their constructors, the CLI resolves it after the --key flag, and the MCP server accepts it as a Bearer header. If the variable is unset, all of them run anonymously.
Client attribution: X-Caesar-Client
First-party clients send an attribution header of the form X-Caesar-Client: cli/0.1.4 (or python-sdk/0.1.1, ts-sdk/0.1.1). It is a convention, not a contract: the server does not validate or act on it. If you build on the raw API, sending X-Caesar-Client: yourtool/1.2.3 is encouraged because it helps the Caesar team understand client traffic.
Key hygiene
Never paste an API key into a chat, an issue, or a commit. Keys belong in CAESAR_API_KEY or your secret manager. The CLI stores keys safely via caesar-search auth login (use --key - to pipe from a secret manager), and masks them in all output. If a key leaks, contact the Caesar team to revoke it — the key itself cannot be recovered or rotated in place.