Living Signals REST API v1#
Use the read-only Living Signals REST API to explore news-derived Claims,
corroborated Signals, and related Topics. All endpoints use the /api/v1
base path.
Start with GET /api/v1/countries to discover your
access. Read GET /api/v1/rubric before you build filters.
You can also read this reference on the documentation page, as
Markdown, download the
OpenAPI 3.1 document, or open the
browsable reference.
Changed from the previous contract:
/clusters, thelevel,cluster, andoffsetparameters, thestable_id,rubric_tags, andtopic_stable_idfields, and thecountriesandlanguagesaliases are not part of v1. There is no compatibility layer.
The model#
Living Signals uses four core concepts:
- A Claim is an immutable assertion extracted from one source. It includes article and Source provenance.
- A Signal combines corroborating Claims into a discrete, time-bounded occurrence. Signals are the primary exploration resource. Signal detail includes every retrievable Claim in the Signal.
- A Topic groups related Signals for browsing.
- The rubric describes each Signal with binary attributes. A category groups related attributes and matches when any member attribute is true. Both attributes and categories support multiple values on one Signal.
Annotation layers independently classify Signals through attributed standards or operational vocabularies. Access to each layer is granted separately.
The rubric and annotation layers describe Signals after they form. They do not determine how Claims form Signals or how Signals form Topics.
Getting started#
Send the API key on authenticated requests:
Authorization: Bearer ls_live_<token>
Then follow this path:
Discover your countries, coverage, and annotation layers:
GET /api/v1/countriesLearn the category and attribute vocabulary:
GET /api/v1/rubricExplore environmental Signals in Cameroon:
GET /api/v1/signals?country=CM&category=environmentalRetrieve one Signal with every supporting Claim:
GET /api/v1/signals/28eeab9d-47f6-4a2e-bd28-cafe6ad6ca19Poll newly extracted Claims by ingestion time:
GET /api/v1/claims?since_extracted=24h
For paginated requests, follow every non-null nextPage unchanged before you
advance a polling watermark.
Authentication and entitlements#
Send an API key in either header:
Authorization: Bearer ls_live_<token>
X-API-Key: ls_live_<token>
Create and manage keys in the Living Signals app at /access#keys. Keys
begin ls_live_. Keys issued before 2026-07-21 may begin ls_cust_; they
behave identically.
| Route | Authentication |
|---|---|
GET /api/v1 |
Public |
GET /api/v1/rubric |
Public |
GET /api/v1/docs |
Public |
GET /api/v1/openapi.json |
Public |
| Every other route in this reference | API key required |
Customer keys can access only their active country grants. Omit country to
use every country available to your key. Requesting any unentitled country
rejects the entire request with 403 country_not_entitled. The API never
returns a partial country subset. Team keys can access every country.
Annotation layer grants are independent of country grants. Customer Signal
responses include only granted layers with stored annotations. Filtering by an
ungranted layer rejects the entire request with
403 annotation_layer_not_entitled. Team keys can filter by every registered
layer. Set include_annotations=true to include stored annotations in a team
response.
Use GET /api/v1/countries to discover annotation layer ids. Use
GET /api/v1/annotation-layers to retrieve their code vocabularies.
Enrichment grants are separate from annotation layer and country grants.
Customer Signal detail includes satellite imagery only when the organization
has the geospatial_v1 enrichment enabled. Team keys can access every
enrichment.
Authentication and entitlement failures use distinct codes:
| HTTP | Code | Meaning |
|---|---|---|
| 401 | missing_credentials |
Neither a Bearer token nor X-API-Key was supplied. |
| 401 | invalid_credentials |
The supplied key is not recognized. |
| 403 | key_revoked |
The key has been revoked. |
| 403 | key_expired |
The key has expired. |
| 403 | customer_inactive |
The customer account is not active. |
| 403 | country_not_entitled |
At least one explicitly requested country is outside the key's grants. |
| 403 | annotation_layer_not_entitled |
An annotation-layer filter names a layer not granted to the customer key. |
Conventions#
Dates and timestamps#
Timestamps use RFC 3339 UTC, such as 2026-07-20T21:31:21.628Z. Timestamp
fields include extracted_at, article.published_at, first_claim_at,
last_claim_at, and formed_at.
event_date, occurred_on, signal_start, and signal_end use
YYYY-MM-DD. These fields can be null. occurred_on is the canonical
occurrence date for a Claim: event_date when the source states one, else the
article's publish date. A null occurred_on means the occurrence time is
unknown; such Claims match only since=all. Because event_date comes from
source content, it can be imprecise or unreliable. Poll Claims with
since_extracted instead.
Every since parameter is an exclusive bound. It accepts:
- One or more digits followed by
h,d, orw. Units are case-insensitive. - An ISO date or timestamp beginning with
YYYY-MM-DD. Use an RFC 3339 timestamp when you need a time of day. all, which removes the bound.
Valid examples include 24h, 7d, 2w, all, 2026-07-20, and
2026-07-20T21:30:00Z. Invalid suffixes and date strings return
400 invalid_parameter.
The default window#
/signals, /topics, and /claims return the last 90 days when you omit
since. Set since to choose a different window, or since=all to search the
whole corpus.
The window measures when something happened, not when it was ingested. A story
published today about a flood two years ago produces a Claim dated two years
ago, and the default window excludes it. Claims filter on occurred_on;
Signals filter on signal_end, the latest occurred_on across their Claims.
Records whose occurrence time is unknown appear only under since=all.
Passing since_extracted turns the default window off, so a poll returns
everything ingested since your last one whatever its occurred_on.
Strict validation#
Query parameters follow these validation rules:
| Input | Behavior |
|---|---|
| A supported parameter with a malformed value | 400 invalid_parameter. |
| A parameter recognized elsewhere in v1 but unsupported by this endpoint | 400 invalid_parameter with an endpoint hint. |
| A retired parameter listed below | 400 invalid_parameter with its replacement. |
| A truly unknown parameter name | Ignored, consistent with ordinary HTTP query handling. |
/docs and /openapi.json serve fixed documents and ignore all query
parameters.
Retired parameters are handled explicitly:
| Retired parameter | Replacement |
|---|---|
countries |
Use repeatable or comma-separated country. |
languages |
Use repeatable or comma-separated language. |
offset |
Pagination is keyset-only; follow nextPage. |
level |
Use the separate /signals and /topics resources. |
cluster |
Use signal on /claims, or use /signals and /topics directly. |
The API applies only safe normalization. It trims country codes and converts
them to uppercase. It trims language codes and converts them to lowercase. It
removes duplicate repeated or comma-separated values. A positive integer
limit above 500 is clamped to 500. Check pagination.limit for the effective
page size.
Every known path answers OPTIONS with 204 and Allow: GET, OPTIONS,
with or without an API key.
Unsupported methods return 405 method_not_allowed with the same Allow
header.
Unknown paths return a JSON 404 not_found response. Authentication runs
before routing under /api/v1/*. An unknown protected path without a valid key
therefore returns 401. Public paths are /api/v1, /rubric, /docs, and
/openapi.json.
Error envelope and codes#
Most errors use this envelope:
{
"error": {
"code": "invalid_parameter",
"message": "Unknown rubric category \"climate\". See GET /api/v1/rubric for valid category ids."
}
}
410 signal_retired is the Signal-detail exception. It uses the structured
retirement body documented under GET /api/v1/signals/{id} so integrations can
distinguish a durable reference with no successor from an id that never
existed.
Error codes:
| HTTP | Code | Meaning |
|---|---|---|
| 400 | invalid_parameter |
A supported value is malformed, a vocabulary value is unknown, or a recognized parameter is unsupported here. |
| 400 | invalid_cursor |
A cursor is empty, malformed, or has the wrong sort-key shape. |
| 401 | missing_credentials |
No API key was supplied. |
| 401 | invalid_credentials |
The supplied key is not recognized. |
| 403 | key_revoked |
The key has been revoked. |
| 403 | key_expired |
The key has expired. |
| 403 | customer_inactive |
The customer account is not active. |
| 403 | country_not_entitled |
An explicitly requested country is not entitled. |
| 403 | annotation_layer_not_entitled |
An annotation filter uses an ungranted layer. |
| 404 | not_found |
The path or requested resource does not exist. |
| 405 | method_not_allowed |
The path exists but does not support the method; check Allow. |
| 410 | signal_retired |
The Signal id existed but has no active successor. |
| 429 | rate_limit_exceeded |
The customer-key limit was exceeded; check Retry-After. |
| 500 | internal_error |
An unexpected server error occurred. |
| 503 | auth_unavailable |
Authentication could not reach its backing service. |
| 503 | release_in_progress |
A coordinated rubric update is in progress. Retry after the Retry-After interval. |
Rate limits#
Customer keys use a sliding-window limit of 240 requests per minute per key by default. Your deployment may use a different limit. Check these headers on authenticated customer responses:
| Header | Meaning |
|---|---|
X-RateLimit-Limit |
Requests allowed in the current window. |
X-RateLimit-Remaining |
Requests remaining in the current window. |
X-RateLimit-Reset |
Seconds until the current window resets; this is a relative duration, not a Unix timestamp. |
A 429 rate_limit_exceeded response also includes Retry-After in seconds.
Authentication runs before rate limiting, so 401 responses do not include
rate limit headers. Public responses and team-key responses do not include
them either. Team keys are not rate limited.
Pagination#
/signals, /topics, /claims, and /sources use keyset pagination:
{
"nextPage": "https://api.livingsignals.example/api/v1/signals?country=CM&limit=50&cursor=MjEw",
"pagination": {
"limit": 50,
"count": 50
}
}
nextPage is an absolute URL on a first-party Living Signals host. Follow it
unchanged until it is null. Its query string preserves your parameters as
you sent them (for example, a lowercase country=cm stays lowercase even
though filtering normalizes it) — treat the URL as opaque rather than parsing
it. count reports rows on the current page, not total results.
Cursors are base64url-encoded sort keys. Treat them as opaque. Omit cursor to
start a page walk. An empty, malformed, or incompatible cursor returns
400 invalid_cursor.
Cursors are not bound to a filter set. Some endpoints share a cursor shape, so
reusing a cursor may not fail even when it points to an undefined page
position. Never create, edit, or reuse a cursor. Follow the nextPage issued
for the exact query you are paging through.
Endpoint reference#
GET /api/v1#
Begin here to find core concepts, authentication rules, pagination guidance, supported parameters, and a recommended integration path.
| Parameter | Meaning |
|---|---|
| None |
Example:
{
"name": "Living Signals REST API",
"version": "v1",
"model": {
"data_primitives": "Claims are immutable assertions extracted from one source. Signals combine corroborating Claims into time-bounded occurrences. Explore Signals as the primary resource.",
"enrichment": "Topics group related Signals for browsing.",
"filtering_and_organization": "The versioned rubric organizes Signals with categories and attributes. Annotation layers add independent classification vocabularies available to your key."
},
"getting_started": [
{
"step": 1,
"request": "GET /api/v1/countries",
"purpose": "Discover your country access, data coverage, and annotation layers."
},
{
"step": 2,
"request": "GET /api/v1/rubric",
"purpose": "Learn the rubric vocabulary before you build filters."
},
{
"step": 3,
"request": "GET /api/v1/signals?country=CM&category=environmental",
"purpose": "Explore corroborated occurrences in an available country."
},
{
"step": 4,
"request": "GET /api/v1/signals/{id}",
"purpose": "Retrieve a Signal with its complete Claim provenance."
},
{
"step": 5,
"request": "GET /api/v1/claims?since_extracted=24h",
"purpose": "Poll /claims with since_extracted. Follow nextPage and deduplicate by Claim id."
}
],
"documentation": "/api/v1/docs",
"documentation_note": "Read the public Markdown reference at /api/v1/docs. Download OpenAPI at /api/v1/openapi.json. Browse the rendered reference at /reference. Manage keys at /access#keys.",
"openapi": "/api/v1/openapi.json",
"reference": "/reference",
"auth": {
"scheme": "Bearer or X-API-Key header",
"customer_example": "Authorization: Bearer ls_live_<token>",
"team_example": "Authorization: Bearer ls_live_<token>",
"key_management": "/access#keys",
"entitlements": "Customer keys can access granted countries, annotation layers, and enrichments. Requesting an unentitled country or annotation layer returns 403; unentitled imagery is absent from Signal detail and its PNG route returns 404. Internal keys can access every country, layer, and enrichment."
},
"rate_limit": {
"applies_to": "Customer keys.",
"default": "240 requests per minute for each API key.",
"response": "HTTP 429 rate_limit_exceeded with Retry-After in seconds.",
"headers": "Metered responses include X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset."
},
"validation": {
"parameters": "On data endpoints, malformed values and parameters supported by a different endpoint return HTTP 400 invalid_parameter. Unknown parameter names are ignored. The static /docs and /openapi.json endpoints ignore all query parameters.",
"vocabulary": "Unknown rubric ids and annotation codes return HTTP 400 invalid_parameter. The error points to /rubric or /annotation-layers.",
"paths": "Unknown paths return a JSON HTTP 404 not_found envelope.",
"methods": "OPTIONS returns HTTP 204. Other non-GET methods return HTTP 405 method_not_allowed with Allow: GET, OPTIONS."
},
"pagination": {
"next_page": "Follow the absolute nextPage URL unchanged until it is null.",
"cursor": "Treat cursors as opaque and endpoint-specific. Omit the cursor to start. Empty or incompatible cursors return HTTP 400 invalid_cursor.",
"response": "pagination contains the effective limit and the number of rows on the current page."
},
"endpoints": {
"GET /api/v1": {
"description": "Public integration guide and endpoint index.",
"auth": "public",
"params": {}
},
"GET /api/v1/countries": {
"description": "Your available countries, Claim coverage, and annotation layer ids.",
"auth": "API key",
"params": {}
},
"GET /api/v1/rubric": {
"description": "Rubric categories and attributes for filtering Signals and Topics.",
"auth": "public",
"params": {}
},
"GET /api/v1/annotation-layers": {
"description": "Annotation vocabularies available to your key.",
"auth": "API key",
"params": {}
},
"GET /api/v1/signals": {
"description": "Corroborated Signals with rubric filters and available annotations.",
"auth": "API key",
"params": {
"country": "Repeat or comma-separate ISO-2 codes to use OR. Omission uses your full country access.",
"category": "Repeat or comma-separate category ids to match any Signal with a member attribute from any listed category.",
"attribute": "Repeat or comma-separate attribute ids. Every listed attribute must be true.",
"attribute_any": "Repeat or comma-separate attribute ids. At least one listed attribute must be true.",
"glide_v1": "Repeat or comma-separate GLIDE codes to use OR within the layer.",
"acled_v1": "Repeat or comma-separate ACLED codes to use OR within the layer.",
"iasc_v1": "Repeat or comma-separate IASC codes to use OR within the layer.",
"iep_positive_peace_v1": "Repeat or comma-separate IEP Positive Peace pillars to use OR within the layer.",
"geospatial_v1": "Repeat or comma-separate geospatial imagery-suitability codes to use OR within the layer.",
"topic": "Parent Topic UUID.",
"since": "Exclusive bound on when the occurrences happened, using signal_end (latest member occurrence date; Signals with no datable occurrence match only all). Defaults to 90d; pass all for the full corpus. Accepts <n>h, <n>d, <n>w, or an ISO date or timestamp.",
"limit": "Page size. Defaults to 50 and clamps at 500.",
"cursor": "Opaque cursor from nextPage.",
"include_annotations": "For team keys, true includes all stored layers. Customer responses always follow grants."
}
},
"GET /api/v1/signals/{id}": {
"description": "The canonical active Signal with all of its Claims and entitled attached imagery. Retired merge and split ids resolve to their primary successor.",
"auth": "API key",
"params": {
"id": "Signal UUID.",
"include_annotations": "For team keys, true includes all stored layers. Customer responses always follow grants."
}
},
"GET /api/v1/signals/{id}/imagery/{kind}.png": {
"description": "An attached satellite imagery chip for the canonical active Signal when geospatial_v1 enrichment access is enabled.",
"auth": "API key",
"params": {
"id": "Signal UUID.",
"kind": "Imagery kind, currently post_event."
}
},
"GET /api/v1/topics": {
"description": "Browse groups of related Signals. Topic ids can change between processing runs, so store Signal or Claim ids instead.",
"auth": "API key",
"params": {
"country": "Repeat or comma-separate ISO-2 codes to use OR.",
"category": "Match any listed category on one grouped Signal.",
"attribute": "Require every listed attribute on the same grouped Signal.",
"attribute_any": "Require any listed attribute on the same grouped Signal.",
"glide_v1": "Match any listed GLIDE code on the same grouped Signal.",
"acled_v1": "Match any listed ACLED code on the same grouped Signal.",
"iasc_v1": "Match any listed IASC code on the same grouped Signal.",
"iep_positive_peace_v1": "Match any listed IEP Positive Peace pillar on the same grouped Signal.",
"geospatial_v1": "Match any listed geospatial imagery-suitability code on the same grouped Signal.",
"since": "Exclusive occurrence-time bound met by one grouped Signal. Defaults to 90d; pass all for the full corpus.",
"limit": "Page size. Defaults to 50 and clamps at 500.",
"cursor": "Opaque cursor from nextPage."
}
},
"GET /api/v1/claims": {
"description": "Extracted Claims with article and Source provenance plus current Signal assignment.",
"auth": "API key",
"params": {
"country": "Repeat or comma-separate ISO-2 codes to use OR.",
"signal": "Current Signal UUID.",
"since": "Exclusive occurrence-time bound on occurred_on (event date, else article publish date; unknown-date Claims match only all). Defaults to 90d unless since_extracted is set; pass all for the full corpus.",
"since_extracted": "Exclusive extracted_at bound for incremental polling. Turns off the default since window so polling stays lossless.",
"limit": "Page size. Defaults to 50 and clamps at 500.",
"cursor": "Opaque cursor from nextPage."
}
},
"GET /api/v1/claims/{id}": {
"description": "One extracted Claim.",
"auth": "API key",
"params": {
"id": "Numeric Claim id."
}
},
"GET /api/v1/sources": {
"description": "Active Sources by country, with recent Claim coverage.",
"auth": "API key",
"params": {
"country": "Repeat or comma-separate ISO-2 codes to use OR.",
"language": "Repeat or comma-separate two- or three-letter language codes to use OR.",
"limit": "Page size. Defaults to 100 and clamps at 500.",
"cursor": "Opaque cursor from nextPage."
}
},
"GET /api/v1/docs": {
"description": "Public Markdown API reference.",
"auth": "public",
"params": {}
},
"GET /api/v1/openapi.json": {
"description": "Public OpenAPI 3.1 document.",
"auth": "public",
"params": {}
}
}
}
Responses use Cache-Control: public, max-age=3600.
GET /api/v1/countries#
Call this endpoint first to discover your country access, data coverage, and
annotation layers. Countries are ordered by code.
| Parameter | Meaning |
|---|---|
| None |
| Field | Meaning |
|---|---|
countries |
Countries available to your key. Customer grants remain visible when country metadata is unavailable. |
annotation_layers |
Layer ids available to your key. Team keys receive layer ids present in stored Signal annotations. |
countries[].code |
ISO 3166-1 alpha-2 country code. |
countries[].name |
Country name, or null when metadata is unavailable. |
countries[].status |
live, in_curation, pending, or archived; null when metadata is unavailable. |
countries[].claim_count |
Retrievable Claims for the country. |
countries[].source_count |
Distinct active Sources available for the country. |
countries[].first_claim_at |
Earliest Claim ingestion timestamp, or null. |
countries[].last_claim_at |
Latest Claim ingestion timestamp, or null. |
Example:
{
"countries": [
{
"code": "CM",
"name": "Cameroon",
"status": "live",
"claim_count": 18420,
"source_count": 37,
"first_claim_at": "2026-05-02T06:14:20.931Z",
"last_claim_at": "2026-07-20T21:26:42.133Z"
}
],
"annotation_layers": ["acled_v1", "geospatial_v1", "glide_v1", "iasc_v1"]
}
Coverage includes only successfully extracted Claims available through
/claims. Rejected and failed extraction outcomes do not contribute. A
country's claim_count equals a complete country-scoped /claims walk. Its
last_claim_at comes from a Claim available through /claims.
Responses use Cache-Control: private, max-age=300.
GET /api/v1/rubric#
Use this public, versioned vocabulary to build category, attribute, and
attribute_any filters. An attribute is a binary property that may be true for
a Signal. A category groups related attributes and matches when any member
attribute is true. Scaled and numeric properties are not returned because they
are not graded or stored.
| Parameter | Meaning |
|---|---|
| None |
| Field | Meaning |
|---|---|
version |
Current rubric vocabulary version, presently v1.1. |
categories[].id |
Exact value accepted by category. |
categories[].label |
Category display label. |
categories[].attributes |
Ordered member attribute ids. |
attributes[].id |
Exact value accepted by attribute and attribute_any. |
attributes[].label |
Short display label when the attribute belongs to a category, or null. |
attributes[].description |
Definition used to grade the attribute. |
attributes[].section |
Group used to organize related attributes. This value is not filterable. |
attributes[].categories |
Categories that include the attribute. An empty array means it does not belong to a category. |
Selected elements from the complete response:
{
"version": "v1.1",
"categories": [
{
"id": "environmental",
"label": "Environmental",
"attributes": [
"involves_environmental_damage",
"involves_deforestation",
"involves_water_contamination",
"involves_extractive_industry"
]
}
],
"attributes": [
{
"id": "involves_environmental_damage",
"label": "Environmental Damage",
"description": "General environmental harm, ecosystem damage",
"section": "harm_type",
"categories": ["environmental"]
},
{
"id": "involves_air_pollution",
"label": null,
"description": "Air quality issues, toxic fumes, emissions, smog, respiratory hazards",
"section": "harm_type",
"categories": []
}
]
}
Ids are case-sensitive. Responses use Cache-Control: public, max-age=3600.
GET /api/v1/annotation-layers#
Retrieve the annotation vocabularies available to your key. Customer
keys receive only granted layers. An empty layers array means no layers are
granted. Team keys receive every registered layer.
| Parameter | Meaning |
|---|---|
| None |
| Field | Meaning |
|---|---|
layers[].id |
Versioned layer id used as the Signal filter parameter and annotations key. |
layers[].name |
Display name for the classification vocabulary. |
layers[].version |
Vocabulary version. |
layers[].attribution.name |
Organization that maintains the vocabulary. |
layers[].attribution.url |
Official website for the vocabulary. |
layers[].codes[].code |
Exact, case-sensitive API filter and annotation value. |
layers[].codes[].canonical |
Canonical value or name in the vocabulary. |
layers[].codes[].meaning |
Definition of the code. |
Selected codes from one granted layer:
{
"layers": [
{
"id": "glide_v1",
"name": "GLIDE disaster event types",
"version": "1",
"attribution": {
"name": "GLIDE",
"url": "https://glidenumber.net"
},
"codes": [
{
"code": "ff",
"canonical": "FF — Flash Flood",
"meaning": "Taxonomy path: natural hazard / flash flood / flash flood. Key phrases: flash flood, sudden flooding, rapid-onset flood, torrential rain flooding, urban flash flood, floodwaters surged, runoff flooding, swept away by flood."
},
{
"code": "fl",
"canonical": "FL — Flood",
"meaning": "Taxonomy path: natural hazard / flood / flood. Key phrases: flood, flooding, river overflow, inundation, overflowing river, waterlogged areas, floodwaters, seasonal flooding."
}
]
}
]
}
Each layer's codes array is complete and ordered. Responses use
Cache-Control: private, max-age=300.
GET /api/v1/signals#
With query, results use word matching and semantic similarity across the accessible corpus. search.mode is hybrid, or lexical when the embedding service is unavailable. search.reranked indicates whether evidence-based reranking succeeded; false means the base retrieval order is used. search.truncated indicates more matches than the result limit; nextPage is null for search. Search is a relevance-ranked retrieval aid, not an exhaustive export. Without query, the existing paginated listing is unchanged. No results means no matching reports under the selected filters, not that no event occurred.
Explore active, corroborated Signals with rubric and annotation filters.
Parameters combine with AND. Values within country, category,
attribute_any, and each annotation layer use OR. Multiple attribute values
use AND. Results use a stable keyset order.
| Parameter | Meaning |
|---|---|
query |
Search words and meaning (2–500 characters). Returns up to limit results ranked by relevance. No cursor is accepted with a query; narrow your query or filters when search.truncated is true. |
country |
Filter by ISO-2 country code. Repeat or comma-separate values to use OR. Matching ignores case. Omission uses your full access; any unentitled value rejects the request. |
category |
Filter by exact category id. Repeat or comma-separate ids to match a Signal with any member attribute from any listed category. |
attribute |
Filter by exact attribute id. Repeat or comma-separate ids; every listed attribute must be true. |
attribute_any |
Filter by exact attribute id. Repeat or comma-separate ids; at least one must be true. This group combines with every other filter using AND. |
glide_v1 |
Filter by exact GLIDE code. Repeat or comma-separate codes to use OR within this layer. |
acled_v1 |
Filter by exact ACLED code. Repeat or comma-separate codes to use OR within this layer. |
iasc_v1 |
Filter by exact IASC code. Repeat or comma-separate codes to use OR within this layer. |
iep_positive_peace_v1 |
Filter by exact IEP Positive Peace pillar. Repeat or comma-separate codes to use OR within this layer. Append :strengthening, :eroding, or :mixed to narrow one pillar, as well_functioning_government:eroding. |
iep_positive_peace_v1_direction |
Filter by strengthening, eroding, or mixed. Repeat or comma-separate to use OR. With a pillar filter the direction must hold for that pillar; alone it matches any pillar carrying it. |
geospatial_v1 |
Filter by exact geospatial imagery-suitability code. Repeat or comma-separate codes to use OR within this layer. |
topic |
Filter by current parent Topic UUID. Invalid UUIDs return 400 invalid_parameter. |
since |
Filter by Signals whose latest occurrence falls after this exclusive bound. Defaults to 90d. Use the shared date and window formats, or all. |
limit |
Set the page size. The default is 50; values above 500 are clamped to 500. |
cursor |
Continue with the opaque cursor from nextPage. Omit it to start; empty or invalid values return 400 invalid_cursor. |
include_annotations |
For team keys, set true to include all stored annotations. false or an empty value omits them. Customer responses always follow grants. |
Within an annotation layer, a Signal matches any requested code. A Signal
without stored data for that layer does not match. Separate annotation layers
combine with AND. Rubric filters, annotation filters, country, topic, and
since also combine with AND.
Unknown category, attribute, or code values return 400 invalid_parameter.
Filtering by an ungranted customer layer returns
403 annotation_layer_not_entitled.
| Field | Meaning |
|---|---|
id |
Signal UUID, subject to the merge lifecycle described below. |
label |
Human-readable name for the occurrence. |
description |
Longer Signal description, or null. |
country_code |
ISO-2 country code. |
signal_start |
Earliest effective date among the Signal's Claims in YYYY-MM-DD format, or null. |
signal_end |
Latest effective date among the Signal's Claims in YYYY-MM-DD format, or null. |
last_claim_at |
Most recent Claim activity timestamp, or null. |
formed_at |
Signal formation timestamp. |
claim_count |
Claims in the Signal. |
source_count |
Distinct Sources supporting the Signal. |
topic |
Current parent {id, label}, or null. |
rubric.version |
Rubric version used to grade the Signal. Legacy rows use the current vocabulary. |
rubric.categories |
Derived category ids in canonical category order. |
rubric.attributes |
True attribute ids in stored order. |
annotations |
Stored annotations available to your key, keyed by layer id. Each value contains codes and rationale, and directions on layers whose codes name a condition. The field is absent when none are included. |
Example:
{
"signals": [
{
"id": "28eeab9d-47f6-4a2e-bd28-cafe6ad6ca19",
"label": "Flooding disrupts homes and water access in Far North",
"description": "Seasonal floodwater affected several communities and interrupted safe-water access.",
"country_code": "CM",
"signal_start": "2026-07-18",
"signal_end": "2026-07-20",
"last_claim_at": "2026-07-20T08:45:00.000Z",
"formed_at": "2026-07-20T09:10:00.000Z",
"claim_count": 1,
"source_count": 1,
"topic": {
"id": "18aad58a-73fb-4966-a640-626c79aa7d39",
"label": "Far North climate and displacement"
},
"rubric": {
"version": "v1.1",
"categories": ["displacement", "natural_disasters", "environmental"],
"attributes": [
"involves_flood",
"involves_displacement",
"involves_water_contamination"
]
},
"annotations": {
"glide_v1": {
"codes": ["fl"],
"rationale": "The Signal describes river flooding affecting several communities."
},
"iasc_v1": {
"codes": ["wash", "shelter"],
"rationale": "The reported impacts concern safe water and emergency shelter."
},
"iep_positive_peace_v1": {
"codes": ["equitable_distribution_of_resources"],
"directions": { "equitable_distribution_of_resources": "eroding" },
"rationale": "Damage to water infrastructure widened the gap in access between affected communities."
}
}
}
],
"nextPage": null,
"pagination": {
"limit": 50,
"count": 1
}
}
Responses use Cache-Control: private, max-age=60.
GET /api/v1/signals/{id}#
Retrieve the canonical active Signal with all of its retrievable Claims. Claims are ordered by numeric id. If the requested id was retired by a merge or split, the API follows its primary successor and returns the canonical Signal instead.
| Parameter | Meaning |
|---|---|
id |
Signal UUID. Invalid UUIDs return 400 invalid_parameter. |
include_annotations |
Uses the same annotation behavior as the Signal list. |
The response adds claims to the Signal fields returned by the list endpoint.
Each embedded Claim uses the list Claim shape. Its signal_id equals the
parent Signal id.
When an attached satellite chip exists and the organization has the
geospatial_v1 enrichment enabled, the response also includes an imagery
array. Each entry contains kind, provider, scene_id,
scene_datetime, scene_cloud_cover, aoi_cloud_fraction, bbox as
[west, south, east, north], pixel width and height, attribution, an
analyst-written caption (a string, or null when none has been written),
and the authenticated PNG url. Cloud values are numbers or null. Entries
are ordered as a before/after story: pre_event, then post_event, then any
derived analysis layer such as burn_map. The entire key is absent without
the enrichment grant, while imagery is pending, when no clear scene was found,
after a failure, or when imagery does not apply to the Signal.
Example:
{
"signal": {
"id": "28eeab9d-47f6-4a2e-bd28-cafe6ad6ca19",
"label": "Flooding disrupts homes and water access in Far North",
"description": "Seasonal floodwater affected several communities and interrupted safe-water access.",
"country_code": "CM",
"signal_start": "2026-07-18",
"signal_end": "2026-07-20",
"last_claim_at": "2026-07-20T08:45:00.000Z",
"formed_at": "2026-07-20T09:10:00.000Z",
"claim_count": 1,
"source_count": 1,
"topic": {
"id": "18aad58a-73fb-4966-a640-626c79aa7d39",
"label": "Far North climate and displacement"
},
"rubric": {
"version": "v1.1",
"categories": ["displacement", "natural_disasters", "environmental"],
"attributes": [
"involves_flood",
"involves_displacement",
"involves_water_contamination"
]
},
"imagery": [
{
"kind": "post_event",
"provider": "sentinel-2-l2a",
"scene_id": "S2B_20260723T091029_CM",
"scene_datetime": "2026-07-23T09:10:29.000Z",
"scene_cloud_cover": 8.42,
"aoi_cloud_fraction": 0.0312,
"bbox": [14.2731, 10.5487, 14.3583, 10.6336],
"width": 512,
"height": 512,
"attribution": "Contains modified Copernicus Sentinel data 2026",
"caption": null,
"url": "/api/v1/signals/28eeab9d-47f6-4a2e-bd28-cafe6ad6ca19/imagery/post_event.png"
}
],
"claims": [
{
"id": "5210",
"claim": "Floodwater entered homes and interrupted access to a community water point.",
"event_date": "2026-07-19",
"occurred_on": "2026-07-19",
"occurred_on": "2026-07-19",
"occurred_on": "2026-07-19",
"extracted_at": "2026-07-20T08:45:00.000Z",
"country_code": "CM",
"geo_scope": "point",
"place_name": "Mayo Crossing",
"place_country": "CM",
"region_code": null,
"lat": 10.5912,
"lng": 14.3157,
"signal_id": "28eeab9d-47f6-4a2e-bd28-cafe6ad6ca19",
"article": {
"url": "https://cameroon-observer.example/far-north-flood-update",
"title": "Communities report flood damage in Far North",
"published_at": "2026-07-20T07:30:00.000Z"
},
"source": {
"id": "a12e699c-cfa2-4ce9-8c01-bec72963ea91",
"name": "Cameroon Observer",
"language": "en",
"country_code": "CM"
}
}
]
}
}
An alias response adds resolved_from beside signal. This abbreviated
example focuses on the response wrapper:
{
"signal": {
"id": "28eeab9d-47f6-4a2e-bd28-cafe6ad6ca19",
"label": "Flooding disrupts homes and water access in Far North",
"claims": []
},
"resolved_from": {
"requested_id": "831ecb98-66b4-4503-b6f7-b66a7477afc0",
"relation": "merged",
"resolved_at_depth": 2,
"overlap": 0.875
}
}
The actual signal object is the complete canonical payload shown above,
including only that Signal's Claims. relation and overlap describe the
first transition from the requested id; resolved_at_depth is the number of
transitions followed. Treat resolved_from as a prompt to replace the stored
reference with signal.id.
If a known id has no active successor, the endpoint returns
410 Gone:
{
"error": "signal_retired",
"id": "831ecb98-66b4-4503-b6f7-b66a7477afc0",
"relation": "dissolved",
"last_seen": "2026-07-20T09:10:00.000Z",
"successors": []
}
last_seen is omitted when it cannot be derived. An id that never existed
still returns 404 not_found.
An existing Signal outside your country access returns
403 country_not_entitled. Responses use
Cache-Control: private, max-age=60.
GET /api/v1/signals/{id}/imagery/{kind}.png#
Retrieve one attached satellite imagery chip. The route resolves retired merge
and split ids to the same canonical active Signal as Signal detail, then applies
the same country entitlement check. Customer organizations must also have the
geospatial_v1 enrichment enabled.
| Parameter | Meaning |
|---|---|
id |
Signal UUID. Invalid UUIDs return 400 invalid_parameter. |
kind |
Imagery kind. The currently emitted value is post_event. |
A missing Signal, unknown imagery kind, pending row, failed row, terminal
no-scene row, absent row, or missing enrichment grant returns the same
404 not_found. An existing Signal outside your country access returns
403 country_not_entitled.
Successful responses use Content-Type: image/png,
Cache-Control: private, max-age=86400, and include the required attribution in
X-Imagery-Attribution.
GET /api/v1/topics#
Topics group related Signals for browsing.
Topic ids are temporary. They can change between processing runs, and the API does not preserve old ids. Store Signal or Claim ids instead. Use filters to find the current Topics.
Results use a stable keyset order. Topic responses do not include rubric or
annotations.
| Parameter | Meaning |
|---|---|
country |
Filter by the Topic's ISO-2 country code. Repeat or comma-separate values to use OR. Matching ignores case. |
category |
Filter by exact category id on a grouped Signal. Repeat or comma-separate ids to use OR. |
attribute |
Require one grouped Signal to have every listed attribute. Repeat or comma-separate exact ids. |
attribute_any |
Require the same grouped Signal to have at least one listed attribute. Repeat or comma-separate exact ids. |
glide_v1 |
Match any listed GLIDE code on the same grouped Signal. Repeat or comma-separate exact codes. |
acled_v1 |
Match any listed ACLED code on the same grouped Signal. Repeat or comma-separate exact codes. |
iasc_v1 |
Match any listed IASC code on the same grouped Signal. Repeat or comma-separate exact codes. |
iep_positive_peace_v1 |
Match any listed IEP Positive Peace pillar on the same grouped Signal. Repeat or comma-separate exact codes. |
iep_positive_peace_v1_direction |
Match any listed direction on the same grouped Signal. Repeat or comma-separate strengthening, eroding, or mixed. |
geospatial_v1 |
Match any listed geospatial imagery-suitability code on the same grouped Signal. Repeat or comma-separate exact codes. |
since |
Filter by Topics grouping a Signal whose latest occurrence falls after this exclusive bound. Defaults to 90d. Use the shared date and window formats, or all. |
limit |
Set the page size. The default is 50; values above 500 are clamped to 500. |
cursor |
Continue with the opaque cursor from nextPage. Omit it to start; empty or invalid values return 400 invalid_cursor. |
One active, labeled Signal within a Topic must satisfy every rubric and
annotation filter. Two Signals cannot satisfy different parts of the same
request.
category, attribute_any, and codes within one annotation layer use OR.
attribute, separate layers, and separate filter groups use AND.
| Field | Meaning |
|---|---|
id |
Temporary Topic UUID. Do not store it. |
label |
Topic label. |
description |
Topic description, or null. |
country_code |
ISO-2 country code. |
signal_count |
Active Signals grouped into the Topic. |
claim_count |
Stored number of Claims represented by the Topic. |
last_claim_at |
Most recent Topic activity timestamp, or null. |
formed_at |
Topic formation timestamp. |
is_fallback |
Whether this is the fallback Topic for Signals that do not form a coherent group. |
Example:
{
"topics": [
{
"id": "18aad58a-73fb-4966-a640-626c79aa7d39",
"label": "Far North climate and displacement",
"description": "Current reporting on seasonal hazards and their community impacts.",
"country_code": "CM",
"signal_count": 4,
"claim_count": 18,
"last_claim_at": "2026-07-20T08:45:00.000Z",
"formed_at": "2026-07-20T09:00:00.000Z",
"is_fallback": false
}
],
"nextPage": null,
"pagination": {
"limit": 50,
"count": 1
}
}
Responses use Cache-Control: private, max-age=60.
GET /api/v1/claims#
With query, results use word matching and semantic similarity across the accessible corpus. search.mode is hybrid, or lexical when the embedding service is unavailable. search.reranked indicates whether evidence-based reranking succeeded; false means the base retrieval order is used. search.truncated indicates more matches than the result limit; nextPage is null for search. Search is a relevance-ranked retrieval aid, not an exhaustive export. Without query, the existing paginated listing is unchanged. No results means no matching reports under the selected filters, not that no event occurred.
List immutable, extracted Claims with article, Source, geography, and current
Signal assignment. Claims are ordered by numeric id.
| Parameter | Meaning |
|---|---|
query |
Search words and meaning (2–500 characters). Returns up to limit results ranked by relevance. No cursor is accepted with a query; narrow your query or filters when search.truncated is true. |
country |
Filter by ISO-2 country code. Repeat or comma-separate values to use OR. Matching ignores case. Omission uses your full country access. |
signal |
Filter by current Signal UUID. Invalid UUIDs return 400 invalid_parameter. A valid UUID with no matches returns an empty list. |
since |
Filter by occurrence time (occurred_on) after this exclusive bound. Claims with a null occurred_on match only all. Defaults to 90d unless you pass since_extracted. |
since_extracted |
Filter by extracted_at after this exclusive bound. Use this parameter for incremental polling. It also turns off the default since window. |
limit |
Set the page size. The default is 50; values above 500 are clamped to 500. |
cursor |
Continue with the opaque cursor from nextPage. Omit it to start; empty or invalid values return 400 invalid_cursor. |
When both time filters are present, both must match. Claims do not support rubric filters because rubric attributes belong to Signals. A new Claim may not have a Signal assignment yet, so rubric filtering would omit it from a poll.
To retrieve Claims under a current Topic, list its Signals with
/signals?topic={id}. Then query Claims by each Signal id.
| Field | Meaning |
|---|---|
id |
Immutable numeric id serialized as a string because database integers can exceed safe JSON integer ranges. |
claim |
Assertion extracted from the source. |
event_date |
Event date stated by the source in YYYY-MM-DD format, or null. |
occurred_on |
Canonical occurrence date: event_date when stated, else the article publish date. null means the occurrence time is unknown. This is the date since filters on. |
extracted_at |
Ingestion timestamp. Poll with since_extracted. |
country_code |
Country used to ingest and authorize access to the Claim. |
geo_scope |
point, country, region, or null. |
place_name |
Extracted place name, or null. |
place_country |
ISO-2 event-place country, or null. |
region_code |
UN M49 region code for a region-scoped Claim, or null. |
lat / lng |
Coordinates only for a point-scoped Claim when both are available; otherwise both null. |
signal_id |
Current Signal UUID, or null while assignment lags ingestion. |
article |
{url, title, published_at}, or null when source content is unavailable. |
source |
{id, name, language, country_code}, or null when the relationship is unavailable. |
Example:
{
"claims": [
{
"id": "5210",
"claim": "Floodwater entered homes and interrupted access to a community water point.",
"event_date": "2026-07-19",
"occurred_on": "2026-07-19",
"occurred_on": "2026-07-19",
"extracted_at": "2026-07-20T08:45:00.000Z",
"country_code": "CM",
"geo_scope": "point",
"place_name": "Mayo Crossing",
"place_country": "CM",
"region_code": null,
"lat": 10.5912,
"lng": 14.3157,
"signal_id": null,
"article": {
"url": "https://cameroon-observer.example/far-north-flood-update",
"title": "Communities report flood damage in Far North",
"published_at": "2026-07-20T07:30:00.000Z"
},
"source": {
"id": "a12e699c-cfa2-4ce9-8c01-bec72963ea91",
"name": "Cameroon Observer",
"language": "en",
"country_code": "CM"
}
}
],
"nextPage": "https://api.livingsignals.example/api/v1/claims?country=CM&limit=1&cursor=NTIxMA",
"pagination": {
"limit": 1,
"count": 1
}
}
article is present when the Claim retains a source-content URL. Its title
and published_at can independently be null. The API decodes common and
numeric HTML entities in article.title.
source is present when the Claim retains a Source id. Its name, language,
and country_code can independently be null.
Distinguish the country fields:
| Field | Meaning |
|---|---|
country_code |
The country used to ingest the Claim. This controls access and may differ from the event location. |
place_country |
The country where the described occurrence happened, when known. |
region_code |
The UN M49 region for a region-scoped Claim when resolved. |
source.country_code |
The outlet's headquarters country. It is often null and can differ from the other country fields. |
Geography values:
| Value | Meaning |
|---|---|
point |
A place-scoped Claim. Coordinates appear only when both are stored. |
country |
A country-scoped Claim. place_country identifies the country. |
region |
A regional Claim. region_code identifies the M49 region when resolution succeeds. |
null |
Geographic precision was not assigned. |
Country- and region-scoped Claims do not include coordinates. Do not display them as point markers.
Availability and assignment timing#
Claims rejected or failed during extraction are not available through the API.
/countries excludes them from Claim counts and coverage dates.
Extraction and Signal assignment happen separately. A new Claim appears in
/claims immediately with signal_id: null. A later processing run may assign
it to a Signal. Polling with since_extracted still returns the Claim. Retrieve
GET /api/v1/claims/{id} again to get its current Signal assignment.
Polling recipe#
For incremental ingestion, record the poll time immediately before the
request. Send it on the next poll as
since_extracted=<previous poll time>. Overlap adjacent windows slightly and
deduplicate by Claim id. This handles boundary timing, retries, and
incomplete page walks.
Follow every non-null nextPage unchanged before you advance the poll time.
This keeps the same filters and server-issued cursor across the page walk.
Do not use occurred_on or since as an incremental cursor. occurred_on
describes source content. It may be old, null, or unreliable. since filters
occurrence time and is not a polling watermark.
Responses use Cache-Control: private, max-age=30.
GET /api/v1/claims/{id}#
Retrieve one Claim in the same shape as a list item. The response wraps it in
{"claim": ...}.
| Parameter | Meaning |
|---|---|
id |
Numeric Claim id. Non-numeric input returns 400 invalid_parameter. |
Example:
{
"claim": {
"id": "5210",
"claim": "Floodwater entered homes and interrupted access to a community water point.",
"event_date": "2026-07-19",
"occurred_on": "2026-07-19",
"extracted_at": "2026-07-20T08:45:00.000Z",
"country_code": "CM",
"geo_scope": "point",
"place_name": "Mayo Crossing",
"place_country": "CM",
"region_code": null,
"lat": 10.5912,
"lng": 14.3157,
"signal_id": "28eeab9d-47f6-4a2e-bd28-cafe6ad6ca19",
"article": {
"url": "https://cameroon-observer.example/far-north-flood-update",
"title": "Communities report flood damage in Far North",
"published_at": "2026-07-20T07:30:00.000Z"
},
"source": {
"id": "a12e699c-cfa2-4ce9-8c01-bec72963ea91",
"name": "Cameroon Observer",
"language": "en",
"country_code": "CM"
}
}
}
An existing Claim outside your country access returns
403 country_not_entitled. A missing, rejected, or failed Claim returns
404 not_found. Responses use Cache-Control: private, max-age=60.
GET /api/v1/sources#
List active Sources by country with recent Claim coverage. Each row represents
one (source, country_code) pair. A Source appears once for each country it
covers. Results are ordered by Source id and then country_code.
| Parameter | Meaning |
|---|---|
country |
Filter by ISO-2 country code. Repeat or comma-separate values to use OR. Matching ignores case. Omission uses your full country access. |
language |
Filter by a two- or three-letter language code. Repeat or comma-separate values to use OR. Matching lowercases input. |
limit |
Set the page size. The default is 100; values above 500 are clamped to 500. |
cursor |
Continue with the opaque cursor from nextPage. Omit it to start; empty or invalid values return 400 invalid_cursor. |
Country and language filters combine with AND.
| Field | Meaning |
|---|---|
id |
Source UUID. |
name |
Source display name. |
url |
Canonical Source URL. |
domain |
Lowercase hostname without a leading www., or null when the URL is invalid. |
language |
Two- or three-letter language code, or null. |
country_code |
Country membership represented by this row, not necessarily Source headquarters. |
type |
Source catalog type string, or null. |
claim_count_30d |
Claims collected for this Source and country during the previous 30 days. This value does not affect ordering. |
Example:
{
"sources": [
{
"id": "a12e699c-cfa2-4ce9-8c01-bec72963ea91",
"name": "Cameroon Observer",
"url": "https://cameroon-observer.example",
"domain": "cameroon-observer.example",
"language": "en",
"country_code": "CM",
"type": "newspaper_independent",
"claim_count_30d": 143
}
],
"nextPage": null,
"pagination": {
"limit": 100,
"count": 1
}
}
Source type values:
| Value | Meaning |
|---|---|
blog |
A blog-format or lightly edited news publisher. |
broadcaster |
A television-first or multi-platform broadcast news outlet. |
gov_official |
An official government publisher or news outlet. |
magazine |
A magazine or periodical journalism outlet. |
news_aggregator |
A service that collects or curates reporting from other publishers. |
newspaper_independent |
An independently controlled newspaper or newsroom. |
newspaper_state |
A state-owned or state-controlled newspaper. |
radio |
A radio-first news outlet. |
wire |
A news agency or wire service that distributes reports to other outlets. |
type may contain any string or null. Preserve values you do not recognize.
Responses use Cache-Control: private, max-age=300.
GET /api/v1/docs and GET /api/v1/openapi.json#
Use these public endpoints to retrieve the Markdown and OpenAPI references. They serve fixed documents, so query parameters do not change the response.
| Parameter | Meaning |
|---|---|
| None |
| Endpoint | Content type | Meaning |
|---|---|---|
GET /api/v1/docs |
text/markdown; charset=utf-8 |
Public Markdown API reference. |
GET /api/v1/openapi.json |
JSON | Public OpenAPI 3.1 route and schema document. |
Markdown response:
# Living Signals REST API v1
Use the read-only Living Signals REST API to explore news-derived Claims,
corroborated Signals, and related Topics.
OpenAPI response excerpt:
{
"openapi": "3.1.0",
"info": {
"title": "Living Signals API",
"version": "v1"
},
"paths": {
"/api/v1/signals": {
"get": {
"summary": "List Signals"
}
},
"/api/v1/claims": {
"get": {
"summary": "List Claims"
}
}
}
}
Browse the OpenAPI document at /reference. Responses from /docs and
/openapi.json use Cache-Control: public, max-age=3600.
Signal lifecycle and id stability#
Claim ids are immutable. Signal ids are durable references. When a merge or
split retires an id, GET /api/v1/signals/{id} follows lineage transitively to
the primary active successor and returns its full payload with
resolved_from. Primary successors are selected by highest stored overlap,
then by the latest transition time.
Claims in the response always belong to the canonical Signal; the API does not
combine Claims from historical identities. When resolved_from appears,
update the stored reference to the returned signal.id.
If an id existed but no active successor remains, the detail endpoint returns
the structured 410 signal_retired body with an empty successors array.
An id that never existed returns 404 not_found.
A Signal can move to a different Topic without receiving a new Claim. Treat
signal.topic as current browsing context, not durable identity.
Signals do not expose updated_at or a since_updated watermark. Incremental
Claim polling cannot fully reveal relabels, merges, annotation updates, or
Topic changes. Periodically perform a complete Signal sync in addition to
polling Claims.
Appendix: rubric vocabulary#
The rubric assigns binary attributes to each Signal. Multiple attributes can be true. Categories group related attributes. A Signal belongs to a category when any member attribute is true, so category membership is derived and can also have multiple values.
GET /api/v1/rubric is the machine-readable source of truth. Its category
order and member order match these tables.
violence_harm — Violence & Harm#
| Attribute id | Label | Description |
|---|---|---|
involves_death |
Deaths/Fatalities | Reports deaths or fatalities |
involves_physical_injury |
Injuries | Reports physical injuries |
involves_sexual_violence |
Sexual Violence | Sexual violence or assault |
involves_domestic_violence |
Domestic Violence | Domestic or intimate partner violence |
involves_kidnapping |
Kidnapping | Kidnapping or hostage-taking |
involves_detention_arrest |
Detention/Arrest | Arrests or detentions |
involves_property_destruction |
Property Destruction | Destruction of property |
civilians_directly_targeted |
Civilians Targeted | Civilians directly targeted |
conflict_intensity — Conflict & Unrest#
| Attribute id | Label | Description |
|---|---|---|
involves_tensions_unrest |
Tensions/Unrest | Social tensions without physical violence |
involves_protest_demonstration |
Protests | Protests or demonstrations |
involves_low_intensity_violence |
Skirmishes | Low-intensity violence, clashes |
involves_firearms |
Firearms Used | Use of firearms or gunfire |
involves_explosives |
Explosives/IEDs | Bombs, IEDs, explosions |
displacement — Displacement & Migration#
| Attribute id | Label | Description |
|---|---|---|
involves_displacement |
Displacement | People displaced from homes |
affects_displaced_persons |
Affects Refugees/IDPs | Impacts on already-displaced |
natural_disasters — Natural Disasters#
| Attribute id | Label | Description |
|---|---|---|
involves_flood |
Flooding | Floods, flash floods |
involves_drought |
Drought | Drought, water scarcity |
involves_storm |
Storms | Hurricanes, cyclones, severe weather |
involves_earthquake_geological |
Earthquakes | Earthquakes, geological events |
involves_wildfire |
Wildfires | Wildfires, bush fires |
health_humanitarian — Health & Humanitarian#
| Attribute id | Label | Description |
|---|---|---|
involves_disease_outbreak |
Disease Outbreak | Epidemics, health emergencies |
involves_humanitarian_response |
Aid Response | Humanitarian aid delivery |
environmental — Environmental#
| Attribute id | Label | Description |
|---|---|---|
involves_environmental_damage |
Environmental Damage | General environmental harm |
involves_deforestation |
Deforestation | Forest destruction, logging |
involves_water_contamination |
Contamination/Pollution | Water pollution or scarcity |
involves_extractive_industry |
Extractive Industry | Mining, oil/gas impacts |
actors — Actors Involved#
| Attribute id | Label | Description |
|---|---|---|
involves_state_military |
State Military | National army, military forces |
involves_state_police |
Police/Security | Police, law enforcement |
involves_non_state_armed_group |
Armed Groups | Rebels, militias, insurgents |
involves_criminal_actors |
Criminal Actors | Gangs, cartels, bandits |
affected_populations — Affected Populations#
| Attribute id | Label | Description |
|---|---|---|
affects_women_girls |
Women & Girls | Gender-specific impacts |
affects_children |
Children | Children as victims |
affects_marginalized_community |
Marginalized Groups | Vulnerable communities |
women_peace_security — Women, Peace & Security#
| Attribute id | Label | Description |
|---|---|---|
involves_women_as_actors |
Women as Actors | Women leading, organizing, mediating, advocating |
involves_gender_policy_action |
Gender Policy Action | Government/institutional action on gender equality |
involves_gender_targeted_rhetoric |
Gender-Targeted Rhetoric | Gender-based hate speech or incitement |
structural — Social Harms#
| Attribute id | Label | Description |
|---|---|---|
involves_discrimination |
Discrimination | Unequal treatment |
involves_marginalization |
Marginalization | Social exclusion |
involves_dispossession |
Dispossession | Loss of land/resources |
involves_chronic_deprivation |
Chronic Deprivation | Long-term poverty |
positive_signals — Peace, Justice & Reform#
| Attribute id | Label | Description |
|---|---|---|
involves_peace_process |
Peace Process | Peace negotiations, ceasefires |
involves_mediation_dialogue |
Mediation/Dialogue | Conflict resolution efforts |
involves_accountability_justice |
Justice Mechanism | Trials, prosecutions, inquiries, transitional justice |
involves_policy_reform |
Institutional Change | New laws, policy changes, institutional reforms |
Attributes without a category#
These attributes do not belong to a category. You can still filter by them
with attribute and attribute_any. They also appear in rubric.attributes.
In GET /api/v1/rubric, they have label: null and an empty categories
array. The section field groups them by theme.
harm_type#
| Attribute id | Description |
|---|---|
involves_harassment_abuse |
Harassment, threats, intimidation, psychological abuse, coercive control, exploitation |
involves_harmful_traditional_practice |
FGM/C, forced/child marriage, honor-based violence, widow inheritance |
involves_forced_immobility |
Trapped populations, movement restrictions, inability to evacuate, siege conditions |
involves_looting_theft |
Looting, armed robbery, highway robbery, theft, pillaging |
involves_economic_loss |
Business closures, job losses, crop failures, financial losses, fiscal crisis |
involves_service_disruption |
Power outages, water supply cut, healthcare unavailable, schools closed |
involves_reproductive_health |
Maternal mortality, reproductive health access, pregnancy complications, family planning barriers |
involves_psychological_trauma |
Trauma, hopelessness, fear, despair, mental health crisis, loneliness epidemic |
involves_air_pollution |
Air quality issues, toxic fumes, emissions, smog, respiratory hazards |
involves_soil_contamination |
Heavy metals, toxic waste, soil poisoning, desertification, erosion |
involves_biodiversity_loss |
Species loss, wildlife deaths, endangered species impacts, ecosystem collapse, bushmeat hunting |
involves_extreme_temperature |
Heat wave, extreme cold, temperature-related deaths or impacts |
involves_arson |
Arson, deliberate burning of buildings/property, fire as weapon |
involves_crop_failure |
Failed harvests, crop destruction, agricultural damage, farm losses |
involves_livestock_loss |
Animal deaths, livestock disease, cattle raiding, herder losses |
involves_market_disruption |
Market closures, supply shortages, price spikes, food scarcity |
actors#
| Attribute id | Description |
|---|---|
involves_terrorist_designation |
Groups explicitly labeled as terrorist by governments or international bodies |
involves_civilian_perpetrators |
Mob violence, individual attackers, community violence |
involves_foreign_actors |
Foreign governments, international forces, cross-border actors |
involves_corporate_actors |
Companies, extractive industries, private contractors |
involves_conservation_actors |
Eco-guards, park rangers, conservation officers, environmental police |
involves_poachers_illegal_extractors |
Poachers, illegal loggers, artisanal/illegal miners, smugglers of natural resources |
involves_traditional_authorities |
Chiefs, traditional councils, customary leaders, elders |
involves_civil_society |
NGOs, community organizations, advocacy groups, humanitarian organizations |
involves_international_organizations |
UN agencies, international NGOs, peacekeepers, international monitors |
affected_population#
| Attribute id | Description |
|---|---|
affects_general_population |
Broad impact not targeting specific demographics |
affects_specific_ethnic_group |
Ethnic targeting, inter-ethnic violence, ethnic minorities affected |
affects_specific_religious_group |
Religious targeting, sectarian violence, religious minorities affected |
affects_elderly |
Elderly/aged as victims or disproportionately affected |
affects_journalists_activists |
Press freedom, civil society targeting, activist persecution |
affects_healthcare_workers |
Attacks on health workers, hospitals targeted, medical staff affected |
causation#
| Attribute id | Description |
|---|---|
cause_natural |
Weather, geological events, natural disasters, disease (natural origin) |
cause_intentional_human |
Deliberate attack, planned action, intentional harm |
cause_unintentional_human |
Accidents, negligence, unintended consequences, human error |
cause_institutional_systemic |
Policy failures, structural issues, systemic neglect, institutional causes |
cause_infrastructure_failure |
Road collapse, dam failure, building collapse, utility failure |
involves_bureaucratic_delay |
Administrative delays, permit denials, bureaucratic obstruction, slow response |
sector#
| Attribute id | Description |
|---|---|
affects_healthcare_system |
Hospitals, clinics, health services, medical supplies, healthcare access |
affects_education_system |
Schools closed, education disrupted, students affected |
affects_water_sanitation |
Water access, clean water, sanitation systems, WASH |
affects_food_security |
Food access, agriculture, food prices, hunger, nutrition |
affects_shelter_housing |
Homelessness, housing destruction, shelter needs |
affects_transportation |
Roads, bridges, airports, transit systems, mobility |
affects_communications |
Internet, phones, media, communications blackouts |
affects_livelihoods |
Jobs, businesses, economic activities, income sources |
affects_governance |
Elections, government function, political institutions, rule of law |
involves_reintegration |
DDR programs, ex-combatant reintegration, refugee return, community reintegration |
involves_community_resilience |
Local coping strategies, community-led response, self-organization, mutual aid |
verification#
| Attribute id | Description |
|---|---|
official_source_cited |
Government statements, official reports, institutional data |
multiple_sources_mentioned |
Corroboration from multiple sources mentioned in the content |
firsthand_account |
Direct witness testimony, on-the-ground reports, first-person accounts |
numbers_explicitly_estimated |
Numbers qualified as estimates, approximations, or uncertain |
Appendix: annotation layers#
Annotation layers map Signals to attributed, independent classification vocabularies. Each layer is versioned. Annotation layers appear only on Signals and do not affect how Signals or Topics form.
Use GET /api/v1/countries to discover available layer ids in
annotation_layers. Use GET /api/v1/annotation-layers to retrieve each
layer's version, attribution, and complete code vocabulary. Customer keys
receive granted layers. Team keys receive every registered layer.
For a customer key, interpret annotations this way:
| Layer granted? | Signal value | Meaning |
|---|---|---|
| Yes | Layer key with non-empty codes |
Graded and stored with the applicable codes. |
| Yes | Layer key with codes: [] |
Graded and stored, but no code applies. |
| Yes | Layer key absent | Grading is not yet stored; treat it as pending. |
| No | Layer key absent | The key is not entitled, so the layer is not exposed. |
For a team key, omitting include_annotations, sending an empty value, or
sending include_annotations=false omits all annotations. An absent layer then
says nothing about its grading state. Send include_annotations=true before
you use the table as an all-layer view.
Annotation example:
{
"annotations": {
"glide_v1": {
"codes": ["fl"],
"rationale": "The Signal describes river flooding."
}
}
}
API codes use lowercase snake_case. GLIDE uses lowercase two-letter codes.
The _v1 suffix pins the vocabulary version. Discover codes from
/annotation-layers instead of assuming that versions share the same values.
glide_v1 — GLIDE disaster event types#
GLIDE is the GLobal IDEntifier number disaster-event taxonomy. API values are lowercase; canonical GLIDE codes are uppercase two-letter codes.
| API code | Canonical GLIDE value | Meaning |
|---|---|---|
cw |
CW — Cold Wave |
Cold-wave events, including cold spells, cold snaps, extreme cold, freezing temperatures, and severe frost. |
ht |
HT — Heat Wave |
Heat-wave events, including extreme, record, scorching, or prolonged heat. |
ce |
CE — Complex Emergency |
A multifaceted or protracted humanitarian crisis, including conflict-driven emergencies or combined shocks. |
dr |
DR — Drought |
Prolonged dry conditions such as rainfall deficit, water scarcity, crop failure, or a failed rainy season. |
eq |
EQ — Earthquake |
Seismic events including earthquakes, quakes, tremors, and aftershocks. |
ep |
EP — Epidemic |
A disease epidemic or outbreak, including rapid transmission and public-health emergencies. |
ec |
EC — Extratropical Cyclone |
A mid-latitude or temperate cyclone, frontal storm, winter cyclone, or intense low-pressure system. |
fr |
FR — Fire |
A fire event such as a structure, urban, building, or industrial fire. |
ff |
FF — Flash Flood |
Sudden, rapid-onset flooding, often associated with torrential rain or runoff. |
fl |
FL — Flood |
General flooding or inundation, including river overflow and seasonal flooding. |
in |
IN — Insect Infestation |
An agricultural insect or pest outbreak, including locust swarms and armyworm infestation. |
sl |
SL — Slide |
Ground, soil, earth, or slope movement and instability classified as a slide. |
ls |
LS — Land Slide |
A landslide or land slide, including slope failure, hillside collapse, and debris slide. |
ms |
MS — Mud Slide |
A mudslide, mudflow, or saturated debris flow, including rain-triggered mud movement. |
av |
AV — Snow Avalanche |
A snow avalanche, snow-slide, slab release, or snowpack collapse. |
st |
ST — Severe Local Storm |
A severe local or convective storm, including thunderstorms, hailstorms, and damaging windstorms. |
ac |
AC — Technological Disaster |
A technological or industrial accident such as a chemical/oil spill, radiological incident, infrastructure failure, or dam failure. |
to |
TO — Tornado |
A tornado or tornadic vortex, including funnel-cloud and touchdown events. |
tc |
TC — Tropical Cyclone |
A tropical cyclone, hurricane, typhoon, or tropical storm, including landfall. |
ss |
SS — Storm Surge |
Storm-driven coastal surge or inundation, including high storm tide and seawater intrusion. |
ts |
TS — Tsunami |
A tsunami or seismic sea wave, including coastal wave run-up and inundation. |
vo |
VO — Volcano |
A volcanic eruption or activity, including ash, lava, pyroclastic flow, and tephra fall. |
wf |
WF — Wild Fire |
A wildfire or uncontrolled forest, bush, vegetation, or grass fire. |
vw |
VW — Violent Wind |
Destructive high-wind events, including damaging gusts and gale-force winds. |
ot |
OT — Other |
An emergency, humanitarian situation, or security incident not classified under another GLIDE event type. |
acled_v1 — ACLED event sub-types#
ACLED is the Armed Conflict Location & Event Data Project taxonomy. API codes are slugified forms of ACLED's canonical sub-event type names. The event-type family in each meaning also comes from the registered definition.
| API code | Canonical ACLED sub-event type | Meaning |
|---|---|---|
armed_clash |
Armed clash | A Battles sub-event recording an armed clash. |
government_regains_territory |
Government regains territory | A Battles sub-event in which government forces regain territory. |
non_state_actor_overtakes_territory |
Non-state actor overtakes territory | A Battles sub-event in which a non-state actor takes territory. |
chemical_weapon |
Chemical weapon | An Explosions/Remote violence sub-event involving a chemical weapon. |
air_or_drone_strike |
Air/drone strike | An Explosions/Remote violence sub-event involving an air or drone strike. |
suicide_bomb |
Suicide bomb | An Explosions/Remote violence sub-event involving a suicide bomb. |
shelling_artillery_missile |
Shelling/artillery/missile attack | An Explosions/Remote violence sub-event involving shelling, artillery, or a missile attack. |
remote_explosive_landmine_ied |
Remote explosive/landmine/IED | An Explosions/Remote violence sub-event involving a remote explosive, landmine, or IED. |
grenade |
Grenade | An Explosions/Remote violence sub-event involving a grenade. |
sexual_violence |
Sexual violence | A Violence against civilians sub-event specifically involving sexual violence; it does not mean restrictions on women's rights. |
attack |
Attack | A Violence against civilians event using ACLED's general Attack sub-event. |
abduction_forced_disappearance |
Abduction/forced disappearance | A Violence against civilians sub-event involving abduction or forced disappearance. |
peaceful_protest |
Peaceful protest | A Protests sub-event recording a peaceful protest. |
protest_with_intervention |
Protest with intervention | A Protests sub-event recording intervention in a protest. |
excessive_force_against_protesters |
Excessive force against protesters | A Protests sub-event recording excessive force against protesters. |
violent_demonstration |
Violent demonstration | A Riots sub-event recording a violent demonstration. |
mob_violence |
Mob violence | A Riots sub-event recording mob violence. |
agreement |
Agreement | A Strategic developments sub-event recording an agreement. |
arrests |
Arrests | A Strategic developments sub-event recording arrests. |
change_to_group_or_activity |
Change to group/activity | A Strategic developments sub-event recording a change to a group or its activity. |
disrupted_weapons_use |
Disrupted weapons use | A Strategic developments sub-event for physical weapon seizure or interception, not arms-control talks or agreements. |
headquarters_or_base_established |
Headquarters or base established | A Strategic developments sub-event recording establishment of a headquarters or base. |
looting_property_destruction |
Looting/property destruction | A Strategic developments sub-event involving looting or property destruction. |
non_violent_transfer_of_territory |
Non-violent transfer of territory | A Strategic developments sub-event recording a non-violent territorial transfer. |
other_strategic_development |
Other | ACLED's other Strategic developments sub-event. |
iasc_v1 — IASC humanitarian coordination clusters#
IASC is the Inter-Agency Standing Committee humanitarian coordination standard. API codes map to its canonical domain names.
| API code | Canonical IASC value | Meaning |
|---|---|---|
protection |
Protection | Safety, dignity, and rights of affected people; child protection, GBV response, mine action, housing/land/property, and rule of law. |
health |
Health | Disease outbreaks, medical care, health facilities and workers, immunization, and mental health. |
wash |
Water, Sanitation and Hygiene | Safe-water access, sanitation, hygiene, and disease-vector control. |
shelter |
Shelter and NFI | Emergency shelter, housing, and non-food relief items. |
food_security |
Food Security | Food access and availability, agriculture, livelihoods, and market disruption affecting food. |
nutrition |
Nutrition | Malnutrition, therapeutic feeding, and infant and young-child feeding. |
education |
Education | Access to schooling, attacks on education, and learning continuity in emergencies. |
cccm |
Camp Coordination and Camp Management | Management of displacement sites and camps, site services, and population tracking. |
logistics |
Logistics | Supply chains, transport, storage, and access constraints for relief. |
early_recovery |
Early Recovery | Restoration of basic services, livelihoods, governance, and infrastructure after crisis. |
emergency_telecommunications |
Emergency Telecommunications | Communications infrastructure, connectivity, and data services for response, including telecom or internet blackouts. |
iep_positive_peace_v1 — IEP Positive Peace pillars#
Positive Peace is the Institute for Economics & Peace framework describing the attitudes, institutions, and structures that sustain peaceful societies. API codes map to its pillar names.
This layer describes the societal condition a Signal speaks to, not what
happened. Positive Peace is defined against the absence of violence, which IEP
measures separately through the Global Peace Index, so violent events, natural
hazards, and their humanitarian impacts carry no pillar and return an empty
codes array. Use glide_v1 and acled_v1 to classify those.
A pillar names the condition under discussion, never a verdict that the
condition is in good health. An anti-corruption prosecution and an embezzlement
scandal both carry low_levels_of_corruption. Read the code together with
directions, which records which way the evidence points for each assigned
code:
| Direction | Meaning |
|---|---|
strengthening |
The Signal shows the condition being built up, improved, or upheld. |
eroding |
The Signal shows it being weakened, damaged, or failing. |
mixed |
The Signal shows both, or the evidence does not point either way. |
So a report of extrajudicial killings returns
well_functioning_government with direction eroding — the Signal is about the
rule of law, and the rule of law is failing.
To filter on direction, attach it to the pillar it applies to:
?iep_positive_peace_v1=well_functioning_government:eroding
The direction is scoped to that pillar, so a Signal whose rule of law is
strengthening does not match, even if another of its pillars is eroding. Pillars
in the same request are independent — well_functioning_government:eroding,low_levels_of_corruption
narrows the first and leaves the second matching in any direction. To ask the
looser question across the whole layer, use iep_positive_peace_v1_direction
on its own.
A pillar is recorded only where the Signal reveals something about how the condition stands. Routine administration — procurement, workshops, ceremonies, appointments, internal meetings — and internal political party business such as primaries and campaign strategy carry no pillar on their own.
| API code | Canonical IEP value | Meaning |
|---|---|---|
well_functioning_government |
Well-Functioning Government | Public service delivery, political stability, rule of law, courts and administration, elections and transfers of power, and trust in governing institutions. |
sound_business_environment |
Sound Business Environment | Economic conditions and the institutions supporting private enterprise, including regulation, banking, competitiveness, and productive economic activity. |
equitable_distribution_of_resources |
Equitable Distribution of Resources | Fairness of access to health care, education, and income, and disputes over how public resources are shared between groups or regions. |
acceptance_of_the_rights_of_others |
Acceptance of the Rights of Others | Formal rights and the norms behind them, including treatment of minorities, women, migrants, and marginalised groups, discrimination, group grievance, and social exclusion. |
good_relations_with_neighbours |
Good Relations with Neighbours | Relations with other countries and between ethnic, religious, and cultural groups, including diplomacy, cross-border cooperation and trade, and reconciliation. |
free_flow_of_information |
Free Flow of Information | Media independence and reach, press freedom and treatment of journalists, censorship, internet and telecommunications access, and disinformation. |
high_levels_of_human_capital |
High Levels of Human Capital | Education systems and attainment, health and life expectancy, youth employment and training, and research capacity. |
low_levels_of_corruption |
Low Levels of Corruption | Bribery, embezzlement and public-sector theft, procurement fraud, entrenched or factionalised elites, and anti-corruption investigations and prosecutions. |
The Positive Peace Index indicators beneath these pillars measure countries over years rather than classify events, and are not part of this layer. No IEP index values are reproduced through this API.
geospatial_v1 — Living Signals geospatial imagery suitability#
This focused operational layer records whether a Signal describes already
observed physical effects that may support a useful 10 m/pixel optical
satellite chip. It is independent of the rubric. Signals about ceremonies,
inaugurations, commissionings, openings, financing approvals, plans, appeals,
or statements about physical things receive an empty codes array.
| API code | Canonical value | Meaning |
|---|---|---|
visible_landscape_change |
Visible landscape change | The event has already altered the land surface with a footprint plausibly visible in 10 m/pixel optical imagery, such as flooding extent, a burn scar, a landslide, large-scale destruction, active land clearing, or a mass displacement site. |
wide_area |
Wide area | The physically affected area spans roughly a hectare or more, such as multiple city blocks, a neighborhood, or a stretch of river or forest, rather than one building, compound, or vehicle. |
persistent_trace |
Persistent trace | The visible trace will remain on the ground for two weeks or more, rather than an ephemeral effect such as smoke, crowds, or a temporary closure. |