Pipedream
Wiring agent identity into a no-code workflow usually means a generic HTTP node, a hand-built JSON body, and a prayer that you got the escaping right.
One unescaped quote in an agent label and your Cypher call breaks; one leaked bearer in a step export and it's in your run history forever. Whisper's Pipedream app removes all of that: a real registered app with typed props, a Cypher-literal builder that can't be broken by user input, and a response decoder that turns the control-plane envelope into a plain array of records — 12 actions, split into a keyless tier anyone can drag onto a canvas and a keyed control tier that provisions and governs your fleet.
Two tiers, one app
The whisper app follows the same Postel's-Law shape as every Whisper integration (see the integration standard): the credential is what unlocks the second tier, not a separate product.
- Tier 1 — keyless. Reads Whisper's public, anonymous identity API at
rdap.whisper.online. No connected account. Same data anyone on the internet can query. - Tier 2 — control plane. Connect a Whisper account (one
whisper_live_…key) and the fleet-management actions unlock: register agents, allocate identities, read logs, set policy, wire up egress, revoke.
The app registers one optional auth field, api_key. Leave it blank and the four keyless actions still work; every keyed action checks for it up front and throws a ConfigurationError — a clear message, not a bare 401 three steps into a workflow — if it's missing.
The 12 actions
| # | Action | Tier | Op / endpoint |
|---|---|---|---|
| 1 | Verify Agent Identity | keyless | GET /verify-identity?ip= |
| 2 | Lookup RDAP Record | keyless | GET /ip/<addr> |
| 3 | Get Transparency Log | keyless | GET /ip/<addr>/transparency |
| 4 | Get Inbound Lookups | keyless | GET /ip/<addr>/lookups |
| 5 | Register Agent | control | op:register |
| 6 | Allocate Identity | control | op:identity |
| 7 | List Agents | control | op:list |
| 8 | Get Agent | control | op:agent |
| 9 | Set Policy | control | op:policy |
| 10 | Get Logs | control | op:logs |
| 11 | Connect Egress | control | op:connect |
| 12 | Revoke Agent | control | op:revoke |
All eight keyed actions carry the same admin:dns (write) or read scope that a matching whisper CLI subcommand carries, and every one is confined to the caller's own tenant — there is no cross-tenant argument to smuggle through args.
Under the hood: one Cypher verb
Every control action is a thin wrapper over a single call: CALL whisper.agents({op:'<op>', args:{…}}), POSTed as {"query": "..."} to https://graph.whisper.security/api/query with the caller's key in X-API-Key — never in the body. This is the exact contract documented in the Graph API reference and implemented once, correctly, in the whisper CLI's reference client.
With stock tools — build and send the same call by hand with curl and jq:
curl -s https://graph.whisper.security/api/query \
-H "X-API-Key: whisper_live_…" \
-H 'content-type: application/json' \
-d '{"query":"CALL whisper.agents({op:'"'"'register'"'"', args:{label:'"'"'scout'"'"'}})"}' \
| jq '.rows[0].result'
Get the string-escaping wrong — an unescaped ' in a label like O'Brien's bot — and that quote closes the Cypher literal early and the query fails, or worse, is misparsed. Doing this safely by hand means writing your own doubled-quote escaper and a two-shape response decoder (the control endpoint can return either a procedure-row table or a flat {ok,status,result,error} envelope — see the reference for both shapes).
With Whisper — the app does the escaping and decoding for you; the action just takes typed props:
Register Agent
Name: scout
Contact Email: (optional)
→ $summary: "Registered agent scout at 2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4"
→ returns: { agent, address, fqdn, ptr, state, api_key }
That api_key field is the new agent's own credential and is returned once — capture it in the same run (write it to a connected secrets step, not to a public output).
The app's Cypher builder mirrors the CLI's exactly: a string value is single-quoted with ' and \ each doubled (Tim O'Reilly → 'Tim O''Reilly'), map keys are emitted in sorted order so the wire query is byte-stable, and the response decoder accepts both envelope shapes plus a bare problem object — surfacing detail (or title, or type) verbatim on failure rather than an opaque 500. That's the Robustness Principle (RFC 761) applied to a no-code canvas: conservative in what the action emits on the wire, liberal in what it accepts back.
A worked example: gate a Slack alert on agent identity
Say a workflow ingests inbound webhook traffic and you want to flag anything not coming from a genuine Whisper agent before it reaches a downstream step.
With stock tools (a Pipedream Node code step, no Whisper software):
import { axios } from "@pipedream/platform";
export default defineComponent({
async run({ steps, $ }) {
const ip = steps.trigger.event.headers["x-forwarded-for"];
const r = await axios($, {
url: "https://rdap.whisper.online/verify-identity",
params: { ip },
headers: { Accept: "application/json" },
validateStatus: () => true,
});
if (!r.is_whisper_agent) throw new Error(`${ip} is not a verified Whisper agent`);
return r;
},
});
With Whisper — drop in the Verify Agent Identity action (no code, no auth needed), then branch on its is_whisper_agent export directly in the workflow's conditional path — one action, typed output, no hand-rolled HTTP client.
Connect Egress — the one action with secrets in it
op:connect is the odd one out: its result carries live transport secrets (an et_… bearer embedded in http_proxy/connection_string for the socks5/anyip tiers, or a client_private_key for a zero-key WireGuard setup). Because a hosted Pipedream step's output can end up in run history and downstream step data, the action follows the same bearer-hygiene rule as every other Whisper integration: don't wire the raw secret fields into a Slack message, a database row, or anything outside the same run's next HTTP step. If your workflow just needs a routed egress endpoint to hand to an HTTP-request node's proxy setting, that's exactly what this action is for — use it as a proxy config, not a value to persist.
Installing it
The app is contributed as source in PipedreamHQ/pipedream under components/whisper/, the same self-serve model as the Whisper n8n, Make, and Power Platform connectors — no vendor account required to review the code, just Pipedream's own app-integration step before a submitted app goes live in the workspace picker. Once live, search "Whisper" when adding an app to a workflow; the keyless actions need nothing further, and the control actions prompt you to connect an account with your whisper_live_… key.
The key-gated DNS resolver (/dns-query) is intentionally not wrapped here — it's a stateful per-tenant :53/DoH endpoint, not a request/response action. Point your own resolver config at it directly; see DoH.
Next
Graph API — the whisper.agents control verb · Integrations catalog