Back to BlogArchitecture

Agent Registries & Kill Switches: Ship Trust in Milliseconds

How to build an agent registry that partners can trust at a glance. Lightweight owner verification, simple permissions/limits, and a /verify endpoint that returns status in <100ms. Plus kill switches that stop harm fast without breaking the experience.

10 min read
by Uchi Uchibeke

TL;DR

  • A registry is a "known-good agents" list that your partners can trust at a glance.
  • Don't let anybody list anything—require lightweight owner verification and simple permissions/limits.
  • Make trust queriable with a tiny /verify endpoint that returns status and core fields in <100ms.
  • Design the kill switch to stop harm fast without breaking the whole experience.
  • This combo is the base layer for an agentic internet that actually works in production.


The moment we stop emailing spreadsheets

In Part 1, I argued that if a bot can act, it needs a passport. A small card that says who it belongs to, what it's allowed to do, where it can operate, and who to call if something goes sideways. This article is about the next step: how others can trust your agent in milliseconds—without a meeting, a spreadsheet, or three weeks of back-and-forth. That's what a registry does.


What is an Agent Registry?

An Agent Registry is a public list of agents you vouch for. It's not fancy. It's just portable truth:

  • Owner and contact: "Acme Support Team" + "security@acme.com"
  • Role: "Tier-2 Support Bot"
  • Permissions and limits: "Refund ≤ $100, Export ≤ 10K rows, No PII"
  • Where it can operate: "US-NY, US-CA, EU-DE"
  • Status: "Active / Suspended / Revoked"
  • Receipts: "Every refund has a signed record."
Partners and platforms check the registry and move on. No guesswork. No cosplay.


"Why a registry? Can't anyone just list agents?"

Short answer: No. Identity without accountability is a costume party. Imagine just accepting an ID card like a Driver's license from anyone and not needing ID to be from trusted issuers like States, Countries, etc. With Agent Registries, keep it simple and borrow what already works in finance:

  • Know Your Bot (KYB): who owns it and why it exists
  • Know Your Creator (KYC): link the agent to a real person or org
  • Permissions & limits: make budgets and data access explicit
  • Signed receipts: log refunds/exports/deletions with proofs
  • Kill switch: suspend in one click—status updates everywhere
This isn't red tape. It's how you pass security reviews and get to "yes" from partners and users.


The Flow: How Agents Get Verified, Added, and Kept Fresh

Here's the smallest useful workflow. Anyone can ship this in weeks, not months or years.

1) Issue the Passport

Create a human-readable card + a machine-checkable record with: owner, role, permissions, limits, regions, contact, and status. Example:

{
  "agent_id": "ap_abc123",
  "name": "Acme Support Bot",
  "owner": {
    "display_name": "Acme Support Team",
    "contact": "security@acme.com"
  },
  "role": "Tier-2 Support",
  "capabilities": [
    {"id": "payments.refund", "params": {"max_amount": 100}},
    {"id": "data.export", "params": {"max_rows": 1000}}
  ],
  "limits": {
    "refund_usd_max_per_tx": 100,
    "refund_usd_daily_cap": 1000,
    "max_export_rows": 1000,
    "allow_pii": false
  },
  "regions": ["US-NY", "US-CA"],
  "assurance_level": "L2",
  "status": "active"
}

2) Submit to the Registry (Owner-Verified)

The owner (or delegated admin) lists the agent. A lightweight owner check happens once (reuse existing vendor records if you have them). The agent gets a registry ID. API:

POST /api/passports/create
Authorization: Bearer <ADMIN_TOKEN>
{
  "name": "Acme Support Bot",
  "owner": {
    "display_name": "Acme Support Team",
    "contact": "security@acme.com"
  },
  "capabilities": [...],
  "limits": {...}
}

Response:

{
  "agent_id": "ap_abc123",
  "status": "active",
  "created_at": "2025-01-16T12:34:56Z"
}

3) Make It Verifiable

Expose a tiny /verify endpoint (or use the shared one) that returns core fields and status in a compact response. API:

GET /api/verify?agent_id=ap_abc123

Response:

{
  "status": "active",
  "owner_display": "Acme Support",
  "role": "Tier-2",
  "capabilities": [
    {"id": "payments.refund"}, 
    {"id": "data.export", "params": {"max_rows": 1000}}
  ],
  "limits": {
    "refund_usd_max_per_tx": 10000,
    "refund_usd_daily_cap": 100000,
    "max_export_rows": 1000,
    "allow_pii": false
  },
  "regions": ["US-NY", "US-CA"],
  "assurance_level": "L2",
  "updated_at": "2025-01-16T12:34:56Z"
}

Agent Verification Endpoint with target latency of <100ms P95 Real numbers from APort:

  • P95 latency: 40-50ms (target: <100ms) ✅
  • Cache hit rate: 87% (87% of requests are <5ms)
  • Throughput: 10,000+ RPS (tested at scale)
  • Global propagation: <15 seconds (US, EU, CA regions)

4) Keep It Fresh

Every change to permissions/limits bumps updated_at and emits a webhook so integrators stay in sync. No surprises. Webhook payload:

