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

Resolve candidates once, select the intended identity, and reuse its returned ID in each destination endpoint’s documented entity parameter. Accepted identifier spaces differ by endpoint: reporting supports spine and news identities, while some source-specific legs require particular identifiers. Check the identifier parameter contracts before chaining calls; an unsupported or unlinked identity must not become a claim of zero records.

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 returns ranked candidates, deduplicated across sources, each carrying a sources availability map and its cross-source identifiers. Use type to narrow an ambiguous name to a person, organization, place or facility; clients should present weak or ambiguous candidates rather than selecting one automatically.
Searching a name written in Cyrillic, Chinese, or another non-Latin script? Native-script matching is not complete yet. For now, send a common Romanized or English spelling in q — for example Gazprom rather than Газпром, or Beijing rather than 北京. Native-script name input returns 400 UNSUPPORTED_SEARCH_SCRIPT instead of plausible but unrelated fuzzy candidates. Native-script search support is on the way; existing Latin-name matching remains the supported fast path.
Select an entity candidate, then reuse its returned ID in the destination endpoint’s documented entity= parameter. Facilities return facility_id, separate from an owner entity or nearby Events. Unlinked source records retain their source key and a null entity ID. Country selection uses strict known source association in recommended requests. Inspect country_evidence: office country, legal registration, citizenship and reporting geography are different relationships. country_match=include_unknown explicitly broadens to unknown associations; omitting the parameter preserves compatibility behavior. Politicians remain people selected through holds_office=true and published office evidence. The reporting directory /api/v2/entities answers which entities appear in a selected reporting window. Initial identity lookup uses /api/v2/search. Source and facility access remains subject to the existing account entitlements; withheld source keys are omitted and failed coverage is unknown. Entity Monitors take a resolved entity id rather than a bare name, and accept every id-space /api/v2/search returns — a spine id (e_…), a news id (wiki:…) or an extracted-identity id (llm:…). Pass whichever the resolver gave you; the monitorable boolean on each search result says outright whether that exact id is accepted as a Monitor subject. Holding out for an e_… id is the one thing to avoid: six of the twenty most-covered organizations — TikTok, the Pentagon, the Senate, the Supreme Court, ICE and North Korea — have no e_ id at all, and an e_-only rule made them unwatchable. A scheduled question must not silently change subjects when name rankings change. Their public v1 match mode is coverage: mention and linked-Story evidence, not a claim of material involvement or actor attribution.
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 the oldest partition build time across the requested window. It is a conservative freshness floor, not the build time of every returned row; a wide historical window can therefore show an old settled_at even when its newest partitions are fresh.

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.

Monitors are standing API questions

A Monitor stores one Event/Story question, evaluates it on an hourly or daily half-open window, and retains triggered runs for seven days. It uses the same serving functions as the Core API. Scheduled evaluation costs 0 QU; an accepted on-demand Preview costs 1 QU and returns representative rows for inspection without saving or delivering anything. Run counts and inline samples are different. result_count is the execution’s reported count, retained_row_count is how many execution rows were stored, and the canonical matches array holds at most ten cards. When semantic retrieval reaches its candidate ceiling, total_matches_is_lower_bound is true and candidate_limit names that ceiling. See Monitors for the complete workflow and exact replay rules.

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.

Conflicting candidate types

Candidate search preserves unresolved disagreement between linked source records. Such a candidate returns entity_type: "entity" with type_evidence.status: "conflicting", the possible types, and each supporting record’s ID, source, and raw type. A type filter may include the candidate when that type is a published possibility; it does not resolve the disagreement. Select the stable identity explicitly and inspect the evidence before treating it as a person or organization. Politician filtering also requires published office evidence. A registry country association can describe the source relationship. For example, an SEC-seeded USA association means SEC filing association; it does not establish the issuer’s headquarters, domicile or citizenship. Candidate country_evidence states this basis when available. Unknown association remains unknown, and strict country matching never guesses a country from an entity’s name.