The Request Envelope
How to build the Cypher map literal by hand, and the columns every answer comes back in.
On this page (5)
The Request Envelope Documentation
Every control call is one HTTP request carrying one Cypher statement, and every answer arrives in the same envelope.
The endpoint
POST https://graph.whisper.online/api/query, with the statement in a JSON field named query. GET and HEAD answer a read the same way.
| Header | Value |
|---|---|
X-API-Key | <your key>, of the form whisper_live_... |
content-type | application/json |
curl -s https://graph.whisper.online/api/query \
-H 'X-API-Key: whisper_live_...' \
-H 'content-type: application/json' \
--data-binary @- <<'JSON'
{"query": "CALL whisper.agents({op: 'agent', args: {agent: 'checkout-bot'}})"}
JSON
A form-encoded body works as well. Send the same statement as a field named q.
curl -s https://graph.whisper.online/api/query \
-H 'X-API-Key: whisper_live_...' \
--data-urlencode "q=CALL whisper.agents({op: 'list', args: {kind: 'agents'}})"
Writing the map literal
whisper.agents takes a single map. op names the operation and args carries that operation's arguments.
- Keys are bare. A quoted key is rejected.
- String values are single-quoted. To put a
'inside a string, double it. - Numbers and booleans are written bare, and arrays in square brackets.
- If you generate the call rather than type it, sort the keys, so the same arguments always produce the same statement.
CALL whisper.agents({op: 'policy', args: {allow: ['api.example.com'], default: 'deny'}})
What comes back
One row, with these columns.
| Column | Holds |
|---|---|
op | The operation you named. |
ok | true when the operation ran. |
status | The status of the operation itself. |
result | The operation's own payload, as {columns, rows}. |
error | Absent on success. On failure a string, or an object with code, message and retryable. |
retry_after | Seconds to wait, on the statuses that carry it. |
elapsed_ms | How long the operation took. |
The outer object has the same {columns, rows} shape as any Cypher answer, and its rows are objects keyed by column name. Inside result, rows are positional arrays that line up with result.columns.
{
"columns": ["op", "ok", "status", "result", "error", "retry_after", "elapsed_ms"],
"rows": [
{
"op": "list",
"ok": true,
"status": 200,
"result": {
"columns": ["kind", "item"],
"rows": [
["agents", {"label": "checkout-bot", "address": "<the agent's /128>", "state": "<state>"}]
]
},
"error": null,
"retry_after": null,
"elapsed_ms": <ms>
}
]
}
Read result.columns for the field order, then walk result.rows positionally. Treat ok: false as a failed operation rather than a failed request, and read error for the reason.
Raw Cypher on the same endpoint
The endpoint serves whisper.agents itself and forwards any other read to the graph with your key. Graph statements are read-only here: a write clause comes back 400 read_only. Query syntax and the graph's own error format are in the HTTP API chapter.
When a call fails
A failed operation keeps the envelope and fills error; Error codes lists each code with its status. A statement the parser cannot read is a different thing, and comes back as a problem document instead, described in Errors.