Skip to main content
Every query below was run against the live API. Copy one, swap the filters, and read applied_filters in the response to confirm the server used what you meant.

Hello World

Two endpoints, three filters: country for geography, category and subcategory for taxonomy. Events — coded incidents.
Rows come back under data; applied_filters echoes what the server actually used.
Stories — the clustered coverage behind them. Same filters.
A Story carries one headline category and matches on any it was tagged with — read matched_categories to see which one answered your filter.

Where the values come from

  • Geographycountry takes plain English, ISO-2, ISO-3 or FIPS, and is listed in the value reference. The wider and narrower alternatives are region, continent and admin1 — that last one is per-country, so list one country’s values with GET /api/v2/geo/admin1?country=Nigeria.
  • categoryevent categories on Events, story categories on Stories. Case-sensitive.
  • subcategory — the leaves under the category you picked: by domain, or all of them. The code and its label both work — subcategory=Energy Infrastructure Event resolves to the same IN01.
Or let the API tell you. A wrong value is a 400 naming the ones valid for the category you sent:
Every closed list is also live at GET /api/v2/meta/enums.
Both responses are real and trimmed to the fields each line discusses. Values move with the news.

Defaults worth adopting

  • limit=10 for exploratory work, then raise it when you need more rows.
  • sort=significance for monitoring and dashboards; sort by recency only when freshness matters more than importance.
  • Plain-English geography in apps, e.g. country=United States.
  • Pass parameters through your HTTP client’s params / URLSearchParams rather than hand-building URLs — clients encode United States correctly, and the API decodes both %20 and +.
  • Omit dates on /events or /stories and you get a rolling 7-day window. Other families differ — the declared default is on each days parameter in the API reference. Explicit date_start/date_end filter by event or story date and the window must be 30 days or less.
  • Start broad, then narrow. search is true semantic retrieval on list endpoints only: the API embeds your query, applies the structured filters as the candidate set, and ranks by cosine similarity. Summary endpoints refuse it.
  • Discover admin1 values per-country from /api/v2/geo/admin1?country=... before filtering on them.
  • Treat inline top_articles as an evidence preview; use /api/v2/stories/{story_id}/articles for the full paginated source list.

Which surface answers which question

Country, region, or continent

For a fixed window rather than a rolling one, swap days for an explicit pair — 30 days or less:

A taxonomy branch

Filter on a CAMEO+ domain or a conflict category — the full tree is in Complete event taxonomy:

A metric threshold

Metric filters use canonical response-field names, and each metric is published by only some event families — a _min/_max pair on a metric the family does not carry narrows to nothing. The API says so rather than leaving you to guess: the first query above comes back with applied_filters.family_scope explaining that the filtered metric is published for one family only, so every other family was excluded. The per-metric family scope, and every filterable field, are in the metric reference.
Use Stories rather than Events when the task is discovery — an emerging project has coverage before it has coded incidents. Keep article_count_min=1 while discovering; raise it when you want source volume:

A narrow slice, today

The same slice as a daily trend line, for a dashboard:

Fatal conflict only

Admin1 drilldown

Discover the values first — they are per-country and spelled the way that country spells them:

Bounding-box drilldown

When country or admin1 is too coarse — straits, ports, basins, border zones, custom viewports — filter directly on event coordinates with bbox=lat_min,lon_min,lat_max,lon_max. This box is the Strait of Hormuz, which belongs to no single country’s admin tree:
Combine with country when you want a specific area of a specific country. A box is geometry, not an administrative boundary: this one is drawn around Washington DC and the rows that come back include Virginia and Maryland, because the box crosses the line.

Full source list for a story

Story list and detail responses carry only the top 3 inline articles. Page the articles endpoint for the rest:

Resolve an entity, then fan out

GET /api/v2/search?q=<name>&type=<person|organization|place|facility>&country_match=strict&limit=10 finds lexical identity candidates. Inspect their match and country evidence, select the intended identity, then reuse its returned entity_id on endpoints that support that ID space. Do not automatically choose the first result. Facility candidates retain facility_id, separate from owner identity. The entity workflow is covered end to end in Track an entity across every surface. Two id-spaces are worth knowing about. Most surfaces take the entity_id directly. The SEC filings detail endpoint is keyed on a CIK instead — and the same search result hands you one under identifiers.us_sec_cik, so the join still costs nothing. It answers with the filer’s recent filings, risk factors, business description and XBRL highlights, and echoes the entity_id back so you can close the loop:
/api/v2/filings does not accept entity. Passing it returns 200 with the global recent-filings list and the parameter echoed under applied_filters.ignored — a response that looks fine and answers a different question. Always read applied_filters before trusting rows.

