Whisper · Docs
API reference

Graph & cognition

An agent about to fetch a URL has about a millisecond to decide whether it should — and "run it through a blocklist" isn't an answer, it's a guess with a timestamp.

A static feed is hours behind a fast-flux C2 domain; whois tells you who registered a name, not who's serving traffic behind the CDN in front of it; and none of it comes back with the receipts a human, an auditor, or another agent needs to trust the call. Whisper answers differently: one call against a live graph of the internet — DNS, BGP, WHOIS, TLS, hosting, threat-intel, fused and current — that hands back a verdict and the exact evidence behind it, in under 300ms.

The question every agent asks before it acts

Three shapes of the same question come up constantly, and none of them are answerable from a flat list:

Whisper's cognition surface is the graph-first answer to all three, and it's the same graph that powers graph-first resolution — the policy engine that decides whether a query even leaves an agent's /128 runs these exact verbs internally, on your behalf, before every answer.

The surface: named verbs over one graph

Every verb below is a read-only CALL against the shared graph. They group into four jobs:

Group Verb What it answers
Attribution identify(target) Who really operates a host or IP — operator, category, and the resolution chain that gets you there, even behind a CDN
asset(id) The full graph record for one node — hostname, IPv4/IPv6, ASN, or organization — by identifier
psl(domain) The registrable domain boundary for a name, per the Public Suffix Listsub.example.co.ukexample.co.uk
Risk assess(targets[]) A risk verdict for one or more indicators — verdict, severity, category (Tor exit, bulletproof hosting, scanner, …)
explain(target) The reasoning behind an assess verdict — which feeds fired, the score, how fresh the observation is
threatintel(indicator) Direct hits against the fused threat-intelligence feeds for one indicator, unscored
lookupTorRelay(ip) Whether an address is a current Tor relay or exit node
lookupTlsFingerprint(ja3\|ja4) Known clients/tooling associated with a TLS client fingerprint
Topology walk(node, depth) Traverse outward from a node along graph edges — infrastructure clusters, shared-hosting genealogies
origins(prefix) BGP origin history for a prefix — who has announced it, and when
topAsnsByPrefixCount() Internet-wide aggregate: ASNs ranked by announced prefix count
variants(domain) Look-alike / typosquat domain variants for a brand or name
Monitoring watch(target) Register a standing watch on an entity so future graph changes surface as events
history(target) The historical timeline of DNS, WHOIS, and ownership changes for a target
submit(indicator) Contribute an observation into the shared graph

Every verb is live today. A caller may also run arbitrary read-only CypherMATCH patterns of your own — directly against the shared subgraph; the named verbs are just the common queries pre-packaged as one call.

How to ask: two doors, one graph

Both doors run the identical query engine and return the identical shape. The only difference is how the caller is authenticated.

With your key, from anywhere, over the gateway:

curl -s https://graph.whisper.security/api/query \
     -H 'X-API-Key: whisper_live_…' \
     --data "CALL whisper.assess(['185.220.101.1'])"

Keyless, from inside a connected agent — the query rides the agent's own routable address, and that /128 is the credential, so no key travels on the wire at all:

curl -s https://[2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4]/api/query \
     --data "CALL whisper.identify('api.stripe.com')"

The same keyless pattern is exposed as a plain HTTP endpoint too, purpose-built for the single most common cognition question — "is the thing I'm about to connect to safe?" — asked from inside an agent that has no key on hand at all:

curl -s https://rdap.whisper.online/identify/api.openai.com
# -> {"host":"api.openai.com","operator":"Cloudflare","category":"cdn",
#     "evidence":"RESOLVES_TO -> IPV4 -> DELEGATED_TO -> cloudflare"}

# the identical call from outside a connected agent's address:
curl -s https://rdap.whisper.online/identify/api.openai.com
# -> 403 — the same lock that authenticates the agent is what authorizes the answer

That 403 is not a bug to route around — it's the point. identify from /identify/<host> is scoped to callers whose source address is already a Whisper agent; the network layer does the authentication, so the endpoint never has to trust a header a caller could forge.

Under the hood: what "evidence" actually means

