Skip to main content
Six nouns carry the entire product. Learn them once and every endpoint reads the same way.
This page is about what the nouns MEAN. Response shapes are in the OpenAPI schemas; the values each filter accepts are in Reference.

The six nouns

Article → Story → Event is the spine

An article is evidence. A story is the deduplicated development several articles describe. An event is the structured claim we are willing to stand behind, coded into a taxonomy with a date, a place, actors and metrics. The distinction matters for counting. Three publishers covering one strike is one story and one event, not three — which is the whole reason the pipeline exists, and it is why an article-count and an event-count answer different questions. It runs the other way too: one story can produce several events. A single cluster covering a border incident may yield an armed clash, a diplomatic protest and an airspace closure — three distinct coded claims, each with its own actors, date and metrics, all citing the same coverage. So stories and events are not two views of the same list, and neither count is a proxy for the other. Ask for events when you want incidents; ask for stories when you want narratives.

Events come in two families

The family is decided by a single test: did it happen, or was it said?
  • Conflict (ACLED) — a discrete act of political violence, armed conflict, protest, riot or explosion that occurred.
  • CAMEO+ — every speech act (a threat, demand, agreement, sanction) and every non-violent event across nine further domains.
So “X bombed Y” is Conflict; “X threatened to bomb Y” is CAMEO+ POLITICAL. A threat is a speech act even when its subject is violence. The complete tree is in Complete event taxonomy; what each individual code means is in Event code definitions.

Conventions every endpoint shares

One identity, everywhere

An entity parameter accepts a spine id (e_…), a news id (wiki:…) or a plain name, and resolves through the same arbiter on every endpoint. That is a contract, not a convenience: if /events and /gov/awards disagreed about what an entity is, a caller chaining them would silently drop half their data.

Finding an entity by name

Start at the unified search endpoint, then reuse the id it hands back:
This is the fuzzy “find the entity” step — use it whenever you have a possibly misspelled, abbreviated or reordered name rather than an id. It searches every entity universe at once (news, plus the structured registry: GEM energy owners, SEC/EDGAR filers, screening-list entries, China financiers) and returns ranked candidates, deduplicated across sources, each carrying a sources availability map and its cross-source identifiers. Narrow the sweep with universe — the accepted values are in Value reference. Resolve once, then fan out: the same id works on the event, entity, energy, facility, filings and screening surfaces. Search itself is open to any authenticated key — it reveals only that an entity exists and which sources carry it; the detail behind a gated source still needs that source’s plan flag.
Some endpoints take a name directly and resolve it for you; those that require an id return 400 INVALID_ENTITY_ID for a bare name. Either way this endpoint is how you get the id. Older material referring to /api/v2/entities/resolve is wrong — no such endpoint exists.

applied_filters tells you what actually happened

Every successful response echoes the filters the server applied. Descriptor-backed endpoints reject an undeclared parameter with 400 UNKNOWN_PARAM and include details.did_you_mean plus the accepted parameter names. Endpoints still being migrated may instead return it under applied_filters.ignored; a non-empty ignored object means those parameters did not affect the rows. Whichever spelling you sent, applied_filters reports the canonical name. The alias table is in Parameter reference.

NULL means unknown; it is never a fabricated 0

A missing observable is UNKNOWN. A 0 asserts a measurement somebody made. This applies to metrics, to coverage counts, and to every derived number the API serves — and it is the reason some fields come back null rather than helpfully zeroed.

Date windows are bounded

Windows are capped (30 days on most endpoints) and days / window / date_start + date_end are resolved together. Bounds and defaults per endpoint are in Parameter reference.

Search is not one thing

Some endpoints run semantic search — the string is embedded and ranked by cosine similarity, so results are conceptual neighbours. Others run a lexical substring match over named columns and keep their own default ordering, which means a query matching more rows than limit returns an arbitrary slice. The per-parameter description says which, and it is worth reading before assuming relevance ordering.

Coverage

Consistently coded history begins in March 2026 and runs to now, refreshed through the day. Earlier dates return a near-empty result that reads like a bug and is not — there is a thin tail of back-dated article noise before that, not usable history, and the window is being extended backwards over time. Coverage is not uniform, and the honest way to find out where it is thin is to ask rather than to trust a number written here: GET /api/v2/intelligence/coverage reports what can and cannot be read, per place and period. Per-dataset windows, cadences and known gaps are in the data catalog, which is generated from the same records the public data page uses. The general shape: world and continent readings are well supported, country readings much less so, and any single day in a low-coverage place should be treated as a sample rather than a census.

How fresh is it

The pipeline runs continuously; nothing here is a nightly batch. Concretely: Two consequences worth designing for:
  • Today is still moving. A query for today returns fewer events than the same query tomorrow, because coding is still in progress. That is not a gap; it is the current state. For stable day-over-day comparisons, end your window yesterday.
  • meta.settled_at tells you when. Every /api/v2/events response carries a meta block: row_source says whether the rows came from a snapshot or were computed live, and settled_at is when that snapshot was built. You never have to guess how fresh a number is.

Where the values live

When you need a value list — a category, a code, a country format, an id space — do not guess and do not hardcode from an example. Every vocabulary the API validates against is published, and each is labelled with whether the list is exhaustive: The distinction that matters most is on How to read the reference: a vocabulary is closed (a fixed list — safe to switch on), observed (what the corpus currently holds — never treat as exhaustive), or an identifier (discovered through a call, never enumerated). Treating an observed list as closed is the single most common way to build a filter that silently misses data.

Next

Quickstart

Make your first call.

Endpoint index

See the whole surface at once.

Event metrics

What the numbers mean.

How events are coded

The pipeline behind an event.