Zapier
Verify, provision, and govern Whisper agent identities from a Zap - no server, no SDK, two tiers.
The pain
Your ops team lives in Zapier. A support ticket lands, a Stripe payment clears, a row appears in a sheet - and somewhere downstream you need to know "is the bot that just called our webhook actually one of ours?", or mint a fresh agent identity the moment a new customer signs up, without anyone touching a terminal.
Rolling that yourself means a webhook step that shells out to curl, hand-rolled JSON for a Cypher-shaped control API, and an API key pasted in plaintext into a "Webhooks by Zapier" action where every collaborator on the Zap can see it. That's the wrong shape for both halves: verification shouldn't need a credential at all, and provisioning shouldn't need you to hand-write a POST body.
The Zapier app collapses both into typed fields - a Search step for "look this address up," a Create step for "make this happen" - and keeps your key where Zapier keeps secrets: in the connection, never in a Zap's visible steps.
Two tiers, one connection
The app follows the same Robustness Principle as every other Whisper surface: liberal in what it accepts. The connection's API-key field is optional.
- No key - the four Searches work immediately: verify an IPv6 address is a genuine Whisper agent, pull its RDAP record, walk its certificate-transparency history, see who's been looking it up. Read-only, anonymous, zero setup.
- With your
whisper_live_...key - the same connection also unlocks three Creates: register a new agent (mints a/128, hostname, RDAP record, and its own key), set your tenant's DNS policy, and revoke an agent. Irreversible actions stay gated behind the key; nothing mutates without one.
A blank connection is a valid connection - the test step succeeds either way, so a teammate can wire up verification Zaps today and an admin can drop in a key later to unlock provisioning, with no re-plumbing. This is exactly the two-tier design also used by the n8n and Make integrations - pick whichever automation tool your team already runs.
The Searches (keyless)
Every Search takes one IPv6 address and hits the public identity API at rdap.whisper.online - no key, ever:
| Search | Endpoint | Returns |
|---|---|---|
| Verify Agent Identity | GET /verify-identity?ip={addr} |
is_whisper_agent, DANE/JWS verdicts, evidence bundle |
| Lookup RDAP Record | GET /ip/{addr} |
the RFC 9083 registry object |
| Get Transparency Log | GET /ip/{addr}/transparency |
certificate-issuance history |
| Get Inbound Lookups | GET /ip/{addr}/lookups |
who has been resolving this agent |
Two design details matter more than they look:
- "Not a Whisper agent" is data, not an error.
verify-identityanswers a negative the same way it answers a positive - HTTP 200, withis_whisper_agent: falseand adetailstring instead of a thrown fault - so the Zapier app always gets one successful Search record and you branch onis_whisper_agentin the Zap editor instead of catching an exception. A malformed address (HTTP 400) or an upstream failure (5xx) does throw, with the API's own message surfaced verbatim - never a bare "unexpected error." - RDAP is a registry lookup, not an identity test, and the difference matters for filters. An address outside Whisper's allocations 404s and becomes an empty Search result, which is what Zapier's "only continue if found" and "find or create" patterns expect. An address inside
2a04:2a01::/32or2a04:2a00::/32that has no assignment returns a record for the covering allocation instead, so the Search is not empty. That is correct RDAP, and it is the wrong thing to gate identity on: use theverify-identitySearch and branch onis_whisper_agent, which answers the question you actually mean and answers it from the DNSSEC chain rather than from a status code.
Input is normalized before it ever leaves the Zap: compressed or expanded IPv6, a stray /128 suffix, surrounding whitespace, an IPv6 zone id - all accepted. Every value that reaches the control plane is escaped through a Cypher-literal escaper (quotes and backslashes doubled), so nothing you paste from a webhook payload can break out of the query.
The Creates (need your key)
Each Create runs the one control verb, CALL whisper.agents({op:'…', args:{…}}), over POST https://graph.whisper.online/api/query - the same call the whisper CLI and every SDK make, just wrapped in typed Zap fields:
| Create | Op | Fields | What it does |
|---|---|---|---|
| Register Agent | register |
Name, Contact Email (optional) | Mints a /128, agents.whisper.online hostname, PTR, RDAP record, and the agent's own API key - returned once |
| Set Policy | policy |
Default Action, Block[], Allow[] | Sets your per-tenant resolver policy: block-list or allow-list mode |
| Revoke Agent | revoke |
Agent (handle or /128) |
Fully withdraws the address, PTR, tokens, and key - irreversible |
Attempt a Create on a keyless connection and you get a clear, actionable error - "add your Whisper API key to unlock the control plane" - never a silent no-op. Set Policy also refuses to run with nothing set, since a Zapier Create must change something rather than merely read; leaving Default, Block, and Allow all empty raises the same kind of explicit error.
A concrete Zap: provision on signup, verify on webhook
Zap 1 - "New Stripe customer → register a Whisper agent."
Trigger: Stripe - New Customer. Action: Whisper - Register Agent, Name = {{customer.name}}-bot, Contact Email = {{customer.email}}. Follow with Google Sheets - Create Row to log the returned address, fqdn, and api_key (shown once - this is the only place it will ever appear again).
Zap 2 - "Inbound webhook → verify the caller, branch."
Trigger: Webhooks by Zapier - Catch Hook (your reverse proxy forwards the caller's source /128). Action: Whisper - Verify Agent Identity, Address = {{ip}}. Filter: continue only if is_whisper_agent is true and dane_ok is true. This half needs no key at all - safe to hand to any teammate who only needs the read side.
Try it - with stock tools, and with Whisper
With stock tools (no Zapier, no Whisper software):
# same keyless verdict a Zapier Search step returns
curl -s "https://rdap.whisper.online/verify-identity?ip=2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4" \
| jq '{is_whisper_agent, dane_ok, jws_ok}'
# the RDAP object a Lookup RDAP Record step returns
curl -s https://rdap.whisper.online/ip/2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4 | jq '.status, .events'
# the exact control call a Register Agent Create makes, by hand
curl -sS https://graph.whisper.online/api/query \
-H 'content-type: application/json' \
-H 'X-API-Key: whisper_live_...' \
--data '{"query":"CALL whisper.agents({op:'"'"'register'"'"', args:{label:'"'"'checkout-bot'"'"'}})"}'
With Whisper (the CLI, for comparison - the Zapier app makes the same calls behind typed fields):
whisper verify 2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4 # same keyless verdict
whisper create --register --name checkout-bot # same register call
whisper kill --revoke checkout-bot # same revoke call
Both paths land on the identical public endpoints and the identical control verb; Zapier just gives each one a typed step and a Zap history instead of a terminal.
Install it
The app - four searches, three creates, a lib/ Cypher-literal builder, and a full zapier validate test suite - is built entirely on Whisper's public control API, so every step's request and response is a contract you can read before you trust it. The source is public at whisper-examples/zapier, down to the authentication module and the test suite. It's currently in Zapier's App Directory review; until it clears, you can drive the same control-plane calls directly against the API - see the control plane reference.
Get a key for the control-plane half at whisper.online/platform; the keyless Searches need nothing beyond a running Zap.
Next
- n8n - the same two-tier design as a self-hostable workflow node
- Verify an agent - the full seven-proof keyless verification model behind every Search