KYA · Know Your Agent

Let verified agents transact.

KYC verifies a person at one point in time. Agent Passport verifies the whole chain of agency behind an action — which agent, under whose mandate, backed by which KYC'd principal, carrying whose liability — so platforms can accept agent traffic instead of blocking it as fraud.

Run the demo Read the spec records, not rails — no custody, no money transmission
  Chain of agency resolve any action → the accountable human
ACTION LIABILITY signs authorizes issued by bears event Action account.refill $500.00 agt_ Agent treasury-bot Ed25519 · claude-code mnd_ Mandate scoped · signed revocable prn_ Principal KYC verified US · accredited bearer Liability accountable party disputes · recourse One signed assertion. One round trip. A resolvable, co-signed record of who is accountable.
The gap

Platforms block agent traffic because they can't answer one question.

An API request arrives that wants to move real value — refill an account, place an order, subscribe to a fund. No compliance regime today can resolve who committed this action, so the safe default is to reject it as fraud. Legitimate, well-funded agent volume gets thrown away at the door.

?

Human or agent?

The request looks like traffic from a person, but it isn't. Nothing on the wire distinguishes the two.

?

Whose agent?

If it's an agent, who runs it? An anonymous key is not a counterparty you can transact with.

?

What authority?

Was it actually allowed to do this — this action, this amount, on this platform, right now?

?

Whose liability?

If it goes wrong, who bears it? Who do you dispute with, screen for sanctions, and hold accountable?

The shift

KYC verified a point — one identity, once. The passport verifies the chain — every action resolved to a scoped mandate and a KYC'd principal who carries the liability. That's the difference between blocking agents and banking them.

How it works

Three moves. One round trip at the edge.

Principals onboard once and hand out narrow, revocable authority. Agents sign every request. Platforms verify the chain with a single call that fails closed.

STEP 01

Principal onboards, issues a scoped mandate

A human or entity passes KYC once, registers an agent's public key, and grants a narrow mandate: this action, these caps, this platform, expiring — and revocable in seconds.

prn_ → mnd_ · signed grant
STEP 02

Agent signs each request

The agent SDK (or MCP server in Claude Code) holds the keypair and signs a per-request assertion — action, amount, platform, nonce, timestamp — attaching it as an X-Passport header.

agt_ key · JWS · nonce + ts
STEP 03

Platform verifies in one call

One middleware line calls /v1/verify. The passport checks signature, mandate, scope, live revocation, period counters, KYC and sanctions — then returns allow/deny with the resolved chain and a signed receipt.

plt_ → vrf_ · allow / deny · co-signable
Integrate

Accept agents safely in about ten lines.

Drop one middleware in front of the routes agents call. It fails closed. Anonymous traffic gets a 403 KYA required with an onboarding link — so the requests you used to reject become qualified leads.

server.tsplatform · @passport/verify
import { requireKYA } from "@passport/verify";

// Accept agent traffic — one round trip, fails closed.
app.post(
  "/v1/account/refill",
  requireKYA({ action: "account.refill" }), // ← the integration
  async (c) => {
    const { chain } = c.get("kya");   // resolved chain
    await accounts.refill(c.req.valid("json"));
    return c.json({ ok: true, principal: chain.principal });
  }
);
requestagent · X-Passport
POST /v1/account/refill HTTP/1.1
Host: northbank.sandbox
Content-Type: application/json
X-Passport: eyJhbGciOiJFZERTQSJ9.eyJtYW5kYXRl
            X2lkIjoibW5kX3RyIiwiYWN0aW9uIjoi…

// agent key signs this assertion, per request
{ "mandate_id": "mnd_tr…", "action": "account.refill",
  "amount": 50000, "currency": "USD",
  "platform_id": "plt_northbank",
  "nonce": "3f9a…", "ts": "2026-07-22T18:04:11Z" }
HTTP 403 · KYA required

No passport on this request.

The middleware never executes the action for anonymous agents. Instead it returns a structured block with a link to onboard — the block-page that turns rejected traffic into a lead.

anonymous agent → 403 → onboard → mandate → verified buyer
The demo · this is the pitch

Northbank Sandbox — a fake brokerage with a real API.

treasury-bot holds a mandate: account.refill ≤ $1,000/tx, ≤ $2,500/week at Northbank. Watch the passport allow what's in scope, deny what isn't, react to a live revocation, and turn away an anonymous caller.

treasury-bot @ claude-code  ·  northbank.sandbox
$ passport present --action account.refill --amount 500
ALLOW$500.00 reason ok · receipt vrf_9c1… signed remaining this week $2,000.00
$ passport present --action account.refill --amount 2000
DENY$2,000.00 reason per_tx_cap · mandate cap $1,000 / tx
$ passport present --action account.refill --amount 900
ALLOW$900.00 reason ok remaining this week $1,100.00
$ passport present --action account.refill --amount 900
ALLOW$900.00 reason ok remaining this week $200.00
$ passport present --action account.refill --amount 900
DENY$900.00 reason period_cap · only $200.00 left this week
⟳ principal revokes mnd_tr7… in the dashboard — one click, propagates in < 2s
$ passport present --action account.refill --amount 500
DENY$500.00 reason mandate_revoked · live revocation check
$ curl -s -X POST northbank.sandbox/v1/account/refill -d amount=250 # no X-Passport header
403KYA required onboard → northbank.sandbox/kya/start
 

