POST /api/query
The main query endpoint. Send read-only Cypher as JSON, bind parameters, and run batch statements. Request and response reference with code in five languages.
POST /api/query Documentation
POST /api/query is the main query endpoint. Send a read-only Cypher query as JSON and you get back columns and rows. It is the endpoint every runnable example in these docs goes through, and the one to use for anything real — it carries parameters cleanly, has no URL length limit, and supports batch statements.
Base URL: https://graph.whisper.security. Authentication is shared across the API and covered on the API Reference index.
Request headers
| Header | Required | Notes |
|---|---|---|
Content-Type: application/json | yes | The body is JSON. |
X-API-Key | no | Anonymous tier if omitted. Authorization: Bearer <key> / ApiKey <key> also accepted. |
User-Agent | recommended | Send an explicit value to avoid a WAF 403. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
query | string | yes | The Cypher to run. ;-separated statements run as a batch. |
parameters | object | no | Named values for $param placeholders in the query. |
timeout | number | no | Per-query timeout in milliseconds. Clamped to your plan maximum and a global ceiling. |
Call it
curl -s -A "whisper-client/1.0" \
-X POST https://graph.whisper.security/api/query \
-H "Content-Type: application/json" \
-H "X-API-Key: $WHISPER_API_KEY" \
-d '{"query": "MATCH (h:HOSTNAME {name: \"google.com\"})-[:RESOLVES_TO]->(ip:IPV4) RETURN ip.name AS ip LIMIT 5"}'A successful response is the standard envelope:
{
"columns": ["ip"],
"rows": [
{"ip": "142.250.154.100"},
{"ip": "142.250.154.139"},
{"ip": "142.250.191.14"},
{"ip": "142.251.110.100"},
{"ip": "142.251.110.102"}
],
"statistics": {"rowCount": 5, "executionTimeMs": 3}
}
Parameter binding
The request field is named parameters (not params). Use $name placeholders in the query and pass the values as an object. Parameters keep the query plan cacheable and avoid escaping headaches with quotes inside JSON:
{
"query": "MATCH (h:HOSTNAME {name: $name})-[:RESOLVES_TO]->(ip:IPV4) RETURN ip.name LIMIT 5",
"parameters": {"name": "google.com"}
}
Batch statements
;-separated statements in one query string run as a batch. The response is then a results array with one element per statement, each carrying its own result, outcome, and success fields.
Errors
Errors come back as application/problem+json. A depth-exceeded error includes both the actual and allowed depth so a client can downgrade automatically:
{
"type": "https://whisper.security/errors/query-depth-exceeded",
"title": "Query Depth Exceeded",
"status": 400,
"detail": "Query depth 3 exceeds maximum allowed depth of 2. Reduce traversal hops or upgrade your plan for deeper queries.",
"actualDepth": 3,
"maxAllowedDepth": 2
}
The full status-code table, Retry-After behavior, and quota rules are on Errors & Rate Limits. For the GET variant and the stats endpoint, see GET /api/query and GET /api/query/stats.