{
  "event": "passport.updated",
  "agent_id": "ap_abc123",
  "changes": {
    "limits": {
      "refund_usd_max_per_tx": {"old": 100, "new": 500}
    }
  },
  "timestamp": "2025-01-16T12:34:56Z"
}

5) Rotate or Revoke

Keys rotate without breaking the agent's identity. If something smells off, flip the status to "suspended" and let policy do the rest. API:

PUT /api/passports/ap_abc123/status
Authorization: Bearer <ADMIN_TOKEN>
{
  "agent_id": "ap_abc123",
  "owner_id": "ap_org_456",
  "status": "suspended",
  "reason": "Suspicious refund pattern detected"
}

Response:

{
  "success": true,
  "data": {
    "previous_status": "active",
    "new_status": "suspended",
    "changed_at": "2025-01-16T12:34:56Z"
  }
}

Suspension Without Drama (Designing the Kill Switch)

Suspension should be a soft stop, not a hard crash.

Design Goals

  • Immediate stop to risky actions (refunds/exports/payments)
  • Graceful degrade: read-only or narrowed permissions while you assess
  • Clear messaging: "This agent is suspended. Contact: security@acme.com."
  • Fast rollback when fixed

Playbook

  1. Flip the registry status to suspended via PUT /api/passports/{agent_id}/status
  2. Downgrade scopes automatically (policy engine does this)
  3. Notify owners & integrators (webhook + email/Slack)
  4. Show it wherever the agent appears (About-this-bot page, UI badge)
  5. Audit the reason with a signed event
Real implementation: Ideal switches update status in <10ms and propagate globally within 15 seconds using Cloudflare's edge network. API:

PUT /api/passports/ap_abc123/status
Authorization: Bearer <ADMIN_TOKEN>
{
  "agent_id": "ap_abc123",
  "owner_id": "ap_org_456",
  "status": "suspended",
  "reason": "Emergency kill switch activated"
}

What happens:

  1. Status update: <10ms (KV write)
  2. Region propagation: <15 seconds (Cloudflare edge network)
  3. Webhook delivery: <5 seconds (async, non-blocking)
  4. Cache invalidation: Immediate (ETag change triggers refresh)
Verification response (suspended agent):

{
  "error": "agent_suspended",
  "message": "Agent is suspended and cannot perform operations",
  "status": "suspended",
  "suspended_at": "2025-01-16T12:34:56Z",
  "contact": "security@acme.com"
}

Real numbers from APort:

  • Suspension latency: <10ms (KV write)
  • Global propagation: <15 seconds (tested across US, EU, CA)
  • Webhook delivery: <5 seconds (99% of webhooks)
  • Zero false positives: Status checks are atomic


A Quick Story (What This Prevents)

A retailer's support agent issued three $500 refunds in an hour. Finance couldn't tell which agent did it or who owned it. Nobody knew the limit. Everyone guessed. With a registry and passports in place, the refund limit (≤ $100), owner contact, and signed receipts are obvious, and the team suspends the agent in one click while they investigate. No spreadsheets. No finger-pointing. Just control. Numbers from a prospective implementation:

  • Verification time: P95 < 100ms globally
  • Cache hit rate: 85%+ (L1 edge cache)
  • Suspension propagation: <15 seconds global
  • API availability: 99.99% uptime


Agent Registries as the Base Layer for an Agentic Internet

Protocols will multiply. Frameworks will argue. Some teams will go decentralized; others will stay web2. That's fine. A neutral registry with portable passports and a dead-simple verify path works across all of it:

  • Interoperable: human-readable, machine-checkable
  • Portable: agents move between platforms without redoing trust
  • Composable: agents can call agents after they verify each other
  • Neutral: chain-agnostic today; ready for ZK/FHE integrations tomorrow
You don't need a new religion. You need a fast yes. An Architecture for Agent Registry and Verification

┌─────────────────┐
│   Agent Owner   │
│  (Acme Corp)    │
└────────┬────────┘
         │
         │ 1. Create Passport
         ▼
┌─────────────────┐
│  Agent Registry │
│  (APort)        │
└────────┬────────┘
         │
         │ 2. Verify (GET /verify)
         ▼
┌─────────────────┐
│   Partner API   │
│  (Stripe, etc)  │
└─────────────────┘

Flow:

  1. Owner creates passport → Registry stores it
  2. Partner verifies agent → Registry returns status + limits
  3. Partner enforces limits → Policy engine blocks unauthorized actions
  4. Owner suspends agent → Registry propagates status globally


Implementation: The Smallest Useful Registry

Here's what you need to ship:

1. Passport Schema

interface Passport {
  agent_id: string;
  name: string;
  owner: {
    display_name: string;
    contact: string;
  };
  role: string;
  capabilities: Capability[];
  limits: Limits;
  regions: string[];
  assurance_level: "L0" | "L1" | "L2" | "L3";
  status: "draft" | "active" | "suspended" | "revoked";
  created_at: string;
  updated_at: string;
}

2. Verify Endpoint

