GET /search
Search articles.
Ranked articles with topics, entities, locations and signals. Equivalent to the `search_news` MCP tool.
Ranking
| Name | Type | Description |
|---|---|---|
| q | string | Query text. Omit for a recency browse. |
| mode | `keyword` · `semantic` · `hybrid` | Ranking mode. `hybrid` is usually right when a model wrote the query, because models paraphrase. |
mode is the parameter worth thinking about. Use hybrid when a model wrote the query —
models paraphrase, and keyword ranking cannot bridge "central bank tightening" to an article that says "Fed raises
rates". Use keyword when a human gave you an exact phrase, a product name or a proper noun they want
matched literally. The guide goes deeper.
Omitting q entirely turns this into a recency browse, which is what
/top-headlines does explicitly.
Filters
Exact matches on indexed attributes. Adding words to q makes ranking fuzzier; adding a filter does not,
and costs nothing.
| Name | Type | Description |
|---|---|---|
| source | string | Source domain, e.g. bbc.co.uk. |
| source_type | string | web | citation | academic_archive | defense_archive | journal_archive | non_textual | other. |
| publisher_country | string | The publisher's canonical two-character country identifier. |
| language | string | Source language, ISO-639-3, e.g. eng, fra, ara, zho. |
| story_id | string | A cluster id from /stories, to expand one story into its articles. |
| topic | string | An exact canonical topic identifier returned by the API. |
| organization | string | An exact organization entity. |
| person | string | An exact person entity. |
| country | string | A mentioned country's canonical two-character identifier. |
| author | string | An exact article author. |
| location | string | An exact mentioned location. |
| location_id | string | An exact canonical location identifier. |
| city | string | An exact mentioned city. |
| region | string | An exact mentioned region. |
| name | string | An exact proper name. |
| mentioned_date | string | An exact date mentioned in the article text. |
| quote_verb | string | An exact verb introducing a quotation. |
| amount_object | string | An exact object described by a numeric amount. |
Values are canonical identifiers, not free text — take them from a previous response or from a facet count. Filters and signals explains the vocabularies.
Signals
Every article carries versioned industry, business-context and risk-context intensities. Range-filtering on them finds coverage with a particular character rather than a particular word.
| Name | Type | Description |
|---|---|---|
| signal | string | A normalized business signal to range-filter on, e.g. finance, energy, conflict. |
| signal_min | number | Inclusive lower bound for `signal`. |
| signal_max | number | Inclusive upper bound for `signal`. |
| signals | string | Several signal ranges at once, ANDed: `name[:min[:max]]`, comma separated, e.g. `finance:1.5:,energy::2`. |
Use signal + signal_min/signal_max for one constraint, or
signals for several at once, ANDed. See Entity and signal
filtering.
Time range
| Name | Type | Description |
|---|---|---|
| from | string | Lower time bound, e.g. 2026-07-09 or 20260709120000. Clamped forward to what the caller's plan may reach; see `history_days` and `from_clamped` in the response. |
| to | string | Upper time bound, same formats as `from`. |
Paging and facets
| Name | Type | Description |
|---|---|---|
| offset | integer | Zero-based result offset, up to 100000. |
| limit | integer | Results per page, 1-100 (default 10). |
| facets | string | Comma-separated fields to count over the full match set, up to 8. |
| facet_limit | integer | Values per facet, 1-100 (default 10). |
See Pagination and facets for what the counts mean and when they are approximate.
Response
| Field | Type | Description |
|---|---|---|
| attribution | string | |
| facets | object | |
| from_clamped | boolean | Whether a `from` you supplied was moved forward to that boundary. Distinguishes a plan limit from a corpus with no coverage. |
| has_more | boolean | |
| history_days | integer | How far back the caller's plan may query; null = the full archive. |
| limit | integer | |
| mode | string | |
| offset | integer | |
| results | Article[] | |
| total | integer | |
| total_relation | `exact` · `approximate` | `exact` for keyword and metadata queries; `approximate` for ANN-derived modes, which rank a bounded candidate set. |
Article
| Field | Type | Description |
|---|---|---|
| authors | string[] | |
| collected_at | string | |
| countries | string[] | |
| id | string | |
| image | string | |
| language | string | |
| locations | string[] | |
| organizations | string[] | |
| persons | string[] | |
| published_at | string | 14-digit YYYYMMDDHHMMSS. |
| publisher_country | string | |
| signals | Signals | |
| source | string | |
| source_type | string | |
| story_id | string | Pass back as the `story_id` filter to expand this story. |
| title | string | |
| tone | number | |
| topics | string[] | |
| url | string | |
| word_count | integer |
Article bodies are never returned — url is where the article lives. For the long tail of an article's
metadata (quotations, structured locations, amounts, alternate URLs), fetch it by id with
/doc/{id}.
Example
curl -s -G "https://api.unzoi.com/search" \
-H "x-api-key: $UNZOI_KEY" \
--data-urlencode "q=port congestion" \
--data-urlencode "mode=hybrid" \
--data-urlencode "language=eng" \
--data-urlencode "from=2026-08-01" \
--data-urlencode "facets=source,country" \
--data-urlencode "limit=10" Errors
| Status | Meaning |
|---|---|
| 200 | Success |
| 401 | Missing or invalid API key |
| 402 | Account suspended (subscription canceled or payment failed) |
| 429 | Rate limit exceeded, or the monthly quota is exhausted on a key that stops at its quota rather than billing overage. `retry-after` says how long to wait. |
See Errors for how to back off correctly.