Country sites, units and publication activity

The default publication window is today in UTC. In data.facilities.by_type, facility_count counts canonical current physical sites and unit_count counts their registry units. These are current inventories, independent of the selected publication window. A null facilities inventory is unavailable to the request; an empty by_type is a successfully read empty inventory. Use the same country and type to inspect sites, then switch granularity explicitly for units:
granularity=unit exposes registry units; paginate either view using its returned cursor. Adding has_geo, status or ownership filters changes the population and will not reproduce the whole country inventory. Facility publication additions in /api/v2/activity and /api/v2/countries count registry-record transitions, not new construction or unique new physical sites. Annual fundamentals and currencies retain their own source dates; missing values are not zero. The country page has two clocks. The default basis=publication reads the activity journal — what we published about the country and when. basis=reporting counts distinct served Events by their occurrence date and location country, and Stories by their reporting date, at day precision (there is no hour on the reporting clock):
To enumerate every registered country — the quiet ones included — ask for the directory. The Explore map and list use this same request:

Event metric averages, leaders and regional context

event_metrics returns maximum values with supporting Event IDs for every tied country; event_metrics_by_country provides the country maxima and averages. Goldstein is the highest signed score, not the greatest conflict severity. entities_spotted counts distinct identity/id-space pairs linked to Events in this occurrence window. edges includes all matching directed country pairs, independently of directory pagination. Missing source coverage remains explicit. event_metric_averages contains metric, value, and scored_event_count for significance, magnitude, systemic importance, propagation potential, and market sensitivity. Each value is the sum of that metric’s finite scored canonical Event observations divided by their count; it is neither an average of country means nor an average of maxima. A known zero is included, while a missing score is excluded from that metric’s denominator. No scored observations returns a null value with count zero; unavailable context returns a null array. Occurrence dates and Event location define the scope, independently of directory pagination. Unrestricted world averages also include Events without a recognized location; country, region and continent filters restrict by location. Confidence and Goldstein remain available in maxima, not in these five averages. context.fundamentals provides geography rollups with their observation period, method, and countries_observed / countries_total. Population and GDP are sums at one common period. Unemployment is labor-force weighted; annual central-government debt is GDP weighted, using same-period denominators. Inflation and quarterly general-government debt are labeled country medians. Currency rates remain country-specific. GET /api/v2/countries/{iso3} exposes the latest stored measurements in data.fundamentals. Use frequency when formatting period: daily FX, monthly CPI, quarterly GDP/debt and annual World Bank values are separate series. FX units name the local currency per US dollar. Quarterly GDP is seasonally adjusted, not an annual replacement. Central-government debt and general- government debt measure different coverage. source_publication_date is nullable; vintage records the known-as-of version and ingested_at is retrieval, not publication. Source and license attribution travels with each observation.

Browse public officials and source lists

The public-official directory can omit q. Follow its returned pagination; directory membership comes from published office-holder records, not prominence in reporting. Status and tenure depend on source assertions. A missing publication date remains unknown rather than using ingestion time. Source lists are already available through GET /api/v2/lists, their combined entries through GET /api/v2/lists/entries, and changes through GET /api/v2/lists/changes. All three are in the API Arena. These are independently collected open-source records; they are not a redistribution of OpenSanctions’ commercial dataset.

Publication activity: walk the journal

/api/v2/activity is the journal of what we published about identities and records — committed batches only. It is observed publication, not source intake: a register the publisher updated yesterday that we have not read yet is not in it. For anything ongoing, read on the recorded clock:
Before counting anything, read meta.coverage (which sources the window covers, and whether the window is complete) and meta.exhaustive. Then follow pagination.next_cursor, keeping every other filter exactly as it was — the cursor pins the committed source sequences it was cut from, and a changed filter under the same cursor is refused rather than silently answering a different question:
A null next_cursor means the OBSERVED journal is complete at its publication cutoff — not that the upstream register has nothing newer. Three dates ride on every row, and they answer three different questions: The kinds of record and the kinds of change the journal carries are closed vocabularies; take the values from activity-kind and activity-change rather than from memory.

Run one of these on a schedule

Use the Monitor query endpoint allowlist to select a supported Event, Story, reporting-Entity or publication-Activity query. For country publication changes, use /api/v2/activity with a country filter and time_basis=recorded; current country inventories provide context for setup. Preview the Monitor before saving, inspect its sample rows and coverage qualifications, then explicitly choose saving, activation and delivery.

Monitors

Subjects, criteria, schedule windows, run counts and exact replay.

Monitor webhooks

Signature verification and safely consuming a delivery.