// GET /api/verify?agent_id=ap_abc123
export async function verifyAgent(
  agentId: string
): Promise<VerificationResponse> {
  const passport = await getPassport(agentId);
  
  if (!passport) {
    return { error: "agent_not_found" };
  }

  if (passport.status === "suspended" || passport.status === "revoked") {
    return {
      error: "agent_suspended",
      status: passport.status,
      contact: passport.owner.contact,
    };
  }

  return {
    status: "active",
    owner_display: passport.owner.display_name,
    role: passport.role,
    capabilities: passport.capabilities,
    limits: passport.limits,
    regions: passport.regions,
    assurance_level: passport.assurance_level,
    updated_at: passport.updated_at,
  };
}

3. Kill Switch

// PUT /api/passports/{agent_id}/status
export async function suspendAgent(
  agentId: string,
  ownerId: string,
  reason: string
): Promise<StatusUpdateResponse> {
  const passport = await getPassport(agentId);
  
  if (!passport) {
    return { error: "agent_not_found" };
  }

  // Update status
  await updatePassport(agentId, {
    status: "suspended",
    suspended_at: new Date().toISOString(),
    suspension_reason: reason,
  });

  // Invalidate cache
  await invalidateCache(agentId);

  // Emit webhook
  await emitWebhook({
    event: "agent.suspended",
    agent_id: agentId,
    reason,
    timestamp: new Date().toISOString(),
  });

  return {
    success: true,
    data: {
      previous_status: "active",
      new_status: "suspended",
      changed_at: new Date().toISOString(),
    },
  };
}

4. Caching Strategy

// Tiered caching for <100ms P95
async function getPassport(agentId: string): Promise<Passport | null> {
  // L1: In-memory cache (<1ms)
  const cached = memoryCache.get(agentId);
  if (cached) return cached;

  // L2: KV cache (<5ms)
  const kvCached = await kv.get(`passport:${agentId}`);
  if (kvCached) {
    memoryCache.set(agentId, kvCached);
    return kvCached;
  }

  // L3: Database (<50ms)
  const passport = await db.getPassport(agentId);
  if (passport) {
    await kv.put(`passport:${agentId}`, passport, { expirationTtl: 300 });
    memoryCache.set(agentId, passport);
    return passport;
  }

  return null;
}

Real-World Examples

Example 1: E-Commerce Refund Agent

Passport:

{
  "agent_id": "ap_refund_bot_001",
  "name": "Acme Refund Bot",
  "owner": {
    "display_name": "Acme Support Team",
    "contact": "security@acme.com"
  },
  "role": "Tier-2 Support",
  "capabilities": [
    {"id": "payments.refund"}
  ],
  "limits": {
    "refund_usd_max_per_tx": 100,
    "refund_usd_daily_cap": 1000
  },
  "regions": ["US-NY", "US-CA"],
  "assurance_level": "L2",
  "status": "active"
}

Verification:

GET /api/verify?agent_id=ap_refund_bot_001
→ 200 OK, <50ms
{
  "status": "active",
  "limits": {
    "refund_usd_max_per_tx": 100,
    "refund_usd_daily_cap": 1000
  }
}

Kill switch:

PUT /api/passports/{agent_id}/status
{
  "agent_id": "ap_refund_bot_001",
  "status": "suspended",
  "reason": "Suspicious refund pattern detected"
}
→ 200 OK, <10ms
{
  "ok": true,
  "status": "suspended",
  "propagated_at": "2025-01-16T12:34:56Z"
}

Result: Agent suspended globally in <15 seconds. All refund attempts blocked.

Example 2: Data Export Agent

Passport:

{
  "agent_id": "ap_export_bot_001",
  "name": "Acme Data Export Bot",
  "owner": {
    "display_name": "Acme Data Team",
    "contact": "data@acme.com"
  },
  "role": "Data Export",
  "capabilities": [
    {"id": "data.export", "params": {"max_rows": 1000, "allow_pii": false}}
  ],
  "limits": {
    "max_export_rows": 1000,
    "allow_pii": false
  },
  "regions": ["US-NY"],
  "assurance_level": "L1",
  "status": "active"
}

Verification:

GET /api/verify?agent_id=ap_export_bot_001
→ 200 OK, <50ms
{
  "status": "active",
  "limits": {
    "max_export_rows": 1000,
    "allow_pii": false
  }
}

Kill switch:

PUT /api/passports/{agent_id}/status
{
  "agent_id": "ap_export_bot_001",
  "status": "suspended",
  "reason": "GDPR compliance review"
}
→ 200 OK, <10ms

Result: Agent suspended globally in <15 seconds. All export attempts blocked.


What's Next

  • Part 3: Signed Receipts - how to sign refunds & data-export actions, how long to keep them, and how to stream them into your finance/security tools
  • Part 4: The Verify API - one page, TS/Python snippets, and an edge-friendly reference
  • Part 5: Policy Packs - copy-paste limits for Support Tier-2 and Billing Assistants
If you've not already done so, read the first article in the Series: AI Passports: A Foundational Framework for AI Accountability and Governance. See you in the next one!


Last updated: September 2025 | Version: OAP v1.0