CLSTR

News for agents: 100k+ articles/day deduplicated into situations with timelines. Free, no key required.

Documentation

CLSTR News API and MCP Server

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

Base URL

https://api.clstr.news/v1

MCP endpoint

https://mcp.clstr.news

Auth

Authorization: Bearer clstr_...

Format

JSON, data on success, error on failure

Versioning

v1, additive only

Quickstart

  1. 1. Create a free API key. In Settings, sign in first, no card needed.
  2.  curl -s "https://api.clstr.news/v1/situations?limit=3" \
       -H "Authorization: Bearer clstr_YOUR_KEY"
    
  3. 3. Or connect an agent instead. The same data is served over MCP: see MCP server.

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

GET /situations

Top developing situations, ranked by relevance: a blend of significance, how many outlets are covering it, and how recently it moved. Pass sort=recent for newest activity first. significance_score is an integer from 1 to 10, where 8 and above is exceptional.

ParameterTypeDefaultDescription
limitinteger201 to 50.
daysinteger71 to your tier's history window (7 on Free). Larger values are clamped, not rejected.
sortstringrelevancerelevance or recent.
categorystringallOne category slug, e.g. international.
countrystringallComma separated ISO country codes, up to 10. Extras are dropped, not rejected.
cursorstringnoneFrom the previous response's next_cursor. Paging stops after 9 pages.

Example request

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

Example response

{
  "data": [
    {
      "id": "8f2b1c6e-0a47-4d93-b8e1-77c5d9a2f410",
      "slug": "red-sea-shipping-attacks",
      "title": "Red Sea shipping attacks",
      "summary_preview": "Attacks on merchant shipping in the southern Red Sea have pushed most container lines onto the Cape route. Insurers have widened the war risk zone twice, and escort capacity remains the binding constraint on convoy slots",
      "cluster_count": 34,
      "source_count": 212,
      "first_seen": "2026-07-02T06:14:00.000Z",
      "last_updated": "2026-08-14T11:38:00.000Z",
      "status": "ACTIVE",
      "category": "international",
      "categories": [
        "international",
        "business"
      ],
      "countries": [
        "YE",
        "EG",
        "US"
      ],
      "significance_score": 9,
      "latest_cluster_title": "Insurers widen the Red Sea war risk zone",
      "url": "https://clstr.news/situations/red-sea-shipping-attacks"
    }
  ],
  "next_cursor": "eyJ2IjoxLCJzIjoicmVsZXZhbmNlIiwicCI6MiwicmVsIjo4LjIsImx1IjoiMjAyNi0wOC0xNFQxMTozODowMC4wMDBaIiwiaWQiOiI4ZjJiMWM2ZS0wYTQ3LTRkOTMtYjhlMS03N2M1ZDlhMmY0MTAiLCJmcCI6IiJ9"
}
  • status is ACTIVE or QUIET.
  • category filters on a situation's full categories list, so the top-level category field (which is just categories[0]) can differ from the value you requested.
  • Cursor pagination stops after 9 pages: past that, next_cursor comes back null. Narrow with days, category or country rather than paging deeper.

Situation detail + timeline

GET /situations/{id}

One situation (by id or slug) with its ordered timeline of member events, newest first.

ParameterTypeDefaultDescription
idpathrequiredSituation id or slug.
timeline_limitinteger1001 to 500.
timeline_beforestringnoneCluster id cursor, from timeline_cursor.next_before. Returns a continuation page.

Example request

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

Example response (truncated timeline)

