CLSTR API

Structured "what is happening": ~100k articles/day deduplicated into multi-source events, grouped into situations with memory. 30 to 90 minutes behind the wires by design. Verified shape, not breaking-news speed.

Authentication

Every request needs an API key. Create a free one in Settings (sign in first, no card needed). Send it as a bearer token or an X-Api-Key header.

Authorization: Bearer clstr_YOUR_KEY

Responses allow any origin (Access-Control-Allow-Origin: *) so you can call the API from a browser during development. Keys are secrets: a key shipped inside front-end JavaScript is a key you have published. Call the API from your own server for anything real.

Endpoints

Base URL: https://api.clstr.news/v1

Four read-only endpoints. All responses are JSON: data on success, error.code + error.message on failure, including 404s on unknown paths and server errors. Timestamps are ISO-8601 UTC.

List situations

Top developing situations. Params: limit (1-50, default 20), days (1-30 on Hobby, default 7. The history window per tier is below), sort (relevance | recent), category, country (comma ISO codes), cursor.

curl -s "https://api.clstr.news/v1/situations?days=1&category=international&sort=relevance&limit=5" \
  -H "Authorization: Bearer clstr_YOUR_KEY"

Returns: id, slug, title, summary_preview, cluster_count, source_count, first_seen, last_updated, status (ACTIVE | QUIET), category, categories, countries, significance_score, latest_cluster_title, url; plus next_cursor.

Cursor pagination stops after 8 pages: past that, next_cursor comes back null. Narrow with days, category or country rather than paging deeper.

Situation detail + timeline

One situation (by id or slug) with its ordered timeline of member events, newest first. Params: timeline_limit (1-500, default 100), timeline_before (cluster id cursor).

curl -s "https://api.clstr.news/v1/situations/SITUATION_ID_OR_SLUG" \
  -H "Authorization: Bearer clstr_YOUR_KEY"

Returns id, slug, title, summary (full), summary_preview, cluster_count, source_count, first_seen, last_updated, status, category, categories, latest_cluster_title, significance_score, url, is_timeline_page (false), timeline[] (id, slug, title, summary, category, countries, significance_score, sources, published_at, updated_at, url), timeline_cursor (has_more, next_before, remaining_count, total_count), day_span. Situation-wide countries is a list-endpoint field only; each timeline entry carries its own.

A timeline_before request is a continuation page: it returns only id, slug, is_timeline_page: true, timeline[] and timeline_cursor. The header fields are deliberately absent rather than zeroed: keep the ones you got from page one instead of overwriting them.

A situation that was merged into another returns the successor with merged_into_shown: true and requested_id set to what you asked for. A retired situation whose successor is an event answers 404 with error.moved_to. A concluded situation whose archive was removed answers 410.

Cluster detail

One event (a cluster of articles from many outlets reporting the same thing), with its source articles.

curl -s "https://api.clstr.news/v1/clusters/CLUSTER_ID_OR_SLUG" \
  -H "Authorization: Bearer clstr_YOUR_KEY"

Returns: id, slug, title, summary, summary_full, keywords, category, countries, significance_score, sources, published_at, updated_at, url, articles[] (source_host, url, title, published_at), situation (id, title, slug, cluster_count) or null. A merged-away cluster returns its successor with merged_into_shown: true; a retired one answers 410.

Search

Semantic search over recent events. Params: q (required, max 200 chars), days (1-30, default 7), limit (1-30).

curl -s "https://api.clstr.news/v1/search?q=venezuela%20oil%20sanctions&days=7" \
  -H "Authorization: Bearer clstr_YOUR_KEY"

The search index only reaches back 30 days, on every tier. query.days in the response is the window actually searched, not what you asked for.

Limits & pricing

Caps are hard limits: requests past the cap get a 429, and there are no overage charges, ever. Search is capped separately because each search runs an embedding.

TierPriceRequests/dayRequests/minSearches/dayHistory window
HobbyFree500202530 days
Starter$99/mo20,0003002,00090 days
Growth$299/mo100,0001,00010,00090 days

Caps apply per key, and an account may hold up to 5 active keys. The history window is the widest days value a tier can ask for; larger values are clamped, not rejected. Search reaches back at most 30 days on every tier.

Hobby is live today. Paid tiers open soon: if the free caps are in your way, get in touch and we will set you up directly.

Free-tier use must link back to clstr.news when displayed publicly.

Every authenticated response carries X-RateLimit-Limit-Day and X-RateLimit-Remaining-Day (both exposed to browsers via CORS). Responses rejected before authentication (a missing or invalid key) carry neither, because there is no key to report usage for. There is also a generous per-address ceiling in front of authentication; a normal client reaches its own tier cap long before it.

Errors

Every failure is {"error": {"code": "…", "message": "…"}} with a matching HTTP status. Branch on code; message is for humans and may change.

StatuscodeMeaning
400bad_requestMissing or malformed parameter (e.g. no q on search).
401unauthorizedNo key, or the key is unknown or revoked.
404not_foundUnknown id, slug, or endpoint. May carry moved_to.
410goneThe record existed and was retired. Do not retry.
429rate_limitedA cap was reached. The message names which one.
500internal_errorOur fault. Safe to retry with backoff.
502upstream_errorAn upstream (embeddings) failed. Retry shortly.
503unavailableTemporarily unavailable. Retry shortly.

Versioning & stability

v1 is stable: we only add fields, never rename or remove them within v1. Breaking changes get a new version prefix and at least 90 days' notice here and via a Sunset header. Caps are hard limits. No overage charges, ever.

MCP server

The same data is available to AI agents over MCP. See the setup on this page once it ships, or watch the About page for updates.

Questions or a use case the caps don't fit? Contact us.