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.
| Parameter | Type | Default | Description |
limit | integer | 20 | 1 to 50. |
days | integer | 7 | 1 to your tier's history window (7 on Free). Larger values are clamped, not rejected. |
sort | string | relevance | relevance or recent. |
category | string | all | One category slug, e.g. international. |
country | string | all | Comma separated ISO country codes, up to 10. Extras are dropped, not rejected. |
cursor | string | none | From the previous response's next_cursor. Paging stops after 81 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 81 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.
| Parameter | Type | Default | Description |
id | path | required | Situation id or slug. |
timeline_limit | integer | 100 | 1 to 500. |
timeline_before | string | none | Cluster 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.
| Parameter | Type | Default | Description |
id | path | required | Cluster 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.
| Parameter | Type | Default | Description |
q | string | required | Max 200 characters. |
days | integer | 7 | 1 to 30, further clamped to your tier's history window. |
limit | integer | 30 | 1 to 30. |
cursor | string | none | From 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.
| Tier | Price | Requests/day | Requests/min | Searches/day | History window |
| Anonymous (MCP taster) | No key | 10 | 5 | Keyed only | 7 days |
| Free | Free | 100 | 20 | 10 | 7 days |
| Builder | $29/mo | 5,000 | 60 | 250 | 30 days |
| Scale | $299/mo | 100,000 | 1,000 | 10,000 | 30 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 account, not per key: an account may hold up to 5 active keys and they all draw on the same limits. 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.
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/mcp
Auth: OAuth sign-in (Claude and ChatGPT connectors), or Authorization: Bearer clstr_YOUR_KEY
Tools: get_top_situations · search_situations · get_situation_timeline · get_cluster
Claude and ChatGPT connectors: add a custom connector with the URL https://mcp.clstr.news/mcp and sign in when prompted. No header, no key: the connector runs an OAuth sign-in against your CLSTR account and gets your plan's caps. Disconnect it any time under Connected apps in Settings.
Use the full URL including /mcp. Pasting the bare host works for tool calls but has been reported to leave some connectors looping on setup.
Clients with an mcpServers config: keep using a key.
"clstr": {
"url": "https://mcp.clstr.news/mcp",
"headers": { "Authorization": "Bearer clstr_YOUR_KEY" }
}
stdio-only client? Bridge with npx mcp-remote https://mcp.clstr.news/mcp --header "Authorization: Bearer clstr_YOUR_KEY".
Check it works, no key:
curl -s https://mcp.clstr.news/mcp -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.