API Documentation
Access real-time news intelligence, market signals, and geopolitical risk data.
In alpha and free while it is. Email us for a key.
Try It
Real responses from the live API, no key required. Pick a query.
The stories with the broadest coverage right now, ordered by source count.
GET https://www.perspecta.news/api/v1/events?limit=3&since=24h{
"data": [
{
"id": "057d0b57-1ee0-4bae-ad78-beb7e385844f",
"title": "Senate Confirms Trump's Former Lawyer Blanche as Attorney General",
"summary": "The GOP-controlled Senate confirmed Donald Trump's former lawyer, Blanche, as the new Attorney General, a move seen as a significant win for Trump and an endorsement of a Justice Department under his influence.",
"topic": "politics",
"sourceCount": 62,
"weightedSourceCount": 129.04,
"maxOutletWeight": 1.84,
"outlets": [
"aktuality-sk",
"aktualne-cz",
"aljazeera",
"balkan-web",
"bbc",
"berlingske",
"bloomberg",
"cnbc",
"copenhagen-post",
"cyprus-mail",
"daily-sabah",
"de-volkskrant",
"delfi-lt",
"der-spiegel",
"der-standard",
"die-presse",
"digi24",
"dw",
"ekathimerini",
"faz",
"forbes",
"foxnews",
"france24",
"guardian",
"hindustan-times",
"hotnews",
"iefimerida",
"il-sole-24-ore",
"independent",
"index-hr",
"indian-express",
"jerusalem-post",
"jutarnji-list",
"korea-herald",
"la-repubblica",
"la-vanguardia",
"mkd-mk",
"n1-bih",
"naftemporiki",
"national-post",
"nme",
"nos",
"npr",
"nytimes",
"observador",
"orf",
"politiken",
"publico",
"rolling-stone",
"ruv",
"rzeczpospolita",
"seeking-alpha",
"svenska-dagbladet",
"tagesschau",
"tehran-times",
"times-india",
"tvn24",
"vanguard-ng",
"vg",
"wapo",
"yahoo",
"zerohedge"
],
"articleLanguages": [
"als",
"bos",
"ces",
"dan",
"deu",
"ell",
"eng",
"fra",
"glg",
"hrv",
"ita",
"lit",
"mkd",
"nld",
"nno",
"pol",
"por",
"ron",
"sco",
"slk",
"spa",
"src",
"srp",
"swe"
],
"sourceSignal": "agree",
"impactScore": 164.4,
"velocity": 2.65,
"publishedAt": "2026-08-08T10:19:46.000Z",
"updatedAt": "2026-08-08T21:19:17.000Z",
"firstSeenAt": "2026-08-08T11:52:46.210Z",
"lastWrittenAt": "2026-08-08T21:47:35.138Z",
"firstIngestedAt": "2026-08-08T05:48:28.809Z",
"ingestionLagMinutes": 93,
"mergedInto": null,
"mergedAt": null,
"regions": [
"United States"
],
"countries": [
"United States"
],
"entities": [
"senate",
"trump",
"former",
"lawyer",
"blanche",
"attorney general",
"attorney",
"general",
"the gop-controlled senate",
"gop-controlled",
"donald trump",
"donald",
"justice department",
"justice",
"department",
"the gop",
"gop",
"trump former lawyer confirmed",
"confirmed",
"amidst",
"political",
"tensions",
"blanche confirmed",
"influence",
"president trump this"
],
"tags": [],
"language": null,
"firstArticleUrl": "https://cyprus-mail.com/2026/08/08/todd-blanche-trumps-ex-lawyer-confirmed-as-us-attorney-general",
"url": "https://perspecta.news/story/057d0b57-1ee0-4bae-ad78-beb7e385844f"
},
{
"id": "eb4daee0-29c3-4b7d-8bf0-39ea2e5e7c1b",
"title": "Iran Sets New Demands for Reopening Strait of Hormuz, Deal Remains Elusive",
"summary": "Iran has issued new, stringent demands to the United States for the reopening of the Strait of Hormuz, indicating that a quick resolution to the waterway's closure is unlikely. Despite some reports of progress in talks, Iran insists the strait will remain closed until its conditions are met.",
"topic": "world",
"sourceCount": 56,
"weightedSourceCount": 117.78,
"maxOutletWeight": 1.8,
"outlets": [
"aftonbladet",
"aktuality-sk",
"aljazeera",
"balkan-web",
"berlingske",
"bloomberg",
"cdm-me",
"channel-news-asia",
"cnbc",
"copenhagen-post",
"cyprus-mail",
"daily-sabah",
"danas",
"delfi-lt",
"der-spiegel",
"der-standard",
"die-presse",
"digi24",
"dr-dk",
"dw",
"forbes",
"ft",
"guardian",
"hindustan-times",
"hotnews",
"hvg",
"iefimerida",
"independent",
"index-hr",
"irozhlas",
"japan-times",
"jerusalem-post",
"klix-ba",
"la-repubblica",
"le-figaro",
"luxemburger-wort",
"mkd-mk",
"n1-serbia",
"naftemporiki",
"national-post",
"ndtv",
"newsbeast",
"nos",
"npr",
"nytimes",
"orf",
"publico",
"rte-news",
"rzeczpospolita",
"scmp",
"seeking-alpha",
"tehran-times",
"the-journal",
"vijesti-me",
"yahoo",
"zerohedge"
],
"articleLanguages": [
"als",
"bos",
"ces",
"dan",
"deu",
"ell",
"eng",
"fra",
"hrv",
"hun",
"ita",
"lit",
"mkd",
"nld",
"pol",
"por",
"ron",
"sco",
"slk",
"srp",
"swe"
],
"sourceSignal": "agree",
"impactScore": 141.4,
"velocity": 2.52,
"publishedAt": "2026-08-08T11:32:05.434Z",
"updatedAt": "2026-08-08T23:03:47.000Z",
"firstSeenAt": "2026-08-08T11:36:36.215Z",
"lastWrittenAt": "2026-08-08T23:31:26.785Z",
"firstIngestedAt": "2026-08-08T11:04:59.482Z",
"ingestionLagMinutes": 5,
"mergedInto": null,
"mergedAt": null,
"regions": [
"UAE",
"Iran"
],
"countries": [
"Iran"
],
"entities": [
"iran",
"sets",
"demands",
"reopening",
"strait",
"hormuz",
"deal",
"remains",
"elusive",
"united states",
"united",
"states",
"strait of hormuz",
"despite",
"iran demands us concessions",
"us",
"concessions",
"reopen strait of hormuz",
"reopen",
"tehran",
"washington",
"meet",
"conditions",
"amidst",
"tensions"
],
"tags": [],
"language": null,
"firstArticleUrl": "https://cyprus-mail.com/2026/08/08/iran-deal-on-strait-of-hormuz-close-but-not-enough-to-open-vital-route",
"url": "https://perspecta.news/story/eb4daee0-29c3-4b7d-8bf0-39ea2e5e7c1b"
},
{
"id": "362a53cf-ccf8-4fd2-94ce-ee324fce70f3",
"title": "Iran Demands US Concessions for Strait of Hormuz Reopening",
"summary": "Iran has outlined several conditions, including compensation for war damages and an end to US military actions, for the reopening of the Strait of Hormuz. This comes as negotiations continue, with Iran stating a deal is close but not yet sufficient to open the vital waterway.",
"topic": "world",
"sourceCount": 45,
"weightedSourceCount": 64.74,
"maxOutletWeight": 1.84,
"outlets": [
"aktuality-sk",
"aljazeera",
"avgi",
"balkan-web",
"bangkok-post",
"bbc",
"berlingske",
"bloomberg",
"cdm-me",
"channel-news-asia",
"daily-nation",
"dawn",
"delo",
"der-standard",
"dh-les-sports",
"express-tribune",
"france24",
"hindustan-times",
"hotnews",
"hvg",
"il-sole-24-ore",
"in-cyprus",
"indian-express",
"jerusalem-post",
"klix-ba",
"le-figaro",
"myjoyonline",
"ndtv",
"newsbeast",
"orf",
"protothema-en",
"punch-ng",
"rappler",
"rte-news",
"ruv",
"sbs-news",
"scmp",
"tagesschau",
"telex",
"the-journal",
"times-india",
"tvn24",
"vanguard-ng",
"vg",
"wapo"
],
"articleLanguages": [
"als",
"bos",
"dan",
"deu",
"ell",
"eng",
"fra",
"hun",
"ita",
"nds",
"nld",
"nno",
"pol",
"ron",
"sco",
"slk",
"slv",
"srp"
],
"sourceSignal": "agree",
"impactScore": 163.3,
"velocity": 3.63,
"publishedAt": "2026-08-08T21:19:00.000Z",
"updatedAt": "2026-08-09T09:04:29.247Z",
"firstSeenAt": "2026-08-09T00:21:39.661Z",
"lastWrittenAt": "2026-08-09T09:31:52.139Z",
"firstIngestedAt": "2026-08-08T19:33:01.632Z",
"ingestionLagMinutes": 183,
"mergedInto": null,
"mergedAt": null,
"regions": [
"Oman",
"Iran",
"UAE",
"United States"
],
"countries": [
"Iran"
],
"entities": [
"iran",
"demands",
"us",
"concessions",
"strait",
"hormuz",
"reopening",
"strait of hormuz this",
"irgc",
"strait of hormuz while",
"june mou iran",
"june",
"mou",
"united states",
"united",
"states",
"strait of hormuz tehran",
"tehran",
"sets",
"conditions",
"amidst",
"tensions",
"strait of hormuz",
"issues",
"de-escalation"
],
"tags": [],
"language": null,
"firstArticleUrl": "https://en.philenews.com/international/iran-says-deal-on-strait-of-hormuz-is-close-but-not-enough-to-open-the-waterway/",
"url": "https://perspecta.news/story/362a53cf-ccf8-4fd2-94ce-ee324fce70f3"
}
],
"meta": {
"timestamp": "2026-08-09T09:42:57.653Z",
"count": 3,
"since": "2026-08-08T09:42:57.636Z",
"orderBy": "sourceCount",
"truncated": true,
"nextCursor": "eyJvIjoic291cmNlQ291bnQiLCJ2Ijo0NSwiaSI6IjM2MmE1M2NmLWNjZjgtNGZkMi05NGNlLWVlMzI0ZmNlNzBmMyJ9"
}
}Live data from the same code path the API serves — not a saved sample. These previews return a couple of rows and are cached for a minute; a real key has neither limit.
Authentication
All API requests require an API key. Pass it via the X-API-Key header or as a Bearer token in the Authorization header.
curl -H "X-API-Key: pk_your_key_here" \ "https://www.perspecta.news/api/v1/events?since=24h"
Response Format
All endpoints return JSON with a consistent structure:
{
"data": [ ... ],
"meta": {
"timestamp": "2026-03-17T08:00:00.000Z",
"count": 20,
"since": "2026-03-16T08:00:00.000Z",
"truncated": true,
"nextCursor": "eyJvIjoibGFzdFdyaXR0ZW4iLCJ2IjoiMjAy..."
}
}Market Signals
Stories scored by impact using source velocity, coverage breadth, and narrative divergence.
/api/v1/signals— Ranked market signalsParameters
since | string | Time window: a duration (30m, 6h, 7d) or an ISO 8601 timestamp (default: 24h) |
sector | string | Filter by sector: geopolitics, policy, markets, tech, energy, healthcare, entertainment |
country | string | Filter by country name (case-insensitive) |
tag | string | Filter by story hashtag |
limit | number | Max results, 1-100 (default: 20) |
Impact Score
Each signal includes an impactScore and velocity. Velocity measures how fast a story accumulated sources (sources/hour). Stories where sources diverge on framing get a 1.5× multiplier, reflecting higher uncertainty.
curl -H "X-API-Key: pk_your_key" \
"https://www.perspecta.news/api/v1/signals?sector=energy&since=6h&limit=5"
# Response:
{
"data": [
{
"id": "3830025b-...",
"title": "Europe Rules Out Joining Trump's Hormuz Armada",
"summary": "Europe has officially ruled out...",
"topic": "world",
"sector": "geopolitics",
"sourceCount": 31,
"sourceSignal": "diverge",
"impactScore": 142.5,
"velocity": 6.2,
"publishedAt": "2026-03-17T02:00:00Z",
"regions": ["europe", "middle-east"],
"countries": ["iran", "united kingdom"],
"entities": ["trump", "hormuz"],
"hashtags": ["IranWar", "Hormuz"]
}
]
}Geopolitical Risk
Country-level risk scores derived from aggregated story impact. Normalized 0–100 with contributing stories.
/api/v1/risk/countries— All countries ranked by risk/api/v1/risk/countries/:code— Single country detailParameters
hours | number | Lookback window in hours, 1-168 (default: 24) |
limit | number | Max countries, 1-200 (default: 50) |
curl -H "X-API-Key: pk_your_key" \
"https://www.perspecta.news/api/v1/risk/countries?hours=24&limit=10"
# Response:
{
"data": [
{
"country": "iran",
"riskScore": 100.0,
"storyCount": 45,
"topStories": [
{
"id": "bcd4f911-...",
"title": "Analysts Say Iran's Attacks Have Collapsed",
"impactScore": 98.3,
"sourceCount": 24
}
]
},
{
"country": "israel",
"riskScore": 82.4,
"storyCount": 31,
"topStories": [ ... ]
}
]
}News Events
Structured, deduplicated events with source articles, perspectives, and entity timelines.
/api/v1/events— List events with filters/api/v1/events/:id— Event detail with all source articles/api/v1/events/:id/perspectives— Articles grouped by outlet/api/v1/merges— Stories folded into other stories/api/v1/entities— Enumerate the entity vocabulary/api/v1/entities/:name/timeline— Event timeline for a person, place, or orgParameters — /events
since | string | Publisher-clock window: a duration (30m, 6h, 7d) or an ISO 8601 timestamp (default: 24h) |
changedSince | string | Wall-clock window — stories Perspecta wrote at or after this point. Duration or ISO 8601. Use this for incremental sweeps, not since |
orderBy | string | sourceCount (default), publishedAt, lastWritten, or firstIngested. lastWritten is stable under concurrent writes; firstIngested is the archive ordering |
order | string | desc (default) or asc. Ascending is how you walk into the past |
until | string | Upper bound on the publisher clock, mirroring since |
ingestedSince | string | Lower bound on the ingestion clock — when we first received content in the cluster |
ingestedUntil | string | Upper bound on the ingestion clock |
cursor | string | Opaque pagination token from meta.nextCursor. Must match the orderBy it was issued for |
include | string | Set to articles to inline each event's top constituent articles |
articlesPerEvent | number | Articles per event when include=articles, 1-10 (default: 3). Also accepted as articleLimit |
includeMerged | boolean | Include stories that were folded into another story (default: false) |
topic | string | Filter by topic: world, politics, business, technology, science, health, entertainment, environment |
country | string | Filter by country name |
tag | string | Filter by hashtag |
entity | string | Filter by entity name (person, org, place) |
minSources | number | Minimum source count (default: 1) |
minVelocity | number | Minimum sources per hour, using the same definition as the velocity field. Combine with ingestedSince to find young, fast-moving stories |
limit | number | Rows per page, 1-200 (default: 50). Not a cap on total rows — page with cursor |
Pagination
Every list endpoint returns meta.truncated and meta.nextCursor. When truncated is true, more rows matched than were returned — pass nextCursor back to continue. Paging is by keyset, not offset, so it neither repeats nor skips rows while the clustering job is writing. A cursor is only valid for the orderBy it was issued for; mixing them is rejected rather than silently returning the wrong rows.
For an incremental sweep, order by lastWritten and pass the previous sweep's highest lastWrittenAt as changedSince. Under orderBy=sourceCount or publishedAt a concurrent write can move a row across a page boundary; lastWritten cannot.
curl -H "X-API-Key: pk_your_key" \ "https://www.perspecta.news/api/v1/events?orderBy=lastWritten\ &changedSince=2026-07-31T08:00:00.000Z&limit=200&include=articles" # then follow meta.nextCursor until it comes back null
Reading the archive
firstIngestedAt is when we first received content in a cluster, derived from the earliest fetch among its articles. This is the field to bound a point-in-time replay on — not firstSeenAt, which only became honest on 2026-07-31 and was backfilled from the publisher clock before that.
It is monotonically non-increasing: it never moves forward, and moves earlier only when a cluster absorbs an article fetched before anything it already held — which happens when stories merge. A replay bounded at a given instant can therefore gain a story it previously excluded, but can never lose one. Direct writes cannot change it at all.
meta.archiveStartsAt on every events response gives the earliest ingestion time we hold. Do not infer the archive depth from publishedAt — a few dozen stories carry publisher dates going back years, which makes the corpus look far deeper than it is.
Ordering by firstIngested drops the 24-hour since default, since a publisher-clock window would truncate an archive read to nothing. Archive reads may also take up to 1000 rows a page, except when inlining articles.
curl -H "X-API-Key: pk_your_key" "https://www.perspecta.news/api/v1/events?orderBy=firstIngested&order=asc&ingestedSince=2026-03-01T00:00:00Z&ingestedUntil=2026-04-01T00:00:00Z&limit=1000" # follow meta.nextCursor until null; the cursor carries its own direction, # so an ascending cursor cannot be replayed through a descending walk.
Parameters — /merges
since | string | Window on mergedAt: duration or ISO 8601 (default: 24h) |
limit | number | Rows per page, 1-200 (default: 50) |
cursor | string | Opaque token from meta.nextCursor |
Parameters — /entities
A bulk endpoint, served from a snapshot refreshed every 30 minutes. storyCount and totalSources are always over a fixed 30-day window whatever since says; since filters on lastSeenAt. meta.computedAt gives the snapshot's age. Names appearing in fewer than three stories in the window are not tracked.
since | string | Only entities last seen at or after this point |
minStories | number | Minimum stories in the 30-day window (default: 1) |
type | string | company, person, country, organization, location, product, event, other. Null on names not yet classified |
minConfidence | number | 0-1. Filters on typeConfidence. Use with type=company for instrument resolution — the extractor emits common nouns, and ambiguous names are scored low rather than guessed |
limit | number | Rows per page, max 2000 (default: 500) |
offset | number | Row offset — this endpoint pages by offset, not cursor |
Parameters — /entities/:name/timeline
days | number | Lookback in days, 1-30 (default: 7) |
limit | number | Max events, 1-200 (default: 50) |
curl -H "X-API-Key: pk_your_key" \ "https://www.perspecta.news/api/v1/events?country=iran&tag=IranWar&minSources=10&limit=5"
curl -H "X-API-Key: pk_your_key" \
"https://www.perspecta.news/api/v1/events/3830025b-8759-44cd-8bd9-20a9b33a16a7"
# Returns the event with all source articles:
{
"data": {
"id": "3830025b-...",
"title": "Europe Rules Out Joining Trump's Hormuz Armada",
"sourceCount": 31,
"sourceSignal": "diverge",
"articles": [
{
"id": "a1b2c3...",
"title": "Europe refuses to join US naval mission",
"outlet": "reuters",
"url": "https://...",
"publishedAt": "2026-03-17T01:30:00Z"
},
...
]
}
}curl -H "X-API-Key: pk_your_key" \
"https://www.perspecta.news/api/v1/events/3830025b-.../perspectives"
# Articles grouped by outlet:
{
"data": {
"eventTitle": "Europe Rules Out Joining Trump's Hormuz Armada",
"sourceSignal": "diverge",
"outletCount": 18,
"perspectives": [
{
"outlet": "reuters",
"articleCount": 3,
"articles": [ ... ]
},
{
"outlet": "al-jazeera",
"articleCount": 2,
"articles": [ ... ]
}
]
}
}curl -H "X-API-Key: pk_your_key" \
"https://www.perspecta.news/api/v1/entities/trump/timeline?days=7"
# All events mentioning "trump" in the last 7 days:
{
"data": {
"entity": "trump",
"storyCount": 42,
"timeline": [
{
"id": "...",
"title": "Trump Criticizes Allies for Rejecting Hormuz Request",
"sourceCount": 28,
"impactScore": 120.4,
"publishedAt": "2026-03-17T03:00:00Z"
},
...
]
}
}AI & Agentic Workflows
Perspecta's structured, multi-source event data is purpose-built for AI agents, RAG pipelines, and LLM-powered applications.
Why Perspecta for AI?
Raw news feeds are noisy — duplicate articles, single-source claims, no event structure. Perspecta solves this by clustering articles into deduplicated events with source counts, consensus signals, entity extraction, and multi-perspective coverage. This means your AI gets clean, structured, verified-by-breadth data instead of raw article soup.
RAG & Grounding
Use /events as a real-time knowledge source for LLMs. Each event includes a summary, source count, and direct article URLs — giving your model grounded, citable, multi-source answers instead of hallucinated ones.
Tool Use & Function Calling
Every endpoint returns structured JSON that maps directly to LLM tool schemas. Define Perspecta as a tool in Claude, GPT, or Gemini and let the model query events, risk scores, and entity timelines autonomously.
Agentic Research
Build agents that monitor geopolitical risk, track entities across events, and surface narrative shifts. The /entities/:name/timeline endpoint gives agents a structured event history for any person, org, or place.
Signal Detection
The impactScore and sourceSignal fields let agents distinguish signal from noise. High velocity + source divergence = something significant is happening and outlets disagree on what it means.
Example: Claude Tool Definition
{
"name": "get_news_events",
"description": "Get recent news events from Perspecta, filtered by topic, country, entity, or tag. Returns structured events with source counts, impact scores, and multi-perspective coverage.",
"input_schema": {
"type": "object",
"properties": {
"topic": {
"type": "string",
"description": "Filter by topic: world, politics, business, technology, science, health"
},
"country": {
"type": "string",
"description": "Filter by country name"
},
"entity": {
"type": "string",
"description": "Filter by entity (person, org, place)"
},
"tag": {
"type": "string",
"description": "Filter by hashtag"
},
"since": {
"type": "string",
"description": "Time window: 1h, 6h, 24h, 7d",
"default": "24h"
},
"minSources": {
"type": "integer",
"description": "Minimum source count for filtering noise",
"default": 3
}
}
}
}Example: Agentic Risk Monitor
import requests, time
API_KEY = "pk_your_key"
HEADERS = {"X-API-Key": API_KEY}
BASE = "https://www.perspecta.news/api/v1"
def check_risk():
"""Agent loop: monitor country risk and alert on spikes."""
r = requests.get(f"{BASE}/risk/countries?hours=6", headers=HEADERS)
countries = r.json()["data"]
for c in countries:
if c["riskScore"] > 80:
# High risk — get details and perspectives
top_story = c["topStories"][0]
detail = requests.get(
f"{BASE}/events/{top_story['id']}/perspectives",
headers=HEADERS
).json()["data"]
print(f"⚠️ {c['country'].upper()} risk={c['riskScore']}")
print(f" {top_story['title']}")
print(f" {detail['outletCount']} outlets, signal: {detail['sourceSignal']}")
# → Feed to LLM for analysis, send Slack alert, update dashboard
while True:
check_risk()
time.sleep(300) # Check every 5 minutesExample: RAG Pipeline
# Fetch high-signal events to inject into LLM context
events = requests.get(
f"{BASE}/events?minSources=5&since=12h&limit=10",
headers=HEADERS
).json()["data"]
context = "\n".join([
f"- {e['title']} ({e['sourceCount']} sources, "
f"impact: {e['impactScore']}, signal: {e['sourceSignal'] or 'neutral'})"
for e in events
])
# Use as system context for any LLM
response = claude.messages.create(
model="claude-sonnet-4-20250514",
system=f"You have access to today's verified news events:\n{context}",
messages=[{"role": "user", "content": "What's happening in the Middle East?"}]
)Rate Limits
There are no tiers. Your limit is set on your key when we issue it, sized to what you told us you were building — including unmetered, which is what partners polling on a short interval get. If your limit turns out to be wrong, email us and we will change the number.
Limits are enforced per key, per calendar minute. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (Unix seconds). Exceeding the limit returns 429 with Retry-After in seconds. An unmetered key returns no rate-limit headers at all — their absence is how you know you have no limit.
Response Contract
- Timestamps are ISO 8601 strings, not numbers or date objects. Parse them before comparing — an ISO string flowing into a date comparison compares lexically and produces wrong answers silently.
- Two clocks, and they mean different things.
publishedAtandupdatedAtare publisher clocks: they come from the outlets, andupdatedAtcan move backwards in real time when a story gains a late-arriving article that was published hours ago.firstSeenAtandlastWrittenAtare our wall clock and only ever move forwards. Poll onlastWrittenAt; never onupdatedAt. Both wall-clock fields are null on stories that predate 2026-07-31. sourceSignalis"agree","diverge"ornull. Null means not yet analysed — it does not mean neutral. Analysis is generated asynchronously, so a fresh story is normally null and gains a signal later.- Merged stories are excluded by default. When two clusters turn out to describe the same event, one is folded into the other and carries a non-null
mergedInto. Its source count did not collapse — its coverage moved. Fetching a merged story by id returns200with{ id, mergedInto, mergedAt }rather than the stale row, and/api/v1/mergeslists them in bulk. - Entity names are lowercased and carry no legal suffixes — the vocabulary contains
ubs, notUBS Group AG. Match case-insensitively and do not expectS.A.orAG.
Get Access
The API is in alpha. There is no self-serve signup and nothing to pay — keys are issued by hand, one conversation at a time, so we can size the rate limit to what you are actually building.
Email hello@perspecta.news with a sentence or two about what you want to pull and how often. That is the whole process.
Request alpha accessAlpha means the endpoints above are stable enough to build on and we will tell you before anything breaks — not that they are frozen.