Whisper · Docs
SDKs & CLI

Node SDK

whisper-id on npm gives a Node agent a real, routable IPv6 identity and a one-line proof of who it is — the keyless half in pure fetch, zero dependencies.

A shared NAT or cloud IP has no identity to give: every request looks like it came from your laptop, or your whole fleet from one exit. A Whisper agent gets its own /128 out of 2a04:2a01::/32 (announced by AS219419) — DNSSEC-signed, DANE-anchored, RDAP-registered — and whisper-id is the Node-runtime SDK that gets you there in one npm i.

Two tiers, one package

whisper-id follows Postel's Law end to end: liberal about who can use it (no key needed for the checks anyone should be able to run), conservative about what it exposes (the control plane only unlocks with your key, and the key never touches argv or logs).

Tier Needs What you get
Keyless Nothing — pure fetch verify, verifyDetails, rdap, egressIp
Control plane WHISPER_API_KEY (pure HTTP, still no CLI) list, identity, agent, policy, logs, revoke
Egress + CLI-backed the whisper binary on PATH register, egress, withEgress, ip
npm i whisper-id
import { verify } from "whisper-id";
await verify("2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4");   // → true, no key, no CLI
import { identity, withEgress } from "whisper-id";        // WHISPER_API_KEY in env
const me = await identity({ label: "my-bot" });            // allocate a routable /128
await withEgress(async (e) => {
  console.log("egress on", e.proxyUrl);                    // curl/axios/got now leave from me.address
});

whisper-id vs whisper-edge — pick by runtime, not by preference

This is the one distinction people get wrong, so get it right up front:

If your agent runs as a plain Node/Bun process (PM2, systemd, Docker, a Kubernetes pod, a LangGraph/LangChain agent loop, an MCP server), use whisper-id. If it runs on someone else's edge runtime, use whisper-edge. Both share the same verify/verifyDetails/rdap keyless surface and the same control-plane shape — the only difference is how (or whether) egress gets wired up under the hood.

The API, in full

Keyless — no key, no CLI

import { verify, verifyDetails, rdap, egressIp } from "whisper-id";

await verify(addr);          // boolean — server-side DANE + DNSSEC + reverse-DNS + JWS
await verifyDetails(addr);   // { is_whisper_agent, fqdn, operator, dane_ok, jws_ok, ... } | null
await rdap(addr);            // the public RDAP object for the /128, or null
await egressIp();            // the IP this process currently leaves from

Under the hood verify/verifyDetails hit the same keyless gateway you can curl directly (see below) — verify-identity/<addr> on rdap.whisper.online. rdap(addr) fetches the RDAP document for the /128, an RFC 9082/9083-shaped JSON ip network object, the same one whois-style tooling resolves via RFC 7484 bootstrap.

Control plane — with a key, still no CLI

Every call here sends your key only in the X-API-Key request header (never argv, never a log line) to graph.whisper.security, and throws a WhisperError (with .status/.retryAfter) on failure instead of returning undefined:

import { list, identity, agent, policy, logs, revoke } from "whisper-id";
// WHISPER_API_KEY=whisper_live_... in the environment

await policy({ default: "deny", allow: ["api.openai.com", "*.githubusercontent.com"] });
for (const a of await list()) console.log(a.address, a.label);
const recent = await logs({ kind: "dns", limit: 100 });
await revoke(me.agent);   // irreversible — needs the admin:dns scope

identity({ label, contact_email }) is the one-call path to a routable /128: it returns { agent, address, fqdn, ptr, state } where fqdn looks like acef2002a323d40d4.<tenant>.agents.whisper.online and ptr is the matching ip6.arpa delegation — both live in authoritative DNS the moment the call returns.

Egress + CLI-backed

import { register, egress, withEgress, ip } from "whisper-id";

const a = await register("checkout-bot", { newKey: true });  // mints agent + its own API key
const e = await egress({ agent: a, tier: "wireguard" });       // routed /128, sets proxy env
console.log(await ip());                                       // → a.address
e.close();                                                      // restores the environment

egress() sets HTTP_PROXY/HTTPS_PROXY/ALL_PROXY for you, so any proxy-env-aware client — curl, axios, got, most CLI tools spawned from your process — leaves from the /128 with zero further code. Node's own global fetch (undici) does not read those env vars, so pass a dispatcher explicitly:

import { egress } from "whisper-id";
import { ProxyAgent } from "undici";

const e = await egress();
const res = await fetch("https://api64.ipify.org", { dispatcher: new ProxyAgent(e.proxyUrl) });
console.log(await res.text());   // ← your /128, not your host's

Verifying an agent — raw fetch vs the typed SDK

Verification is keyless. In Node the "raw" way is a single fetch; the SDK is the same call, typed and null-safe:

// raw — one fetch, no package
const r = await fetch("https://rdap.whisper.online/verify-identity/2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4");
const { is_whisper_agent, dane_ok, jws_ok } = await r.json();

// with whisper-id — typed, and returns null (not a throw) for a non-agent
import { verifyDetails } from "whisper-id";
const v = await verifyDetails("2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4");
console.log(v?.is_whisper_agent, v?.dane_ok, v?.jws_ok);   // true true true

Both ask Whisper's server to run the chain. To re-derive it yourself from the DNSSEC root, trusting no server, that's a terminal job (dig, openssl) or whisper verify --trustless — see Verify an agent and DNSSEC.

Requirements

Zero runtime dependencies. Keyless checks and the control plane need only Node ≥18 (global fetch) and, for the control plane, WHISPER_API_KEY in the environment or { apiKey } on each call. Only register, egress, withEgress, and ip need the whisper binary on PATH:

curl -fsSL https://get.whisper.online | sh

$WHISPER_BIN overrides the CLI path; $WHISPER_CONTROL_URL / $WHISPER_RDAP_URL override the endpoints for self-hosted or staging setups. Source: github.com/whisper-sec/whisper-node, MIT licensed. Every other language and runtime combination — Python (pip install whisper-id), edge/serverless, n8n, MCP — is catalogued on /docs/integrations.


Next: whisper-edge for fetch-only edge runtimes · whisper CLI for the trustless verification chain and local egress daemon.