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.