Every ALLOW returns the full resolved chain and a JWS receipt. After executing, the platform can countersign the verification — a record signed by both sides is nearly incontestable.

Mandates

A scoped, signed, revocable grant — the heart of the system.

A mandate is the narrowest possible authority: one principal, one agent, specific actions with hard caps, an expiry, and a live status. Platforms read the attributes they need — never the identity documents behind them.

mandate.jsonsigned grant
{
  "id": "mnd_tr7…",
  "principal": "prn_a1…",
  "agent": "agt_9f…",
  "scopes": [{
    "action": "account.refill",
    "max_amount_per_tx": 100000,
    "max_amount_per_period": 250000,
    "period": "week",
    "currency": "USD",
    "platforms": ["plt_northbank"],
    "purpose": "trading-capital"
  }],
  "not_before": "2026-07-22T00:00:00Z",
  "expires_at": "2026-08-22T00:00:00Z",
  "status": "active",
  "issuer_sig": "<JWS by passport issuance key>"
}
max_amount_per_tx · per_period

Hard caps

Per-transaction and cumulative-per-period ceilings in minor units. The passport maintains the counters and enforces them server-side.

not_before · expires_at

Time-boxed

Authority is valid only inside a window. Outside it, the passport denies before any other check runs.

status: active → revoked

Instant revocation

One click in the principal dashboard. Verification is a live check, so the next request denies within seconds — no waiting on token expiry.

selective disclosure

Attributes, not documents

Platforms see KYC level, country, and an accreditation flag — never the underlying identity documents, unless the mandate grants it or a lawful request compels it.

Where we sit
Category law

Records, not rails. We attest decisions; we never custody or move value.

Rails-neutral

x402 · AP2 · ACP interop. AP2 mandates map to ours 1:1 — the KYA layer any rail can call.

Regulatory posture

No custody, no money transmission. KYC through licensed vendors; attestation only.

Subject rights

FCRA-shaped by design. Access, correction, and dispute flows are first-class — regulation as moat.

Standards path

W3C VC / JWS migration. Token format tracks the standard; a migration is a serializer change.

FAQ

Regulatory posture, privacy, and who goes first.

01 Are you a money transmitter or custodian?
No. Agent Passport is an attestation layer. We sell decisions and records, never movement of value — we never touch, hold, or route funds. KYC runs through licensed vendors behind a pluggable interface. That keeps us out of custody and money-transmission regimes by design.
02 What does a platform actually see about the principal?
Attributes, not identity documents. A verify response exposes KYC level, country, and an accreditation flag — enough to make a decision, nothing more. Full identity is disclosed only when the mandate explicitly grants it, or a lawful request compels it. Subject access, correction, and dispute flows are built in from day one (FCRA-shaped).
03 Who integrates first?
Platforms losing agent-originated volume they'd love to accept: trading and prop platforms, exchanges and on-ramps, ad-budget top-ups, API-credit refills, and marketplaces. The refill/deposit primitive generalizes everywhere agents want to move value into a platform.
04 Do you compete with x402 / AP2 / ACP payment rails?
No — we're the identity layer any of them can call. Rails-neutral by the law of the category: AP2's mandates and ours are meant to map 1:1. A payment rail moves the value; the passport answers whether the agent moving it is authorized and who's accountable.
05 How do agents hold keys today, and where's this going?
The agent runtime holds an Ed25519 keypair and registers the public key with us. MVP mandate issuance is custodial — we sign mandates after the principal authorizes in the dashboard (the CA model). The documented upgrade path is principal-held keys and W3C Verifiable Credentials with identical semantics, so the migration is a serializer change rather than a rewrite.
06 What's in the alpha, and what's deliberately out?
In: the full chain model, sandbox KYC + stub sanctions, mandates with caps and revocation, the verify + countersign API, the Northbank demo, the MCP server, a CLI, and audit export. Documented but not built yet: real KYC vendors, principal-held keys/VCs, webhooks, multi-sig mandates, per-jurisdiction rulepacks, and agent reputation scores.
Alpha · live sandbox

Give your agents a passport they can prove.

The sandbox is live right now: the passport service runs at passport‑production‑f136.up.railway.app and the KYA‑gated Northbank brokerage at northbank‑production.up.railway.app — try an anonymous POST /api/refill and get the 403. Or spin it all up locally, issue a mandate, and watch the chain of agency resolve — allow, deny, revoke, block — in one command.

$ npx @passport/demo up