cURL
Base URL and spec
| Base URL | https://search-api-staging-779189860552.europe-west1.run.app |
| OpenAPI spec | GET /openapi/public.json — stable, machine-readable, served unauthenticated |
Authentication
Bearer tokens are optional: sendAuthorization: Bearer $CAESAR_API_KEY for keyed access (100 requests/second, account-level attribution), or send nothing and run as the anonymous tier (30 requests/second per IP). If a token is present it is always validated — a bad key returns 401 invalid_api_key rather than falling back to anonymous. See Authentication.
Conventions
| Convention | Detail |
|---|---|
| JSON only | Requests and responses are application/json. Bodies must be a single JSON object; unknown fields are rejected with 400 validation_error; max body size is 1 MiB. |
| snake_case | All field names are snake_case (doc_id, max_results, canonical_url) — exactly as the API returns them. |
| UUIDs everywhere | Every identifier (request_id, search_id, session_id, doc_id, passage_id, capture_id, feedback_id) is a plain UUID string. |
request_id | Every response — success or error — carries one. Quote it when reporting an issue. |
session_id | If you do not supply one (session_id body field on /v1/search and /v1/feedback; the X-Session-ID header on any endpoint — /v1/document accepts only the header), the server issues a fresh UUID per request and echoes it. Pass it back on later calls for continuity. See Sessions. |
access block | Success responses include your tier and live rate-limit state. |
usage block | Success responses include requests, bytes_returned, and approx_tokens — a bytes_returned / 4 estimate, not a tokenizer count. |
access and usage blocks look like this:
Endpoints
| Endpoint | Description |
|---|---|
POST /v1/search | Run ranked retrieval over canonical documents and passages. |
POST /v1/document | Inspect one canonical document and retrieve selected content. |
POST /v1/feedback | Persist an agent or evaluation feedback event. |
Rate limits
Every response carries four headers:X-RateLimit-Tier, X-RateLimit-Limit-RPS, X-RateLimit-Remaining, and X-RateLimit-Reset (RFC3339). Exceeding your tier’s per-second limit returns 429 rate_limited. There is no Retry-After header — wait until X-RateLimit-Reset or back off exponentially. Details in Rate limits.
Errors
All errors share one envelope:type is the literal string "error", plus request_id and an error object with a stable snake_case code, a human-readable message, and optional details.
error.code, not message. The full code table is in Errors.
Idempotency and caching
All three endpoints are POST and there is no idempotency key. Repeating an identical search is not guaranteed to return identical results: ordering, scores, andsearch_id values can differ between replays. score.value is response-local — comparable only within the response that returned it, never across responses, modes, or ranker versions. Treat each response as a snapshot, and use doc_id plus provenance when you need stable references.