{
  "data": {
    "id": "8f2b1c6e-0a47-4d93-b8e1-77c5d9a2f410",
    "slug": "red-sea-shipping-attacks",
    "title": "Red Sea shipping attacks",
    "summary": "Attacks on merchant shipping in the southern Red Sea have pushed most container lines onto the Cape route. Insurers have widened the war risk zone twice, and escort capacity remains the binding constraint on convoy slots.",
    "summary_preview": "Attacks on merchant shipping in the southern Red Sea have pushed most container lines onto the Cape route. Insurers have widened the war risk zone twice, and escort capacity remains the binding constraint on convoy slots",
    "cluster_count": 34,
    "source_count": 212,
    "first_seen": "2026-07-02T06:14:00.000Z",
    "last_updated": "2026-08-14T11:38:00.000Z",
    "status": "ACTIVE",
    "category": "international",
    "categories": [
      "international",
      "business"
    ],
    "latest_cluster_title": "Insurers widen the Red Sea war risk zone",
    "significance_score": 9,
    "url": "https://clstr.news/situations/red-sea-shipping-attacks",
    "is_timeline_page": false,
    "timeline": [
      {
        "id": "4f3c0a11-9d21-4b7e-8a55-2c9f1d6b0e34",
        "slug": "insurers-widen-red-sea-war-risk-zone",
        "title": "Insurers widen the Red Sea war risk zone",
        "summary": "Marine underwriters extended the listed war risk area to the southern Red Sea, raising premiums for Suez transits. Two carriers said they would keep routing around the Cape.",
        "category": "business",
        "countries": [
          "YE",
          "EG"
        ],
        "significance_score": 8,
        "sources": 18,
        "published_at": "2026-08-14T09:12:00.000Z",
        "updated_at": "2026-08-14T11:38:00.000Z",
        "url": "https://clstr.news/cluster/insurers-widen-red-sea-war-risk-zone"
      },
      {
        "id": "2d7ae803-64bf-41c0-9a1d-58e0c3f2b917",
        "slug": "second-naval-escort-group-ordered-to-bab-el-mandeb",
        "title": "A second naval escort group is ordered to Bab el-Mandeb",
        "summary": "A second escort group was ordered to the strait, roughly doubling the convoy slots on offer to commercial traffic.",
        "category": "international",
        "countries": [
          "YE",
          "US",
          "FR"
        ],
        "significance_score": 7,
        "sources": 24,
        "published_at": "2026-08-13T17:45:00.000Z",
        "updated_at": "2026-08-13T21:02:00.000Z",
        "url": "https://clstr.news/cluster/second-naval-escort-group-ordered-to-bab-el-mandeb"
      }
    ],
    "timeline_cursor": {
      "has_more": true,
      "next_before": "2d7ae803-64bf-41c0-9a1d-58e0c3f2b917",
      "remaining_count": 32,
      "total_count": 34
    },
    "day_span": 43
  }
}

Example continuation page (timeline_before set)

{
  "data": {
    "id": "8f2b1c6e-0a47-4d93-b8e1-77c5d9a2f410",
    "slug": "red-sea-shipping-attacks",
    "is_timeline_page": true,
    "timeline": [
      {
        "id": "9c81b4f2-3e6d-42a8-b0d7-1f5a7e2c98db",
        "slug": "cape-route-diversions-add-two-weeks-to-asia-europe-runs",
        "title": "Cape route diversions add two weeks to Asia to Europe runs",
        "summary": "Schedule reliability fell again as lines rerouted around southern Africa. Two alliances published revised port rotations with longer transit times.",
        "category": "business",
        "countries": [
          "ZA",
          "EG",
          "CN"
        ],
        "significance_score": 7,
        "sources": 21,
        "published_at": "2026-08-12T14:20:00.000Z",
        "updated_at": "2026-08-12T18:05:00.000Z",
        "url": "https://clstr.news/cluster/cape-route-diversions-add-two-weeks-to-asia-europe-runs"
      },
      {
        "id": "b5e6f70a-8c13-4d29-9f44-6a2b0e17c3d5",
        "slug": "container-lines-add-a-red-sea-risk-surcharge",
        "title": "Container lines add a Red Sea risk surcharge",
        "summary": "Three carriers filed a per-container surcharge covering the higher war risk premium. Shippers asked regulators to review how long it stays on.",
        "category": "business",
        "countries": [
          "DK",
          "CH"
        ],
        "significance_score": 6,
        "sources": 15,
        "published_at": "2026-08-11T08:30:00.000Z",
        "updated_at": "2026-08-11T12:15:00.000Z",
        "url": "https://clstr.news/cluster/container-lines-add-a-red-sea-risk-surcharge"
      }
    ],
    "timeline_cursor": {
      "has_more": true,
      "next_before": "b5e6f70a-8c13-4d29-9f44-6a2b0e17c3d5",
      "remaining_count": 30,
      "total_count": 34
    }
  }
}
  • 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.
  • The cursor is exclusive: a continuation page starts strictly after the cluster named by next_before, so the entry you paged from is never repeated.
  • 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

GET /clusters/{id}

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

ParameterTypeDefaultDescription
idpathrequiredCluster id or slug.

Example request

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

Example response

