Pagination and facets
Paging
Offset-based: offset and limit. limit is 1–100 and defaults to 10;
offset goes up to 100,000.
curl -s -G "https://api.unzoi.com/search" -H "x-api-key: $UNZOI_KEY" \
--data-urlencode "q=inflation" \
--data-urlencode "offset=20" --data-urlencode "limit=20"
Stop on has_more: false rather than by comparing offset + limit to total.
The two agree for keyword queries and can disagree for ranked ones, for the reason below.
Deep paging
The offset ceiling is not arbitrary: a large offset makes the server rank and discard everything before it. If you genuinely need to walk a large result set, narrow by time instead and page within each window — a month at a time is both faster and cheaper than an offset in the tens of thousands. There is no cursor API.
Totals
total_relation tells you how much to trust total.
| Value | Means | When |
|---|---|---|
exact | total is the true number of matching articles. | Keyword and metadata-only queries, which the inverted index can count exhaustively. |
approximate | total is how many candidates were considered, not how many exist. | Semantic, hybrid and similarity queries, which rank a bounded candidate set rather than scoring the whole corpus. |
So do not render "About 4,132 results" for a hybrid query — it is a count of what the ANN pass looked at. If you
need a true count, run the same filters as a keyword query and read that total instead.
Facets
Facets count over the whole match set, not over the page you were handed. That is what makes them worth a request: they tell you what exists before you filter on it.
curl -s -G "https://api.unzoi.com/search" -H "x-api-key: $UNZOI_KEY" \
--data-urlencode "q=lithium supply" \
--data-urlencode "facets=source,country,topic" \
--data-urlencode "facet_limit=10" \
--data-urlencode "limit=5" "facets": {
"country": {
"values": [
{ "value": "AU", "count": 214 },
{ "value": "CL", "count": 168 }
],
"sum_other_doc_count": 91,
"doc_count_error_upper_bound": 0,
"approximate": false
}
} Up to 8 facet fields per request, each returning up to 100 values. Any filter field can be faceted.
Reading the error bounds
-
sum_other_doc_count— how many matches fell outside the returned values. A large number meansfacet_limitis cutting off a long tail. -
doc_count_error_upper_bound— the most any returned count could be understated.0means the counts are exact. -
approximate—truewhen that upper bound is non-zero. Counts are exact for keyword queries and can be approximate for ranked ones, for the same reason totals are.
The practical use is to discover rather than to report: facet by source and
country, see who is actually covering something, then re-query filtered to one of them. Presenting a
facet count to a user as a precise figure is only safe when approximate is false.
Evaluating coverage works through it.
Stories page too
/stories takes the same offset and limit and
reports the same total, total_relation and has_more — where
total counts clusters, not articles. It does not take facets, because facet counts are over
articles and belong on the article endpoints.