Skip to content
unzoi docs
Search and navigation
Start here
REST API
MCP
Limits and plans
Agent clients
SDKs
Guides

Relationships

Four endpoints answer "who is reported alongside whom" from the index, at the moment you ask. Each starts from entity ids, counts the articles that mention entities together, and returns the newest of those articles as evidence.

OperationMCP toolWhat it does
GET /graph/related related_entities Entities co-mentioned with one entity.
GET /graph/path connection_path How two entities connect.
GET /graph/network entity_network One entity's neighbours, and what changed.
GET /graph/exposures shared_exposures What several entities have in common.

Co-mention, not relationship

Every number on this page counts articles. The link between two entities is their co-mentions: the articles in your window that mention both. No record of who owns, supplies, funds or employs whom sits behind these endpoints. They count what journalists wrote about together.

Entities are the ids /entities returns, such as organization:asml. An id stands for every spelling in its alias group, looked up within the request window, and the response lists the spellings it used as aliases_used. An empty aliases_used means the index holds no spelling of that id in the window, so nothing can be connected to it there. It does not mean the entity has no connections.

How an answer is built

Nothing is precomputed. A call resolves each id to its spellings. It then takes the articles that mention the starting entity and counts which other entities they mention, one facet per entity type. Spellings that share a normalised key count as one neighbour, with the id /entities would give it. Evidence is a bounded search, newest first, over the articles that mention both ends of a link. Nothing is cached between calls, so an answer is as current as the index.

Reading an edge

Each neighbour, each hop of a path and each change is described by one edge:

Field Type Description
aliases string[] Every spelling grouped under the id.
approximate boolean Whether the counts came from a capped facet, from spellings one article can repeat, or were summed across indexes.
co_mentions integer Articles mentioning both. Exact when the edge carries evidence; otherwise a facet count (see approximate).
entity_id string The associated entity; pass it back as an entity_id.
evidence CompactArticle[] The newest articles mentioning both. Empty when evidence was not requested, the edge ranked below the evidence cut, or the call's query budget was spent.
first_seen string The earliest article mentioning both, when evidence was gathered.
label string Its most frequent spelling.
last_seen string The newest article mentioning both, when evidence was gathered.
share number co_mentions over the articles mentioning the entity the edge is seen from, 0-1: the starting entity for related_entities, entity_network, and a path's direct edge and first hop; the end entity on a path's second hop. Compare shares, not counts, between a large entity and a small one.
sources integer Distinct publishers among the co-mentions, when evidence was gathered. More sources is broader reporting, not necessarily independent reporting.
stories integer Distinct clustered stories among the co-mentions, when evidence was gathered.
type `organization` · `person` · `location` · `city` · `region` · `topic` · `name` Its entity field.
  • co_mentions counts articles, not events. Forty outlets running one wire story that names both entities are forty co-mentions.
  • share is co_mentions divided by the articles that mention the entity the edge is seen from, rounded to three decimals. On /graph/related and /graph/network that is the starting entity (seed.articles). On a path, the direct edge and the first hop are seen from from_entity, and the second hop from to_entity. A heavily covered entity has large co-mention counts with almost everything. Share says how much of its coverage the neighbour appears in, so compare shares, not counts.
  • Evidence goes to the strongest edges only: the first evidence of them (default 3), each with up to evidence articles. Gathering it recounts co_mentions exactly. It also adds sources and stories, the distinct publishers and clustered stories among those articles, and first_seen and last_seen. Edges below the cut carry counts and an empty evidence. evidence=0 asks for counts only.
  • sources against stories. Many sources and few stories is one or two events carried widely. Many stories spread between first_seen and last_seen is a pattern that recurs. More sources means broader reporting, not necessarily independent reporting.
  • approximate: true means a count came from a capped facet or was summed across indexes. The flag is also set when a neighbour's spellings were counted separately, which can count one article twice. Read an approximate count as an upper bound. Evidence replaces it with an exact count.

Freshness, cost and bounds

Every graph response carries the same fields about the answer itself:

  • note: the association caveat, verbatim, so it travels with the data.
  • indexed_through: the newest article the answering index holds in your window. It says how current the associations are. The newest shared article is an edge's last_seen.
  • entity_resolution_version: the normalisation the ids were computed with, er-v1. Ids are stable within a version, so store the version next to any id you keep.
  • credits_charged: a credit per index query the call issued, which is what it is charged. Also sent as the x-credits-charged header.
  • partial and coverage: whether the index fully answered, as on every search.