{
  "data": {
    "id": "4f3c0a11-9d21-4b7e-8a55-2c9f1d6b0e34",
    "slug": "insurers-widen-red-sea-war-risk-zone",
    "title": "Insurers widen the Red Sea war risk zone",
    "summary": "Marine underwriters extended the listed war risk area to the southern Red Sea, raising premiums for Suez transits. Two carriers said they would keep routing around the Cape.",
    "summary_full": "Marine underwriters extended the listed war risk area to the southern Red Sea, raising premiums for Suez transits. Two carriers said they would keep routing around the Cape until escort capacity increases. Brokers put the added cost of a single transit in the low hundreds of thousands of dollars.",
    "keywords": [
      "red sea",
      "war risk",
      "marine insurance",
      "suez"
    ],
    "category": "business",
    "countries": [
      "YE",
      "EG"
    ],
    "significance_score": 8,
    "sources": 18,
    "published_at": "2026-08-14T09:12:00.000Z",
    "updated_at": "2026-08-14T11:38:00.000Z",
    "url": "https://clstr.news/cluster/insurers-widen-red-sea-war-risk-zone",
    "articles": [
      {
        "source_host": "newswire.example.com",
        "url": "https://newswire.example.com/business/red-sea-war-risk",
        "title": "Underwriters widen Red Sea war risk area",
        "published_at": "2026-08-14T09:12:00.000Z"
      },
      {
        "source_host": "shipping.example.com",
        "url": "https://shipping.example.com/premiums-rise",
        "title": "Premiums rise again for southern Red Sea transits",
        "published_at": "2026-08-14T10:40:00.000Z"
      }
    ],
    "situation": {
      "id": "8f2b1c6e-0a47-4d93-b8e1-77c5d9a2f410",
      "title": "Red Sea shipping attacks",
      "slug": "red-sea-shipping-attacks",
      "cluster_count": 34
    }
  }
}
  • summary is the short form, summary_full the long one. situation is null for an event that has not joined one.
  • A merged-away cluster returns its successor with merged_into_shown: true. A retired one answers 410.

Search

GET /search

Semantic search over recent events. Results are timeline entries, the same shape a situation timeline carries.

ParameterTypeDefaultDescription
qstringrequiredMax 200 characters.
daysinteger71 to 30, further clamped to your tier's history window.
limitinteger301 to 30.
cursorstringnoneFrom the previous response's next_cursor. Its own token, not the situations cursor.

Example request

curl -s "https://api.clstr.news/v1/search?q=red%20sea%20shipping%20insurance&days=7" \
  -H "Authorization: Bearer clstr_YOUR_KEY"

Example response

{
  "data": [
    {
      "id": "4f3c0a11-9d21-4b7e-8a55-2c9f1d6b0e34",
      "slug": "insurers-widen-red-sea-war-risk-zone",
      "title": "Insurers widen the Red Sea war risk zone",
      "summary": "Marine underwriters extended the listed war risk area to the southern Red Sea, raising premiums for Suez transits. Two carriers said they would keep routing around the Cape.",
      "category": "business",
      "countries": [
        "YE",
        "EG"
      ],
      "significance_score": 8,
      "sources": 18,
      "published_at": "2026-08-14T09:12:00.000Z",
      "updated_at": "2026-08-14T11:38:00.000Z",
      "url": "https://clstr.news/cluster/insurers-widen-red-sea-war-risk-zone"
    },
    {
      "id": "2d7ae803-64bf-41c0-9a1d-58e0c3f2b917",
      "slug": "second-naval-escort-group-ordered-to-bab-el-mandeb",
      "title": "A second naval escort group is ordered to Bab el-Mandeb",
      "summary": "A second escort group was ordered to the strait, roughly doubling the convoy slots on offer to commercial traffic.",
      "category": "international",
      "countries": [
        "YE",
        "US",
        "FR"
      ],
      "significance_score": 7,
      "sources": 24,
      "published_at": "2026-08-13T17:45:00.000Z",
      "updated_at": "2026-08-13T21:02:00.000Z",
      "url": "https://clstr.news/cluster/second-naval-escort-group-ordered-to-bab-el-mandeb"
    }
  ],
  "query": {
    "q": "red sea shipping insurance",
    "days": 7
  },
  "next_cursor": "eyJ2IjoxLCJvIjozMH0"
}
  • The search index reaches back at most 30 days, further clamped to your tier's history window.
  • query.days in the response is the window actually searched, not what you asked for.
  • Results are relevance ordered and bounded: the pool is the top matches, not an unbounded scan. Pass next_cursor back as cursor to page further; it comes back null once the candidate pool is exhausted.
  • Search has its own daily cap because every query runs an embedding, and each page re-runs the search: one page counts as one search against the cap. See Limits.

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
Anonymous (MCP taster)No key105Keyed only7 days
FreeFree10020107 days
Builder$29/mo5,0006025030 days
Scale$299/mo100,0001,00010,00030 days

