Skip to content
unzoi docs

GET /stories

GET https://api.unzoi.com/stories

Search, collapsed into deduplicated stories.

One real event across many outlets, with an article count, an outlet count and a representative headline. Use this whenever results go into a context window. Equivalent to the `list_stories` MCP tool.

How clustering works

Articles are clustered offline, not at query time, so the same event always carries the same story_id whichever query surfaced it. Clustering runs in two passes: URL canonicalisation and near-duplicate detection catch syndication and light rewrites, then a second pass over the entities and topics in the text catches independent coverage of the same event that shares no wording.

That means the counts are meaningful. count is how many articles are in the cluster; outlets is how many distinct publishers. A story with 40 articles across 3 outlets is one wire story republished; 40 articles across 35 outlets is a story the whole world is covering. Those are very different facts and it is worth reading them separately.

Parameters

The same query, filter, signal and time parameters as /search — clustering changes how results are grouped, not what matches. Facets are the one exception: they count over articles, so they belong on the article endpoints.

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.
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.
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`.
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`.
offset integer Zero-based result offset, up to 100000.
limit integer Results per page, 1-100 (default 10).

Response

Field Type Description
attribution string
from_clamped boolean
has_more boolean
history_days integer
limit integer
offset integer
stories Story[]
total integer
total_relation string

Story

Field Type Description
count integer Articles in the cluster.
outlets integer Distinct outlets in the cluster.
sources string[]
story_id string
title string
url string

title and url are a representative article from the cluster, not a synthesised summary — the API never generates text.

Expanding a story

Pass a story_id back to /search as a filter to get every article in that cluster:

# One event, then every article in it.
curl -s -G "https://api.unzoi.com/stories" -H "x-api-key: $UNZOI_KEY" \
  --data-urlencode "q=grid outage" --data-urlencode "limit=5"

curl -s -G "https://api.unzoi.com/search" -H "x-api-key: $UNZOI_KEY" \
  --data-urlencode "story_id=s-9f2c" --data-urlencode "limit=50"

That two-step is the usual shape for an agent: cluster to decide what happened, expand to compare how it was covered. The guide works through it.

When not to use this

When coverage is the question. "How many outlets ran this?", "did the framing differ by country?", "find me every mention of this company" — those want articles, and collapsing them throws away the answer. Use /search with facets instead.