The query language is openCypher — the same declarative graph pattern language used across the property-graph ecosystem — sent as plain text in the request body and answered as JSON rows. A verb like identify is a named, parameterized Cypher procedure; running it is equivalent to writing the underlying MATCH pattern yourself, without needing to know the schema.

What matters for trust is what comes back alongside the verdict. Every attribution or risk answer carries an evidence field that is the literal traversal the graph made to reach its conclusion — a chain of typed nodes and relationships, not a black-box score:

identify('api.openai.com')
  -> operator=Cloudflare · category=cdn
  -> evidence: (HOSTNAME)-[:RESOLVES_TO]->(IPV4)-[:DELEGATED_TO]->(ORGANIZATION:Cloudflare)

assess(['185.220.101.1'])
  -> suspicious · MEDIUM · Tor exit
explain('185.220.101.1')
  -> 3 feeds · score 5.3 · last seen 3h ago

identify walked RESOLVES_TO (a DNS answer) into DELEGATED_TO (a WHOIS/RDAP organization edge) and stopped at an ORGANIZATION node — that's the whole chain, reproducible, and disprovable if it's wrong. explain unpacks an assess verdict the same way: which of the fused threat-intel feeds contributed, the resulting score, and the age of the freshest observation behind it. Nothing here is a magic number; it's a graph traversal you can read.

Dual example: attribution, the hard way and the easy way

With stock tools — chase the resolution chain yourself and hope the last hop tells you something:

dig +short api.openai.com                          # CNAME/A chain, ends on a CDN edge IP
whois -h whois.arin.net 104.18.0.0                  # org on the IP -- usually the CDN, not the tenant
curl -s https://rdap.whisper.online/ip/104.18.0.0 | jq .entities
# best case: "Cloudflare, Inc." -- correct, but you still don't know who's BEHIND Cloudflare

None of those three commands tells you the tenant behind the edge — CDNs exist specifically to hide that. identify says "Cloudflare, cdn" honestly rather than guess further; for names it fully resolves and owns, the chain terminates at the real organization instead.

With Whisper — the same investigative chain, pre-walked, in one round trip:

curl -s https://graph.whisper.security/api/query -H 'X-API-Key: whisper_live_…' \
     --data "CALL whisper.identify('api.openai.com')" | jq .
# {"host":"api.openai.com","operator":"Cloudflare","category":"cdn",
#  "evidence":"RESOLVES_TO -> IPV4 -> DELEGATED_TO -> cloudflare"}

Dual example: risk, the hard way and the easy way

With stock tools, checking one IP against Tor and whatever abuse databases you have accounts for means several disjoint tools that don't agree on a scale or a timestamp:

curl -s https://check.torproject.org/torbulkexitlist | grep -qx 185.220.101.1 && echo "tor exit"
whois -h whois.abuseipdb.example 185.220.101.1 2>/dev/null   # only if you have an abuse-DB account

With Whisper, one verdict and one explanation, on the same fused graph the resolver itself queries:

curl -s https://graph.whisper.security/api/query -H 'X-API-Key: whisper_live_…' \
     --data "CALL whisper.assess(['185.220.101.1'])"        # -> suspicious · MEDIUM · Tor exit
curl -s https://graph.whisper.security/api/query -H 'X-API-Key: whisper_live_…' \
     --data "CALL whisper.explain('185.220.101.1')"         # -> 3 feeds · score 5.3 · seen 3h ago

Latency, and what happens when the graph is slow

Cognition calls target under 300ms end to end, including the graph traversal. That budget matters beyond the API itself: graph-first resolution calls assess on the resolver's hot path before letting a DNS query proceed, under the same strict timeout — and if the graph doesn't answer inside it, the resolver treats that as no opinion and fails open, never a resolution outage. A slow cognition call degrades gracefully everywhere it's used; it never becomes the single point of failure for traffic that has nothing to do with it.

A verdict without evidence is an opinion. Every assess, identify, and explain response here returns the graph rows behind the answer — the same rows you could walk yourself with raw Cypher — so the decision holds up outside the call that made it.

Next