A call issues one query to find indexed_through, one or two to resolve each id, one to count neighbours, and two for each edge that gets evidence. /graph/related with the default three evidence edges is usually nine or ten credits. An edge the budget cannot afford keeps its counts and goes without evidence; the call is not refused. Across indexes, a call is charged the most any one index needed, not the sum. A network comparison adds a flat 3 credits. Credits and overage lists what other calls cost.

BoundLimit
Hops in a path2: the direct connection, or through one shared neighbour
Neighbours returned50 on /graph/related; 20 per type on /graph/network
Paths returned5
Evidence10 articles per edge, on at most the 10 strongest edges
Entities in one /graph/exposures call5
Index queries16 per index, per call

The window and the corpus

Every graph call takes from and to, plus four filters that narrow which articles are counted: language, publisher_country, source_type and country. They mean what they mean on /search. Ids are resolved over the same window; the four filters narrow the counts, not the lookup.

Pass a window. With a key, an omitted from is your plan's archive boundary, and a neighbourhood over a year answers a different question from one over a week. from_clamped says when your from was moved forward.

GET https://api.unzoi.com/graph/related

Entities co-mentioned with one entity.

The organizations, people, places and topics most often mentioned alongside one entity in a window, strongest first, with evidence for the strongest. Answered at request time from the index: co-mention counts come from facets over the articles mentioning an entity, evidence from bounded searches. Co-mention in reporting is evidence of association, not of ownership, partnership, causation or exposure. Bounded: two hops, fifty neighbours, ten evidence articles and sixteen index queries per index, reported and charged as `credits_charged`. Equivalent to the `related_entities` MCP tool. Credits: 2 up to 4 + 2 per edge that gets evidence, at most 16; evidence=0 keeps it to 4 or less. Pass estimate=true to get the exact range without running the call, or max_credits to refuse anything costlier.

Name Type Description
entity_id required string The entity to start from: one id from resolve_entity, e.g. organization:asml.
types string Neighbour types to return, comma separated: organization, person, location, city, region, topic, name (default organization,person,location,topic).
limit integer Neighbours to return, 1-50 (default 20).
evidence integer How many of the strongest connections get evidence, and how many articles each carries (default 3; 0 for counts only). Evidence costs index queries, reported as credits_charged.
estimate boolean Return this call's price instead of running it: the credit range, a breakdown, your remaining credits and whether the call would run. A preview costs 0 credits.
max_credits integer Refuse the call, at no cost, when its worst case would cost more than this many credits. The refusal carries the estimate.
Corpus scope
source_typepublisher_countrylanguagecountry

One id in entity_id. Several are refused; /graph/exposures takes up to five. types defaults to organizations, people, locations and topics. Neighbours of every requested type are ranked together by co_mentions, strongest first, and cut at limit (default 20). The starting entity is never its own neighbour.

