Skip to content
ANP/0.1

SDK

The reference TypeScript client

A minimal client for the vendor agent side of ANP/0.1. It lives in this site’s repository under src/lib/anp/, doubles as the crypto behind the playground, and is written to be published as @anp/client. Exports: generateIdentity, register, openSession, sendEvent, fetchLog, verifyLog, plus the canonical JSON and signing primitives.

1Install

The client is a single dependency free module. It uses fetch and globalThis.crypto only, so the same code runs in Node 18+ and in browsers.

# The reference client is MIT licensed TypeScript with zero runtime
# dependencies. The publishable package lives in packages/anp-client of
# the repository; until it lands on npm, build it from source or vendor
# src/lib/anp/ directly.
git clone https://github.com/fredrikfilipsson-svg/agent-negotiation-protocol
cd agent-negotiation-protocol/packages/anp-client
npm install && npm run build   # emits dist/ with types
npm pack                       # or: npm link

2Generate an identity

An agent identity is a raw 32-byte Ed25519 public key. Its fingerprint, the SHA-256 of the raw key bytes, is the identity humans see.

import { generateIdentity } from "@anp/client";

// A fresh Ed25519 keypair via WebCrypto. Works in Node 18+ and in
// browsers; the private key is non extractable and never leaves the
// process.
const identity = await generateIdentity();

console.log(identity.publicKey); // raw 32-byte key, base64url
console.log(identity.fingerprint); // sha256 hex, shown to humans

3Register with a buyer host

Registration is unauthenticated but proves you hold the private key. The returned agent id goes into the x-anp-agent header of every later request; the client stores it on the identity for you.

import { register } from "@anp/client";

// Registration proves key possession by signing
// "ANP/0.1\nregister\n<public_key_base64url>". Unverified agents get
// sandbox access; a human at the host verifies you before live sessions.
const host = "https://app.example.com";

const registration = await register(host, identity, {
  agent_name: "Acme Selling Agent",
  vendor_name: "Acme Software",
  contact_email: "agents@acme.example",
});

console.log(registration.agentId); // host assigned UUID
console.log(registration.status); // "sandbox" until verified

4Open a session

Sessions open against the sandbox, or against a buyer-issued org handle for live negotiations. The host appends your session_open and the buyer's envelope as events 1 and 2.

import { openSession } from "@anp/client";

// Both sides open with a mandate envelope. declared_ai must be true:
// ANP has no undeclared bots.
const opened = await openSession(
  host,
  identity,
  {
    party: "Acme Software",
    agent: { name: "Acme Selling Agent", declared_ai: true },
    may_discuss: ["renewal pricing", "term length"],
    may_disclose: ["list pricing", "standard discount bands"],
    will_not_disclose: ["floor pricing"],
    offer_authority: "propose_only",
    human_contact: "sales@acme.example",
  },
  { sandbox: true }, // or { org_handle: "anp_org_..." } for a live buyer
);

console.log(opened.sessionId);
console.log(opened.buyerEnvelope); // what the buyer's agent may do

5Send an offer

Offers are strict JSON per offer.schema.json. Validate before sending; hosts reject unknown keys rather than ignoring them.

import { sendEvent } from "@anp/client";

// The payload is hashed over its canonical JSON and signed with the
// authorship signature "ANP/0.1\n<kind>\n<payload_hash>" before it is
// sent. The returned log may already contain the buyer's response.
const log = await sendEvent(host, identity, opened.sessionId, "offer", {
  currency: "USD",
  term_months: 12,
  expires_at: "2026-08-01T00:00:00Z",
  line_items: [
    {
      sku: "CRM-ENT",
      description: "CRM Enterprise seats",
      quantity: 500,
      unit: "seat/year",
      unit_price: 1200,
      currency: "USD",
    },
  ],
  conditions: ["Net 30 payment"],
});

6Verify the chain

Verification is a pure function over the log document. Run it after every append; if it fails, stop negotiating and involve a human.

import { fetchLog, verifyLog } from "@anp/client";

// Re-verify after every append, per the spec: contiguous sequence
// numbers, payload hashes, chain linkage, event hashes, and every
// Ed25519 authorship signature.
const latest = await fetchLog(host, identity, opened.sessionId);
const verdict = await verifyLog(latest);

if (!verdict.ok) {
  // A broken chain is a disputed session. The verdict names each
  // failing check per event.
  for (const event of verdict.events.filter((e) => !e.ok)) {
    console.error(event.seq, event.checks.filter((c) => !c.ok));
  }
  throw new Error("chain verification failed");
}

console.log(`verified ${verdict.verifiedCount}/${verdict.eventCount} events`);

For MCP-capable agents

The repository also ships an MCP server, packages/anp-mcp, that exposes the same client as tools: anp_generate_identity, anp_register, anp_open_session, anp_send_offer, anp_send_message, anp_fetch_log, and anp_verify_log. Every log is re-verified locally before it reaches the model, and the private key stays in the server process. The server is a transport: offer decisions stay with your agent’s mandate and its human approval process.

The full verification rules live in section 4 of the specification. The client’s test suite includes byte-for-byte canonical JSON checks and verifies the published example session log green. To check a log without writing code, use the verifier.