The anonymous row is the MCP taster: 2 tools (get_top_situations, get_situation_timeline), no signup, counted per network rather than per person and capped platform-wide. Everything else, including search, needs a key.

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, and never beyond the tier's history window.

Builder and Scale are live: upgrade on the pricing page. If the caps still do not fit, get in touch.

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

Every authenticated response carries X-RateLimit-Limit-Day, X-RateLimit-Remaining-Day and X-RateLimit-Limit-Minute (all exposed to browsers via CORS). There is no remaining-count for the per-minute window: it is enforced per Cloudflare location and reports no count, so any number here would be a guess. Pace against the daily remaining, and back off on a 429 using Retry-After. /search additionally carries X-RateLimit-Limit-Search and X-RateLimit-Remaining-Search for the daily search cap, which is the limit a free key reaches first. Responses rejected before authentication (a missing or invalid key) carry none of them, 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.

A 429 carries Retry-After in seconds: the exact time left in the window that fired, not a fixed guess.

Errors

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

{
  "error": {
    "code": "rate_limited",
    "message": "Daily cap reached for the hobby tier. Caps: https://clstr.news/developers#limits."
  }
}

Error messages name tiers by their internal key, which is what your key record stores. The Free tier's key is hobby.

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.

The error object is additive in the same way data is: a 404 for a retired situation carries moved_to next to code and message. Read the fields you know and ignore the rest, because more of them will appear within v1.

A 429 may carry error.upgrade_url, a link to the plan that lifts the cap you hit.

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 on this page. Caps are hard limits. No overage charges, ever.

MCP server

Your agent can search the web. It can't tell you what's happening: which developing situations matter, what 40 sources collectively report, and how a story evolved over six weeks. CLSTR can, over MCP.

One event covered by many outlets becomes a single cluster, deduplicated, with a source count and a significance score. Related clusters link into a situation that carries a maintained summary and a full timeline, so an agent gets memory, not just the latest headline.

Remote server, no install. Same API key, same caps (one tool call counts as one request).

Try it with no key: get_top_situations, get_situation_timeline answer anonymously, 10 calls per day per network (burst 5 per minute), and anonymous timelines come back at most 50 entries deep. A free key lifts that to 100 requests per day, full timeline depth, and search.

Endpoint:  https://mcp.clstr.news
Auth:      Authorization: Bearer clstr_YOUR_KEY
Tools:     get_top_situations · search_situations · get_situation_timeline · get_cluster
ToolREST equivalent
get_top_situationsGET /situations
search_situationsGET /search
get_situation_timelineGET /situations/{id}
get_clusterGET /clusters/{id}

Claude (custom connector): Settings > Connectors > Add custom connector > URL https://mcp.clstr.news, header Authorization: Bearer clstr_YOUR_KEY.

Clients with an mcpServers config:

"clstr": {
  "url": "https://mcp.clstr.news",
  "headers": { "Authorization": "Bearer clstr_YOUR_KEY" }
}

stdio-only client? Bridge with npx mcp-remote https://mcp.clstr.news --header "Authorization: Bearer clstr_YOUR_KEY".

Check it works, no key:

curl -s https://mcp.clstr.news -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
       "params":{"name":"get_top_situations","arguments":{"window":"24h","limit":3}}}'

The tools obey the same windows as the REST endpoints: search_situations reaches back at most 30 days, and get_top_situations takes 24h, 7d or 30d. Refusals a caller can act on (a cap, an unknown id) come back as readable tool results; transport problems come back as JSON-RPC errors with the HTTP status to match.

get_top_situations and search_situations paginate: when more results exist, the tool ends with a cursor to pass back. For get_top_situations, send the same window and category with it. For search_situations, each page re-runs the search, so one page counts as one search against the cap.

Questions or a use case the caps don't fit? Contact us. There is a markdown copy of this page for agents.