Field Type Description
attribution string Required source attribution for any use of these results.
coverage `complete` · `timed_out` · `range_too_wide` · `recent_unavailable` · `field_unavailable` Why the answer is or is not complete, named for what you can do about it. `complete`: everything in range was read (or provably could not have changed the page). `timed_out`: the query ran out of budget -- retry, or narrow the range. `range_too_wide`: the range spans more of the corpus than one request may read -- narrow it; retrying unchanged will not help. `recent_unavailable`: the most recent data in range could not be read -- retry shortly; widening the range will not help. `field_unavailable`: a filter needs a field part of the index was built without (geographic, event-class and amount fields arrive with each shard's rebuild) -- the answer covers only the rebuilt part; retrying before the rebuild will not help.
credits_charged integer Index queries this answer took, and what the call is charged. At most 16 per index; a network comparison across indexes is two passes.
entity_resolution_version string The normalisation entity ids were computed with; ids are stable within one version.
from_clamped boolean Whether the window was moved forward to the plan's boundary.
history_days integer How far back the caller's plan may query; null = the full archive.
indexed_through string The newest article the answering index holds in the window, 14-digit YYYYMMDDHHMMSS: how fresh these associations are.
note string Co-mention in reporting is evidence of association, not of ownership, partnership, causation or exposure.
partial boolean Whether this answer is incomplete. `true` means part of the index could not be read, so an empty or short result set is NOT evidence of absence -- retry rather than caching it as a negative.
related GraphEdge[] Neighbours, strongest first; the strongest carry evidence.
seed GraphSeed The entity the query started from.

GraphSeed

Field Type Description
aliases_used string[] The spellings it matched in the window. Empty means none: nothing can be connected to it there.
articles integer Articles mentioning it in the window, when the call counted them.
entity_id string The id as passed.
type `organization` · `person` · `location` · `city` · `region` · `name` · `topic` · `author` · `source` The entity field.
curl -s -G "https://api.unzoi.com/graph/related" -H "x-api-key: $UNZOI_KEY" \
  --data-urlencode "entity_id=organization:asml" \
  --data-urlencode "types=organization,person" \
  --data-urlencode "from=2026-08-01" \
  --data-urlencode "to=2026-08-31" \
  --data-urlencode "limit=5" \
  --data-urlencode "evidence=1"
{
  "seed": {
    "entity_id": "organization:asml",
    "type": "organization",
    "aliases_used": ["asml", "asml holding nv"],
    "articles": 1271
  },
  "related": [
    {
      "entity_id": "organization:tsmc",
      "type": "organization",
      "label": "tsmc",
      "aliases": ["tsmc", "tsmc ltd"],
      "co_mentions": 212,
      "share": 0.167,
      "stories": 64,
      "sources": 118,
      "first_seen": "20260801031500",
      "last_seen": "20260830214500",
      "evidence": [
        {
          "id": "20260830214500-a1b2c3",
          "title": "Chip equipment orders climb as foundries add capacity",
          "url": "https://example.com/chip-orders",
          "source": "example.com",
          "published_at": "20260830214500",
          "language": "eng",
          "story_id": "s-4e7a"
        }
      ],
      "approximate": false
    },
    {
      "entity_id": "organization:nvidia",
      "type": "organization",
      "label": "nvidia",
      "aliases": ["nvidia"],
      "co_mentions": 97,
      "share": 0.076,
      "evidence": [],
      "approximate": true
    }
  ],
  "indexed_through": "20260831234500",
  "entity_resolution_version": "er-v1",
  "credits_charged": 5,
  "note": "Co-mention in reporting is evidence of association, not of ownership, partnership, causation or exposure. Read the evidence before stating a relationship.",
  "partial": false,
  "coverage": "complete",
  "history_days": 365,
  "from_clamped": false,
  "attribution": "Data derived from the GDELT Project (https://www.gdeltproject.org/)."
}

With evidence=1, only the strongest edge is recounted and carries an article. The second keeps its facet count, marked approximate. Five units: the freshness check, one lookup for the id, one neighbour count, and two for the evidence.

Connection path

GET https://api.unzoi.com/graph/path

How two entities connect.

The articles mentioning both, and up to five paths through one shared neighbour. Answered at request time from the index: co-mention counts come from facets over the articles mentioning an entity, evidence from bounded searches. Co-mention in reporting is evidence of association, not of ownership, partnership, causation or exposure. Bounded: two hops, fifty neighbours, ten evidence articles and sixteen index queries per index, reported and charged as `credits_charged`. Equivalent to the `connection_path` MCP tool. Credits: 3-8 with max_hops=1, 3-9 with evidence=0, up to 16 otherwise. Pass estimate=true to get the exact range without running the call, or max_credits to refuse anything costlier.

Name Type Description
from_entity required string Where the path starts: an id from resolve_entity.
to_entity required string Where the path ends: an id from resolve_entity.
max_hops integer 1 for the direct connection only; 2 (default) also looks through one shared neighbour. Paths are bounded to two hops by design.
evidence integer How many of the strongest connections get evidence, and how many articles each carries (default 3; 0 for counts only). Evidence costs index queries, reported as credits_charged.
estimate boolean Return this call's price instead of running it: the credit range, a breakdown, your remaining credits and whether the call would run. A preview costs 0 credits.
max_credits integer Refuse the call, at no cost, when its worst case would cost more than this many credits. The refusal carries the estimate.
Corpus scope
source_typepublisher_countrylanguagecountry

direct is always present: an edge reaching to_entity, counted exactly over the articles that mention both, with up to evidence of them. co_mentions: 0 means no article in the window names both.

With max_hops=2, the default, the call also lists up to 50 neighbours of each type for each end and keeps those the two share. A path runs from the start, through one shared neighbour, to the end. Paths are ranked by their weaker hop, and at most five come back. strength is that weaker hop's co-mentions: a path is only as well reported as its thinner link. Each hop gets evidence while evidence is above zero and the call can afford it.

A path chains two co-mentions from different articles: the start reported with the neighbour, and the neighbour reported with the end. It never shows the two ends in one article; that is direct. An empty paths means no shared neighbour among each end's strongest, not that no connection exists. Compare hops by co_mentions. The first hop's share is over from.articles and the second hop's over to.articles, so the two are fractions of different coverage. With max_hops=1 the call counts the starting entity's articles, one more index query: from.articles is set, to.articles is absent, and direct.share is measured over from.articles as it is at two hops.

Response

Field Type Description
attribution string Required source attribution for any use of these results.
coverage `complete` · `timed_out` · `range_too_wide` · `recent_unavailable` · `field_unavailable` Why the answer is or is not complete, named for what you can do about it. `complete`: everything in range was read (or provably could not have changed the page). `timed_out`: the query ran out of budget -- retry, or narrow the range. `range_too_wide`: the range spans more of the corpus than one request may read -- narrow it; retrying unchanged will not help. `recent_unavailable`: the most recent data in range could not be read -- retry shortly; widening the range will not help. `field_unavailable`: a filter needs a field part of the index was built without (geographic, event-class and amount fields arrive with each shard's rebuild) -- the answer covers only the rebuilt part; retrying before the rebuild will not help.
credits_charged integer Index queries this answer took, and what the call is charged. At most 16 per index; a network comparison across indexes is two passes.
direct GraphEdge The articles mentioning both, as an edge reaching `to`.
entity_resolution_version string The normalisation entity ids were computed with; ids are stable within one version.
from GraphSeed Where the path starts.
from_clamped boolean Whether the window was moved forward to the plan's boundary.
history_days integer How far back the caller's plan may query; null = the full archive.
indexed_through string The newest article the answering index holds in the window, 14-digit YYYYMMDDHHMMSS: how fresh these associations are.
note string Co-mention in reporting is evidence of association, not of ownership, partnership, causation or exposure.
partial boolean Whether this answer is incomplete. `true` means part of the index could not be read, so an empty or short result set is NOT evidence of absence -- retry rather than caching it as a negative.
paths GraphPath[] Up to five paths through one shared neighbour, strongest first; empty with max_hops=1.
to GraphSeed Where the path ends.

GraphPath

Field Type Description
edges GraphEdge[] One edge per hop, each describing the entity it reaches.
hops string[] Entity ids from the start, through the neighbour, to the end.
strength integer The weaker hop's co-mentions.
curl -s -G "https://api.unzoi.com/graph/path" -H "x-api-key: $UNZOI_KEY" \
  --data-urlencode "from_entity=organization:asml" \
  --data-urlencode "to_entity=organization:rapidus" \
  --data-urlencode "from=2026-08-01" \
  --data-urlencode "to=2026-08-31" \
  --data-urlencode "evidence=1" \
  | jq '{direct: (.direct | {co_mentions, stories, sources}), paths: [.paths[] | {hops, strength}], credits_charged}'
{
  "direct": { "co_mentions": 14, "stories": 6, "sources": 12 },
  "paths": [
    { "hops": ["organization:asml", "organization:tokyo electron", "organization:rapidus"], "strength": 9 },
    { "hops": ["organization:asml", "location:hokkaido japan", "organization:rapidus"], "strength": 7 }
  ],
  "credits_charged": 15
}

Ids can contain spaces, so pass them URL-encoded. Here the two ends appear together in six stories, and both are also reported alongside Tokyo Electron and Hokkaido. Neither path says anything the articles do not.

Entity network

GET https://api.unzoi.com/graph/network

One entity's neighbours, and what changed.

Neighbours by type for a window; with `compare_from` or `compare_to`, new and gone neighbours and ties that strengthened or weakened. Answered at request time from the index: co-mention counts come from facets over the articles mentioning an entity, evidence from bounded searches. Co-mention in reporting is evidence of association, not of ownership, partnership, causation or exposure. Bounded: two hops, fifty neighbours, ten evidence articles and sixteen index queries per index, reported and charged as `credits_charged`. Equivalent to the `entity_network` MCP tool. Credits: 2 up to 4 + 2 per edge that gets evidence, at most 16, plus 3 for a comparison window. Pass estimate=true to get the exact range without running the call, or max_credits to refuse anything costlier.

Name Type Description
entity_id required string The entity to start from: one id from resolve_entity, e.g. organization:asml.
types string Neighbour types to return, comma separated: organization, person, location, city, region, topic, name (default organization,person,location,topic).
limit integer Neighbours per type, 1-20 (default 10).
evidence integer How many of the strongest connections get evidence, and how many articles each carries (default 3; 0 for counts only). Evidence costs index queries, reported as credits_charged.
compare_from string Start of a second window to compare the network against, in the same formats as `from`. With compare_from or compare_to the response carries `changes`.
compare_to string End of the comparison window, in the same formats as `to`.
estimate boolean Return this call's price instead of running it: the credit range, a breakdown, your remaining credits and whether the call would run. A preview costs 0 credits.
max_credits integer Refuse the call, at no cost, when its worst case would cost more than this many credits. The refusal carries the estimate.
Corpus scope
source_typepublisher_countrylanguagecountry

One entity's neighbourhood grouped by type. groups is keyed by entity type, and each list is strongest first and cut at limit per type (default 10, at most 20). Evidence goes to the strongest evidence edges across all the groups.

What changed: compare_from and compare_to

Pass either, and the same neighbourhood is computed over a second window and compared with the first. An end you omit is open. The comparison window is bound by your plan's archive depth, as from is.

  • new: shown now, and not among the comparison window's neighbours.
  • gone: shown in the comparison window, and not among this window's neighbours.
  • strengthened: a share at least one and a half times what it was, with at least two co-mentions now.
  • weakened: a share down by a third or more.

Before comparing, each window's neighbours are read to three times limit per type. So gone means a neighbour fell well out of the other window's list, not just below the cut. Shares are over each window's own article count for the entity, so a month with twice the coverage does not strengthen every tie. The comparison is a second pass, charged in full.

A change is a change in the reporting. A neighbour is new when journalists started writing about the two together, and one large story is enough to cause it. Check the edge's stories and evidence before calling it a development.

Response

Field Type Description
attribution string Required source attribution for any use of these results.
changes GraphNetworkChanges Present with compare_from or compare_to, unless the call's index-query budget ran out before the comparison: lower `evidence` to make room.
coverage `complete` · `timed_out` · `range_too_wide` · `recent_unavailable` · `field_unavailable` Why the answer is or is not complete, named for what you can do about it. `complete`: everything in range was read (or provably could not have changed the page). `timed_out`: the query ran out of budget -- retry, or narrow the range. `range_too_wide`: the range spans more of the corpus than one request may read -- narrow it; retrying unchanged will not help. `recent_unavailable`: the most recent data in range could not be read -- retry shortly; widening the range will not help. `field_unavailable`: a filter needs a field part of the index was built without (geographic, event-class and amount fields arrive with each shard's rebuild) -- the answer covers only the rebuilt part; retrying before the rebuild will not help.
credits_charged integer Index queries this answer took, and what the call is charged. At most 16 per index; a network comparison across indexes is two passes.
entity_resolution_version string The normalisation entity ids were computed with; ids are stable within one version.
from_clamped boolean Whether the window was moved forward to the plan's boundary.
groups object Neighbours by entity type, strongest first.
history_days integer How far back the caller's plan may query; null = the full archive.
indexed_through string The newest article the answering index holds in the window, 14-digit YYYYMMDDHHMMSS: how fresh these associations are.
note string Co-mention in reporting is evidence of association, not of ownership, partnership, causation or exposure.
partial boolean Whether this answer is incomplete. `true` means part of the index could not be read, so an empty or short result set is NOT evidence of absence -- retry rather than caching it as a negative.
seed GraphSeed The entity the query started from.

GraphNetworkChanges

Field Type Description
gone GraphEdge[] Neighbours shown then that are not neighbours now.
new GraphEdge[] Neighbours shown now that were not neighbours then.
strengthened GraphChange[] Ties whose share grew by half or more, with at least two co-mentions now.
weakened GraphChange[] Ties whose share fell by a third or more.

GraphChange

Field Type Description
after integer Co-mentions in the requested window.
after_share number Share in the requested window.
before integer Co-mentions in the comparison window.
before_share number Share in the comparison window.
entity_id string The neighbour.
label string Its most frequent spelling.
# August against July, counts only: evidence for the changes worth reporting comes after.
curl -s -G "https://api.unzoi.com/graph/network" -H "x-api-key: $UNZOI_KEY" \
  --data-urlencode "entity_id=organization:asml" \
  --data-urlencode "types=organization,person" \
  --data-urlencode "from=2026-08-01" \
  --data-urlencode "to=2026-08-31" \
  --data-urlencode "compare_from=2026-07-01" \
  --data-urlencode "compare_to=2026-07-31" \
  --data-urlencode "evidence=0" \
  | jq '.changes | {new: [.new[].label], gone: [.gone[].label], strengthened, weakened}'
{
  "new": ["rapidus"],
  "gone": ["imec"],
  "strengthened": [
    { "entity_id": "organization:tsmc", "label": "tsmc", "before": 118, "after": 212, "before_share": 0.102, "after_share": 0.167 }
  ],
  "weakened": [
    { "entity_id": "organization:intel", "label": "intel", "before": 105, "after": 61, "before_share": 0.091, "after_share": 0.048 }
  ]
}

Shared exposures

GET https://api.unzoi.com/graph/exposures

What several entities have in common.

The articles mentioning up to five entities together, with their facets, signal intensities and evidence. Answered at request time from the index: co-mention counts come from facets over the articles mentioning an entity, evidence from bounded searches. Co-mention in reporting is evidence of association, not of ownership, partnership, causation or exposure. Bounded: two hops, fifty neighbours, ten evidence articles and sixteen index queries per index, reported and charged as `credits_charged`. Equivalent to the `shared_exposures` MCP tool. Credits: 3, plus 1-2 per entity id, plus 1 with signal_stats. Pass estimate=true to get the exact range without running the call, or max_credits to refuse anything costlier.

Name Type Description
entity_id required string Up to five entity ids from resolve_entity, comma separated (over REST the parameter may also repeat). Each matches any spelling in its alias group in the requested window; several ids must all match. The spellings used are reported in `resolved`.
facets string Comma-separated fields to count over the full match set, up to 8.
facet_limit integer Values per facet, 1-100 (default 10).
signal_stats string Signal names to summarise over the shared articles, comma separated, e.g. finance,supply_disruption.
evidence integer How many of the strongest connections get evidence, and how many articles each carries (default 3; 0 for counts only). Evidence costs index queries, reported as credits_charged.
estimate boolean Return this call's price instead of running it: the credit range, a breakdown, your remaining credits and whether the call would run. A preview costs 0 credits.
max_credits integer Refuse the call, at no cost, when its worst case would cost more than this many credits. The refusal carries the estimate.
Corpus scope
source_typepublisher_countrylanguagecountry

Up to five ids, comma separated, or with entity_id repeated. An article counts when it mentions every one of them. The name describes the question a watchlist asks ("what reporting do these share?"). It is not a claim that any of them is exposed to anything.

  • articles is exact. stories and sources are distinct counts over those articles; approximate: true says one of them was capped.
  • facets counts the fields you name over the shared articles: which countries, topics or outlets the shared reporting is about. Comma separated over REST, an array over MCP.
  • signal_stats names signals, and signals reports each one's mean and 50th and 95th percentile intensity over the shared articles, the same statistics /aggregate reports.
  • evidence is the newest shared articles, up to evidence of them.

An id with an empty aliases_used in entities makes the intersection empty, so check entities before reading articles: 0 as nothing shared. Five ids ask for articles that name all five, which is usually very few. For overlap across a watchlist, call once per pair.

Response

Field Type Description
approximate boolean Whether the distinct story or source counts were capped or summed across indexes.
articles integer Articles mentioning every entity.
attribution string Required source attribution for any use of these results.
coverage `complete` · `timed_out` · `range_too_wide` · `recent_unavailable` · `field_unavailable` Why the answer is or is not complete, named for what you can do about it. `complete`: everything in range was read (or provably could not have changed the page). `timed_out`: the query ran out of budget -- retry, or narrow the range. `range_too_wide`: the range spans more of the corpus than one request may read -- narrow it; retrying unchanged will not help. `recent_unavailable`: the most recent data in range could not be read -- retry shortly; widening the range will not help. `field_unavailable`: a filter needs a field part of the index was built without (geographic, event-class and amount fields arrive with each shard's rebuild) -- the answer covers only the rebuilt part; retrying before the rebuild will not help.
credits_charged integer Index queries this answer took, and what the call is charged. At most 16 per index; a network comparison across indexes is two passes.
entities GraphSeed[] The entities, as the index spells them.
entity_resolution_version string The normalisation entity ids were computed with; ids are stable within one version.
evidence CompactArticle[] The newest shared articles.
facets object The facets requested, counted over the shared articles.
from_clamped boolean Whether the window was moved forward to the plan's boundary.
history_days integer How far back the caller's plan may query; null = the full archive.
indexed_through string The newest article the answering index holds in the window, 14-digit YYYYMMDDHHMMSS: how fresh these associations are.
note string Co-mention in reporting is evidence of association, not of ownership, partnership, causation or exposure.
partial boolean Whether this answer is incomplete. `true` means part of the index could not be read, so an empty or short result set is NOT evidence of absence -- retry rather than caching it as a negative.
signals object Per requested signal: mean and percentile intensity over the shared articles.
sources integer Distinct publishers among them.
stories integer Distinct clustered stories among them.
curl -s -G "https://api.unzoi.com/graph/exposures" -H "x-api-key: $UNZOI_KEY" \
  --data-urlencode "entity_id=organization:asml,organization:tsmc" \
  --data-urlencode "facets=country,topic" \
  --data-urlencode "signal_stats=supply_disruption,trade" \
  --data-urlencode "from=2026-08-01" \
  --data-urlencode "to=2026-08-31" \
  --data-urlencode "evidence=3" \
  | jq '{articles, stories, sources, countries: .facets.country[:3], signals: (.signals | map_values({mean, p95: .percentiles["95"]})), credits_charged}'
{
  "articles": 212,
  "stories": 64,
  "sources": 118,
  "countries": [
    { "value": "TW", "count": 131 },
    { "value": "NL", "count": 97 },
    { "value": "US", "count": 88 }
  ],
  "signals": {
    "supply_disruption": { "mean": 0.84, "p95": 2.61 },
    "trade": { "mean": 1.12, "p95": 2.95 }
  },
  "credits_charged": 6
}

Errors

The four operations return the same statuses.

Status Meaning
200 Success
400 Invalid request, charged nothing. Bounds, enums, dates and offsets are validated BEFORE any index work, so this never means a partially-served query. `credit_budget_exceeded`: the call's worst case is more than `max_credits`.
401 Missing or invalid API key. `code` is `unauthorized`.
402 Account suspended (subscription canceled or payment failed). `code` is `suspended`.
429 Refused before running, and charged nothing. `credit_rate_limited`: this minute's credits are spent. `message_rate_limited`: too many free calls or refused requests this minute. `insufficient_credits`: the key stops at its monthly allocation and does not have this call's worst case left. `retry-after` says how long to wait.
503 The index could not be read for this request. This is NOT an empty result set and NOT a statement that nothing matched — retry rather than caching it as a negative. `coverage` says which part was unreadable.

400 with code: invalid_parameter covers the refusals particular to these endpoints: a missing entity_id, from_entity or to_entity; more than one id on /graph/related or /graph/network, or more than five on /graph/exposures; an entity_id that is not <type>:<name>; and a limit, evidence or max_hops out of range. A parameter an endpoint does not take is unknown_parameter, with the name you probably meant.

Over MCP

The same four requests are the related_entities, connection_path, entity_network and shared_exposures tools, with the same arguments. Their descriptions tell a model to read the evidence and present co-mentions as a pattern in the reporting. Reading relationships goes from a name to an answer you can defend.

{
  "name": "related_entities",
  "arguments": {
    "entity_id": "organization:asml",
    "from": "2026-08-01",
    "to": "2026-08-31",
    "types": "organization,person",
    "evidence": 3
  }
}