Quick start
The API is read-only and needs no authentication. Everything lives under /v1, which is versioned and stable — new fields may appear, but existing ones will not change type or vanish without a new version.
Latest ten Kinyarwanda headlines
curl "https://api.newz.dushv.dev/v1/articles?language=rw&limit=10"The unversioned endpoints this site uses internally are not part of the contract and will change without notice. Build on /v1.
Rate limits
60 requests per 60 seconds, per IP. Every response tells you where you stand, so you can slow down before you are cut off.
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 57
X-RateLimit-Reset: 1787734140Exceed it and you get a 429 with how long to wait:
{
"error": "rate_limited",
"message": "Too many requests. The limit is 60 per 60s.",
"retryAfterSeconds": 48
}Ingestion runs every 20 minutes, so polling faster than that returns the same stories. Cache on your side and the limit will never trouble you.
Articles
GET/v1/articles
The fresh feed, newest first. Only stories inside the freshness window.
| Parameter | Type | Notes |
|---|---|---|
| category | string | national, world, politics, economy, sports, entertainment, health, tech, opinion… |
| language | string | en, rw, fr, sw |
| outlet | string | Exact outlet name, e.g. KT Press |
| limit | int | Default 30, maximum 100 |
| cursor | string | From nextCursor — see pagination |
Response
{
"items": [
{
"id": "b1f0…",
"url": "https://igihe.com/amakuru/article/…",
"title": "…",
"excerpt": "…",
"imageUrl": "https://igihe.com/IMG/…jpg",
"outlet": "Igihe",
"sourceKey": "igihe_rw",
"category": "national",
"language": "rw",
"publishedAt": "2026-08-26T09:47:06.000Z",
"isVideo": false,
"videoId": null
}
],
"nextCursor": "MjAyNi0wOC0yNlQwOTo0Nzow…",
"freshnessWindowHours": 48
}GET/v1/articles/:id
A single article. Returns 404 with {"error":"not_found"} if it does not exist or has aged out of the window.
Sources
GET/v1/sources
The outlets being aggregated and what each publishes — useful for building a filter. Operational detail such as health and scraper configuration stays internal.
{
"items": [
{ "key": "ktpress_national", "outlet": "KT Press",
"language": "en", "category": "national", "kind": "rss" }
]
}Pagination
Keyset, not offset, so a page cannot shift under you when new stories arrive mid-scroll. Pass back the nextCursor you were given; null means you have reached the end.
curl "https://api.newz.dushv.dev/v1/articles?limit=50"
curl "https://api.newz.dushv.dev/v1/articles?limit=50&cursor=MjAyNi0wOC0yNlQ…"Using the data
NEWZ aggregates; it does not license. Every headline, excerpt and image belongs to the newsroom that published it, so two things are not optional:
- Attribute each item to its
outlet. - Link to its
url, so readers reach the original.
Excerpts identify a story; they are not the article and must not be presented as one. No endpoint returns article text — we have no right to give it to you. Bulk mirroring and reselling are not permitted; see the terms.