REST API
18 endpoints. Every one takes an API key and returns JSON. Every one that reads the index is a
GET; POST /watches and DELETE /watches/{id}
manage watches.
Base URL: https://api.unzoi.com. Authentication is one header. Everything below is
generated from the OpenAPI document the API serves about itself, so a
parameter listed here is a parameter the server accepts.
Which one do I want
Three of these search, and the choice between them changes the shape of the answer more than any parameter does. The others expand what a search found, count it over time, find the value a filter needs, show who is reported alongside whom, or keep asking for you.
| The question | Endpoint | Why |
|---|---|---|
| "What happened with X?" | /stories | One event, returned once, with the outlets that covered it. Forty outlets running the same wire story collapse to one row. |
| "What has been written about X?" | /search | Coverage itself is the answer — you want the articles, not the events. |
| "What is happening right now?" | /top-headlines | Recency rather than relevance. No query needed; every filter still applies. |
| "What is happening near this place?" | near or bbox | Not an endpoint but a filter on /search, /stories and /top-headlines: articles that mention a city inside a circle or a box, with the cities that matched on each hit. |
| "How did attention move over time?" | /aggregate | Articles, distinct stories and distinct outlets per hour, day, week or month, over the same match set. A fortnight's series is one request, not fourteen. |
| "Tell me everything about that event" | /stories/{id} | One story expanded: counts, every outlet, first and last seen, what it is about, its newest articles. One request, no re-search. |
| "Which spelling of X does the index use?" | /entities | Filters are exact matches on the index's own values. Resolve the name to an id first; entity_id then matches every spelling at once, where a spelling the index does not hold matches nothing. |
| "Who is reported alongside X?" | /graph/related | Organizations, people, places and topics co-mentioned with one entity, strongest first, with the shared articles as evidence. Association in reporting, not a relationship in the world. |
| "How are X and Y connected?" | /graph/path | The articles naming both, and up to five paths through one shared neighbour, each hop with its co-mentions. |
| "What changed around X?" | /graph/network | Neighbours by type for a window, and with a comparison window the ones that are new, gone, strengthened or weakened. |
| "What do these companies share?" | /graph/exposures | The reporting that names up to five entities together: how much, where, in what register, and the newest articles. |
| "Tell me when X happens" | /watches | A saved /stories query the index runs on an interval. New and growing stories arrive as events in a feed, or as signed webhooks. It replaces a polling loop. |
The rest follow a thread you already have: /doc/{id} for one
article in full, /similar/{id} for what else covered it, and
/account for where you stand.
Shared conventions
- Filters are exact. Every filter field matches an indexed attribute exactly, not fuzzily. Take
values from a previous response, or resolve a name with
/entities, rather than inventing them — Filters and signals lists all of them. - Unknown parameters are refused. A name an endpoint does not take is
400withcode: unknown_parameterand the name you probably meant. It is not ignored, so a typo cannot silently widen a query. Every error body carries a stablecode— Errors. - Every answer says whether it is complete.
partial,coverageandfrom_clampedride on every search-shaped response. Read them before concluding that something was not covered — Reading completeness. - Times are 14 digits.
fromandtoaccept2026-07-09or20260709120000; both are normalised toYYYYMMDDHHMMSSUTC, withfrompadded to the start of the period andtoto the end. - Paging is by offset, or by cursor.
offsetandlimitpage any query, withhas_morein the response;cursorandnext_cursorpage a newest-first browse without drifting as articles arrive — see Pagination and facets. - Every call says what it cost.
credits_chargedin the body andx-credits-chargedon the response: 1 credit for a plain search, more for a call that made the index do more.estimate=trueprices a call without running it — see Credits and overage. - Every response says where you stand. Credit and archive-depth headers ride on all of them; see Limits and plans.
- Bodies are never returned. The index stores article metadata and derived signals, not full text.
urlis where the article lives.
Generating a client
The spec is a normal OpenAPI 3.1 document with no vendor extensions, so any generator handles it. See OpenAPI for the commands, or SDKs if you would rather write the forty lines by hand — for a handful of endpoints, that is often the smaller thing to maintain.