# Public API contract v1 The REST surface is rooted at `/api/v1` and is read-only. Every successful page carries the exact Dataset revision, bounded `returned` count and an opaque next cursor. Limits are 1–100; query text is at most 120 characters and cursors at most 1,024 characters. Cursors are base64url JSON containing contract version, endpoint kind, Dataset revision and stable sort values. They are opaque to consumers. A malformed or wrong-endpoint cursor returns `400 invalid_cursor`; a cursor from another Dataset revision returns `409 stale_cursor` so pages can never mix releases. Errors always use: ```json { "error": { "code": "invalid_request", "message": "Request parameters failed validation", "details": [], "dataset_revision": "<40-character commit>" } } ``` FastAPI serves the authoritative schema at `/openapi.json`. Company search is served from the revision-pinned screener/company Parquet in one DuckDB query. `/api/v1/companies/{ticker}` combines one exact company summary with up to 100 dilutive instruments, their supporting document identities, Dataset revision, citation and source freshness for the site-native company dashboard. Document filtering supports exchange, ticker, instrument, document type and date bounds. Ordering uses announcement time plus canonical document ID, so equal timestamps cannot cause duplicates or skips across pages. Document pages include a canonical public ASX source link resolved in one batched SQLite lookup, plus optional HF raw/markdown artifact keys. Consumers never need a signed GCS link. Canonical instrument IDs accept only alphanumeric, colon, period, underscore and hyphen characters and are capped at 240 characters. Full-text document search rejects more than 12 terms or 120 characters, uses parameterized SQLite FTS, supports ticker/type/date constraints and returns at most 50 ranked results per page. Snippets are capped at 600 characters; full markdown bodies are never returned by search. Public requests are protected by bounded global request and concurrency budgets. Overload returns `429 rate_limited` or `503 service_busy` with a one-second retry hint; URLs over 2,048 characters return `414 request_too_large`. Non-read API methods return `405 read_only_surface`. File/upload/reset, login and monitoring routes are disabled. The complete boundary is documented in [`SECURITY.md`](SECURITY.md).