API Reference
The Whisper API in three endpoints: POST /api/query, GET /api/query, and GET /api/query/stats. Start here, then open the page for the endpoint you need.
API Reference Documentation
The Whisper query API is three HTTP endpoints on https://graph.whisper.security. This page covers what they share — authentication, the response envelope, pagination, timeouts — and links to a dedicated page for each endpoint with request and response details and ready-to-run code in five languages.
For the one-screen overview and auth tiers, see Whisper API; for the full status-code table and quota semantics, see Errors & Rate Limits.
The endpoints
| Endpoint | Use it for |
|---|---|
POST /api/query | The main query endpoint. Send Cypher as JSON, with parameter binding and batch statements. |
GET /api/query | The same query from a URL parameter — for quick checks and browser-pasteable links. |
GET /api/query/stats | Graph-wide node and edge counts, precomputed and cached. |
Authentication
Authentication is optional and shared across all three endpoints. A request without a key runs at the anonymous tier, capped at 2 traversal hops. A free key raises the cap to 3 hops, raises the rate limits, and unlocks the full procedure set. Pass it in the X-API-Key header; Authorization: Bearer <key> and Authorization: ApiKey <key> are also accepted. An invalid key does not fail the request — it degrades to the anonymous tier. Get a free key, no card required.
One header to know about: production sits behind a WAF that rejects some default programmatic user agents with HTTP 403. Send an explicit User-Agent (any descriptive string works) and you will not hit it.
Response envelope
Every successful single-statement response has the same shape, whichever endpoint produced it:
| Field | Type | Description |
|---|---|---|
columns | string[] | Column names in RETURN order. |
rows | object[] | One object per row, keyed by column name. |
statistics.rowCount | number | Number of rows returned. |
statistics.executionTimeMs | number | Server-side execution time. Excludes network latency, so your measured round trip will be larger. |
Prefix a query with EXPLAIN and the envelope carries a single plan column holding the query plan instead of results; the query does not execute. A NodeLookup at the leaf of the plan means your anchor is hitting the index; a label scan there is a warning that the query will be slow. See Syntax & Clauses for the clause details.
Pagination
There is no cursor. Page with a stable ORDER BY and walk SKIP forward: SKIP 0 LIMIT 15, then SKIP 15 LIMIT 15, and so on. Use literal numbers in SKIP and LIMIT.
MATCH (sub:HOSTNAME)-[:CHILD_OF]->(:HOSTNAME {name: "google.com"})
RETURN sub.name AS subdomain
ORDER BY sub.name SKIP 0 LIMIT 15
Timeouts
Every query runs under a time cap. The default and maximum are set by your plan; the timeout request field on POST /api/query overrides the default per query, clamped to your plan maximum and a global ceiling. A query that exceeds its cap returns HTTP 408. If you hit it, anchor the query, add a LIMIT, or replace the scan with a procedure.
Read the caps that apply to your request at any time:
CALL whisper.quota()
whisper.quota() returns your plan tier, usage, and per-request limits, and does not count against your quota. Quota semantics and the rate-limit headers are covered in Errors & Rate Limits.
Errors
Errors come back as application/problem+json with a type, title, status, and detail, and often a suggestions array that proposes a rewrite. Depth-exceeded errors include both the actual and allowed depth, so a client can downgrade the query automatically. The full table of status codes, Retry-After behavior on 429, and per-tier quota details is on Errors & Rate Limits.