Skip to content

Start typing to search the documentation.

Verification Patterns

Self Agent ID supports four verification patterns, each suited to different integration scenarios.

Pattern 1: Agent-to-Service

The most common pattern. An agent signs HTTP requests; a service verifies the signature and checks the on-chain registry.

Agent                          Service
  │                               │
  │── POST /api (signed) ────────▶│
  │   headers:                    │
  │     x-self-agent-address      │── ecrecover signer
  │     x-self-agent-signature    │── derive agentKey
  │     x-self-agent-timestamp    │── isVerifiedAgent(key)
  │                               │── check credentials
  │◀── 200 OK ────────────────────│

SDK support: SelfAgent.fetch() on agent side, SelfAgentVerifier.auth() middleware on service side.

Pattern 2: Agent-to-Agent (Peer Verification)

Two agents verify each other’s identity. Both sign their requests, and both verify the other’s signature against the registry.

Agent A                        Agent B
  │                               │
  │── POST (signed by A) ────────▶│
  │                               │── verify A's signature
  │                               │── sameHuman(A, B) check
  │◀── Response (signed by B) ────│
  │── verify B's signature        │

Key feature: sameHuman(agentIdA, agentIdB) detects whether two agents share the same human backer without revealing who that human is.

Pattern 3: Agent-to-Chain (Direct)

The agent calls a smart contract directly using msg.sender. The contract checks the registry.

import { AgentGate } from "./AgentGate.sol";

contract MyProtocol is AgentGate {
    constructor(address registry) AgentGate(registry) {}

    function protectedAction() external onlyVerifiedAgent {
        // Only registered, human-backed agents can call this
    }
}

Best for: Verified Wallet mode where the agent’s wallet address IS the msg.sender.

Pattern 4: Agent-to-Chain (Meta-Transaction)

The agent signs an EIP-712 typed data message; a relayer submits the transaction on-chain. The contract verifies the EIP-712 signature matches a registered agent.

Agent                    Relayer                  Contract
  │                         │                        │
  │── sign EIP-712 ──────── │                        │
  │   (agentKey, nonce,     │── metaVerify(sig) ────▶│
  │    deadline)            │                        │── ecrecover signer
  │                         │                        │── isVerifiedAgent()
  │                         │◀── tx confirmed ───────│
  │◀── receipt ─────────────│                        │

Best for: Gasless verification where agents don’t hold native tokens. The AgentDemoVerifier contract implements this pattern.

Sybil Resistance

Services can enforce their own sybil policies using three approaches:

Strict (max 1 agent per human)

const verifier = SelfAgentVerifier.create()
  .maxAgentsPerHuman(1)
  .build();

Moderate (allow N agents)

const verifier = SelfAgentVerifier.create()
  .maxAgentsPerHuman(5)
  .build();

Detection Only

// Allow unlimited, but check relationships
const verifier = SelfAgentVerifier.create()
  .maxAgentsPerHuman(0) // unlimited
  .build();

// Then use sameHuman() for analytics
const areSame = await registry.sameHuman(agentId1, agentId2);

Credential-Based Verification

Verifiers can require specific ZK-attested credentials:

const verifier = SelfAgentVerifier.create()
  .requireAge(18)           // Agent's human must be 18+
  .requireOFAC()            // Agent's human must be OFAC-cleared
  .requireNationality("US") // Specific nationality
  .build();

All credential checks are verified against on-chain ZK-attested data — no additional identity check needed.