NewsCord API v1
The article archive, in your tools.
Read every published NewsCord story with its full saved text, sources, images and analysis. Choose a topic, set a date range, or work through the complete archive.
https://newscord.org/api/v1Make your first request
- Open organisation settings and find Article API. An organisation owner can create a key.
- Give the key a name, such as “Research dashboard”, then copy it. The full key is shown only once.
- Save it as
NEWSCORD_FEED_KEYin your server environment and send this request.
curl 'https://newscord.org/api/v1/articles?limit=20' -H "Authorization: Bearer $NEWSCORD_FEED_KEY"Each request returns JSON. No date filter means the whole published archive is available through pagination.
Your organisation’s API keys
Send Authorization: Bearer ncf_YOUR_KEY with every request. Keys work with the article endpoints only. The AI assistant connector has its own sign-in flow.
Owners can create and revoke keys in Settings. Members can see names, last four characters and usage dates. The full secret cannot be retrieved after creation: create a replacement if you lose it, then revoke the old key.
Keep keys on your server or in a trusted local client. Do not put them in public browser code, URL parameters or a Git repository. Revocation takes effect on the next request; a suspended organisation’s keys also stop working.
Three endpoints
| Request | Returns |
|---|---|
| GET /articles | A page of published stories with full content. |
| GET /articles/{id} | One story. Use its id or collection_id, URL-encoded. |
| GET /topics | Exact topic labels and their published article counts. |
Choose a topic or date range
| Parameter | Meaning |
|---|---|
| topic | Exact, case-sensitive label from /topics, for example Britain or War on Gaza. Matches a story's main topic. |
| from | First UTC calendar day, inclusive. Format: YYYY-MM-DD. |
| to | Last UTC calendar day, inclusive. Format: YYYY-MM-DD. |
| limit | Stories per page: 1 to 50. Defaults to 20. |
| cursor | Opaque continuation value from the previous page. Preserve your filters. |
https://newscord.org/api/v1/articles?topic=Britain&from=2026-10-01&to=2026-10-14&limit=20Date filters use created_at, when the story entered NewsCord. Source publication dates and the last analysis time, where saved, are returned separately. A topic with no matches returns an empty list.
What each article contains
One item is a NewsCord story that brings together coverage from multiple outlets. Its text contains the saved NewsCord story; sources[].text contains each saved source article. These fields are not truncated by the API.
The original structured summary, citations, source metadata, key_points, quantitative_analysis and other stored analysis fields are retained. images contains image URLs; url is the canonical NewsCord page.
photo is the story's lead photograph, chosen from openly licensed sources, or null. It carries what it shows (caption), where and when it was taken (place, date), whether it is an archive photo, an illustration or a map (label), and its credit, licence and source_url. Show the credit and licence beside the photo wherever you use it.
Older records without a saved analysis remain in the archive with content_available: false and text: null. Some sources have no saved text. The feed does not generate missing content. Pending and merged stories are excluded; a missing or merged ID returns 404.
Illustrative response. Text is shortened here for readability, and stored analysis fields vary by story.
{
"data": [
{
"id": "Story_example",
"collection_id": "Story_example",
"headline": "An example story",
"topic": "Britain",
"topics": [
"Britain",
"Protests"
],
"created_at": "2026-10-14T09:00:00Z",
"text": "The complete saved NewsCord story text…",
"images": [
"https://example.org/image.jpg"
],
"photo": {
"kind": "place",
"src": "https://example.org/photo-1600.jpg",
"src_small": "https://example.org/photo-800.jpg",
"caption": "The parliament building at dusk",
"place": "London",
"date": "2024-03-12",
"label": "archive",
"credit": "Photographer name",
"licence": "CC BY-SA 4.0",
"licence_url": "https://creativecommons.org/licenses/by-sa/4.0/",
"source_url": "https://commons.wikimedia.org/wiki/File:Example.jpg",
"provider": "commons"
},
"sources": [
{
"title": "Source headline",
"url": "https://example.org/story",
"text": "The full saved source text…"
}
],
"summary": [
{
"subheader": "What happened",
"paragraphs": [
"Story paragraph…"
]
}
],
"quantitative_analysis": {},
"metadata": {
"number_of_sources": 1,
"min_date": "2026-10-14"
},
"content_available": true
}
],
"pagination": {
"limit": 20,
"has_more": true,
"next_cursor": "opaque_cursor",
"next_url": "/api/v1/articles?limit=20&cursor=opaque_cursor",
"snapshot_at": "2026-10-14T10:00:00Z"
}
}Additional analysis fields may appear over time. Ignore unknown fields. This feed covers published NewsCord stories; the separate Watchdog scoring database is not part of this response.
Read the full archive
Follow pagination.next_url until it is null, sending your key on every request. This relative URL preserves your topic and date filters. Do not construct page numbers or change filters midway through a cursor walk.
import os
import time
from urllib.parse import urljoin
import requests
url = "https://newscord.org/api/v1/articles?limit=50"
headers = {"Authorization": "Bearer " + os.environ["NEWSCORD_FEED_KEY"]}
while url:
response = requests.get(url, headers=headers, timeout=30)
if response.status_code == 429:
time.sleep(int(response.headers["Retry-After"]))
continue
response.raise_for_status()
page = response.json()
for article in page["data"]:
print(article["id"], article["headline"])
next_url = page["pagination"]["next_url"]
url = urljoin("https://newscord.org", next_url) if next_url else NoneStories are ordered by created_at descending, then ID. snapshot_at fixes the creation-time ceiling for the walk, so newly created stories do not move into it. Existing stories can still be updated or merged during an export. This is an archive feed, not a change log.
Limits and errors
Organisation keys allow 3,600 requests per UTC clock hour, per key. You can have up to 10 active keys. Requests that reach the feed with a valid key count towards the allowance, including invalid filters and missing article lookups.
X-RateLimit-Limit and X-RateLimit-Remaining report your allowance. When it is exhausted, wait for the number of seconds in Retry-After before retrying.
| Status | What to do |
|---|---|
| 400 | Check date formats, parameter names, range, limit and cursor. |
| 401 | Supply a valid API key. Check whether it was revoked or the organisation is suspended. |
| 404 | The ID is not a published story. Refresh your article list. |
| 429 | Wait for Retry-After seconds before retrying. |
| 503 | The service is temporarily unavailable. Retry later. |
Errors use {"error":{"code":"…","message":"…"}}. Responses are private and are not cached by shared CDNs. Cross-origin clients can use GET and OPTIONS with an Authorization header.