Endpoint#
GET /api/datasets
Public filtered read-only archive access, without sign-in or inference calls. Ordered by collection timestamp descending then stable ID descending. Cursor pages keep a fixed query cutoff and insertion high-water mark; document metadata remains a current projection, not an immutable historical edition. Social rows are repeated list observations, not distinct posts or public-opinion measures. Economic collection dates differ from reference periods. Original extraction is released only under reviewed per-document rights tied to the exact original text; other records link to the publisher. WeChat heat is null because historical raw_score values were ordering positions. Unknown and repeated query parameters are rejected. GET and OPTIONS permit cross-origin access. next_cursor is null on the last page. Order is collection timestamp descending, then id descending, so a page is stable for the lifetime of its cursor. row_count is the rows in this response, not a total.
Authentication#
[]An empty security requirement means this operation does not declare authentication. Read operation notes for entitlement and protocol-method requirements.
Parameters#
| Name | In | Required | Description |
|---|---|---|---|
| dataset | query | No | Choose the retained source documents, sampled social hot-list observations, or indicators. |
| mode | query | No | raw: one row per record (documents) or per collection run (social, indicators). release (indicators): one row per (series_id, period), with previous value, first and latest capture, and a revised flag. changes (documents): new and revised events after since=, oldest first; GET /api/changes is the contract route for this feed. topics (social): one row per (platform, topic) within the from/to window (default 30 days, max 92). |
| watch | query | No | Alias of topic (the older name). Passing both with different values is invalid_parameter. |
| topic | query | No | Reviewed bilingual topic filter (documents, social): a case-insensitive title match on one of the listed terms, nothing inferred. export-controls is conservative: every term names export control or dual-use items itself. Terms and review dates: list_watchlists (MCP) or api/_watchlists.py. |
| since | query | No | mode=changes only, and required there: an ISO-8601 instant with a timezone (UTC recommended, e.g. 2026-10-29T00:00:00Z), inclusive, compared with the event time (change_at / event_at, our collection clock). To continue, pass the previous next_since back as since. A malformed or altered next_since token is invalid_cursor. |
| series | query | No | Indicators only. Exact series_id, e.g. cpi-yoy. |
| q | query | No | Literal case-insensitive substring of displayed/original title or publisher. No semantic search, query translation, or full-body search. |
| source | query | No | Case-insensitive exact publisher label; use the response sources list. |
| from | query | No | Inclusive start day, YYYY-MM-DD, read as 00:00:00 UTC. It filters the COLLECTION timestamp, not the publication date: documents use first_seen (when we first collected the record), social observations use the captured_at time of the list read, indicators use captured_at (mode=release: first capture). published_at and the economic reference period period are returned but cannot be filtered. Years 2000 through 2099. Must not be after to. A tier's history window (x-api-tiers history_days) raises the effective start; a from before it is rejected with invalid_parameter. |
| to | query | No | Inclusive end day, YYYY-MM-DD, UTC: records collected before 00:00:00 UTC of the following day are included. Same timestamp as from (first_seen / captured_at, not publication date or reference period). |
| limit | query | No | Rows per page, 1 to the caller's tier ceiling, default 50. Ceilings come from api/tiers.py: Anonymous 100; Free key 500; Pro 5,000; Team 5,000. A larger value returns invalid_parameter, never a silently smaller page. max_page_size in the response repeats the ceiling. |
| cursor | query | No | Pass the previous page's next_cursor unchanged, with the same dataset, q, source, from, to, text, mode and series; limit, fields and format may change. The cursor fixes the query cutoff (as_of) and a row high-water mark taken on the first page, so rows collected later never appear mid-walk and no row repeats or is skipped. It is signed, opaque and expires 24 hours after the FIRST page (not after each page): an expired, altered or mismatched cursor returns invalid_cursor, and the fix is to restart without a cursor. Document metadata is a current projection, so a row can change between a walk's pages even though the set of rows cannot. |
| change_type | query | No | Documents only (mode=raw): new, newly_discovered (published more than 2 days, Beijing date, before first_seen) or revised (a changed body observed after first_seen). Field meanings: /data/data-contract.json. |
| text | query | No | Documents only: select records with individually approved original text. Omit to browse all document metadata. |
| fields | query | No | Comma-separated unique field keys from fields in this dataset response. Defaults to all available fields. original_text/text_truncated/rights_basis_url require a documents id request. |
| format | query | No | CSV downloads one bounded page as UTF-8 with BOM and formula-safe string cells, never the entire matching archive. The selected fields are followed by a computed citation column. |
| id | query | No | Stable record ID returned by this dataset. Cannot combine with q/source/from/to/text/cursor. Document detail includes only individually approved original text, capped at 120,000 characters, otherwise null. |
Responses and errors#
| HTTP status | Meaning |
|---|---|
| 200 | A real retained-archive page or single record; no fabricated totals or static fallback. |
| 400 | Invalid query, field, date or cursor. Body carries code: see x-error-codes. |
| 404 | Requested record is absent. Body carries code: see x-error-codes. |
| 405 | Use GET. Body carries code: see x-error-codes. |
| 429 | Rate limit exceeded (60 requests per minute). Body carries code: see x-error-codes. |
| 503 | Retained archive or request protection unavailable; retry later. Body carries code: see x-error-codes. |
Response examples#
No response example is supplied by OpenAPI for this operation. The complete response schemas are preserved below; use an actual response for observed values.
Runnable request#
curl --fail-with-body --silent --show-error --max-time 30 "https://china-snapshot.com/api/datasets?dataset=documents&limit=1"import json
from urllib.request import Request, urlopen
request = Request('https://china-snapshot.com/api/datasets?dataset=documents&limit=1')
with urlopen(request, timeout=30) as response:
data = json.load(response)
print(json.dumps(data, ensure_ascii=False))const response = await fetch("https://china-snapshot.com/api/datasets?dataset=documents&limit=1");
if (!response.ok) throw new Error(`HTTP ${response.status}`);
console.log(await response.json());Retry guidance#
See errors and retries. Honor operation-specific response headers. A POST may create state; do not replay it automatically.
Complete operation contract#
The expanded contract below includes all parameter constraints, response headers, schemas and examples from OpenAPI.
{
"path": "/api/datasets",
"method": "GET",
"parameters": [
{
"name": "dataset",
"in": "query",
"required": false,
"schema": {
"type": "string",
"enum": [
"documents",
"social",
"indicators"
],
"default": "documents"
},
"description": "Choose the retained source documents, sampled social hot-list observations, or indicators."
},
{
"name": "mode",
"in": "query",
"required": false,
"schema": {
"type": "string",
"enum": [
"raw",
"release",
"changes",
"topics"
],
"default": "raw"
},
"description": "raw: one row per record (documents) or per collection run (social, indicators). release (indicators): one row per (series_id, period), with previous value, first and latest capture, and a revised flag. changes (documents): new and revised events after since=, oldest first; GET /api/changes is the contract route for this feed. topics (social): one row per (platform, topic) within the from/to window (default 30 days, max 92)."
},
{
"name": "watch",
"in": "query",
"required": false,
"schema": {
"type": "string",
"enum": [
"data-security",
"export-controls",
"property-support",
"semiconductors"
]
},
"description": "Alias of topic (the older name). Passing both with different values is invalid_parameter."
},
{
"name": "topic",
"in": "query",
"required": false,
"schema": {
"type": "string",
"enum": [
"data-security",
"export-controls",
"property-support",
"semiconductors"
]
},
"description": "Reviewed bilingual topic filter (documents, social): a case-insensitive title match on one of the listed terms, nothing inferred. export-controls is conservative: every term names export control or dual-use items itself. Terms and review dates: list_watchlists (MCP) or api/_watchlists.py."
},
{
"name": "since",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "mode=changes only, and required there: an ISO-8601 instant with a timezone (UTC recommended, e.g. 2026-10-29T00:00:00Z), inclusive, compared with the event time (change_at / event_at, our collection clock). To continue, pass the previous next_since back as since. A malformed or altered next_since token is invalid_cursor."
},
{
"name": "series",
"in": "query",
"required": false,
"schema": {
"type": "string",
"pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
"maxLength": 120
},
"description": "Indicators only. Exact series_id, e.g. cpi-yoy."
},
{
"name": "q",
"in": "query",
"required": false,
"schema": {
"type": "string",
"maxLength": 180
},
"description": "Literal case-insensitive substring of displayed/original title or publisher. No semantic search, query translation, or full-body search."
},
{
"name": "source",
"in": "query",
"required": false,
"schema": {
"type": "string",
"maxLength": 180
},
"description": "Case-insensitive exact publisher label; use the response sources list."
},
{
"name": "from",
"in": "query",
"required": false,
"schema": {
"type": "string",
"format": "date"
},
"description": "Inclusive start day, YYYY-MM-DD, read as 00:00:00 UTC. It filters the COLLECTION timestamp, not the publication date: documents use first_seen (when we first collected the record), social observations use the captured_at time of the list read, indicators use captured_at (mode=release: first capture). published_at and the economic reference period `period` are returned but cannot be filtered. Years 2000 through 2099. Must not be after `to`. A tier's history window (x-api-tiers history_days) raises the effective start; a `from` before it is rejected with invalid_parameter."
},
{
"name": "to",
"in": "query",
"required": false,
"schema": {
"type": "string",
"format": "date"
},
"description": "Inclusive end day, YYYY-MM-DD, UTC: records collected before 00:00:00 UTC of the following day are included. Same timestamp as `from` (first_seen / captured_at, not publication date or reference period)."
},
{
"name": "limit",
"in": "query",
"required": false,
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 5000,
"default": 50
},
"description": "Rows per page, 1 to the caller's tier ceiling, default 50. Ceilings come from api/tiers.py: Anonymous 100; Free key 500; Pro 5,000; Team 5,000. A larger value returns invalid_parameter, never a silently smaller page. max_page_size in the response repeats the ceiling."
},
{
"name": "cursor",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "Pass the previous page's next_cursor unchanged, with the same dataset, q, source, from, to, text, mode and series; limit, fields and format may change. The cursor fixes the query cutoff (as_of) and a row high-water mark taken on the first page, so rows collected later never appear mid-walk and no row repeats or is skipped. It is signed, opaque and expires 24 hours after the FIRST page (not after each page): an expired, altered or mismatched cursor returns invalid_cursor, and the fix is to restart without a cursor. Document metadata is a current projection, so a row can change between a walk's pages even though the set of rows cannot."
},
{
"name": "change_type",
"in": "query",
"required": false,
"schema": {
"type": "string",
"enum": [
"new",
"newly_discovered",
"revised"
]
},
"description": "Documents only (mode=raw): new, newly_discovered (published more than 2 days, Beijing date, before first_seen) or revised (a changed body observed after first_seen). Field meanings: /data/data-contract.json."
},
{
"name": "text",
"in": "query",
"required": false,
"schema": {
"type": "string",
"enum": [
"available"
]
},
"description": "Documents only: select records with individually approved original text. Omit to browse all document metadata."
},
{
"name": "fields",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "Comma-separated unique field keys from fields in this dataset response. Defaults to all available fields. original_text/text_truncated/rights_basis_url require a documents id request."
},
{
"name": "format",
"in": "query",
"required": false,
"schema": {
"type": "string",
"enum": [
"json",
"csv"
],
"default": "json"
},
"description": "CSV downloads one bounded page as UTF-8 with BOM and formula-safe string cells, never the entire matching archive. The selected fields are followed by a computed citation column."
},
{
"name": "id",
"in": "query",
"required": false,
"schema": {
"type": "string",
"pattern": "^(documents|social|indicators):[1-9][0-9]*$"
},
"description": "Stable record ID returned by this dataset. Cannot combine with q/source/from/to/text/cursor. Document detail includes only individually approved original text, capped at 120,000 characters, otherwise null."
}
],
"operationId": "browsePublicDatasets",
"summary": "Browse and export retained China records",
"description": "Public filtered read-only archive access, without sign-in or inference calls. Ordered by collection timestamp descending then stable ID descending. Cursor pages keep a fixed query cutoff and insertion high-water mark; document metadata remains a current projection, not an immutable historical edition. Social rows are repeated list observations, not distinct posts or public-opinion measures. Economic collection dates differ from reference periods. Original extraction is released only under reviewed per-document rights tied to the exact original text; other records link to the publisher. WeChat heat is null because historical raw_score values were ordering positions. Unknown and repeated query parameters are rejected. GET and OPTIONS permit cross-origin access. next_cursor is null on the last page. Order is collection timestamp descending, then id descending, so a page is stable for the lifetime of its cursor. row_count is the rows in this response, not a total.",
"tags": [
"data",
"Find records",
"Retrieve a record",
"Inspect observations",
"Export"
],
"security": [],
"responses": {
"200": {
"description": "A real retained-archive page or single record; no fabricated totals or static fallback.",
"headers": {
"X-Dataset-Row-Count": {
"schema": {
"type": "integer"
},
"description": "Rows in this response."
},
"X-Dataset-Next-Cursor": {
"schema": {
"type": "string"
},
"description": "Continuation cursor; empty at the end. Also exposed to cross-origin browsers."
},
"X-Dataset-Next-Since": {
"schema": {
"type": "string"
},
"description": "mode=changes and /api/changes: the next_since token; empty otherwise."
},
"X-Dataset-Export-Scope": {
"schema": {
"enum": [
"page",
"record"
]
},
"description": "Explicit export scope."
}
},
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"schema_version",
"dataset",
"mode",
"as_of",
"items",
"row_count",
"next_cursor",
"sources",
"sources_truncated",
"coverage",
"fields",
"export_scope",
"max_page_size",
"links"
],
"properties": {
"schema_version": {
"const": 1
},
"dataset": {
"type": "string",
"enum": [
"documents",
"social",
"indicators"
]
},
"mode": {
"type": "string",
"enum": [
"raw",
"release",
"changes",
"topics"
]
},
"as_of": {
"type": "string",
"format": "date-time",
"description": "Query cutoff fixed on the first page; not a claim about source freshness."
},
"items": {
"type": "array",
"maxItems": 5000,
"items": {
"anyOf": [
{
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"pattern": "^documents:[1-9][0-9]*$",
"description": "Record ID"
},
"title": {
"type": [
"string",
"null"
],
"description": "Title"
},
"title_lang": {
"type": [
"string",
"null"
],
"description": "Title language"
},
"is_translated": {
"type": [
"boolean",
"null"
],
"description": "Title is a machine translation"
},
"source": {
"type": [
"string",
"null"
],
"description": "Publisher"
},
"source_url": {
"type": [
"string",
"null"
],
"description": "Original source"
},
"original_title": {
"type": [
"string",
"null"
],
"description": "Original title"
},
"published_at": {
"type": [
"string",
"null"
],
"description": "Publication date",
"format": "date"
},
"collected_at": {
"type": [
"string",
"null"
],
"description": "First collected",
"format": "date-time"
},
"language": {
"type": [
"string",
"null"
],
"description": "Original language"
},
"topic": {
"type": [
"string",
"null"
],
"description": "Topic"
},
"text_status": {
"type": [
"string",
"null"
],
"description": "Text availability",
"enum": [
"available",
"source_only",
"not_extracted"
]
},
"publisher": {
"type": [
"string",
"null"
],
"description": "Publisher"
},
"acquisition_route": {
"type": [
"string",
"null"
],
"description": "Acquisition route"
},
"translated_title": {
"type": [
"string",
"null"
],
"description": "Translated title"
},
"first_seen": {
"type": [
"string",
"null"
],
"description": "First seen",
"format": "date-time"
},
"last_seen": {
"type": [
"string",
"null"
],
"description": "Last seen",
"format": "date-time"
},
"observation_count": {
"type": [
"integer",
"null"
],
"description": "Observations"
},
"change_type": {
"type": [
"string",
"null"
],
"description": "Change type",
"enum": [
"new",
"newly_discovered",
"revised",
null
]
},
"version_count": {
"type": [
"integer",
"null"
],
"description": "Retained versions"
},
"last_revised_at": {
"type": [
"string",
"null"
],
"description": "Last changed body observed",
"format": "date-time"
},
"content_hash": {
"type": [
"string",
"null"
],
"description": "Hash of the current extracted text"
},
"original_text": {
"type": [
"string",
"null"
],
"description": "Original-language extraction"
},
"text_truncated": {
"type": [
"boolean",
"null"
],
"description": "Text truncated"
},
"rights_basis_url": {
"type": [
"string",
"null"
],
"description": "Republication basis"
},
"observations": {
"type": [
"array",
"null"
],
"description": "Collections of this document"
},
"observations_total": {
"type": [
"integer",
"null"
],
"description": "Total collections"
},
"revisions": {
"type": [
"array",
"null"
],
"description": "Retained content versions"
}
},
"description": "documents: selected fields only; null means not retained or not available."
},
{
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"pattern": "^documents:[1-9][0-9]*$",
"description": "Record ID"
},
"title": {
"type": [
"string",
"null"
],
"description": "Title"
},
"title_lang": {
"type": [
"string",
"null"
],
"description": "Title language"
},
"is_translated": {
"type": [
"boolean",
"null"
],
"description": "Title is a machine translation"
},
"source": {
"type": [
"string",
"null"
],
"description": "Publisher"
},
"source_url": {
"type": [
"string",
"null"
],
"description": "Original source"
},
"change_type": {
"type": [
"string",
"null"
],
"description": "Change type",
"enum": [
"new",
"newly_discovered",
"revised",
null
]
},
"change_at": {
"type": [
"string",
"null"
],
"description": "Change time (UTC)",
"format": "date-time"
},
"event": {
"type": [
"string",
"null"
],
"description": "Event"
},
"event_at": {
"type": [
"string",
"null"
],
"description": "Event time",
"format": "date-time"
},
"original_title": {
"type": [
"string",
"null"
],
"description": "Original title"
},
"published_at": {
"type": [
"string",
"null"
],
"description": "Publication date",
"format": "date"
},
"first_seen_at": {
"type": [
"string",
"null"
],
"description": "First collected",
"format": "date-time"
},
"content_hash": {
"type": [
"string",
"null"
],
"description": "Hash of the extracted text at this event"
},
"language": {
"type": [
"string",
"null"
],
"description": "Original language"
}
},
"description": "document_changes: selected fields only; null means not retained or not available."
},
{
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"pattern": "^social_topics:[1-9][0-9]*$",
"description": "Record ID"
},
"title": {
"type": [
"string",
"null"
],
"description": "Title"
},
"title_lang": {
"type": [
"string",
"null"
],
"description": "Title language"
},
"is_translated": {
"type": [
"boolean",
"null"
],
"description": "Title is a machine translation"
},
"source": {
"type": [
"string",
"null"
],
"description": "Publisher"
},
"source_url": {
"type": [
"string",
"null"
],
"description": "Original source"
},
"topic": {
"type": [
"string",
"null"
],
"description": "Topic"
},
"original_title": {
"type": [
"string",
"null"
],
"description": "Original title"
},
"first_seen_at": {
"type": [
"string",
"null"
],
"description": "First seen in window",
"format": "date-time"
},
"last_seen_at": {
"type": [
"string",
"null"
],
"description": "Last seen in window",
"format": "date-time"
},
"observations": {
"type": [
"integer",
"null"
],
"description": "List appearances in window"
},
"best_rank": {
"type": [
"integer",
"null"
],
"description": "Best rank in window"
},
"item_key": {
"type": [
"string",
"null"
],
"description": "Stable item key"
}
},
"description": "social_topics: selected fields only; null means not retained or not available."
},
{
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"pattern": "^social:[1-9][0-9]*$",
"description": "Record ID"
},
"title": {
"type": [
"string",
"null"
],
"description": "Title"
},
"title_lang": {
"type": [
"string",
"null"
],
"description": "Title language"
},
"is_translated": {
"type": [
"boolean",
"null"
],
"description": "Title is a machine translation"
},
"source": {
"type": [
"string",
"null"
],
"description": "Publisher"
},
"source_url": {
"type": [
"string",
"null"
],
"description": "Original source"
},
"original_title": {
"type": [
"string",
"null"
],
"description": "Original title"
},
"observed_at": {
"type": [
"string",
"null"
],
"description": "Observed at",
"format": "date-time"
},
"rank": {
"type": [
"integer",
"null"
],
"description": "Observed rank"
},
"heat": {
"type": [
"string",
"null"
],
"description": "Publisher heat score"
},
"platform": {
"type": [
"string",
"null"
],
"description": "Platform"
},
"board": {
"type": [
"string",
"null"
],
"description": "Board"
},
"collected_at": {
"type": [
"string",
"null"
],
"description": "Collected at",
"format": "date-time"
},
"original_topic": {
"type": [
"string",
"null"
],
"description": "Original topic"
},
"translated_topic": {
"type": [
"string",
"null"
],
"description": "Translated topic"
},
"item_key": {
"type": [
"string",
"null"
],
"description": "Stable item key"
}
},
"description": "social: selected fields only; null means not retained or not available."
},
{
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"pattern": "^indicators:[1-9][0-9]*$",
"description": "Record ID"
},
"title": {
"type": [
"string",
"null"
],
"description": "Title"
},
"title_lang": {
"type": [
"string",
"null"
],
"description": "Title language"
},
"is_translated": {
"type": [
"boolean",
"null"
],
"description": "Title is a machine translation"
},
"source": {
"type": [
"string",
"null"
],
"description": "Publisher"
},
"source_url": {
"type": [
"string",
"null"
],
"description": "Original source"
},
"period": {
"type": [
"string",
"null"
],
"description": "Reference period"
},
"value": {
"type": [
"string",
"null"
],
"description": "Published value"
},
"numeric_value": {
"type": [
"number",
"null"
],
"description": "Numeric value"
},
"unit": {
"type": [
"string",
"null"
],
"description": "Unit"
},
"collected_at": {
"type": [
"string",
"null"
],
"description": "Collected at",
"format": "date-time"
},
"series_id": {
"type": [
"string",
"null"
],
"description": "Series ID"
},
"frequency": {
"type": [
"string",
"null"
],
"description": "Frequency"
},
"release_date": {
"type": [
"string",
"null"
],
"description": "Release date (Beijing)",
"format": "date"
},
"revision_status": {
"type": [
"string",
"null"
],
"description": "Revision status",
"enum": [
"first_release",
"repeat_collection",
"revised",
"unknown",
null
]
}
},
"description": "indicators: selected fields only; null means not retained or not available."
},
{
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"pattern": "^indicator_releases:[1-9][0-9]*$",
"description": "Record ID"
},
"title": {
"type": [
"string",
"null"
],
"description": "Title"
},
"title_lang": {
"type": [
"string",
"null"
],
"description": "Title language"
},
"is_translated": {
"type": [
"boolean",
"null"
],
"description": "Title is a machine translation"
},
"source": {
"type": [
"string",
"null"
],
"description": "Publisher"
},
"source_url": {
"type": [
"string",
"null"
],
"description": "Original source"
},
"series_id": {
"type": [
"string",
"null"
],
"description": "Series ID"
},
"frequency": {
"type": [
"string",
"null"
],
"description": "Frequency"
},
"period": {
"type": [
"string",
"null"
],
"description": "Reference period"
},
"value": {
"type": [
"string",
"null"
],
"description": "Latest value"
},
"numeric_value": {
"type": [
"number",
"null"
],
"description": "Latest numeric value"
},
"unit": {
"type": [
"string",
"null"
],
"description": "Unit"
},
"previous_period": {
"type": [
"string",
"null"
],
"description": "Previous period"
},
"previous_value": {
"type": [
"string",
"null"
],
"description": "Previous value"
},
"previous_numeric_value": {
"type": [
"number",
"null"
],
"description": "Previous numeric value"
},
"first_value": {
"type": [
"string",
"null"
],
"description": "First captured value"
},
"revised": {
"type": [
"boolean",
"null"
],
"description": "Changed after first capture"
},
"release_date": {
"type": [
"string",
"null"
],
"description": "First seen (Beijing date)",
"format": "date"
},
"first_seen_at": {
"type": [
"string",
"null"
],
"description": "First captured at",
"format": "date-time"
},
"last_seen_at": {
"type": [
"string",
"null"
],
"description": "Last captured at",
"format": "date-time"
},
"observations": {
"type": [
"integer",
"null"
],
"description": "Captures of this release"
},
"collected_at": {
"type": [
"string",
"null"
],
"description": "Collected at",
"format": "date-time"
},
"revision_status": {
"type": [
"string",
"null"
],
"description": "Revision status",
"enum": [
"first_release",
"repeat_collection",
"revised",
"unknown",
null
]
}
},
"description": "indicator_releases: selected fields only; null means not retained or not available."
}
]
}
},
"row_count": {
"type": "integer",
"minimum": 0,
"maximum": 5000,
"description": "Rows in this response, not total matching rows."
},
"next_cursor": {
"type": [
"string",
"null"
],
"description": "Opaque signed continuation, or null at the end. Valid for 24 hours and tied to dataset/q/source/from/to/text."
},
"sources": {
"type": "array",
"maxItems": 500,
"items": {
"type": "string"
},
"description": "Observed publisher labels in this public dataset, not monitored-channel configuration."
},
"sources_truncated": {
"type": "boolean"
},
"coverage": {
"type": "object",
"required": [
"kind",
"unit",
"date_field",
"date_timezone",
"order",
"notes"
],
"properties": {
"kind": {
"const": "retained_archive"
},
"unit": {
"enum": [
"documents",
"document_events",
"hot_list_observations",
"platform_topics",
"indicator_observations",
"indicator_releases"
]
},
"date_field": {
"enum": [
"collected_at",
"observed_at",
"first_seen_at",
"last_seen_at",
"event_at"
]
},
"date_timezone": {
"const": "UTC"
},
"order": {
"enum": [
"date_desc_id_desc",
"event_at_asc"
]
},
"notes": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"fields": {
"type": "array",
"items": {
"type": "object",
"required": [
"key",
"label"
],
"properties": {
"key": {
"type": "string"
},
"label": {
"type": "string"
}
}
}
},
"export_scope": {
"enum": [
"page",
"record"
]
},
"max_page_size": {
"type": "integer",
"minimum": 1,
"maximum": 5000,
"description": "The caller's tier ceiling for limit (see x-api-tiers)."
},
"links": {
"type": "object",
"required": [
"share_url",
"csv_url",
"curl"
],
"description": "List responses only (absent on an id request). The same query, first page, no cursor.",
"properties": {
"share_url": {
"type": "string",
"format": "uri",
"description": "An /explore URL that reopens this query (topic= names the topic filter)."
},
"csv_url": {
"type": "string",
"format": "uri",
"description": "This request as format=csv. The CSV adds a computed citation column (publisher, original title, publication date, source_url, record id and permalink)."
},
"api_url": {
"type": "string",
"format": "uri",
"description": "This request as JSON."
},
"curl": {
"type": "string",
"description": "The equivalent curl command."
}
}
}
}
}
},
"text/csv": {
"schema": {
"type": "string"
}
}
}
},
"400": {
"description": "Invalid query, field, date or cursor. Body carries `code`: see x-error-codes.",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error",
"code"
],
"properties": {
"error": {
"type": "string"
},
"retry_after": {
"type": "integer"
},
"code": {
"type": "string",
"enum": [
"invalid_parameter",
"invalid_cursor",
"unauthorized",
"forbidden",
"not_found",
"method_not_allowed",
"rate_limited",
"server_error",
"unavailable"
],
"description": "Stable machine code; see x-error-codes."
}
}
}
}
}
},
"404": {
"description": "Requested record is absent. Body carries `code`: see x-error-codes.",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error",
"code"
],
"properties": {
"error": {
"type": "string"
},
"retry_after": {
"type": "integer"
},
"code": {
"type": "string",
"enum": [
"invalid_parameter",
"invalid_cursor",
"unauthorized",
"forbidden",
"not_found",
"method_not_allowed",
"rate_limited",
"server_error",
"unavailable"
],
"description": "Stable machine code; see x-error-codes."
}
}
}
}
}
},
"405": {
"description": "Use GET. Body carries `code`: see x-error-codes.",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error",
"code"
],
"properties": {
"error": {
"type": "string"
},
"retry_after": {
"type": "integer"
},
"code": {
"type": "string",
"enum": [
"invalid_parameter",
"invalid_cursor",
"unauthorized",
"forbidden",
"not_found",
"method_not_allowed",
"rate_limited",
"server_error",
"unavailable"
],
"description": "Stable machine code; see x-error-codes."
}
}
}
}
}
},
"429": {
"description": "Rate limit exceeded (60 requests per minute). Body carries `code`: see x-error-codes.",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error",
"code"
],
"properties": {
"error": {
"type": "string"
},
"retry_after": {
"type": "integer"
},
"code": {
"type": "string",
"enum": [
"invalid_parameter",
"invalid_cursor",
"unauthorized",
"forbidden",
"not_found",
"method_not_allowed",
"rate_limited",
"server_error",
"unavailable"
],
"description": "Stable machine code; see x-error-codes."
}
}
}
}
},
"headers": {
"Retry-After": {
"schema": {
"type": "integer"
},
"description": "Seconds until retry; also sends RateLimit-* and X-RateLimit-* headers."
}
}
},
"503": {
"description": "Retained archive or request protection unavailable; retry later. Body carries `code`: see x-error-codes.",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"error",
"code"
],
"properties": {
"error": {
"type": "string"
},
"retry_after": {
"type": "integer"
},
"code": {
"type": "string",
"enum": [
"invalid_parameter",
"invalid_cursor",
"unauthorized",
"forbidden",
"not_found",
"method_not_allowed",
"rate_limited",
"server_error",
"unavailable"
],
"description": "Stable machine code; see x-error-codes."
}
}
}
}
}
}
},
"x-codeSamples": [
{
"lang": "curl",
"label": "curl",
"source": "curl -s 'https://china-snapshot.com/api/datasets?dataset=documents&q=export&from=2026-10-01&limit=3'"
},
{
"lang": "curl",
"label": "curl",
"source": "curl -s 'https://china-snapshot.com/api/datasets?dataset=indicators&mode=release&series=cpi-yoy&limit=3'"
},
{
"lang": "curl",
"label": "curl",
"source": "curl -s -o social-page.csv 'https://china-snapshot.com/api/datasets?dataset=social&format=csv&limit=3'"
}
],
"x-pagination": {
"cursor_lifetime_hours": 24,
"cursor_expires": "24 hours after the first page",
"end_of_results": "next_cursor is null"
}
}