PageSourceSearch

https://siwa.id/docs

html siwa.id collected 2026-10-04 14:47:20 UTC 504,076 bytes, 120 lines download raw bytes

1<!DOCTYPE html><!--J85DJ4d2_pu0tm2EaWtIp--><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/_next/static/media/797e433ab948586e-s.p.dbea232f.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="preload" href="/_next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="preload" as="image" href="/siwa-flow.png"/><link rel="stylesheet" href="/_next/static/chunks/43ec3b8db83f7d7e.css?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/7f7d21b762b07143.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7"/>
1<script src="/_next/static/chunks/f880dec594879f64.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7" async=""></script>
1<script src="/_next/static/chunks/ae750b60a60fe50a.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7" async=""></script>
1<script src="/_next/static/chunks/8b72cfc40036c827.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7" async=""></script>
1<script src="/_next/static/chunks/turbopack-9e29effca3a14174.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7" async=""></script>
1<script src="/_next/static/chunks/da6c1156e80d635a.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7" async=""></script>
1<script src="/_next/static/chunks/33074d3ff5d0cd2d.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7" async=""></script>
1<script src="/_next/static/chunks/4141b86737d3d211.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7" async=""></script>
1<script src="/_next/static/chunks/b9e18a9181222732.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7" async=""></script>
1<script src="/_next/static/chunks/1d3b3a30a1d781ce.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7" async=""></script>
1<meta name="next-size-adjust" content=""/><title>Docs — SIWA</title><meta name="description" content="Documentation for SIWA (Sign In With Agent) — getting started, API reference, wallet integration, and contract addresses."/><meta property="og:title" content="SIWA — Sign In With Agent"/><meta property="og:description" content="Trustless identity and authentication for AI agents. An open standard built on ERC-8004 and ERC-8128."/><meta property="og:image" content="https://siwa.id/og.png"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="SIWA — Sign In With Agent"/><meta property="og:type" content="website"/><meta name="twitter:card" content="summary_large_image"/><meta name="twitter:title" content="SIWA — Sign In With Agent"/><meta name="twitter:description" content="Trustless identity and authentication for AI agents. An open standard built on ERC-8004 and ERC-8128."/><meta name="twitter:image" content="https://siwa.id/og.png"/><link rel="icon" href="/favicon.ico?favicon.4c82eb06.ico" sizes="32x32" type="image/x-icon"/>
1<script src="/_next/static/chunks/a6dad97d9634a72d.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7" noModule=""></script>
1</head><body class="geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable antialiased font-sans"><div hidden=""><!--$--><!--/$--></div><nav class="fixed top-0 left-0 right-0 z-50 border-b border-border bg-background/80 backdrop-blur-sm"><div class="mx-auto flex h-14 max-w-5xl items-center justify-between px-6"><a class="font-mono text-sm font-semibold tracking-tight text-foreground hover:text-accent transition-colors duration-200" href="/">Sign-in with Agent</a><div class="hidden md:flex items-center gap-6"><a class="text-sm text-muted hover:text-foreground transition-colors duration-200 cursor-pointer" href="/docs">Docs</a><a class="text-sm text-muted hover:text-foreground transition-colors duration-200 cursor-pointer" href="/docs/endpoints">Endpoints</a><a href="https://github.com/builders-garden/siwa" target="_blank" rel="noopener noreferrer" class="text-sm text-muted hover:text-foreground transition-colors duration-200 cursor-pointer">GitHub</a><a href="https://8004.org" target="_blank" rel="noopener noreferrer" class="text-sm text-muted hover:text-foreground transition-colors duration-200 cursor-pointer">ERC-8004</a></div><button class="md:hidden flex flex-col justify-center items-center w-8 h-8 gap-1.5 cursor-pointer" aria-label="Toggle menu"><span class="block h-px w-5 bg-muted transition-all duration-200 "></span><span class="block h-px w-5 bg-muted transition-all duration-200 "></span></button></div></nav><main class="pt-14"><div class="mx-auto flex max-w-6xl px-6 py-12"><aside class="hidden md:block w-56 shrink-0 sticky top-20 h-fit max-h-[calc(100vh-6rem)] overflow-y-auto"><nav class="space-y-4"><div><a href="#getting-started" class="block font-mono text-xs font-semibold transition-colors duration-200 cursor-pointer text-foreground hover:text-accent">Getting Started</a></div><div><a href="#architecture" class="block font-mono text-xs font-semibold transition-colors duration-200 cursor-pointer text-foreground hover:text-accent">How It Works</a><div class="mt-1.5 ml-2 border-l border-border pl-3"><div class="mt-1"><a href="#auth-flow" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Auth Flow</a></div></div></div><div><a href="#signing" class="block font-mono text-xs font-semibold transition-colors duration-200 cursor-pointer text-foreground hover:text-accent">Signing (Agent-Side)</a><div class="mt-1.5 ml-2 border-l border-border pl-3"><div class="mt-2 first:mt-0"><span class="block text-[10px] font-mono font-medium text-dim/60 uppercase tracking-wider mb-1">Agentic Wallets</span><div class="space-y-1"><a href="#wallet-bankr" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Bankr</a><a href="#wallet-circle" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Circle</a><a href="#wallet-openfort" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Openfort</a><a href="#wallet-privy" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Privy</a></div></div><div class="mt-2 first:mt-0"><span class="block text-[10px] font-mono font-medium text-dim/60 uppercase tracking-wider mb-1">Other Signers</span><div class="space-y-1"><a href="#wallet-privatekey" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Private Key</a><a href="#wallet-keyring" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Keyring Proxy</a><a href="#smart-accounts" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Smart Accounts</a></div></div><div class="mt-2 first:mt-0"><span class="block text-[10px] font-mono font-medium text-dim/60 uppercase tracking-wider mb-1">Sign &amp; Send</span><div class="space-y-1"><a href="#signing-siwa" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">SIWA Sign-In</a><a href="#signing-erc8128" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">ERC-8128 Request Signing</a></div></div></div></div><div><a href="#verification" class="block font-mono text-xs font-semibold transition-colors duration-200 cursor-pointer text-foreground hover:text-accent">Verification (Server-Side)</a><div class="mt-1.5 ml-2 border-l border-border pl-3"><div class="mt-2 first:mt-0"><span class="block text-[10px] font-mono font-medium text-dim/60 uppercase tracking-wider mb-1">Verify</span><div class="space-y-1"><a href="#verify-siwa" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">SIWA Verification</a><a href="#verify-erc8128" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">ERC-8128 Request Verification</a></div></div><div class="mt-2 first:mt-0"><span class="block text-[10px] font-mono font-medium text-dim/60 uppercase tracking-wider mb-1">Auth State</span><div class="space-y-1"><a href="#verify-receipts" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Receipts</a></div></div><div class="mt-2 first:mt-0"><span class="block text-[10px] font-mono font-medium text-dim/60 uppercase tracking-wider mb-1">Server Middleware</span><div class="space-y-1"><a href="#verify-wrappers-next" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Next.js</a><a href="#verify-wrappers-express" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Express</a><a href="#verify-wrappers-hono" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Hono</a><a href="#verify-wrappers-fastify" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Fastify</a></div></div><div class="mt-2 first:mt-0"><span class="block text-[10px] font-mono font-medium text-dim/60 uppercase tracking-wider mb-1">Nonce Store</span><div class="space-y-1"><a href="#nonce-why" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">
1Why Nonces</a><a href="#nonce-memory" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Memory</a><a href="#nonce-redis" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Redis</a><a href="#nonce-kv" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Cloudflare KV</a><a href="#nonce-database" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Database</a></div></div><div class="mt-2 first:mt-0"><span class="block text-[10px] font-mono font-medium text-dim/60 uppercase tracking-wider mb-1">Captcha</span><div class="space-y-1"><a href="#captcha-how" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">How It Works</a><a href="#captcha-signin" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Sign-In Captcha</a><a href="#captcha-perrequest" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Per-Request Captcha</a><a href="#captcha-difficulty" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Difficulty Levels</a></div></div></div></div><div><a href="#x402" class="block font-mono text-xs font-semibold transition-colors duration-200 cursor-pointer text-foreground hover:text-accent">x402 Payments</a><div class="mt-1.5 ml-2 border-l border-border pl-3"><div class="mt-2 first:mt-0"><span class="block text-[10px] font-mono font-medium text-dim/60 uppercase tracking-wider mb-1">Server</span><div class="space-y-1"><a href="#x402-overview" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Overview</a><a href="#x402-server" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Server Setup</a><a href="#x402-sessions" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Sessions</a><a href="#x402-config" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Config Reference</a></div></div><div class="mt-2 first:mt-0"><span class="block text-[10px] font-mono font-medium text-dim/60 uppercase tracking-wider mb-1">Middleware</span><div class="space-y-1"><a href="#x402-express" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Express</a><a href="#x402-next" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Next.js</a><a href="#x402-hono" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Hono</a><a href="#x402-fastify" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Fastify</a></div></div><div class="mt-2 first:mt-0"><span class="block text-[10px] font-mono font-medium text-dim/60 uppercase tracking-wider mb-1">Agent</span><div class="space-y-1"><a href="#x402-agent" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Agent-Side</a></div></div></div></div><div><a href="#identity" class="block font-mono text-xs font-semibold transition-colors duration-200 cursor-pointer text-foreground hover:text-accent">Identity &amp; Registry</a><div class="mt-1.5 ml-2 border-l border-border pl-3"><div class="mt-1"><a href="#identity-file" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Identity File</a></div><div class="mt-1"><a href="#identity-registry" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Onchain Registry</a></div></div></div><div><a href="#protocol" class="block font-mono text-xs font-semibold transition-colors duration-200 cursor-pointer text-foreground hover:text-accent">Protocol Spec</a><div class="mt-1.5 ml-2 border-l border-border pl-3"><div class="mt-1"><a href="#protocol-message" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Message Format</a></div><div class="mt-1"><a href="#protocol-fields" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Field Definitions</a></div><div class="mt-1"><a href="#protocol-vs-siwe" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">SIWA vs SIWE</a></div></div></div><div><a href="#contracts" class="block font-mono text-xs font-semibold transition-colors duration-200 cursor-pointer text-foreground hover:text-accent">Contracts</a><div class="mt-1.5 ml-2 border-l border-border pl-3"><div class="mt-1"><a href="#contracts-mainnet" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Mainnet</a></div><div class="mt-1"><a href="#contracts-testnet" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Testnets</a></div><div class="mt-1"><a href="#contracts-format" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Registry Format</a></div><div class="mt-1"><a href="#contracts-rpc" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">RPC Endpoints</a></div><div class="mt-1"><a href="#contracts-explorer" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Explorer</a></div></div></div></nav></aside><article class="min-w-0 flex-1 pl-0 md:pl-12"><div class="mb-6 rounded-lg bg-yellow-500/10 border border-yellow-500/30 px-5 py-3"><p class="text-sm font-mono text-yellow-400">This project is a work in progress. Use at your own risk — we welcome<!-- --> <a href="https://github.com/builders-garden/siwa" target="_blank" rel="noopener noreferrer" class="underline underline-offset-2 hover:text-yellow-300 transition-colors duration-200">feedback and contributions</a>.</p></div><h1 class="font-mono text-2xl font-bold text-foreground mb-2">SIWA Documentation</h1><p class="text-sm text-dim mb-8">Sign In With Agent — v1.0</p><div class="mb-12 rounded-lg border border-accent/30 bg-accent/5 px-5 py-4"><p class="text-sm text-muted leading-relaxed"><span class="font-mono font-semibold text-accent">What is SIWA?</span> <!-- -->SIWA (Sign In With Agent) helps AI agents authenticate with services using their<!-- --> <a href="https://8004.org" target="_blank" rel="noopener noreferrer" class="text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200">ERC-8004</a> <!-- -->onchain identity. Like SIWE (Sign In With Ethereum) for humans, but for agents with verifiable registration.</p><p class="text-sm text-muted leading-relaxed mt-3"><span class="font-mono font-semibold text-accent">For AI agents:</span> <!-- -->Read<!-- --> <a href="https://siwa.id/skill.md" class="text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200 cursor-pointer">/skill.md</a> <!-- -->
1for structured instructions.</p></div><section id="getting-started" class="scroll-mt-20 pb-16"><h2 class="font-mono text-xl font-semibold text-foreground mb-6">Getting Started</h2><p class="text-sm leading-relaxed text-muted mb-4">SIWA provides two core capabilities:</p><ul class="space-y-2 mb-6 text-sm leading-relaxed text-muted list-none"><li class="flex gap-3"><span class="text-accent shrink-0">•</span><span><strong class="text-foreground">Agent-side:</strong> Sign SIWA messages to prove ownership of an ERC-8004 identity</span></li><li class="flex gap-3"><span class="text-accent shrink-0">•</span><span><strong class="text-foreground">Server-side:</strong> Verify signatures and check onchain registration with multiple modular criteria</span></li></ul><div><div class="flex border-b border-border mb-6"><button class="px-4 py-2 font-mono text-sm transition-colors duration-200 border-b-2 -mb-px text-accent border-accent">Build Agents (signer side)</button><button class="px-4 py-2 font-mono text-sm transition-colors duration-200 border-b-2 -mb-px text-muted border-transparent hover:text-foreground">Build Apps (verifier side)</button></div><div><p class="text-sm leading-relaxed text-muted mb-4">Agents use SIWA to authenticate with services by signing a structured message that proves ownership of their ERC-8004 identity. The service verifies the signature and checks onchain registration.</p><div class="flex gap-4 mb-6"><div class="flex-shrink-0 w-8 h-8 rounded-full bg-accent/10 border border-accent/30 flex items-center justify-center"><span class="font-mono text-sm font-semibold text-accent">1</span></div><div class="flex-1 pt-1"><h4 class="font-mono text-sm font-semibold text-foreground mb-2">Install the SDK</h4><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token plain">npm install @buildersgarden/siwa</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div></div><div class="flex gap-4 mb-6"><div class="flex-shrink-0 w-8 h-8 rounded-full bg-accent/10 border border-accent/30 flex items-center justify-center"><span class="font-mono text-sm font-semibold text-accent">2</span></div><div class="flex-1 pt-1"><h4 class="font-mono text-sm font-semibold text-foreground mb-2">Create a Signer</h4><p class="text-sm leading-relaxed text-muted mb-4">Choose any wallet provider. See<!-- --> <a href="#wallets" class="text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200">Wallet Options</a> <!-- -->for all options.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> createLocalAccountSigner </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;@buildersgarden/siwa/signer&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">
1import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> privateKeyToAccount </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;viem/accounts&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
2</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Example: private key signer</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> account </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">privateKeyToAccount</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">process</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">env</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token constant" style="color:rgb(130, 170, 255)">PRIVATE_KEY</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">as</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:rgb(173, 219, 103)">`</span><span class="token template-string string" style="color:rgb(173, 219, 103)">0x</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation builtin" style="color:rgb(130, 170, 255)">string</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string template-punctuation string" style="color:rgb(173, 219, 103)">`</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> signer </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createLocalAccountSigner</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">account</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div></div><div class="flex gap-4 mb-6"><div class="flex-shrink-0 w-8 h-8 rounded-full bg-accent/10 border border-accent/30 flex items-center justify-center"><span class="font-mono text-sm font-semibold text-accent">3</span></div><div class="flex-1 pt-1"><h4 class="font-mono text-sm font-semibold text-foreground mb-2">Request a Nonce</h4><p class="text-sm leading-relaxed text-muted mb-4">Get a nonce from the service you want to authenticate with.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> response </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">&quot;https://api.example.com/siwa/nonce&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  method</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;POST&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  headers</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token string-property property" style="color:rgb(128, 203, 196)">&quot;Content-Type&quot;</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;application/json&quot;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  body</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">JSON</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">stringify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> address</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> signer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getAddress</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> nonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> issuedAt </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> response</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">json</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div></div><div class="flex gap-4 mb-6"><div class="flex-shrink-0 w-8 h-8 rounded-full bg-accent/10 border border-accent/30 flex items-center justify-center"><span class="font-mono text-sm font-semibold text-accent">4</span></div><div class="flex-1 pt-1"><h4 class="font-mono text-sm font-semibold text-foreground mb-2">Sign and Submit</h4><p class="text-sm leading-relaxed text-muted mb-4">Build and sign the SIWA message, then submit it to the service.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">
2import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> signSIWAMessage </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;@buildersgarden/siwa&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
3</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> message</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> signature </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">signSIWAMessage</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  domain</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;api.example.com&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  uri</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;https://api.example.com/siwa&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  agentId</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">42</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain">  </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Your ERC-8004 token ID</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  agentRegistry</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  chainId</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">84532</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  nonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  issuedAt</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> signer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
4</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Submit to service</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> verifyResponse </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">&quot;https://api.example.com/siwa/verify&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  method</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;POST&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  headers</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token string-property property" style="color:rgb(128, 203, 196)">&quot;Content-Type&quot;</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;application/json&quot;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  body</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">JSON</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">stringify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> message</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> signature </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> receipt </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> verifyResponse</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">json</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div></div><div class="flex gap-4 mb-6"><div class="flex-shrink-0 w-8 h-8 rounded-full bg-accent/10 border border-accent/30 flex items-center justify-center"><span class="font-mono text-sm font-semibold text-accent">5</span></div><div class="flex-1 pt-1"><h4 class="font-mono text-sm font-semibold text-foreground mb-2">Make Authenticated Requests</h4><p class="text-sm leading-relaxed text-muted mb-4">Use the receipt for subsequent API calls with ERC-8128 signatures.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">
4import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> signAuthenticatedRequest </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;@buildersgarden/siwa/erc8128&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
5</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> request </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 139)">Request</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">&quot;https://api.example.com/action&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  method</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;POST&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  headers</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token string-property property" style="color:rgb(128, 203, 196)">&quot;Content-Type&quot;</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;application/json&quot;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  body</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">JSON</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">stringify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> action</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;transfer&quot;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
6</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> signedRequest </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">signAuthenticatedRequest</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">request</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> receipt</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> signer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">84532</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> response </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">signedRequest</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div></div></div></div><div class="mt-8 mb-4 grid gap-3 sm:grid-cols-3"><a href="#wallets" class="rounded-lg border border-border bg-surface px-4 py-3 hover:border-accent/40 transition-colors duration-200 cursor-pointer block"><h4 class="font-mono text-xs font-semibold text-foreground mb-1">Wallet Options</h4><p class="text-xs text-dim">Use any wallet: Bankr, Circle, Openfort, Privy, private key, or keyring proxy.</p></a><a href="#api" class="rounded-lg border border-border bg-surface px-4 py-3 hover:border-accent/40 transition-colors duration-200 cursor-pointer block"><h4 class="font-mono text-xs font-semibold text-foreground mb-1">API Reference</h4><p class="text-xs text-dim">SDK functions, modules, and types.</p></a><a href="#protocol" class="rounded-lg border border-border bg-surface px-4 py-3 hover:border-accent/40 transition-colors duration-200 cursor-pointer block"><h4 class="font-mono text-xs font-semibold text-foreground mb-1">Protocol Spec</h4><p class="text-xs text-dim">Message format and authentication flow.</p></a></div></section><section id="architecture" class="scroll-mt-20 pb-16"><h2 class="font-mono text-xl font-semibold text-foreground mb-6">How It Works</h2><div id="auth-flow" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Authentication Flow</h3><ol class="space-y-3 mb-6 text-sm leading-relaxed text-muted list-none"><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">1.</span><span>The agent requests a <strong class="text-foreground">nonce</strong> from the service, sending its address and agent ID.</span></li><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">2.</span><span>The service returns the nonce along with timestamps.</span></li><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">3.</span><span>The agent builds a SIWA message and <strong class="text-foreground">signs it</strong>
6 with its wallet.</span></li><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">4.</span><span>The agent sends the message and signature to the service.</span></li><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">5.</span><span>The service <strong class="text-foreground">verifies</strong> the signature and calls the blockchain to confirm the agent owns that identity NFT.</span></li><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">6.</span><span>If verified, the service returns a <strong class="text-foreground">receipt</strong>. The agent uses this for subsequent authenticated requests.</span></li></ol><p class="text-sm leading-relaxed text-muted mb-4">The SDK provides two main functions:</p><ul class="space-y-2 mb-6 text-sm leading-relaxed text-muted list-none"><li class="flex gap-3"><span class="text-accent shrink-0">•</span><span><strong class="text-foreground">Agent-side:</strong> <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">signSIWAMessage(fields, signer)</code> — builds and signs the message</span></li><li class="flex gap-3"><span class="text-accent shrink-0">•</span><span><strong class="text-foreground">Server-side:</strong> <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">verifySIWA(message, signature, domain, nonceValid, client, criteria?)</code> — validates signature and checks onchain ownership</span></li></ul><img src="/siwa-flow.png" alt="SIWA authentication flow: Agent requests nonce, signs SIWA message, Service verifies signature and checks onchain ownership, returns HMAC-signed verification receipt, then subsequent API requests use ERC-8128 HTTP signatures" class="w-full rounded-lg border border-border cursor-pointer hover:opacity-90 transition-opacity" width="800" height="730"/></div></section><section id="signing" class="scroll-mt-20 pb-16"><h2 class="font-mono text-xl font-semibold text-foreground mb-6">Signing (Agent-Side)</h2><p class="text-sm leading-relaxed text-muted mb-4">Everything an agent needs to authenticate: choose a signer, sign SIWA messages for initial sign-in, then sign subsequent API requests with ERC-8128. <br/> SIWA supports both <strong class="text-foreground">EOA</strong> (Externally Owned Account) and <strong class="text-foreground">SCA</strong> (Smart Contract Account) signers — agents backed by smart wallets like Safe, Base Accounts, or ERC-6551 Token Bound Accounts work alongside traditional EOA-based agents.</p><div id="wallet-bankr" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Bankr</h3><p class="text-sm leading-relaxed text-muted mb-4">Bankr&#x27;s Agent API provides smart contract wallets (ERC-4337) for AI agents with built-in signing capabilities. No additional SDK is needed — the signer communicates directly with the Bankr API over HTTP. Signatures are verified via ERC-1271 automatically.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token plain"># No extra package needed — only @buildersgarden/siwa</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">Create a signer from your Bankr API key:</p><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Bankr Signer Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span>
6<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import { signSIWAMessage } from &quot;@buildersgarden/siwa&quot;;
7import { createBankrSiwaSigner } from &quot;@buildersgarden/siwa/signer&quot;;
8<!-- -->
9...</code></pre></div></div><p class="text-sm leading-relaxed text-muted mb-4">Already using Bankr&#x27;s <a href="https://github.com/BankrBot/openclaw-skills/tree/main/bankr" class="text-accent hover:underline" target="_blank" rel="noopener noreferrer">OpenClaw trading skill</a> for swaps and DeFi? This signer adds SIWA authentication on top — same API key, same wallet.</p></div><div id="wallet-circle" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Circle</h3><p class="text-sm leading-relaxed text-muted mb-4">Circle&#x27;s developer-controlled wallets provide secure key management for AI agents. Install the Circle SDK alongside SIWA:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token plain">npm install @circle-fin/developer-controlled-wallets</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">Create a signer from your Circle wallet credentials:</p><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Circle Signer Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import { signSIWAMessage } from &quot;@buildersgarden/siwa&quot;;
10import { createCircleSiwaSigner } from &quot;@buildersgarden/siwa/signer&quot;;
11<!-- -->
12...</code></pre></div></div><p class="text-sm leading-relaxed text-muted mb-4">If you already have a Circle client instance, use <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">createCircleSiwaSignerFromClient</code>:</p><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">From Existing Client</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import { initiateDeveloperControlledWalletsClient } from &quot;@circle-fin/developer-controlled-wallets&quot;;
13import { createCircleSiwaSignerFromClient } from &quot;@buildersgarden/siwa/signer&quot;;
14<!-- -->
15...</code></pre></div></div></div><div id="wallet-openfort" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Openfort</h3><p class="text-sm leading-relaxed text-muted mb-4">Openfort&#x27;s backend wallets provide secure key management and account abstraction for AI agents. Install the Openfort Node SDK alongside SIWA:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token plain">
15npm install @openfort/openfort-node</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">Create a signer from your Openfort wallet credentials:</p><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Openfort Signer Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import { signSIWAMessage } from &quot;@buildersgarden/siwa&quot;;
16import { createOpenfortSiwaSigner } from &quot;@buildersgarden/siwa/signer&quot;;
17<!-- -->
18...</code></pre></div></div><p class="text-sm leading-relaxed text-muted mb-4">If you already have an Openfort client instance, use <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">createOpenfortSiwaSignerFromClient</code>:</p><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">From Existing Client</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import Openfort from &quot;@openfort/openfort-node&quot;;
19import { createOpenfortSiwaSignerFromClient } from &quot;@buildersgarden/siwa/signer&quot;;
20<!-- -->
21...</code></pre></div></div></div><div id="wallet-privy" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Privy</h3><p class="text-sm leading-relaxed text-muted mb-4">Privy&#x27;s server wallets provide embedded wallet infrastructure for AI agents. Install the Privy Node SDK alongside SIWA:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token plain">npm install @privy-io/node</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">Create a signer from your Privy wallet:</p><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Privy Signer Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span>
21<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import { PrivyClient } from &quot;@privy-io/node&quot;;
22import { signSIWAMessage } from &quot;@buildersgarden/siwa&quot;;
23import { createPrivySiwaSigner } from &quot;@buildersgarden/siwa/signer&quot;;<!-- -->
24...</code></pre></div></div></div><div id="wallet-privatekey" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Private Key (Backend Scripts)</h3><p class="text-sm leading-relaxed text-muted mb-4">For server-side agents or scripts with direct private key access:</p><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Private Key Signer Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import { signSIWAMessage } from &quot;@buildersgarden/siwa&quot;;
25import { createLocalAccountSigner } from &quot;@buildersgarden/siwa/signer&quot;;
26import { privateKeyToAccount } from &quot;viem/accounts&quot;;<!-- -->
27...</code></pre></div></div></div><div id="wallet-keyring" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Keyring Proxy (Self-Hosted, Non-Custodial)</h3><p class="text-sm leading-relaxed text-muted mb-4">For AI agents that need secure key isolation, we provide an optional <strong class="text-foreground">keyring proxy</strong> — a separate service that holds the encrypted private key and performs all signing. The agent never touches the key.</p><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Keyring Proxy Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import { signSIWAMessage } from &quot;@buildersgarden/siwa&quot;;
28import { createKeyringProxySigner } from &quot;@buildersgarden/siwa/signer&quot;;
29<!-- -->
30...</code></pre></div></div><p class="text-sm leading-relaxed text-muted mb-4">The keyring proxy is completely optional. It&#x27;s useful when you want:</p><ul class="space-y-2 mb-4 text-sm leading-relaxed text-muted list-none"><li class="flex gap-3"><span class="text-accent shrink-0">•</span><span>Key isolation from the agent process (protection against prompt injection)</span></li><li class="flex gap-3"><span class="text-accent shrink-0">•</span><span>Optional 2FA via Telegram for transaction approval</span></li><li class="flex gap-3"><span class="text-accent shrink-0">•</span><span>Self-hosted, non-custodial key management</span></li></ul><p class="text-sm leading-relaxed text-muted mb-4">See<!-- --> <a href="/docs/deploy" class="text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200">Deploy</a> <!-- -->for keyring proxy setup, architecture, and security model.</p></div><div id="smart-accounts" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Smart Accounts</h3><p class="text-sm leading-relaxed text-muted mb-4">Smart contract wallets (Safe, ZeroDev/Kernel, Coinbase Smart Wallet) work with the same <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">createWalletClientSigner</code> — their SDKs expose a standard WalletClient or EIP-1193 provider. The SDK detects the signer type automatically during verification via ERC-1271.</p><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Smart Account Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span>
30<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import { signSIWAMessage } from &quot;@buildersgarden/siwa&quot;;
31import { createWalletClientSigner } from &quot;@buildersgarden/siwa/signer&quot;;
32import { createWalletClient, custom } from &quot;viem&quot;;<!-- -->
33...</code></pre></div></div></div><div id="signing-siwa" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">SIWA Sign-In</h3><p class="text-sm leading-relaxed text-muted mb-4">Build and sign a SIWA message to prove ownership of an ERC-8004 identity. The authentication flow consists of two steps:</p><ul class="space-y-2 mb-4 text-sm leading-relaxed text-muted list-none"><li class="flex gap-3"><span class="text-accent shrink-0">1.</span><span><strong class="text-foreground">Get a nonce</strong> from the server&#x27;s <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">/siwa/nonce</code> endpoint</span></li><li class="flex gap-3"><span class="text-accent shrink-0">2.</span><span><strong class="text-foreground">Sign and verify</strong> by sending the signature to <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">/siwa/verify</code></span></li></ul><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Function</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Returns</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">signSIWAMessage(fields, signer)</td><td class="py-2 pr-4 text-muted font-mono text-xs">{ message, signature, address }</td><td class="py-2 pr-4 text-muted font-mono text-xs">Build and sign a SIWA message.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">buildSIWAMessage(fields)</td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Build a formatted SIWA message string.</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa</code>.</p><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Full Authentication Flow</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import { signSIWAMessage } from &quot;@buildersgarden/siwa&quot;;
34
35// Step 1: Request nonce from server<!-- -->
36...</code></pre></div></div></div><div id="signing-erc8128" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">ERC-8128 Request Signing</h3><p class="text-sm leading-relaxed text-muted mb-4">After SIWA sign-in, sign every outgoing API request with ERC-8128 HTTP Message Signatures.</p><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Function</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Returns</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">signAuthenticatedRequest(req, receipt, signer, chainId, options?)</td><td class="py-2 pr-4 text-muted font-mono text-xs">Request</td><td class="py-2 pr-4 text-muted font-mono text-xs">Sign outgoing request with ERC-8128.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">createErc8128Signer(signer, chainId, options?)</td><td class="py-2 pr-4 text-muted font-mono text-xs">EthHttpSigner</td><td class="py-2 pr-4 text-muted font-mono text-xs">Create ERC-8128 HTTP signer from SIWA Signer.</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/erc8128</code>.</p><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Request Signing Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span>
36<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import { signAuthenticatedRequest } from &quot;@buildersgarden/siwa/erc8128&quot;;
37
38const request = new Request(&quot;https://api.example.com/action&quot;, {<!-- -->
39...</code></pre></div></div></div></section><section id="verification" class="scroll-mt-20 pb-16"><h2 class="font-mono text-xl font-semibold text-foreground mb-6">Verification (Server-Side)</h2><p class="text-sm leading-relaxed text-muted mb-4">Everything a service needs to verify agents: validate SIWA sign-in, verify ERC-8128 signed requests, issue receipts, and plug into Express or Next.js.</p><div id="verify-siwa" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">SIWA Verification</h3><p class="text-sm leading-relaxed text-muted mb-4">Verify a signed SIWA message, check onchain ownership, and optionally validate ERC-8004 agent profile criteria. Implement two endpoints:</p><ul class="space-y-2 mb-4 text-sm leading-relaxed text-muted list-none"><li class="flex gap-3"><span class="text-accent shrink-0">1.</span><span><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">/siwa/nonce</code> — Issue a nonce for the agent to sign</span></li><li class="flex gap-3"><span class="text-accent shrink-0">2.</span><span><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">/siwa/verify</code> — Verify the signed message and issue a receipt</span></li></ul><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Function</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Returns</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">verifySIWA(msg, sig, domain, nonceValid, client, criteria?)</td><td class="py-2 pr-4 text-muted font-mono text-xs">SIWAVerificationResult</td><td class="py-2 pr-4 text-muted font-mono text-xs">Verify signature + onchain ownership + criteria.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">parseSIWAMessage(message)</td><td class="py-2 pr-4 text-muted font-mono text-xs">SIWAMessageFields</td><td class="py-2 pr-4 text-muted font-mono text-xs">Parse SIWA message string to fields.</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa</code>. Parameters:</p><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Parameter</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Type</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">message</td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">The full SIWA message string.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">signature</td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">EIP-191 signature hex string.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">expectedDomain</td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Must match message domain.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">nonceValid</td><td class="py-2 pr-4 text-muted font-mono text-xs">function | object</td><td class="py-2 pr-4 text-muted font-mono text-xs">Nonce validator: callback (nonce) =&gt; boolean, <!-- -->{ nonceToken, secret }<!-- --> for stateless, or <!-- -->{ nonceStore }<!-- --> for store-based replay protection. See <a href="#nonce-store" class="text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200">Nonce Store</a>.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">client</td><td class="py-2 pr-4 text-muted font-mono text-xs">PublicClient</td><td class="py-2 pr-4 text-muted font-mono text-xs">viem PublicClient for onchain verification.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">criteria?</td><td class="py-2 pr-4 text-muted font-mono text-xs">SIWAVerifyCriteria</td><td class="py-2 pr-4 text-muted font-mono text-xs">Optional criteria to filter agents (see below).</td></tr></tbody></table></div><div class="mt-4 mb-4"><h4 class="font-mono text-sm font-semibold text-foreground mb-3">Criteria Options</h4></div><p class="text-sm leading-relaxed text-muted mb-4">Use criteria to enforce policies on which agents can authenticate. These are checked during sign-in and encoded into the receipt.</p><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Criteria</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Type</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">allowedSignerTypes</td><td class="py-2 pr-4 text-muted font-mono text-xs">(&#x27;eoa&#x27; | &#x27;sca&#x27;)[]</td><td class="py-2 pr-4 text-muted font-mono text-xs">Restrict to EOA-only or allow smart contract accounts.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">mustBeActive</td><td class="py-2 pr-4 text-muted font-mono text-xs">boolean</td><td class="py-2 pr-4 text-muted font-mono text-xs">Require agent metadata.active === true.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">requiredServices</td><td class="py-2 pr-4 text-muted font-mono text-xs">string[]</td><td class="py-2 pr-4 text-muted font-mono text-xs">Agent must support these services (e.g., &#x27;llm&#x27;, &#x27;web3&#x27;).</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">requiredTrust</td><td class="py-2 pr-4 text-muted font-mono text-xs">string[]</td><td class="py-2 pr-4 text-muted font-mono text-xs">Agent must support these trust models (e.g., &#x27;tee&#x27;, &#x27;crypto-economic&#x27;).</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">minScore</td><td class="py-2 pr-4 text-muted font-mono text-xs">number</td><td class="py-2 pr-4 text-muted font-mono text-xs">Minimum reputation score (requires reputationRegistryAddress).</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">minFeedbackCount</td><td class="py-2 pr-4 text-muted font-mono text-xs">number</td><td class="py-2 pr-4 text-muted font-mono text-xs">Minimum feedback count (requires reputationRegistryAddress).</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">reputationRegistryAddress</td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Reputation registry address for score/feedback checks.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">custom</td><td class="py-2 pr-4 text-muted font-mono text-xs">(agent) =&gt; Promise&lt;boolean&gt;</td><td class="py-2 pr-4 text-muted font-mono text-xs">Custom validation function with full agent profile.</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">The result includes <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">signerType</code> and optionally <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">agent</code> (full profile if criteria fetched metadata).</p><div class="mt-6 mb-3"><h4 class="font-mono text-sm font-semibold text-foreground">Nonce Endpoint Examples</h4><p class="text-xs text-dim mt-1">Issue a nonce for the agent to sign. Import <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">createSIWANonce</code> from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa</code>.</p></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Next.js Nonce Endpoint</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span>
39<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>// app/api/siwa/nonce/route.ts
40import { createSIWANonce } from &quot;@buildersgarden/siwa&quot;;
41import { corsJson, siwaOptions } from &quot;@buildersgarden/siwa/next&quot;;<!-- -->
42...</code></pre></div></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Express Nonce Endpoint</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>// routes/siwa.ts
43import express from &quot;express&quot;;
44import { createSIWANonce } from &quot;@buildersgarden/siwa&quot;;<!-- -->
45...</code></pre></div></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Hono Nonce Endpoint</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>// src/routes/siwa.ts
46import { Hono } from &quot;hono&quot;;
47import { cors } from &quot;hono/cors&quot;;<!-- -->
48...</code></pre></div></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Fastify Nonce Endpoint</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>// src/routes/siwa.ts
49import { FastifyPluginAsync } from &quot;fastify&quot;;
50import { createSIWANonce } from &quot;@buildersgarden/siwa&quot;;<!-- -->
51...</code></pre></div></div><div class="mt-6 mb-3"><h4 class="font-mono text-sm font-semibold text-foreground">Verify Endpoint Examples</h4><p class="text-xs text-dim mt-1">Verify the signed message and issue a receipt.</p></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Next.js Verify Endpoint</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span>
51<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>// app/api/siwa/verify/route.ts
52import { verifySIWA } from &quot;@buildersgarden/siwa&quot;;
53import { createReceipt } from &quot;@buildersgarden/siwa/receipt&quot;;<!-- -->
54...</code></pre></div></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Express Verify Endpoint</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>// routes/siwa.ts (add to same router as nonce)
55import { verifySIWA } from &quot;@buildersgarden/siwa&quot;;
56import { createReceipt } from &quot;@buildersgarden/siwa/receipt&quot;;<!-- -->
57...</code></pre></div></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Hono Verify Endpoint</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>// src/routes/siwa.ts (add to same app as nonce)
58import { verifySIWA } from &quot;@buildersgarden/siwa&quot;;
59import { createReceipt } from &quot;@buildersgarden/siwa/receipt&quot;;<!-- -->
60...</code></pre></div></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Fastify Verify Endpoint</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>// src/routes/siwa.ts (add to same plugin as nonce)
61import { verifySIWA } from &quot;@buildersgarden/siwa&quot;;
62import { createReceipt } from &quot;@buildersgarden/siwa/receipt&quot;;<!-- -->
63...</code></pre></div></div></div><div id="verify-erc8128" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">ERC-8128 Request Verification</h3><p class="text-sm leading-relaxed text-muted mb-4">Verify incoming ERC-8128 signed requests from authenticated agents.</p><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Function</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Returns</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">
63verifyAuthenticatedRequest(req, options)</td><td class="py-2 pr-4 text-muted font-mono text-xs">AuthResult</td><td class="py-2 pr-4 text-muted font-mono text-xs">Verify incoming signed request.</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/erc8128</code>. Options accept <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">allowedSignerTypes</code> for policy enforcement. The verified agent includes a <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">signerType</code> field.</p></div><div id="verify-receipts" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Receipts</h3><p class="text-sm leading-relaxed text-muted mb-4">Stateless HMAC-signed tokens issued after successful SIWA verification. The agent includes the receipt in subsequent requests, and the server verifies it.</p><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Function</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Returns</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">createReceipt(payload, options)</td><td class="py-2 pr-4 text-muted font-mono text-xs">{ receipt, expiresAt }</td><td class="py-2 pr-4 text-muted font-mono text-xs">Create an HMAC-signed receipt.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">verifyReceipt(receipt, secret)</td><td class="py-2 pr-4 text-muted font-mono text-xs">ReceiptPayload | null</td><td class="py-2 pr-4 text-muted font-mono text-xs">Verify and decode. Returns null if invalid.</td></tr></tbody></table></div><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Payload Field</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Type</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">address</td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Agent wallet address.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">agentId</td><td class="py-2 pr-4 text-muted font-mono text-xs">number</td><td class="py-2 pr-4 text-muted font-mono text-xs">ERC-8004 token ID.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">signerType</td><td class="py-2 pr-4 text-muted font-mono text-xs">SignerType?</td><td class="py-2 pr-4 text-muted font-mono text-xs">Optional: &#x27;eoa&#x27; or &#x27;sca&#x27;.</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/receipt</code>.</p></div><div id="verify-wrappers" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Server Middleware</h3><p class="text-sm leading-relaxed text-muted mb-4">Drop-in middleware for popular frameworks. Each handles ERC-8128 verification, receipt checking, and CORS.</p><div class="rounded-lg border border-accent/30 bg-accent/5 px-4 py-3 mb-6"><p class="text-sm text-muted leading-relaxed"><span class="font-mono font-semibold text-accent">Note:</span> <!-- -->ERC-8004 criteria (reputation, services, trust models) are checked during SIWA sign-in via<!-- --> <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">verifySIWA()</code>. The middleware below verifies ERC-8128 signatures on subsequent requests — it accepts<!-- --> <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">allowedSignerTypes</code> and <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">verifyOnchain</code> options for per-request policy.</p></div><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Option</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Type</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">receiptSecret</td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">HMAC secret for receipt verification. Defaults to RECEIPT_SECRET env.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">allowedSignerTypes</td><td class="py-2 pr-4 text-muted font-mono text-xs">(&#x27;eoa&#x27; | &#x27;sca&#x27;)[]</td><td class="py-2 pr-4 text-muted font-mono text-xs">Restrict to EOA-only or SCA-only agents.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">
63verifyOnchain</td><td class="py-2 pr-4 text-muted font-mono text-xs">boolean</td><td class="py-2 pr-4 text-muted font-mono text-xs">Re-check ownerOf on every request (slower but more secure).</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">rpcUrl</td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">RPC URL for onchain verification.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">publicClient</td><td class="py-2 pr-4 text-muted font-mono text-xs">PublicClient</td><td class="py-2 pr-4 text-muted font-mono text-xs">viem PublicClient for ERC-1271 smart account signatures.</td></tr></tbody></table></div><div id="verify-wrappers-next" class="scroll-mt-20 mt-8 mb-2"><h4 class="font-mono text-sm font-semibold text-foreground">Next.js (App Router)</h4><p class="text-xs text-dim mb-3">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/next</code> — exports: withSiwa, siwaOptions, corsJson</p></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Next.js Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>// app/api/protected/route.ts
64import { withSiwa, siwaOptions } from &quot;@buildersgarden/siwa/next&quot;;
65<!-- -->
66...</code></pre></div></div><div id="verify-wrappers-express" class="scroll-mt-20 mt-8 mb-2"><h4 class="font-mono text-sm font-semibold text-foreground">Express</h4><p class="text-xs text-dim mb-3">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/express</code> — exports: siwaMiddleware, siwaJsonParser, siwaCors</p></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Express Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import express from &quot;express&quot;;
67import { siwaMiddleware, siwaJsonParser, siwaCors } from &quot;@buildersgarden/siwa/express&quot;;
68import { createPublicClient, http } from &quot;viem&quot;;<!-- -->
69...</code></pre></div></div><div id="verify-wrappers-hono" class="scroll-mt-20 mt-8 mb-2"><h4 class="font-mono text-sm font-semibold text-foreground">Hono</h4><p class="text-xs text-dim mb-3">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/hono</code> — exports: siwaMiddleware, siwaCors</p></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Hono Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span>
69<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import { Hono } from &quot;hono&quot;;
70import { siwaMiddleware, siwaCors } from &quot;@buildersgarden/siwa/hono&quot;;
71import { createPublicClient, http } from &quot;viem&quot;;<!-- -->
72...</code></pre></div></div><div id="verify-wrappers-fastify" class="scroll-mt-20 mt-8 mb-2"><h4 class="font-mono text-sm font-semibold text-foreground">Fastify</h4><p class="text-xs text-dim mb-3">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/fastify</code> — exports: siwaPlugin, siwaAuth</p></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Fastify Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import Fastify from &quot;fastify&quot;;
73import { siwaPlugin, siwaAuth } from &quot;@buildersgarden/siwa/fastify&quot;;
74import { createPublicClient, http } from &quot;viem&quot;;<!-- -->
75...</code></pre></div></div></div><div id="nonce-store" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Nonce Store</h3><p class="text-sm leading-relaxed text-muted mb-4">Pluggable server-side nonce tracking for replay protection. The SDK ships built-in adapters for Memory, Redis, Cloudflare KV, and any SQL database — no extra dependencies, you bring your own client.</p></div><div id="nonce-why" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Why Nonces Matter</h3><p class="text-sm leading-relaxed text-muted mb-4">A SIWA message is valid for its entire TTL window (default 5 minutes). Without server-side tracking, an attacker who intercepts a signed message can <strong class="text-foreground">replay</strong> it — submitting the same signature multiple times to authenticate as the agent.</p><p class="text-sm leading-relaxed text-muted mb-4">A nonce store solves this by recording every issued nonce and consuming it on first use. Once consumed, the nonce is deleted and any replay attempt is rejected.</p><p class="text-sm leading-relaxed text-muted mb-4">The SDK provides three nonce validation strategies:</p><ul class="space-y-2 mb-6 text-sm leading-relaxed text-muted list-none"><li class="flex gap-3"><span class="text-accent shrink-0">•</span><span><strong class="text-foreground">Callback</strong> — <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">(nonce) =&gt; boolean</code>: you manage nonce storage yourself</span></li><li class="flex gap-3"><span class="text-accent shrink-0">•</span><span><strong class="text-foreground">Stateless token</strong> — <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">{ nonceToken, secret }</code>: HMAC-signed token, no server storage needed (but replayable within TTL)</span></li><li class="flex gap-3"><span class="text-accent shrink-0">•</span><span><strong class="text-foreground">Nonce store</strong> — <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">{ nonceStore }</code>: server-side tracking with exactly-once consumption (recommended for production)</span></li></ul><p class="text-sm leading-relaxed text-muted mb-4">The <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">SIWANonceStore</code> interface:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">interface</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 139)">SIWANonceStore</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token doc-comment comment" style="color:rgb(99, 119, 119);font-style:italic">/** Store an issued nonce. Returns true on success, false if already exists. */</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">issue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">nonce</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> ttlMs</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">number</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">
75Promise</span><span class="token operator" style="color:rgb(127, 219, 202)">&lt;</span><span class="token builtin" style="color:rgb(130, 170, 255)">boolean</span><span class="token operator" style="color:rgb(127, 219, 202)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token doc-comment comment" style="color:rgb(99, 119, 119);font-style:italic">/** Atomically check-and-delete a nonce. Returns true if it existed. */</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">consume</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">nonce</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">Promise</span><span class="token operator" style="color:rgb(127, 219, 202)">&lt;</span><span class="token builtin" style="color:rgb(130, 170, 255)">boolean</span><span class="token operator" style="color:rgb(127, 219, 202)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">Wire the store into both <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">createSIWANonce</code> (issue) and <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">verifySIWA</code> (consume):</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> createSIWANonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> verifySIWA </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;@buildersgarden/siwa&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> createMemorySIWANonceStore </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;@buildersgarden/siwa/nonce-store&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
76</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> nonceStore </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createMemorySIWANonceStore</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
77</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Nonce endpoint — issue</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> result </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createSIWANonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">params</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> nonceStore </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
78</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Verify endpoint — consume</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> verification </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">verifySIWA</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  message</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> signature</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> domain</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> nonceStore </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div><div id="nonce-memory" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Memory (Default)</h3><p class="text-sm leading-relaxed text-muted mb-4">In-memory store using a <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">Map</code> with TTL-based expiry. Suitable for single-process servers. Nonces are lost on restart.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">
78import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> createMemorySIWANonceStore </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;@buildersgarden/siwa/nonce-store&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
79</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> nonceStore </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createMemorySIWANonceStore</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div><div id="nonce-redis" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Redis</h3><p class="text-sm leading-relaxed text-muted mb-4">Redis-backed store using <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">SET ... PX ttl NX</code> for atomic issue and <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">DEL</code> for atomic consume. Works with any Redis client that implements <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">set()</code> and <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">del()</code>.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> createRedisSIWANonceStore </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;@buildersgarden/siwa/nonce-store&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
80</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// ioredis (works out of the box)</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> Redis </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;ioredis&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> redis </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 139)">Redis</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> nonceStore </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createRedisSIWANonceStore</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">redis</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">For <strong class="text-foreground">node-redis v4</strong>, wrap with a small adapter since its <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">set()</code> signature differs:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">
80import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> createClient </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;redis&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> createRedisSIWANonceStore </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;@buildersgarden/siwa/nonce-store&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
81</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> client </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">connect</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
82</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> nonceStore </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createRedisSIWANonceStore</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">set</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(127, 219, 202)">...</span><span class="token plain">args</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">unknown</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=&gt;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    client</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">as</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">as</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token constant" style="color:rgb(130, 170, 255)">PX</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token number" style="color:rgb(247, 140, 108)">3</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">as</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">number</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token constant" style="color:rgb(130, 170, 255)">NX</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">
82then</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">r</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=&gt;</span><span class="token plain"> r </span><span class="token operator" style="color:rgb(127, 219, 202)">??</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">null</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">del</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">key</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">unknown</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=&gt;</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">del</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">key </span><span class="token keyword" style="color:rgb(127, 219, 202)">as</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div><div id="nonce-kv" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Cloudflare KV</h3><p class="text-sm leading-relaxed text-muted mb-4">Cloudflare Workers KV-backed store. Uses <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">put</code> with <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">expirationTtl</code> for auto-expiry. The consume path does a <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">get</code> + <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">delete</code> — not fully atomic, but acceptable for random nonces.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> createKVSIWANonceStore </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;@buildersgarden/siwa/nonce-store&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
83</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// In a Cloudflare Worker</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">default</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token keyword" style="color:rgb(127, 219, 202)">async</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">request</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> Request</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> env</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> Env</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> nonceStore </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createKVSIWANonceStore</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">
83env</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token constant" style="color:rgb(130, 170, 255)">SIWA_NONCES</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// use with createSIWANonce / verifySIWA</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">Bind a KV namespace called <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">SIWA_NONCES</code> in your <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">wrangler.toml</code>:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token plain">[[kv_namespaces]]</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">binding = &quot;SIWA_NONCES&quot;</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">id = &quot;&lt;your-kv-namespace-id&gt;&quot;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div><div id="nonce-database" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Database</h3><p class="text-sm leading-relaxed text-muted mb-4">For databases, implement <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">SIWANonceStore</code> directly — it&#x27;s just two methods. No factory needed.</p><p class="text-sm leading-relaxed text-muted mb-4"><strong class="text-foreground">Schema</strong> — create a table with a unique nonce column and an expiry timestamp:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token plain">CREATE TABLE siwa_nonces (</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  nonce      VARCHAR(64) PRIMARY KEY,</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  expires_at TIMESTAMPTZ NOT NULL</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">);</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">-- Optional: periodic cleanup of expired rows</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">-- DELETE FROM siwa_nonces WHERE expires_at &lt; NOW();</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4"><strong class="text-foreground">Prisma</strong>:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">
83import</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">type</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> SIWANonceStore </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;@buildersgarden/siwa/nonce-store&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
84</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> nonceStore</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> SIWANonceStore </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token keyword" style="color:rgb(127, 219, 202)">async</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">issue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">nonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> ttlMs</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">try</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> prisma</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">siwaNonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">create</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        data</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> nonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> expiresAt</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 139)">Date</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Date</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">now</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">+</span><span class="token plain"> ttlMs</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">e</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token keyword" style="color:rgb(127, 219, 202)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">e</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">code </span><span class="token operator" style="color:rgb(127, 219, 202)">===</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;P2002&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">
84false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// unique constraint</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token keyword" style="color:rgb(127, 219, 202)">throw</span><span class="token plain"> e</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token keyword" style="color:rgb(127, 219, 202)">async</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">consume</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">nonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">try</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> prisma</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">siwaNonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">delete</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> where</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> nonce </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">
84false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4"><strong class="text-foreground">Drizzle</strong>:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">type</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> SIWANonceStore </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;@buildersgarden/siwa/nonce-store&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> eq</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> and</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> gt </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;drizzle-orm&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> siwaNonces </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;./schema&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
85</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> nonceStore</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> SIWANonceStore </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token keyword" style="color:rgb(127, 219, 202)">async</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">issue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">nonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> ttlMs</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">try</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> db</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">insert</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">siwaNonces</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">values</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        nonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        expiresAt</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 139)">Date</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Date</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">now</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">+</span><span class="token plain"> ttlMs</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">e</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token keyword" style="color:rgb(127, 219, 202)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">e</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">code </span><span class="token operator" style="color:rgb(127, 219, 202)">===</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;23505&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">
85false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// unique violation</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token keyword" style="color:rgb(127, 219, 202)">throw</span><span class="token plain"> e</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token keyword" style="color:rgb(127, 219, 202)">async</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">consume</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">nonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> result </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> db</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">delete</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">siwaNonces</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">where</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token function" style="color:rgb(130, 170, 255)">and</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">          </span><span class="token function" style="color:rgb(130, 170, 255)">eq</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">siwaNonces</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">nonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> nonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">          </span><span class="token function" style="color:rgb(130, 170, 255)">gt</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">siwaNonces</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">expiresAt</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 139)">Date</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">result</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">rowCount </span><span class="token operator" style="color:rgb(127, 219, 202)">??</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">&gt;</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div><div id="captcha-how" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Captcha (Reverse CAPTCHA)</h3><p class="text-sm leading-relaxed text-muted mb-4">SIWA includes a <strong class="text-foreground">reverse CAPTCHA</strong> — inspired by <a href="https://github.com/MoltCaptcha/MoltCaptcha" class="text-accent hover:underline" target="_blank" rel="noopener noreferrer">MoltCaptcha</a> — that proves an entity <em>is</em> an AI agent, not a human. Challenges exploit how LLMs generate text in a single autoregressive pass, satisfying multiple constraints simultaneously, while humans must iterate.</p><p class="text-sm leading-relaxed text-muted mb-4">The server generates a challenge with constraints the agent must satisfy in its response text — line count, sum of ASCII values of first characters, word count, character at a specific position, and total character count. Higher difficulty levels add more constraints with tighter time limits.</p><p class="text-sm leading-relaxed text-muted mb-4">Two integration points:</p><ul class="space-y-2 mb-6 text-sm leading-relaxed text-muted list-none"><li class="flex gap-3"><span class="text-accent shrink-0">•</span><span><strong class="text-foreground">Sign-in flow</strong> — server requires captcha before issuing a nonce</span></li><li class="flex gap-3"><span class="text-accent shrink-0">•</span><span><strong class="text-foreground">Per-request</strong> — middleware randomly challenges agents during authenticated API calls (server-defined policy/probability)</span></li></ul></div><div id="captcha-signin" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Sign-In Captcha</h3><p class="text-sm leading-relaxed text-muted mb-4">Add <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">captchaPolicy</code> and <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">captchaOptions</code> to your nonce endpoint. The policy function receives the agent&#x27;s identity and returns a difficulty level or <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">null</code> to skip.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">
85import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> createSIWANonce </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;@buildersgarden/siwa&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
86</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> result </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createSIWANonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> address</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> agentId</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> agentRegistry</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> challengeResponse </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    secret</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">SIWA_SECRET</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">captchaPolicy</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">async</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> address </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> known </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> db</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">agents</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">exists</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">address</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> known </span><span class="token operator" style="color:rgb(127, 219, 202)">?</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">null</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&#x27;medium&#x27;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// challenge unknown agents</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    captchaOptions</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">
86 secret</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">SIWA_SECRET</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
87</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// result.status is &#x27;captcha_required&#x27; | &#x27;nonce_issued&#x27; | SIWAResponse</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">Agent-side: use <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">solveCaptchaChallenge()</code> to detect and solve in one step.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> solveCaptchaChallenge </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;@buildersgarden/siwa/captcha&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
88</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> res </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">&quot;/api/siwa/nonce&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  method</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;POST&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  body</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">JSON</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">stringify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> address</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> agentId</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> agentRegistry </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> data </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> res</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">json</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
89</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> captcha </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">solveCaptchaChallenge</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">data</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">async</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">challenge</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// LLM generates text satisfying all constraints in a single pass</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Your LLM generates text satisfying all constraints in one pass.</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Use any provider (Anthropic, OpenAI, etc.) — just return a string.</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">generateText</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">challenge</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
90</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">captcha</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">solved</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Retry with challengeResponse</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">&quot;/api/siwa/nonce&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    method</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;POST&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    body</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">JSON</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">stringify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">...</span><span class="token plain">params</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> challengeResponse</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> captcha</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">challengeResponse </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div>
90<div id="captcha-perrequest" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Per-Request Captcha</h3><p class="text-sm leading-relaxed text-muted mb-4">Add <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">captchaPolicy</code> to middleware for random spot-checks on authenticated requests.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Next.js</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">POST</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">withSiwa</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">handler</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">captchaPolicy</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> request </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">request</span><span class="token operator" style="color:rgb(127, 219, 202)">?.</span><span class="token plain">url</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">includes</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">&#x27;/transfer&#x27;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">&amp;&amp;</span><span class="token plain"> Math</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">random</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">&lt;</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0.05</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&#x27;hard&#x27;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">null</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  captchaOptions</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">
90 secret</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> process</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">env</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token constant" style="color:rgb(130, 170, 255)">SIWA_SECRET</span><span class="token operator" style="color:rgb(127, 219, 202)">!</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
91</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Express</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">use</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token function" style="color:rgb(130, 170, 255)">siwaMiddleware</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">captchaPolicy</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=&gt;</span><span class="token plain"> Math</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">random</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">&lt;</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0.05</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">?</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&#x27;easy&#x27;</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">null</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  captchaOptions</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> secret</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">SIWA_SECRET</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">Agent-side: use <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">retryWithCaptcha()</code> to detect a 401 captcha challenge, solve it, re-sign with ERC-8128, and get a ready-to-send retry request.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">
91import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> signAuthenticatedRequest</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> retryWithCaptcha </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;@buildersgarden/siwa/erc8128&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
92</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> url </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;https://api.example.com/action&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> body </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">JSON</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">stringify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> key</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;value&quot;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
93</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Sign and send</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> signed </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">signAuthenticatedRequest</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token keyword" style="color:rgb(127, 219, 202)">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 139)">Request</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">url</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> method</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;POST&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> body </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> receipt</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> signer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> chainId</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> response </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">signed</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
94</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Detect + solve + re-sign if captcha required</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> result </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">retryWithCaptcha</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  response</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token keyword" style="color:rgb(127, 219, 202)">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 139)">Request</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">url</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> method</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;POST&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> body </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// fresh request</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  receipt</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> signer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> chainId</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token keyword" style="color:rgb(127, 219, 202)">async</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">challenge</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">generateText</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">challenge</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// your LLM solver</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
95</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">result</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">retry</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> retryResponse </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">result</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">request</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div><div id="captcha-difficulty" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Difficulty Levels &amp; Configuration</h3><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Level</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Time Limit</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Constraints</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">easy</td><td class="py-2 pr-4 text-muted font-mono text-xs">30s</td><td class="py-2 pr-4 text-muted font-mono text-xs">Line count + ASCII sum of first chars</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">medium</td><td class="py-2 pr-4 text-muted font-mono text-xs">20s</td><td class="py-2 pr-4 text-muted font-mono text-xs">+ word count</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">hard</td><td class="py-2 pr-4 text-muted font-mono text-xs">15s</td><td class="py-2 pr-4 text-muted font-mono text-xs">+ character at specific position</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">extreme</td><td class="py-2 pr-4 text-muted font-mono text-xs">10s</td><td class="py-2 pr-4 text-muted font-mono text-xs">+ total character count</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">All verification behavior is configurable via <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">captchaOptions.verify</code>:</p><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Option</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Default</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">useServerTiming</td><td class="py-2 pr-4 text-muted font-mono text-xs">true</td><td class="py-2 pr-4 text-muted font-mono text-xs">Use server wall-clock time instead of trusting the agent&#x27;s solvedAt.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">timingToleranceSeconds</td><td class="py-2 pr-4 text-muted font-mono text-xs">2</td><td class="py-2 pr-4 text-muted font-mono text-xs">Extra seconds added to time limit for network latency.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">asciiTolerance</td><td class="py-2 pr-4 text-muted font-mono text-xs">0</td><td class="py-2 pr-4 text-muted font-mono text-xs">Allow ±N tolerance on ASCII sum comparison.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">revealConstraints</td><td class="py-2 pr-4 text-muted font-mono text-xs">true</td><td class="py-2 pr-4 text-muted font-mono text-xs">Include actual vs target values in verification results.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">consumeChallenge</td><td class="py-2 pr-4 text-muted font-mono text-xs">—</td><td class="py-2 pr-4 text-muted font-mono text-xs">Callback for one-time-use tokens. Return false to reject replays.</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">Override difficulty settings per tier with <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">captchaOptions.difficulties</code>:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4
95 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token plain">captchaOptions</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  secret</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">SIWA_SECRET</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  verify</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    useServerTiming</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    timingToleranceSeconds</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">5</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    revealConstraints</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">consumeChallenge</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">token</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=&gt;</span><span class="token plain"> redis</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token template-string template-punctuation string" style="color:rgb(173, 219, 103)">`</span><span class="token template-string string" style="color:rgb(173, 219, 103)">captcha:</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation">token</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string template-punctuation string" style="color:rgb(173, 219, 103)">`</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&#x27;1&#x27;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&#x27;NX&#x27;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&#x27;EX&#x27;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">60</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">
95then</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">r </span><span class="token operator" style="color:rgb(127, 219, 202)">=&gt;</span><span class="token plain"> r </span><span class="token operator" style="color:rgb(127, 219, 202)">===</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&#x27;OK&#x27;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  difficulties</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    easy</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> timeLimitSeconds</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">45</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    extreme</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> timeLimitSeconds</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">8</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/captcha</code>.</p><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Export</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Side</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">solveCaptchaChallenge(nonceResponse, solver)</td><td class="py-2 pr-4 text-muted font-mono text-xs">Agent</td><td class="py-2 pr-4 text-muted font-mono text-xs">Detect + solve captcha from nonce response.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">retryWithCaptcha(response, request, ...)</td><td class="py-2 pr-4 text-muted font-mono text-xs">Agent</td><td class="py-2 pr-4 text-muted font-mono text-xs">Detect captcha in 401, solve, re-sign, return retry request. (from erc8128 module)</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">packCaptchaResponse(token, text)</td><td class="py-2 pr-4 text-muted font-mono text-xs">Agent</td><td class="py-2 pr-4 text-muted font-mono text-xs">Package solution for submission.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">createCaptchaChallenge(difficulty, opts)</td><td class="py-2 pr-4 text-muted font-mono text-xs">Server</td><td class="py-2 pr-4 text-muted font-mono text-xs">Generate challenge + HMAC-signed token.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">
95verifyCaptchaSolution(token, solution, secret, verifyOpts?)</td><td class="py-2 pr-4 text-muted font-mono text-xs">Server</td><td class="py-2 pr-4 text-muted font-mono text-xs">Verify all constraints + timing. Async.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">unpackCaptchaResponse(packed)</td><td class="py-2 pr-4 text-muted font-mono text-xs">Server</td><td class="py-2 pr-4 text-muted font-mono text-xs">Unpack agent response.</td></tr></tbody></table></div></div></section><section id="x402" class="scroll-mt-20 pb-16"><h2 class="font-mono text-xl font-semibold text-foreground mb-6">x402 Payments</h2><div id="x402-overview" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Overview</h3><p class="text-sm leading-relaxed text-muted mb-4">The <a href="https://www.x402.org/" target="_blank" rel="noopener noreferrer" class="text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200">x402 protocol</a> adds pay-per-request monetization to any SIWA-protected endpoint. When a route requires payment, the middleware enforces a two-gate flow: <strong class="text-foreground">SIWA authentication first</strong>, then <strong class="text-foreground">payment verification</strong>. Both must pass before the handler runs.</p><ol class="space-y-3 mb-6 text-sm leading-relaxed text-muted list-none"><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">1.</span><span>Agent sends a request with <strong class="text-foreground">ERC-8128 SIWA headers</strong> (always required).</span></li><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">2.</span><span>Middleware verifies SIWA identity. If invalid, returns <strong class="text-foreground">401</strong>.</span></li><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">3.</span><span>If no <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">Payment-Signature</code> header is present, returns <strong class="text-foreground">402</strong> with a <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">Payment-Required</code> header containing accepted payment options.</span></li><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">4.</span><span>Agent constructs a payment, encodes it as a <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">Payment-Signature</code> header, and retries.</span></li><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">5.</span><span>Middleware sends the payment to a <strong class="text-foreground">facilitator</strong> for verification and on-chain settlement.</span></li><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">6.</span><span>On success, the handler runs and the response includes a <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">Payment-Response</code> header with the transaction hash.</span></li></ol><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Header</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Direction</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">Payment-Required</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">Server to Agent</td><td class="py-2 pr-4 text-muted font-mono text-xs">Base64-encoded JSON with accepted payment options. Sent with 402 responses.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">Payment-Signature</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">Agent to Server</td><td class="py-2 pr-4 text-muted font-mono text-xs">Base64-encoded signed payment payload from the agent.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">Payment-Response</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">Server to Agent</td><td class="py-2 pr-4 text-muted font-mono text-xs">Base64-encoded settlement result with transaction hash.</td></tr></tbody></table></div></div><div id="x402-server" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Server Setup</h3><p class="text-sm leading-relaxed text-muted mb-4">Three things are needed to enable x402 on a route: a <strong class="text-foreground">facilitator client</strong> (verifies and settles payments), a <strong class="text-foreground">resource description</strong>, and an <strong class="text-foreground">accepts array</strong>
95 listing payment options.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  createFacilitatorClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token keyword" style="color:rgb(127, 219, 202)">type</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 139)">X402Config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;@buildersgarden/siwa/x402&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
96</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// 1. Create facilitator client</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> facilitator </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createFacilitatorClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  url</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;https://x402-facilitator.example.com&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
97</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// 2. Define x402 config</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> x402</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> X402Config </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  facilitator</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  resource</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    url</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;/api/premium&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    description</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;Premium data access&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  accepts</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      scheme</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;exact&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      network</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;eip155:84532&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain">      </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Base Sepolia</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      amount</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;1000000&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain">             </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// 1 USDC (6 decimals)</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      asset</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;0x036CbD53842c5426634e7929541eC2318f3dCF7e&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      payTo</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;0xYourAddress&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">      maxTimeoutSeconds</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">60</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">Pass the <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">x402</code> config to any framework middleware. Routes without <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">x402</code> remain SIWA-only (free).</p></div><div id="x402-sessions" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Sessions (Pay-Once)</h3><p class="text-sm leading-relaxed text-muted mb-4">By default, every request requires a new payment. Add <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">session</code> to the x402 config to enable <strong class="text-foreground">pay-once mode</strong>: the agent pays on the first request and subsequent requests within the TTL window pass through without payment.</p><p class="text-sm leading-relaxed text-muted mb-4">Sessions are keyed by <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">(address, resource.url)</code> — different agents and different routes are isolated from each other.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">
97import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  createFacilitatorClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  createMemoryX402SessionStore</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;@buildersgarden/siwa/x402&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
98</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> facilitator </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createFacilitatorClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  url</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> process</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">env</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token constant" style="color:rgb(130, 170, 255)">X402_FACILITATOR_URL</span><span class="token operator" style="color:rgb(127, 219, 202)">!</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
99</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// In-memory store (use Redis/DB in production)</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> sessionStore </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createMemoryX402SessionStore</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
100</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Pass to any middleware</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> x402Config </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  facilitator</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  resource</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> url</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;/api/premium&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> description</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">&quot;Premium access&quot;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  accepts</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">/* ... */</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  session</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    store</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> sessionStore</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">    ttl</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">3600_000</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain">  </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// 1 hour</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">On the first request, the agent pays and the middleware stores a session. On subsequent requests from the same agent to the same resource, the session is found and payment is skipped. After TTL expiry, payment is required again.</p><p class="text-sm leading-relaxed text-muted mb-4">For production, implement the <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">X402SessionStore</code> interface with a shared store:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">interface</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 139)">X402SessionStore</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">
100get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">address</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> resource</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">Promise</span><span class="token operator" style="color:rgb(127, 219, 202)">&lt;</span><span class="token plain">X402Session </span><span class="token operator" style="color:rgb(127, 219, 202)">|</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">null</span><span class="token operator" style="color:rgb(127, 219, 202)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">address</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> resource</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> session</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> X402Session</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> ttlMs</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">number</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">Promise</span><span class="token operator" style="color:rgb(127, 219, 202)">&lt;</span><span class="token keyword" style="color:rgb(127, 219, 202)">void</span><span class="token operator" style="color:rgb(127, 219, 202)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
101</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">interface</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 139)">X402Session</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  paidAt</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">number</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  txHash</span><span class="token operator" style="color:rgb(127, 219, 202)">?</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div><div id="x402-config" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Config Reference</h3><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Field</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Type</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">facilitator</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">FacilitatorClient</td><td class="py-2 pr-4 text-muted font-mono text-xs">Client for payment verification and settlement.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">resource</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">ResourceInfo</td><td class="py-2 pr-4 text-muted font-mono text-xs">The resource being paid for: { url, description? }.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">accepts</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">PaymentRequirements[]</td><td class="py-2 pr-4 text-muted font-mono text-xs">
101Array of accepted payment options.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">session?</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">X402SessionConfig</td><td class="py-2 pr-4 text-muted font-mono text-xs">Optional pay-once session: { store, ttl }.</td></tr></tbody></table></div><div class="mt-6 mb-3"><h4 class="font-mono text-sm font-semibold text-foreground">PaymentRequirements</h4></div><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Field</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Type</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">scheme</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Payment scheme (e.g. <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">&quot;exact&quot;</code>).</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">network</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Chain identifier (e.g. <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">&quot;eip155:84532&quot;</code>).</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">amount</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Payment amount in smallest unit (e.g. wei, USDC base units).</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">asset</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Token contract address.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">payTo</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Recipient address.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">maxTimeoutSeconds?</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">number</td><td class="py-2 pr-4 text-muted font-mono text-xs">Maximum time for settlement.</td></tr></tbody></table></div><div class="mt-6 mb-3"><h4 class="font-mono text-sm font-semibold text-foreground">X402Payment (verified payment on request)</h4></div><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Field</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Type</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">scheme</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Payment scheme.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">network</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Chain identifier.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">amount</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Amount paid.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">asset</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Token address.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">payTo</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Recipient address.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">txHash?</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">On-chain transaction hash from settlement.</td></tr></tbody></table></div><div class="mt-6 mb-3"><h4 class="font-mono text-sm font-semibold text-foreground">FacilitatorClient</h4></div><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Method</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Returns</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">verify(payload, requirements)</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">VerifyResponse</td><td class="py-2 pr-4 text-muted font-mono text-xs">Validate a payment signature.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">settle(payload, requirements)</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">SettleResponse</td><td class="py-2 pr-4 text-muted font-mono text-xs">Execute on-chain settlement. Returns txHash on success.</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">Use <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">createFacilitatorClient(<!-- -->{ url }<!-- -->)</code> to create a client that POSTs to <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">/verify</code> and <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">/settle</code> endpoints on the facilitator. Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/x402</code>.</p></div><div id="x402-middleware" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Middleware</h3><p class="text-sm leading-relaxed text-muted mb-4">Each framework wrapper accepts an optional <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">x402</code> field. When set, both SIWA authentication <strong class="text-foreground">and</strong> a valid payment are required. The verified payment is available in the handler.</p><div id="x402-express" class="scroll-mt-20 mt-8 mb-2"><h4 class="font-mono text-sm font-semibold text-foreground">Express</h4><p class="text-xs text-dim mb-3">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/express</code>. Payment is available on <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">req.payment</code>.</p></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Express x402 Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span>
101<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import express from &quot;express&quot;;
102import { siwaMiddleware, siwaJsonParser, siwaCors } from &quot;@buildersgarden/siwa/express&quot;;
103import { createFacilitatorClient } from &quot;@buildersgarden/siwa/x402&quot;;<!-- -->
104...</code></pre></div></div><div id="x402-next" class="scroll-mt-20 mt-8 mb-2"><h4 class="font-mono text-sm font-semibold text-foreground">Next.js</h4><p class="text-xs text-dim mb-3">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/next</code>. Payment is the 3rd argument to the handler.</p></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Next.js x402 Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>// app/api/premium/route.ts
105import { withSiwa, siwaOptions } from &quot;@buildersgarden/siwa/next&quot;;
106import { createFacilitatorClient } from &quot;@buildersgarden/siwa/x402&quot;;<!-- -->
107...</code></pre></div></div><div id="x402-hono" class="scroll-mt-20 mt-8 mb-2"><h4 class="font-mono text-sm font-semibold text-foreground">Hono</h4><p class="text-xs text-dim mb-3">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/hono</code>. Payment is available via <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">c.get(&quot;payment&quot;)</code>.</p></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Hono x402 Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import { Hono } from &quot;hono&quot;;
108import { siwaMiddleware, siwaCors } from &quot;@buildersgarden/siwa/hono&quot;;
109import { createFacilitatorClient } from &quot;@buildersgarden/siwa/x402&quot;;<!-- -->
110...</code></pre></div></div><div id="x402-fastify" class="scroll-mt-20 mt-8 mb-2"><h4 class="font-mono text-sm font-semibold text-foreground">Fastify</h4><p class="text-xs text-dim mb-3">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/fastify</code>. Payment is available on <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">req.payment</code>.</p></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Fastify x402 Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span>
110<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import Fastify from &quot;fastify&quot;;
111import { siwaPlugin, siwaAuth } from &quot;@buildersgarden/siwa/fastify&quot;;
112import { createFacilitatorClient } from &quot;@buildersgarden/siwa/x402&quot;;<!-- -->
113...</code></pre></div></div></div><div id="x402-agent" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Agent-Side</h3><p class="text-sm leading-relaxed text-muted mb-4">When an agent receives a <strong class="text-foreground">402</strong> response, it should:</p><ol class="space-y-2 mb-4 text-sm leading-relaxed text-muted list-none"><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">1.</span><span>Read the <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">Payment-Required</code> header and decode the payment options.</span></li><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">2.</span><span>Construct a <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">PaymentPayload</code> with the signed payment.</span></li><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">3.</span><span>Encode it as a <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">Payment-Signature</code> header and retry the request.</span></li></ol><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Agent Payment Flow</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import {
114  encodeX402Header,
115  decodeX402Header,<!-- -->
116...</code></pre></div></div></div></section><section id="identity" class="scroll-mt-20 pb-16"><h2 class="font-mono text-xl font-semibold text-foreground mb-6">Identity &amp; Registry</h2><p class="text-sm leading-relaxed text-muted mb-4">Read and write agent identity state, and query onchain profiles.</p><div id="identity-file" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Identity File</h3><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Function</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">ensureIdentityExists(path, template)</td><td class="py-2 pr-4 text-muted font-mono text-xs">Initialize SIWA_IDENTITY.md if missing.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">readIdentity(path)</td><td class="py-2 pr-4 text-muted font-mono text-xs">Parse SIWA_IDENTITY.md to typed object.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">writeIdentityField(key, value, path)</td><td class="py-2 pr-4 text-muted font-mono text-xs">Write a field to SIWA_IDENTITY.md.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">isRegistered({ identityPath, client? })</td><td class="py-2 pr-4 text-muted font-mono text-xs">Check registration status.</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/identity</code>.</p></div><div id="identity-registry" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Onchain Registry</h3><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Function</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Returns</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">registerAgent(options)</td><td class="py-2 pr-4 text-muted font-mono text-xs">RegisterResult</td><td class="py-2 pr-4 text-muted font-mono text-xs">
116Register as ERC-8004 agent onchain.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">getAgent(agentId, options)</td><td class="py-2 pr-4 text-muted font-mono text-xs">AgentProfile</td><td class="py-2 pr-4 text-muted font-mono text-xs">Read agent profile from registry.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">getReputation(agentId, options)</td><td class="py-2 pr-4 text-muted font-mono text-xs">ReputationSummary</td><td class="py-2 pr-4 text-muted font-mono text-xs">Read agent reputation.</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/registry</code>.</p></div></section><section id="protocol" class="scroll-mt-20 pb-16"><h2 class="font-mono text-xl font-semibold text-foreground mb-6">Protocol Specification</h2><div id="protocol-message" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Message Format</h3><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token plain">{domain} wants you to sign in with your Agent account:</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">{address}</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
117</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">{statement}</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
118</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">URI: {uri}</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">Version: 1</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">Agent ID: {agentId}</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">Agent Registry: {agentRegistry}</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">Chain ID: {chainId}</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">Nonce: {nonce}</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">Issued At: {issuedAt}</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">[Expiration Time: {expirationTime}]</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">[Not Before: {notBefore}]</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">[Request ID: {requestId}]</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div><div id="protocol-fields" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Field Definitions</h3><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Field</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Required</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">domain</td><td class="py-2 pr-4 text-muted font-mono text-xs">Yes</td><td class="py-2 pr-4 text-muted font-mono text-xs">Origin domain requesting authentication.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">address</td><td class="py-2 pr-4 text-muted font-mono text-xs">Yes</td><td class="py-2 pr-4 text-muted font-mono text-xs">Agent wallet address. Must be EIP-55 checksummed (mixed-case encoding).</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">statement</td><td class="py-2 pr-4 text-muted font-mono text-xs">No</td><td class="py-2 pr-4 text-muted font-mono text-xs">Human-readable purpose string.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">uri</td><td class="py-2 pr-4 text-muted font-mono text-xs">Yes</td><td class="py-2 pr-4 text-muted font-mono text-xs">RFC 3986 URI of the resource.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">version</td><td class="py-2 pr-4 text-muted font-mono text-xs">Yes</td><td class="py-2 pr-4 text-muted font-mono text-xs">Must be &quot;1&quot;.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">agentId</td><td class="py-2 pr-4 text-muted font-mono text-xs">Yes</td><td class="py-2 pr-4 text-muted font-mono text-xs">ERC-721 tokenId in the Identity Registry (numeric).</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">agentRegistry</td><td class="py-2 pr-4 text-muted font-mono text-xs">Yes</td><td class="py-2 pr-4 text-muted font-mono text-xs">CAIP-10 reference: eip155:{chainId}:{registryAddress}. See Address Formatting.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">chainId</td><td class="py-2 pr-4 text-muted font-mono text-xs">Yes</td><td class="py-2 pr-4 text-muted font-mono text-xs">EIP-155 chain ID (numeric). Must match the chain in agentRegistry.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">nonce</td><td class="py-2 pr-4 text-muted font-mono text-xs">Yes</td><td class="py-2 pr-4 text-muted font-mono text-xs">Server-generated, &gt;= 8 alphanumeric chars.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">issuedAt</td><td class="py-2 pr-4 text-muted font-mono text-xs">Yes</td><td class="py-2 pr-4 text-muted font-mono text-xs">RFC 3339 datetime.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">expirationTime</td><td class="py-2 pr-4 text-muted font-mono text-xs">No</td><td class="py-2 pr-4 text-muted font-mono text-xs">RFC 3339 datetime.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">notBefore</td><td class="py-2 pr-4 text-muted font-mono text-xs">No</td><td class="py-2 pr-4 text-muted font-mono text-xs">RFC 3339 datetime.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">requestId</td><td class="py-2 pr-4 text-muted font-mono text-xs">No</td><td class="py-2 pr-4 text-muted font-mono text-xs">Opaque request identifier.</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">See <a href="#contracts-format" class="text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200">Address Formatting Standards</a> for details on CAIP-10, EIP-55, and EIP-155.</p></div><div id="protocol-vs-siwe" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">SIWA vs SIWE</h3><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Aspect</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">SIWE (EIP-4361)</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">SIWA</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Purpose</td><td class="py-2 pr-4 text-muted font-mono text-xs">Human wallet auth</td><td class="py-2 pr-4 text-muted font-mono text-xs">Agent identity auth</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Identity proof</td><td class="py-2 pr-4 text-muted font-mono text-xs">Owns an Ethereum address</td><td class="py-2 pr-4 text-muted font-mono text-xs">Owns an ERC-8004 agent NFT</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Onchain check</td><td class="py-2 pr-4 text-muted font-mono text-xs">None required</td><td class="py-2 pr-4 text-muted font-mono text-xs">ownerOf(agentId) REQUIRED</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Extra fields</td><td class="py-2 pr-4 text-muted font-mono text-xs">None</td><td class="py-2 pr-4 text-muted font-mono text-xs">agentId, agentRegistry</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Signing</td><td class="py-2 pr-4 text-muted font-mono text-xs">EIP-191</td><td class="py-2 pr-4 text-muted font-mono text-xs">EIP-191 (same)</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Message prefix</td><td class="py-2 pr-4 text-muted font-mono text-xs">...your Ethereum account</td><td class="py-2 pr-4 text-muted font-mono text-xs">...your Agent account</td></tr></tbody></table></div></div></section><section id="contracts" class="scroll-mt-20 pb-16"><h2 class="font-mono text-xl font-semibold text-foreground mb-6">Contract Addresses</h2><div id="contracts-mainnet" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Mainnet</h3><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Chain</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Chain ID</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Identity Registry</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Reputation Registry</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Ethereum</td><td class="py-2 pr-4 text-muted font-mono text-xs">1</td><td class="py-2 pr-4"><span class="inline-flex items-center gap-1.5 group"><code class="font-mono text-xs text-muted">0x8004A169FB4a3325136EB29fA0ceB6D2e539a432</code><button class="opacity-0 group-hover:opacity-100 transition-opacity duration-200 cursor-pointer" aria-label="Copy 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim hover:text-muted"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg></button></span></td><td class="py-2 pr-4"><span class="inline-flex items-center gap-1.5 group"><code class="font-mono text-xs text-muted">0x8004BAa17C55a88189AE136b182e5fdA19dE9b63</code><button class="opacity-0 group-hover:opacity-100 transition-opacity duration-200 cursor-pointer" aria-label="Copy 0x8004BAa17C55a88189AE136b182e5fdA19dE9b63"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim hover:text-muted"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg></button></span></td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Base</td><td class="py-2 pr-4 text-muted font-mono text-xs">8453</td><td class="py-2 pr-4"><span class="inline-flex items-center gap-1.5 group"><code class="font-mono text-xs text-muted">0x8004A169FB4a3325136EB29fA0ceB6D2e539a432</code><button class="opacity-0 group-hover:opacity-100 transition-opacity duration-200 cursor-pointer" aria-label="Copy 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim hover:text-muted"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg></button></span></td><td class="py-2 pr-4"><span class="inline-flex items-center gap-1.5 group"><code class="font-mono text-xs text-muted">0x8004BAa17C55a88189AE136b182e5fdA19dE9b63</code><button class="opacity-0 group-hover:opacity-100 transition-opacity duration-200 cursor-pointer" aria-label="Copy 0x8004BAa17C55a88189AE136b182e5fdA19dE9b63"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim hover:text-muted"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg></button></span></td></tr></tbody></table></div></div><div id="contracts-testnet" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Testnets</h3><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Chain</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Chain ID</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Identity Registry</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Ethereum Sepolia</td><td class="py-2 pr-4 text-muted font-mono text-xs">11155111</td><td class="py-2 pr-4"><span class="inline-flex items-center gap-1.5 group"><code class="font-mono text-xs text-muted">0x8004A818BFB912233c491871b3d84c89A494BD9e</code><button class="opacity-0 group-hover:opacity-100 transition-opacity duration-200 cursor-pointer" aria-label="Copy 0x8004A818BFB912233c491871b3d84c89A494BD9e"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim hover:text-muted"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg></button></span></td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Base Sepolia</td><td class="py-2 pr-4 text-muted font-mono text-xs">84532</td><td class="py-2 pr-4"><span class="inline-flex items-center gap-1.5 group"><code class="font-mono text-xs text-muted">0x8004A818BFB912233c491871b3d84c89A494BD9e</code><button class="opacity-0 group-hover:opacity-100 transition-opacity duration-200 cursor-pointer" aria-label="Copy 0x8004A818BFB912233c491871b3d84c89A494BD9e"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim hover:text-muted"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg></button></span></td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Linea Sepolia</td><td class="py-2 pr-4 text-muted font-mono text-xs">59141</td><td class="py-2 pr-4"><span class="inline-flex items-center gap-1.5 group"><code class="font-mono text-xs text-muted">0x8004A818BFB912233c491871b3d84c89A494BD9e</code><button class="opacity-0 group-hover:opacity-100 transition-opacity duration-200 cursor-pointer" aria-label="Copy 0x8004A818BFB912233c491871b3d84c89A494BD9e"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim hover:text-mu
118ted"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg></button></span></td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Polygon Amoy</td><td class="py-2 pr-4 text-muted font-mono text-xs">80002</td><td class="py-2 pr-4"><span class="inline-flex items-center gap-1.5 group"><code class="font-mono text-xs text-muted">0x8004A818BFB912233c491871b3d84c89A494BD9e</code><button class="opacity-0 group-hover:opacity-100 transition-opacity duration-200 cursor-pointer" aria-label="Copy 0x8004A818BFB912233c491871b3d84c89A494BD9e"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim hover:text-muted"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg></button></span></td></tr></tbody></table></div></div><div id="contracts-format" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Address Formatting Standards</h3><p class="text-sm leading-relaxed text-muted mb-4">SIWA uses standardized address formats from the blockchain ecosystem:</p><div class="mt-4 mb-2"><h4 class="font-mono text-sm font-semibold text-foreground">CAIP-10: Agent Registry Reference</h4><p class="text-xs text-dim mt-1 mb-3"><a href="https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-10.md" target="_blank" rel="noopener noreferrer" class="text-accent hover:underline">CAIP-10</a> (Chain Agnostic Improvement Proposal) defines a standard way to reference blockchain accounts across different networks.</p></div><p class="text-sm leading-relaxed text-muted mb-4">The <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">agentRegistry</code> field uses CAIP-10 format to uniquely identify the ERC-8004 Identity Registry contract on a specific chain:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token plain">{namespace}:{chainId}:{contractAddress}</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
119</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">Format breakdown:</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  namespace       = &quot;eip155&quot; (EVM-compatible chains per EIP-155)</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  chainId         = numeric chain identifier (e.g., 8453 for Base)</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  contractAddress = EIP-55 checksummed contract address</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block">
120</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">Examples:</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  eip155:8453:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432    (Base mainnet)</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e   (Base Sepolia)</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">  eip155:1:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432      (Ethereum mainnet)</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><div class="mt-6 mb-2"><h4 class="font-mono text-sm font-semibold text-foreground">EIP-55: Checksummed Addresses</h4><p class="text-xs text-dim mt-1 mb-3"><a href="https://eips.ethereum.org/EIPS/eip-55" target="_blank" rel="noopener noreferrer" class="text-accent hover:underline">EIP-55</a> defines mixed-case checksum encoding for Ethereum addresses.</p></div><p class="text-sm leading-relaxed text-muted mb-4">All wallet addresses (<code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">address</code> field) must be EIP-55 checksummed. This provides error detection for typos:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token plain">Correct (checksummed):   0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">Incorrect (lowercase):   0x742d35cc6634c0532925a3b844bc9e7595f0beb0</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">Most libraries (viem, ethers.js) automatically return checksummed addresses. You can use <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">getAddress()</code> from viem to ensure proper formatting.</p><div class="mt-6 mb-2"><h4 class="font-mono text-sm font-semibold text-foreground">EIP-155: Chain IDs</h4><p class="text-xs text-dim mt-1 mb-3"><a href="https://eips.ethereum.org/EIPS/eip-155" target="_blank" rel="noopener noreferrer" class="text-accent hover:underline">EIP-155</a> introduced chain IDs to prevent replay attacks across different networks.</p></div><p class="text-sm leading-relaxed text-muted mb-4">The <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">chainId</code> field identifies which blockchain network the agent is registered on. Common chain IDs:</p><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Network</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Chain ID</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Type</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Ethereum</td><td class="py-2 pr-4 text-muted font-mono text-xs">1</td><td class="py-2 pr-4 text-muted font-mono text-xs">Mainnet</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Base</td><td class="py-2 pr-4 text-muted font-mono text-xs">8453</td><td class="py-2 pr-4 text-muted font-mono text-xs">Mainnet</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Base Sepolia</td><td class="py-2 pr-4 text-muted font-mono text-xs">84532</td><td class="py-2 pr-4 text-muted font-mono text-xs">Testnet</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Ethereum Sepolia</td><td class="py-2 pr-4 text-muted font-mono text-xs">11155111</td><td class="py-2 pr-4 text-muted font-mono text-xs">Testnet</td></tr></tbody></table></div></div><div id="contracts-rpc" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Public RPC Endpoints</h3><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Chain</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">RPC URL</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Base</td><td class="py-2 pr-4 text-muted font-mono text-xs">https://mainnet.base.org</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Ethereum Sepolia</td><td class="py-2 pr-4 text-muted font-mono text-xs">https://rpc.sepolia.org</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Base Sepolia</td><td class="py-2 pr-4 text-muted font-mono text-xs">https://sepolia.base.org</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Linea Sepolia</td><td class="py-2 pr-4 text-muted font-mono text-xs">https://rpc.sepolia.linea.build</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Polygon Amoy</td><td class="py-2 pr-4 text-muted font-mono text-xs">https://rpc-amoy.polygon.technology</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">For production, use a provider like Alchemy or Infura with your own API key.</p></div><div id="contracts-explorer" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Explorer</h3><p class="text-sm leading-relaxed text-muted mb-4">View registered agents at<!-- --> <a href="https://www.8004scan.io/" target="_blank" rel="noopener noreferrer" class="text-accent hover:text-blue-400 transition-colors duration-200 underline underline-offset-4 cursor-pointer">8004scan.io</a></p></div></section><div class="mt-4 grid gap-4 sm:grid-cols-2"><a href="/docs/endpoints" class="rounded-lg border border-border bg-surface p-5 hover:border-accent/40 transition-colors duration-200 cursor-pointer block"><h4 class="font-mono text-sm font-semibold text-foreground mb-1">API Endpoints</h4><p class="text-xs text-muted">Live HTTP endpoints to try the full SIWA auth flow.</p></a><a href="/docs/deploy" class="rounded-lg border border-border bg-surface p-5 hover:border-accent/40 transition-colors duration-200 cursor-pointer block"><h4 class="font-mono text-sm font-semibold text-foreground mb-1">Deploy Keyring Proxy</h4><p class="text-xs text-muted">Self-hosted key management with optional 2FA for AI agents.</p></a></div></article></div><!--$--><!--/$--></main><footer class="border-t border-border py-8 text-sm text-dim"><div class="mx-auto max-w-5xl px-6 flex flex-col items-center gap-3"><div>Built by<!-- --> <a href="https://builders.garden" target="_blank" rel="noopener noreferrer" class="text-foreground hover:text-accent transition-colors duration-200 cursor-pointer">Builders Garden</a> <!-- -->&amp;<!-- --> <a href="https://ai.ethereum.foundation/" target="_blank" rel="noopener noreferrer" class="text-foreground hover:text-accent transition-colors duration-200 cursor-pointer">dAI team</a></div><div>SIWA<!-- --> <span class="text-border mx-2">/</span> <a href="https://8004.org" target="_blank" rel="noopener noreferrer" class="hover:text-muted transition-colors duration-200 cursor-pointer">ERC-8004</a> <span class="text-border mx-2">/</span> <a href="https://erc8128.org/" target="_blank" rel="noopener noreferrer" class="hover:text-muted transition-colors duration-200 cursor-pointer">ERC-8128</a> <span class="text-border mx-2">/</span> <a href="https://github.com/builders-garden/siwa/blob/main/LICENSE" target="_blank" rel="noopener noreferrer" class="hover:text-muted transition-colors duration-200 cursor-pointer">MIT License</a></div></div></footer>
120<script src="/_next/static/chunks/7f7d21b762b07143.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7" id="_R_" async=""></script>
120<script>(self.__next_f=self.__next_f||[]).push([0])</script>
120<script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[26431,[\"/_next/static/chunks/da6c1156e80d635a.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"Navbar\"]\n3:I[3097,[\"/_next/static/chunks/33074d3ff5d0cd2d.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/4141b86737d3d211.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"default\"]\n4:I[99299,[\"/_next/static/chunks/33074d3ff5d0cd2d.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/4141b86737d3d211.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"default\"]\n5:I[24023,[\"/_next/static/chunks/da6c1156e80d635a.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/b9e18a9181222732.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/1d3b3a30a1d781ce.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"DocsSidebar\"]\n16:I[16153,[],\"default\"]\n:HL[\"/_next/static/chunks/43ec3b8db83f7d7e.css?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"style\"]\n:HL[\"/_next/static/media/797e433ab948586e-s.p.dbea232f.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n"])</script>
120<script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"J85DJ4d2-pu0tm2EaWtIp\",\"c\":[\"\",\"docs\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"docs\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/43ec3b8db83f7d7e.css?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/da6c1156e80d635a.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"children\":[\"$\",\"body\",null,{\"className\":\"geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable antialiased font-sans\",\"children\":[[\"$\",\"$L2\",null,{}],[\"$\",\"main\",null,{\"className\":\"pt-14\",\"children\":[\"$\",\"$L3\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L4\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],[]],\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}],[\"$\",\"footer\",null,{\"className\":\"border-t border-border py-8 text-sm text-dim\",\"children\":[\"$\",\"div\",null,{\"className\":\"mx-auto max-w-5xl px-6 flex flex-col items-center gap-3\",\"children\":[[\"$\",\"div\",null,{\"children\":[\"Built by\",\" \",[\"$\",\"a\",null,{\"href\":\"https://builders.garden\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"className\":\"text-foreground hover:text-accent transition-colors duration-200 cursor-pointer\",\"children\":\"Builders Garden\"}],\" \",\"\u0026\",\" \",[\"$\",\"a\",null,{\"href\":\"https://ai.ethereum.foundation/\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"className\":\"text-foreground hover:text-accent transition-colors duration-200 cursor-pointer\",\"children\":\"dAI team\"}]]}],[\"$\",\"div\",null,{\"children\":[\"SIWA\",\" \",[\"$\",\"span\",null,{\"className\":\"text-border mx-2\",\"children\":\"/\"}],\" \",[\"$\",\"a\",null,{\"href\":\"https://8004.org\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"className\":\"hover:text-muted transition-colors duration-200 cursor-pointer\",\"children\":\"ERC-8004\"}],\" \",[\"$\",\"span\",null,{\"className\":\"text-border mx-2\",\"children\":\"/\"}],\" \",[\"$\",\"a\",null,{\"href\":\"https://erc8128.org/\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"className\":\"hover:text-muted transition-colors duration-200 cursor-pointer\",\"children\":\"ERC-8128\"}],\" \",[\"$\",\"span\",null,{\"className\":\"text-border mx-2\",\"children\":\"/\"}],\" \",[\"$\",\"a\",null,{\"href\":\"https://github.com/builders-garden/siwa/blob/main/LICENSE\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"className\":\"hover:text-muted transition-colors duration-200 cursor-pointer\",\"children\":\"MIT License\"}]]}]]}]}]]}]}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L3\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L4\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"div\",null,{\"className\":\"mx-auto flex max-w-6xl px-6 py-12\",\"children\":[[\"$\",\"$L5\",null,{}],[\"$\",\"article\",null,{\"className\":\"min-w-0 flex-1 pl-0 md:pl-12\",\"children\":[[\"$\",\"div\",null,{\"className\":\"mb-6 rounded-lg bg-yellow-500/10 border border-yellow-500/30 px-5 py-3\",\"children\":[\"$\",\"p\",null,{\"className\":\"text-sm font-mono text-yellow-400\",\"children\":[\"This project is a work in progress. Use at your own risk — we welcome\",\" \",[\"$\",\"a\",null,{\"href\":\"https://github.com/builders-garden/siwa\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"className\":\"underline underline-offset-2 hover:text-yellow-300 transition-colors duration-200\",\"children\":\"feedback and contributions\"}],\".\"]}]}],\"$L6\",\"$L7\",\"$L8\",\"$L9\",\"$La\",\"$Lb\",\"$Lc\",\"$Ld\",\"$Le\",\"$Lf\",\"$L10\",\"$L11\"]}]]}],[\"$L12\",\"$L13\"],\"$L14\"]}],{}
120,null,false,false]},null,false,false]},null,false,false],\"$L15\",false]],\"m\":\"$undefined\",\"G\":[\"$16\",[]],\"S\":true}\n"])</script>
120<script>self.__next_f.push([1,"17:I[70832,[\"/_next/static/chunks/da6c1156e80d635a.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/b9e18a9181222732.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/1d3b3a30a1d781ce.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"GettingStartedTabs\"]\n18:I[80661,[\"/_next/static/chunks/da6c1156e80d635a.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/b9e18a9181222732.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/1d3b3a30a1d781ce.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"ImageModal\"]\n19:I[98067,[\"/_next/static/chunks/da6c1156e80d635a.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/b9e18a9181222732.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/1d3b3a30a1d781ce.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"CodeBlock\"]\n1a:I[98067,[\"/_next/static/chunks/da6c1156e80d635a.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/b9e18a9181222732.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/1d3b3a30a1d781ce.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"CollapsibleCodeBlock\"]\n56:I[33875,[\"/_next/static/chunks/da6c1156e80d635a.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/b9e18a9181222732.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/1d3b3a30a1d781ce.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"CopyableAddress\"]\n5a:I[36345,[\"/_next/static/chunks/33074d3ff5d0cd2d.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/4141b86737d3d211.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"OutletBoundary\"]\n5b:\"$Sreact.suspense\"\n5d:I[36345,[\"/_next/static/chunks/33074d3ff5d0cd2d.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/4141b86737d3d211.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"ViewportBoundary\"]\n5f:I[36345,[\"/_next/static/chunks/33074d3ff5d0cd2d.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/4141b86737d3d211.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"MetadataBoundary\"]\n6:[\"$\",\"h1\",null,{\"className\":\"font-mono text-2xl font-bold text-foreground mb-2\",\"children\":\"SIWA Documentation\"}]\n7:[\"$\",\"p\",null,{\"className\":\"text-sm text-dim mb-8\",\"children\":\"Sign In With Agent — v1.0\"}]\n8:[\"$\",\"div\",null,{\"className\":\"mb-12 rounded-lg border border-accent/30 bg-accent/5 px-5 py-4\",\"children\":[[\"$\",\"p\",null,{\"className\":\"text-sm text-muted leading-relaxed\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent\",\"children\":\"What is SIWA?\"}],\" \",\"SIWA (Sign In With Agent) helps AI agents authenticate with services using their\",\" \",[\"$\",\"a\",null,{\"href\":\"https://8004.org\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"className\":\"text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200\",\"children\":\"ERC-8004\"}],\" \",\"onchain identity. Like SIWE (Sign In With Ethereum) for humans, but for agents with verifiable registration.\"]}],[\"$\",\"p\",null,{\"className\":\"text-sm text-muted leading-relaxed mt-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent\",\"children\":\"For AI agents:\"}],\" \",\"Read\",\" \",[\"$\",\"a\",null,{\"href\":\"https://siwa.id/skill.md\",\"className\":\"text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200 cursor-pointer\",\"children\":\"/skill.md\"}],\" \",\"for structured instructions.\"]}]]}]\n"])</script>
120<script>self.__next_f.push([1,"9:[\"$\",\"section\",null,{\"id\":\"getting-started\",\"className\":\"scroll-mt-20 pb-16\",\"children\":[[\"$\",\"h2\",null,{\"className\":\"font-mono text-xl font-semibold text-foreground mb-6\",\"children\":\"Getting Started\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"SIWA provides two core capabilities:\"}],[\"$\",\"ul\",null,{\"className\":\"space-y-2 mb-6 text-sm leading-relaxed text-muted list-none\",\"children\":[[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"•\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Agent-side:\"}],\" Sign SIWA messages to prove ownership of an ERC-8004 identity\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"•\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Server-side:\"}],\" Verify signatures and check onchain registration with multiple modular criteria\"]}]]}]]}],[\"$\",\"$L17\",null,{}],[\"$\",\"div\",null,{\"className\":\"mt-8 mb-4 grid gap-3 sm:grid-cols-3\",\"children\":[[\"$\",\"a\",null,{\"href\":\"#wallets\",\"className\":\"rounded-lg border border-border bg-surface px-4 py-3 hover:border-accent/40 transition-colors duration-200 cursor-pointer block\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-xs font-semibold text-foreground mb-1\",\"children\":\"Wallet Options\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim\",\"children\":\"Use any wallet: Bankr, Circle, Openfort, Privy, private key, or keyring proxy.\"}]]}],[\"$\",\"a\",null,{\"href\":\"#api\",\"className\":\"rounded-lg border border-border bg-surface px-4 py-3 hover:border-accent/40 transition-colors duration-200 cursor-pointer block\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-xs font-semibold text-foreground mb-1\",\"children\":\"API Reference\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim\",\"children\":\"SDK functions, modules, and types.\"}]]}],[\"$\",\"a\",null,{\"href\":\"#protocol\",\"className\":\"rounded-lg border border-border bg-surface px-4 py-3 hover:border-accent/40 transition-colors duration-200 cursor-pointer block\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-xs font-semibold text-foreground mb-1\",\"children\":\"Protocol Spec\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim\",\"children\":\"Message format and authentication flow.\"}]]}]]}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"a:[\"$\",\"section\",null,{\"id\":\"architecture\",\"className\":\"scroll-mt-20 pb-16\",\"children\":[[\"$\",\"h2\",null,{\"className\":\"font-mono text-xl font-semibold text-foreground mb-6\",\"children\":\"How It Works\"}],[\"$\",\"div\",null,{\"id\":\"auth-flow\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Authentication Flow\"}],[[\"$\",\"ol\",null,{\"className\":\"space-y-3 mb-6 text-sm leading-relaxed text-muted list-none\",\"children\":[[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"1.\"}],[\"$\",\"span\",null,{\"children\":[\"The agent requests a \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"nonce\"}],\" from the service, sending its address and agent ID.\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"2.\"}],[\"$\",\"span\",null,{\"children\":\"The service returns the nonce along with timestamps.\"}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"3.\"}],[\"$\",\"span\",null,{\"children\":[\"The agent builds a SIWA message and \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"signs it\"}],\" with its wallet.\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"4.\"}],[\"$\",\"span\",null,{\"children\":\"The agent sends the message and signature to the service.\"}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"5.\"}],[\"$\",\"span\",null,{\"children\":[\"The service \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"verifies\"}],\" the signature and calls the blockchain to confirm the agent owns that identity NFT.\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"6.\"}],[\"$\",\"span\",null,{\"children\":[\"If verified, the service returns a \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"receipt\"}],\". The agent uses this for subsequent authenticated requests.\"]}]]}]]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"The SDK provides two main functions:\"}],[\"$\",\"ul\",null,{\"className\":\"space-y-2 mb-6 text-sm leading-relaxed text-muted list-none\",\"children\":[[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"•\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Agent-side:\"}],\" \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"signSIWAMessage(fields, signer)\"}],\" — builds and signs the message\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"•\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Server-side:\"}],\" \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"verifySIWA(message, signature, domain, nonceValid, client, criteria?)\"}],\" — validates signature and checks onchain ownership\"]}]]}]]}],[\"$\",\"$L18\",null,{\"src\":\"/siwa-flow.png\",\"alt\":\"SIWA authentication flow: Agent requests nonce, signs SIWA message, Service verifies signature and checks onchain ownership, returns HMAC-signed verification receipt, then subsequent API requests use ERC-8128 HTTP signatures\",\"className\":\"w-full rounded-lg border border-border\",\"width\":800,\"height\"
120:730}]]]}]]}]\n"])</script>
120<script>self.__next_f.push([1,"b:[\"$\",\"section\",null,{\"id\":\"signing\",\"className\":\"scroll-mt-20 pb-16\",\"children\":[[\"$\",\"h2\",null,{\"className\":\"font-mono text-xl font-semibold text-foreground mb-6\",\"children\":\"Signing (Agent-Side)\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Everything an agent needs to authenticate: choose a signer, sign SIWA messages for initial sign-in, then sign subsequent API requests with ERC-8128. \",[\"$\",\"br\",null,{}],\" SIWA supports both \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"EOA\"}],\" (Externally Owned Account) and \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"SCA\"}],\" (Smart Contract Account) signers — agents backed by smart wallets like Safe, Base Accounts, or ERC-6551 Token Bound Accounts work alongside traditional EOA-based agents.\"]}],[\"$\",\"div\",null,{\"id\":\"wallet-bankr\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Bankr\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Bankr's Agent API provides smart contract wallets (ERC-4337) for AI agents with built-in signing capabilities. No additional SDK is needed — the signer communicates directly with the Bankr API over HTTP. Signatures are verified via ERC-1271 automatically.\"}],[\"$\",\"$L19\",null,{\"language\":\"bash\",\"children\":\"# No extra package needed — only @buildersgarden/siwa\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Create a signer from your Bankr API key:\"}],[\"$\",\"$L1a\",null,{\"title\":\"Bankr Signer Example\",\"language\":\"typescript\",\"children\":\"import { signSIWAMessage } from \\\"@buildersgarden/siwa\\\";\\nimport { createBankrSiwaSigner } from \\\"@buildersgarden/siwa/signer\\\";\\n\\n// Create signer - wallet address is fetched automatically from Bankr\\nconst signer = await createBankrSiwaSigner({\\n  apiKey: process.env.BANKR_API_KEY!,\\n});\\n\\n// Sign SIWA message\\nconst { message, signature, address } = await signSIWAMessage({\\n  domain: \\\"api.example.com\\\",\\n  uri: \\\"https://api.example.com/siwa\\\",\\n  agentId: 42,\\n  agentRegistry: \\\"eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e\\\",\\n  chainId: 84532,\\n  nonce,\\n  issuedAt: new Date().toISOString(),\\n}, signer);\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Already using Bankr's \",[\"$\",\"a\",null,{\"href\":\"https://github.com/BankrBot/openclaw-skills/tree/main/bankr\",\"className\":\"text-accent hover:underline\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"children\":\"OpenClaw trading skill\"}],\" for swaps and DeFi? This signer adds SIWA authentication on top — same API key, same wallet.\"]}]]]}],[\"$\",\"div\",null,{\"id\":\"wallet-circle\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Circle\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Circle's developer-controlled wallets provide secure key management for AI agents. Install the Circle SDK alongside SIWA:\"}],[\"$\",\"$L19\",null,{\"language\":\"bash\",\"children\":\"npm install @circle-fin/developer-controlled-wallets\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Create a signer from your Circle wallet credentials:\"}],[\"$\",\"$L1a\",null,{\"title\":\"Circle Signer Example\",\"language\":\"typescript\",\"children\":\"import { signSIWAMessage } from \\\"@buildersgarden/siwa\\\";\\nimport { createCircleSiwaSigner } from \\\"@buildersgarden/siwa/signer\\\";\\n\\n// Create signer - wallet address is fetched automatically from Circle\\nconst signer = await createCircleSiwaSigner({\\n  apiKey: process.env.CIRCLE_API_KEY!,\\n  entitySecret: process.env.CIRCLE_ENTITY_SECRET!,\\n  walletId: process.env.CIRCLE_WALLET_ID!,\\n});
120\\n\\n// Sign SIWA message\\nconst { message, signature, address } = await signSIWAMessage({\\n  domain: \\\"api.example.com\\\",\\n  uri: \\\"https://api.example.com/siwa\\\",\\n  agentId: 42,\\n  agentRegistry: \\\"eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e\\\",\\n  chainId: 84532,\\n  nonce,\\n  issuedAt: new Date().toISOString(),\\n}, signer);\"}],\"$L1b\",\"$L1c\"]]}],\"$L1d\",\"$L1e\",\"$L1f\",\"$L20\",\"$L21\",\"$L22\",\"$L23\"]]}]\n"])</script>
120<script>self.__next_f.push([1,"c:[\"$\",\"section\",null,{\"id\":\"verification\",\"className\":\"scroll-mt-20 pb-16\",\"children\":[[\"$\",\"h2\",null,{\"className\":\"font-mono text-xl font-semibold text-foreground mb-6\",\"children\":\"Verification (Server-Side)\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Everything a service needs to verify agents: validate SIWA sign-in, verify ERC-8128 signed requests, issue receipts, and plug into Express or Next.js.\"}],[\"$\",\"div\",null,{\"id\":\"verify-siwa\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"SIWA Verification\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Verify a signed SIWA message, check onchain ownership, and optionally validate ERC-8004 agent profile criteria. Implement two endpoints:\"}],[\"$\",\"ul\",null,{\"className\":\"space-y-2 mb-4 text-sm leading-relaxed text-muted list-none\",\"children\":[[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"1.\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"/siwa/nonce\"}],\" — Issue a nonce for the agent to sign\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"2.\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"/siwa/verify\"}],\" — Verify the signed message and issue a receipt\"]}]]}]]}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Function\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Function\"}],[\"$\",\"th\",\"Returns\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Returns\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"verifySIWA(msg, sig, domain, nonceValid, client, criteria?)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"SIWAVerificationResult\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Verify signature + onchain ownership + criteria.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"parseSIWAMessage(message)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"SIWAMessageFields\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Parse SIWA message string to fields.\"}]]}]]}]]}]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa\"}],\". Parameters:\"]}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Parameter\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Parameter\"}],[\"$\",\"th\",\"Type\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Type\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"message\"}],\"$L24\",\"$L25\"]}],\"$L26\",\"$L27\",\"$L28\",\"$L29\",\"$L2a\"]}]]}]}],\"$L2b\",\"$L2c\",\"$L2d\",\"$L2e\",\"$L2f\",\"$L30\",\"$L31\",\"$L32\",\"$L33\",\"$L34\",\"$L35\",\"$L36\",\"$L37\",\"$L38\"]]}],\"$L39\",\"$L3a\",\"$L3b\",\"$L3c\",\"$L3d\",\"$L3e\",\"$L3f\",\"$L40\",\"$L41\",\"$L42\",\"$L43\",\"$L44\",\"$L45\"]]}]\n"])</script>
120<script>self.__next_f.push([1,"d:[\"$\",\"section\",null,{\"id\":\"x402\",\"className\":\"scroll-mt-20 pb-16\",\"children\":[[\"$\",\"h2\",null,{\"className\":\"font-mono text-xl font-semibold text-foreground mb-6\",\"children\":\"x402 Payments\"}],[[\"$\",\"div\",null,{\"id\":\"x402-overview\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Overview\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"The \",[\"$\",\"a\",null,{\"href\":\"https://www.x402.org/\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"className\":\"text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200\",\"children\":\"x402 protocol\"}],\" adds pay-per-request monetization to any SIWA-protected endpoint. When a route requires payment, the middleware enforces a two-gate flow: \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"SIWA authentication first\"}],\", then \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"payment verification\"}],\". Both must pass before the handler runs.\"]}],[\"$\",\"ol\",null,{\"className\":\"space-y-3 mb-6 text-sm leading-relaxed text-muted list-none\",\"children\":[[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"1.\"}],[\"$\",\"span\",null,{\"children\":[\"Agent sends a request with \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"ERC-8128 SIWA headers\"}],\" (always required).\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"2.\"}],[\"$\",\"span\",null,{\"children\":[\"Middleware verifies SIWA identity. If invalid, returns \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"401\"}],\".\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"3.\"}],[\"$\",\"span\",null,{\"children\":[\"If no \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"Payment-Signature\"}],\" header is present, returns \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"402\"}],\" with a \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"Payment-Required\"}],\" header containing accepted payment options.\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"4.\"}],[\"$\",\"span\",null,{\"children\":[\"Agent constructs a payment, encodes it as a \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"Payment-Signature\"}],\" header, and retries.\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"5.\"}],[\"$\",\"span\",null,{\"children\":[\"Middleware sends the payment to a \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"facilitator\"}],\" for verification and on-chain settlement.\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"6.\"}],[\"$\",\"span\",null,{\"children\":[\"On success, the handler runs and the response includes a \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"Payment-Response\"}],\" header with the transaction hash.\"]}]]}]]}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Header\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Header\"}],[\"$\",\"th\",\"Direction\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Direction\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],\"$L46\"]}]}]]]}],\"$L47\",\"$L48\",\"$L49\",\"$L4a\",\"$L4b\"]]}]\n"])</script>
120<script>self.__next_f.push([1,"e:[\"$\",\"section\",null,{\"id\":\"identity\",\"className\":\"scroll-mt-20 pb-16\",\"children\":[[\"$\",\"h2\",null,{\"className\":\"font-mono text-xl font-semibold text-foreground mb-6\",\"children\":\"Identity \u0026 Registry\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Read and write agent identity state, and query onchain profiles.\"}],[\"$\",\"div\",null,{\"id\":\"identity-file\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Identity File\"}],[[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Function\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Function\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"ensureIdentityExists(path, template)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Initialize SIWA_IDENTITY.md if missing.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"readIdentity(path)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Parse SIWA_IDENTITY.md to typed object.\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"writeIdentityField(key, value, path)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Write a field to SIWA_IDENTITY.md.\"}]]}],[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"isRegistered({ identityPath, client? })\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Check registration status.\"}]]}]]}]]}]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/identity\"}],\".\"]}]]]}],[\"$\",\"div\",null,{\"id\":\"identity-registry\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Onchain Registry\"}],[[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Function\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Function\"}],[\"$\",\"th\",\"Returns\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Returns\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"registerAgent(options)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"RegisterResult\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Register as ERC-8004 agent onchain.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"getAgent(agentId, options)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"AgentProfile\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Read agent profile from registry.\"}]]}],\"$L4c\"]}]]}]}],\"$L4d\"]]}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"f:[\"$\",\"section\",null,{\"id\":\"protocol\",\"className\":\"scroll-mt-20 pb-16\",\"children\":[[\"$\",\"h2\",null,{\"className\":\"font-mono text-xl font-semibold text-foreground mb-6\",\"children\":\"Protocol Specification\"}],[[\"$\",\"div\",null,{\"id\":\"protocol-message\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Message Format\"}],[\"$\",\"$L19\",null,{\"language\":\"text\",\"children\":\"{domain} wants you to sign in with your Agent account:\\n{address}\\n\\n{statement}\\n\\nURI: {uri}\\nVersion: 1\\nAgent ID: {agentId}\\nAgent Registry: {agentRegistry}\\nChain ID: {chainId}\\nNonce: {nonce}\\nIssued At: {issuedAt}\\n[Expiration Time: {expirationTime}]\\n[Not Before: {notBefore}]\\n[Request ID: {requestId}]\"}]]}],[\"$\",\"div\",null,{\"id\":\"protocol-fields\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Field Definitions\"}],[[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Field\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Field\"}],[\"$\",\"th\",\"Required\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Required\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"domain\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Yes\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Origin domain requesting authentication.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"address\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Yes\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Agent wallet address. Must be EIP-55 checksummed (mixed-case encoding).\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"statement\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"No\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Human-readable purpose string.\"}]]}],[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"uri\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Yes\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"RFC 3986 URI of the resource.\"}]]}],[\"$\",\"tr\",\"4\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"version\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Yes\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Must be \\\"1\\\".\"}]]}],[\"$\",\"tr\",\"5\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"agentId\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Yes\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"ERC-721 tokenId in the Identity Registry (numeric).\"}]]}],[\"$\",\"tr\",\"6\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"agentRegistry\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Yes\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"CAIP-10 reference: eip155:{chainId}:{registryAddress}. See Address Formatting.\"}]]}],\"$L4e\",\"$L4f\",\"$L50\",\"$L51\",\"$L52\",\"$L53\"]}]]}]}],\"$L54\"]]}],\"$L55\"]]}]\n"])</script>
120<script>self.__next_f.push([1,"10:[\"$\",\"section\",null,{\"id\":\"contracts\",\"className\":\"scroll-mt-20 pb-16\",\"children\":[[\"$\",\"h2\",null,{\"className\":\"font-mono text-xl font-semibold text-foreground mb-6\",\"children\":\"Contract Addresses\"}],[[\"$\",\"div\",null,{\"id\":\"contracts-mainnet\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Mainnet\"}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",null,{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Chain\"}],[\"$\",\"th\",null,{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Chain ID\"}],[\"$\",\"th\",null,{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Identity Registry\"}],[\"$\",\"th\",null,{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Reputation Registry\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",null,{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",null,{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Ethereum\"}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"1\"}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4\",\"children\":[\"$\",\"$L56\",null,{\"address\":\"0x8004A169FB4a3325136EB29fA0ceB6D2e539a432\"}]}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4\",\"children\":[\"$\",\"$L56\",null,{\"address\":\"0x8004BAa17C55a88189AE136b182e5fdA19dE9b63\"}]}]]}],[\"$\",\"tr\",null,{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",null,{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Base\"}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"8453\"}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4\",\"children\":[\"$\",\"$L56\",null,{\"address\":\"0x8004A169FB4a3325136EB29fA0ceB6D2e539a432\"}]}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4\",\"children\":[\"$\",\"$L56\",null,{\"address\":\"0x8004BAa17C55a88189AE136b182e5fdA19dE9b63\"}]}]]}]]}]]}]}]]}],[\"$\",\"div\",null,{\"id\":\"contracts-testnet\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Testnets\"}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",null,{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Chain\"}],[\"$\",\"th\",null,{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Chain ID\"}],[\"$\",\"th\",null,{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Identity Registry\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",null,{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",null,{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Ethereum Sepolia\"}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"11155111\"}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4\",\"children\":[\"$\",\"$L56\",null,{\"address\":\"0x8004A818BFB912233c491871b3d84c89A494BD9e\"}]}]]}],[\"$\",\"tr\",null,{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",null,{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Base Sepolia\"}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"84532\"}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4\",\"children\":[\"$\",\"$L56\",null,{\"address\":\"0x8004A818BFB912233c491871b3d84c89A494BD9e\"}]}]]}],[\"$\",\"tr\",null,{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",null,{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Linea Sepolia\"}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"59141\"}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4\",\"children\":[\"$\",\"$L56\",null,{\"address\":\"0x8004A818BFB912233c491871b3d84c89A494BD9e\"}]}]]}],[\"$\",\"tr\",null,{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",null,{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Polygon Amoy\"}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"80002\"}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4\",\"children\":[\"$\",\"$L56\",null,{\"address\":\"0x8004A818BFB912233c491871b3d84c89A494BD9e\"}]}]]}]]}]]}]}]]}],\"$L57\",\"$L58\",\"$L59\"]]}]\n"])</script>
120<script>self.__next_f.push([1,"11:[\"$\",\"div\",null,{\"className\":\"mt-4 grid gap-4 sm:grid-cols-2\",\"children\":[[\"$\",\"a\",null,{\"href\":\"/docs/endpoints\",\"className\":\"rounded-lg border border-border bg-surface p-5 hover:border-accent/40 transition-colors duration-200 cursor-pointer block\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground mb-1\",\"children\":\"API Endpoints\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-muted\",\"children\":\"Live HTTP endpoints to try the full SIWA auth flow.\"}]]}],[\"$\",\"a\",null,{\"href\":\"/docs/deploy\",\"className\":\"rounded-lg border border-border bg-surface p-5 hover:border-accent/40 transition-colors duration-200 cursor-pointer block\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground mb-1\",\"children\":\"Deploy Keyring Proxy\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-muted\",\"children\":\"Self-hosted key management with optional 2FA for AI agents.\"}]]}]]}]\n12:[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/b9e18a9181222732.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"async\":true,\"nonce\":\"$undefined\"}]\n13:[\"$\",\"script\",\"script-1\",{\"src\":\"/_next/static/chunks/1d3b3a30a1d781ce.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"async\":true,\"nonce\":\"$undefined\"}]\n14:[\"$\",\"$L5a\",null,{\"children\":[\"$\",\"$5b\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@5c\"}]}]\n15:[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$L5d\",null,{\"children\":\"$L5e\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$L5f\",null,{\"children\":[\"$\",\"$5b\",null,{\"name\":\"Next.Metadata\",\"children\":\"$L60\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}]\n"])</script>
120<script>self.__next_f.push([1,"1b:[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"If you already have a Circle client instance, use \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"createCircleSiwaSignerFromClient\"}],\":\"]}]\n1c:[\"$\",\"$L1a\",null,{\"title\":\"From Existing Client\",\"language\":\"typescript\",\"children\":\"import { initiateDeveloperControlledWalletsClient } from \\\"@circle-fin/developer-controlled-wallets\\\";\\nimport { createCircleSiwaSignerFromClient } from \\\"@buildersgarden/siwa/signer\\\";\\n\\nconst client = initiateDeveloperControlledWalletsClient({\\n  apiKey: process.env.CIRCLE_API_KEY!,\\n  entitySecret: process.env.CIRCLE_ENTITY_SECRET!,\\n});\\n\\nconst signer = await createCircleSiwaSignerFromClient({\\n  client,\\n  walletId: process.env.CIRCLE_WALLET_ID!,\\n});\"}]\n"])</script>
120<script>self.__next_f.push([1,"1d:[\"$\",\"div\",null,{\"id\":\"wallet-openfort\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Openfort\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Openfort's backend wallets provide secure key management and account abstraction for AI agents. Install the Openfort Node SDK alongside SIWA:\"}],[\"$\",\"$L19\",null,{\"language\":\"bash\",\"children\":\"npm install @openfort/openfort-node\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Create a signer from your Openfort wallet credentials:\"}],[\"$\",\"$L1a\",null,{\"title\":\"Openfort Signer Example\",\"language\":\"typescript\",\"children\":\"import { signSIWAMessage } from \\\"@buildersgarden/siwa\\\";\\nimport { createOpenfortSiwaSigner } from \\\"@buildersgarden/siwa/signer\\\";\\n\\n// Create signer - wallet address is fetched automatically from Openfort\\nconst signer = await createOpenfortSiwaSigner({\\n  apiKey: process.env.OPENFORT_PROJECT_PUBLISHABLE_KEY!,\\n  walletSecret: process.env.OPENFORT_WALLET_SECRET!,\\n  accountId: process.env.OPENFORT_BACKEND_WALLET_ACCOUNT_ID!,\\n});\\n\\n// Sign SIWA message\\nconst { message, signature, address } = await signSIWAMessage({\\n  domain: \\\"api.example.com\\\",\\n  uri: \\\"https://api.example.com/siwa\\\",\\n  agentId: 42,\\n  agentRegistry: \\\"eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e\\\",\\n  chainId: 84532,\\n  nonce,\\n  issuedAt: new Date().toISOString(),\\n}, signer);\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"If you already have an Openfort client instance, use \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"createOpenfortSiwaSignerFromClient\"}],\":\"]}],[\"$\",\"$L1a\",null,{\"title\":\"From Existing Client\",\"language\":\"typescript\",\"children\":\"import Openfort from \\\"@openfort/openfort-node\\\";\\nimport { createOpenfortSiwaSignerFromClient } from \\\"@buildersgarden/siwa/signer\\\";\\n\\nconst client = new Openfort(process.env.OPENFORT_PROJECT_PUBLISHABLE_KEY!, {\\n  walletSecret: process.env.OPENFORT_WALLET_SECRET!,\\n});\\n\\nconst signer = await createOpenfortSiwaSignerFromClient({\\n  client,\\n  accountId: process.env.OPENFORT_BACKEND_WALLET_ACCOUNT_ID!,\\n});\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"1e:[\"$\",\"div\",null,{\"id\":\"wallet-privy\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Privy\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Privy's server wallets provide embedded wallet infrastructure for AI agents. Install the Privy Node SDK alongside SIWA:\"}],[\"$\",\"$L19\",null,{\"language\":\"bash\",\"children\":\"npm install @privy-io/node\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Create a signer from your Privy wallet:\"}],[\"$\",\"$L1a\",null,{\"title\":\"Privy Signer Example\",\"language\":\"typescript\",\"children\":\"import { PrivyClient } from \\\"@privy-io/node\\\";\\nimport { signSIWAMessage } from \\\"@buildersgarden/siwa\\\";\\nimport { createPrivySiwaSigner } from \\\"@buildersgarden/siwa/signer\\\";\\n\\nconst privy = new PrivyClient({\\n  appId: process.env.PRIVY_APP_ID!,\\n  appSecret: process.env.PRIVY_APP_SECRET!,\\n});\\n\\nconst signer = createPrivySiwaSigner({\\n  client: privy,\\n  walletId: process.env.PRIVY_WALLET_ID!,\\n  walletAddress: process.env.PRIVY_WALLET_ADDRESS! as `0x${string}`,\\n});\\n\\n// Sign SIWA message\\nconst { message, signature, address } = await signSIWAMessage({\\n  domain: \\\"api.example.com\\\",\\n  uri: \\\"https://api.example.com/siwa\\\",\\n  agentId: 42,\\n  agentRegistry: \\\"eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e\\\",\\n  chainId: 84532,\\n  nonce,\\n  issuedAt: new Date().toISOString(),\\n}, signer);\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"1f:[\"$\",\"div\",null,{\"id\":\"wallet-privatekey\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Private Key (Backend Scripts)\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"For server-side agents or scripts with direct private key access:\"}],[\"$\",\"$L1a\",null,{\"title\":\"Private Key Signer Example\",\"language\":\"typescript\",\"children\":\"import { signSIWAMessage } from \\\"@buildersgarden/siwa\\\";\\nimport { createLocalAccountSigner } from \\\"@buildersgarden/siwa/signer\\\";\\nimport { privateKeyToAccount } from \\\"viem/accounts\\\";\\n\\nconst account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);\\nconst signer = createLocalAccountSigner(account);\\n\\n// Sign SIWA message\\nconst { message, signature } = await signSIWAMessage({\\n  domain: \\\"api.example.com\\\",\\n  uri: \\\"https://api.example.com/siwa\\\",\\n  agentId: 42,\\n  agentRegistry: \\\"eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e\\\",\\n  chainId: 84532,\\n  nonce,\\n  issuedAt: new Date().toISOString(),\\n}, signer);\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"20:[\"$\",\"div\",null,{\"id\":\"wallet-keyring\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Keyring Proxy (Self-Hosted, Non-Custodial)\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"For AI agents that need secure key isolation, we provide an optional \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"keyring proxy\"}],\" — a separate service that holds the encrypted private key and performs all signing. The agent never touches the key.\"]}],[\"$\",\"$L1a\",null,{\"title\":\"Keyring Proxy Example\",\"language\":\"typescript\",\"children\":\"import { signSIWAMessage } from \\\"@buildersgarden/siwa\\\";\\nimport { createKeyringProxySigner } from \\\"@buildersgarden/siwa/signer\\\";\\n\\nconst signer = createKeyringProxySigner({\\n  proxyUrl: process.env.KEYRING_PROXY_URL,\\n  proxySecret: process.env.KEYRING_PROXY_SECRET,\\n});\\n\\n// Sign SIWA message\\nconst { message, signature } = await signSIWAMessage({\\n  domain: \\\"api.example.com\\\",\\n  uri: \\\"https://api.example.com/siwa\\\",\\n  agentId: 42,\\n  agentRegistry: \\\"eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e\\\",\\n  chainId: 84532,\\n  nonce,\\n  issuedAt: new Date().toISOString(),\\n}, signer);\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"The keyring proxy is completely optional. It's useful when you want:\"}],[\"$\",\"ul\",null,{\"className\":\"space-y-2 mb-4 text-sm leading-relaxed text-muted list-none\",\"children\":[[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"•\"}],[\"$\",\"span\",null,{\"children\":\"Key isolation from the agent process (protection against prompt injection)\"}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"•\"}],[\"$\",\"span\",null,{\"children\":\"Optional 2FA via Telegram for transaction approval\"}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"•\"}],[\"$\",\"span\",null,{\"children\":\"Self-hosted, non-custodial key management\"}]]}]]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"See\",\" \",[\"$\",\"a\",null,{\"href\":\"/docs/deploy\",\"className\":\"text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200\",\"children\":\"Deploy\"}],\" \",\"for keyring proxy setup, architecture, and security model.\"]}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"21:[\"$\",\"div\",null,{\"id\":\"smart-accounts\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Smart Accounts\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Smart contract wallets (Safe, ZeroDev/Kernel, Coinbase Smart Wallet) work with the same \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"createWalletClientSigner\"}],\" — their SDKs expose a standard WalletClient or EIP-1193 provider. The SDK detects the signer type automatically during verification via ERC-1271.\"]}],[\"$\",\"$L1a\",null,{\"title\":\"Smart Account Example\",\"language\":\"typescript\",\"children\":\"import { signSIWAMessage } from \\\"@buildersgarden/siwa\\\";\\nimport { createWalletClientSigner } from \\\"@buildersgarden/siwa/signer\\\";\\nimport { createWalletClient, custom } from \\\"viem\\\";\\nimport { baseSepolia } from \\\"viem/chains\\\";\\n\\n// Safe example\\nimport Safe from \\\"@safe-global/protocol-kit\\\";\\nconst safe = await Safe.init({ provider, safeAddress });\\nconst walletClient = createWalletClient({\\n  chain: baseSepolia,\\n  transport: custom(safe.getProvider()),\\n});\\nconst signer = createWalletClientSigner(walletClient);\\n\\n// ZeroDev / Kernel example\\n// const walletClient = kernelClient.toWalletClient();\\n// const signer = createWalletClientSigner(walletClient);\\n\\n// Sign SIWA message — same as any other signer\\nconst { message, signature } = await signSIWAMessage({\\n  domain: \\\"api.example.com\\\",\\n  uri: \\\"https://api.example.com/siwa\\\",\\n  agentId: 42,\\n  agentRegistry: \\\"eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e\\\",\\n  chainId: 84532,\\n  nonce,\\n  issuedAt: new Date().toISOString(),\\n}, signer);\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"61:T46d,import { signSIWAMessage } from \"@buildersgarden/siwa\";\n\n// Step 1: Request nonce from server\nconst nonceRes = await fetch(\"https://api.example.com/siwa/nonce\", {\n  method: \"POST\",\n  headers: { \"Content-Type\": \"application/json\" },\n  body: JSON.stringify({\n    address: await signer.getAddress(),\n    agentId: 42,\n    agentRegistry: \"eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e\",\n  }),\n});\nconst { nonce, issuedAt, expirationTime } = await nonceRes.json();\n\n// Step 2: Sign the SIWA message\nconst { message, signature, address } = await signSIWAMessage({\n  domain: \"api.example.com\",\n  uri: \"https://api.example.com/siwa\",\n  agentId: 42,\n  agentRegistry: \"eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e\",\n  chainId: 84532,\n  nonce,\n  issuedAt,\n  expirationTime,\n}, signer);\n\n// Step 3: Send to server for verification\nconst verifyRes = await fetch(\"https://api.example.com/siwa/verify\", {\n  method: \"POST\",\n  headers: { \"Content-Type\": \"application/json\" },\n  body: JSON.stringify({ message, signature }),\n});\n\nconst { receipt, agentId } = await verifyRes.json();\n// Store the receipt for authenticated API calls"])</script>
120<script>self.__next_f.push([1,"22:[\"$\",\"div\",null,{\"id\":\"signing-siwa\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"SIWA Sign-In\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Build and sign a SIWA message to prove ownership of an ERC-8004 identity. The authentication flow consists of two steps:\"}],[\"$\",\"ul\",null,{\"className\":\"space-y-2 mb-4 text-sm leading-relaxed text-muted list-none\",\"children\":[[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"1.\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Get a nonce\"}],\" from the server's \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"/siwa/nonce\"}],\" endpoint\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"2.\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Sign and verify\"}],\" by sending the signature to \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"/siwa/verify\"}]]}]]}]]}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Function\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Function\"}],[\"$\",\"th\",\"Returns\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Returns\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"signSIWAMessage(fields, signer)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"{ message, signature, address }\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Build and sign a SIWA message.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"buildSIWAMessage(fields)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Build a formatted SIWA message string.\"}]]}]]}]]}]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa\"}],\".\"]}],[\"$\",\"$L1a\",null,{\"title\":\"Full Authentication Flow\",\"language\":\"typescript\",\"children\":\"$61\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"23:[\"$\",\"div\",null,{\"id\":\"signing-erc8128\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"ERC-8128 Request Signing\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"After SIWA sign-in, sign every outgoing API request with ERC-8128 HTTP Message Signatures.\"}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Function\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Function\"}],[\"$\",\"th\",\"Returns\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Returns\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"signAuthenticatedRequest(req, receipt, signer, chainId, options?)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Request\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Sign outgoing request with ERC-8128.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"createErc8128Signer(signer, chainId, options?)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"EthHttpSigner\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Create ERC-8128 HTTP signer from SIWA Signer.\"}]]}]]}]]}]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/erc8128\"}],\".\"]}],[\"$\",\"$L1a\",null,{\"title\":\"Request Signing Example\",\"language\":\"typescript\",\"children\":\"import { signAuthenticatedRequest } from \\\"@buildersgarden/siwa/erc8128\\\";\\n\\nconst request = new Request(\\\"https://api.example.com/action\\\", {\\n  method: \\\"POST\\\",\\n  headers: { \\\"Content-Type\\\": \\\"application/json\\\" },\\n  body: JSON.stringify({ action: \\\"transfer\\\" }),\\n});\\n\\nconst signedRequest = await signAuthenticatedRequest(\\n  request,\\n  receipt,  // from SIWA sign-in\\n  signer,\\n  84532\\n);\\n\\nconst response = await fetch(signedRequest);\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"24:[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}]\n25:[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"The full SIWA message string.\"}]\n26:[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"signature\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"EIP-191 signature hex string.\"}]]}]\n27:[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"expectedDomain\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Must match message domain.\"}]]}]\n28:[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"nonceValid\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"function | object\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"Nonce validator: callback (nonce) =\u003e boolean, \",\"{ nonceToken, secret }\",\" for stateless, or \",\"{ nonceStore }\",\" for store-based replay protection. See \",[\"$\",\"a\",null,{\"href\":\"#nonce-store\",\"className\":\"text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200\",\"children\":\"Nonce Store\"}],\".\"]}]]}]\n29:[\"$\",\"tr\",\"4\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"client\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"PublicClient\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"viem PublicClient for onchain verification.\"}]]}]\n2a:[\"$\",\"tr\",\"5\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"criteria?\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"SIWAVerifyCriteria\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Optional criteria to filter agents (see below).\"}]]}]\n2b:[\"$\",\"div\",null,{\"className\":\"mt-4 mb-4\",\"children\":[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground mb-3\",\"children\":\"Criteria Options\"}]}]\n2c:[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Use criteria to enforce policies on which agents can authenticate. These are checked during sign-in and encoded into the receipt.\"}]\n"])</script>
120<script>self.__next_f.push([1,"2d:[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Criteria\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Criteria\"}],[\"$\",\"th\",\"Type\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Type\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"allowedSignerTypes\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"('eoa' | 'sca')[]\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Restrict to EOA-only or allow smart contract accounts.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"mustBeActive\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"boolean\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Require agent metadata.active === true.\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"requiredServices\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string[]\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Agent must support these services (e.g., 'llm', 'web3').\"}]]}],[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"requiredTrust\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string[]\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Agent must support these trust models (e.g., 'tee', 'crypto-economic').\"}]]}],[\"$\",\"tr\",\"4\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"minScore\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"number\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Minimum reputation score (requires reputationRegistryAddress).\"}]]}],[\"$\",\"tr\",\"5\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"minFeedbackCount\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"number\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Minimum feedback count (requires reputationRegistryAddress).\"}]]}],[\"$\",\"tr\",\"6\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"reputationRegistryAddress\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Reputation registry address for score/feedback checks.\"}]]}],[\"$\",\"tr\",\"7\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"custom\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"(agent) =\u003e Promise\u003cboolean\u003e\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Custom validation function with full agent profile.\"}]]}]]}]]}]}]\n"])</script>
120<script>self.__next_f.push([1,"2e:[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"The result includes \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"signerType\"}],\" and optionally \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"agent\"}],\" (full profile if criteria fetched metadata).\"]}]\n2f:[\"$\",\"div\",null,{\"className\":\"mt-6 mb-3\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"Nonce Endpoint Examples\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mt-1\",\"children\":[\"Issue a nonce for the agent to sign. Import \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"createSIWANonce\"}],\" from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa\"}],\".\"]}]]}]\n30:[\"$\",\"$L1a\",null,{\"title\":\"Next.js Nonce Endpoint\",\"language\":\"typescript\",\"children\":\"// app/api/siwa/nonce/route.ts\\nimport { createSIWANonce } from \\\"@buildersgarden/siwa\\\";\\nimport { corsJson, siwaOptions } from \\\"@buildersgarden/siwa/next\\\";\\nimport { createPublicClient, http } from \\\"viem\\\";\\nimport { baseSepolia } from \\\"viem/chains\\\";\\n\\nconst client = createPublicClient({\\n  chain: baseSepolia,\\n  transport: http(process.env.RPC_URL),\\n});\\n\\n// Simple in-memory nonce store (use Redis in production)\\nconst nonceStore = new Map\u003cstring, number\u003e();\\n\\nexport async function POST(req: Request) {\\n  const { address, agentId, agentRegistry } = await req.json();\\n\\n  const result = await createSIWANonce(\\n    { address, agentId, agentRegistry },\\n    client,\\n  );\\n\\n  // Store nonce for verification\\n  nonceStore.set(result.nonce, Date.now());\\n\\n  return corsJson({\\n    nonce: result.nonce,\\n    issuedAt: result.issuedAt,\\n    expirationTime: result.expirationTime,\\n  });\\n}\\n\\nexport { siwaOptions as OPTIONS };\"}]\n31:[\"$\",\"$L1a\",null,{\"title\":\"Express Nonce Endpoint\",\"language\":\"typescript\",\"children\":\"// routes/siwa.ts\\nimport express from \\\"express\\\";\\nimport { createSIWANonce } from \\\"@buildersgarden/siwa\\\";\\nimport { siwaCors, siwaJsonParser } from \\\"@buildersgarden/siwa/express\\\";\\nimport { createPublicClient, http } from \\\"viem\\\";\\nimport { baseSepolia } from \\\"viem/chains\\\";\\n\\nconst router = express.Router();\\nrouter.use(siwaJsonParser());\\nrouter.use(siwaCors());\\n\\nconst client = createPublicClient({\\n  chain: baseSepolia,\\n  transport: http(process.env.RPC_URL),\\n});\\n\\nconst nonceStore = new Map\u003cstring, number\u003e();\\n\\nrouter.post(\\\"/nonce\\\", async (req, res) =\u003e {\\n  const { address, agentId, agentRegistry } = req.body;\\n\\n  const result = await createSIWANonce(\\n    { address, agentId, agentRegistry },\\n    client,\\n  );\\n\\n  nonceStore.set(result.nonce, Date.now());\\n\\n  res.json({\\n    nonce: result.nonce,\\n    issuedAt: result.issuedAt,\\n    expirationTime: result.expirationTime,\\n  });\\n});\\n\\nexport default router;\"}]\n32:[\"$\",\"$L1a\",null,{\"title\":\"Hono Nonce Endpoint\",\"language\":\"typescript\",\"children\":\"// src/routes/siwa.ts\\nimport { Hono } from \\\"hono\\\";\\nimport { cors } from \\\"hono/cors\\\";\\nimport { createSIWANonce } from \\\"@buildersgarden/siwa\\\";\\nimport { createPublicClient, http } from \\\"viem\\\";\\nimport { baseSepolia } from \\\"viem/chains\\\";\\n\\nconst app = new Hono();\\n\\napp.use(\\\"*\\\", cors({\\n  origin: \\\"*\\\",\\n  allowHeaders: [\\\"Content-Type\\\", \\\"X-SIWA-Receipt\\\", \\\"Signature\\\", \\\"Signature-Input\\\", \\\"Content-Digest\\\"],\\n}));\\n\\nconst client = createPublicClient({\\n  chain: baseSepolia,\\n  transport: http(process.env.RPC_URL),\\n});\\n\\nconst nonceStore = new Map\u003cstring, number\u003e();\\n\\napp.post(\\\"/nonce\\\", async (c) =\u003e {\\n  const { address, agentId, agentRegistry } = await c.req.json();\\n\\n  const result = await createSIWANonce(\\n    { address, agentId, agentRegistry },\\n    client,\\n  );\\n\\n  nonceStore.set(result.nonce, Date.now());\\n\\n  return c.json({\\n    nonce: result.nonce,\\n    issuedAt: result.issuedAt,\\n    expirationTime: result.e"])</script>
120<script>self.__next_f.push([1,"xpirationTime,\\n  });\\n});\\n\\nexport default app;\"}]\n33:[\"$\",\"$L1a\",null,{\"title\":\"Fastify Nonce Endpoint\",\"language\":\"typescript\",\"children\":\"// src/routes/siwa.ts\\nimport { FastifyPluginAsync } from \\\"fastify\\\";\\nimport { createSIWANonce } from \\\"@buildersgarden/siwa\\\";\\nimport { createPublicClient, http } from \\\"viem\\\";\\nimport { baseSepolia } from \\\"viem/chains\\\";\\n\\nconst client = createPublicClient({\\n  chain: baseSepolia,\\n  transport: http(process.env.RPC_URL),\\n});\\n\\nconst nonceStore = new Map\u003cstring, number\u003e();\\n\\nconst siwaRoutes: FastifyPluginAsync = async (fastify) =\u003e {\\n  fastify.post(\\\"/nonce\\\", async (req) =\u003e {\\n    const { address, agentId, agentRegistry } = req.body as {\\n      address: string;\\n      agentId: number;\\n      agentRegistry: string;\\n    };\\n\\n    const result = await createSIWANonce(\\n      { address, agentId, agentRegistry },\\n      client,\\n    );\\n\\n    nonceStore.set(result.nonce, Date.now());\\n\\n    return {\\n      nonce: result.nonce,\\n      issuedAt: result.issuedAt,\\n      expirationTime: result.expirationTime,\\n    };\\n  });\\n};\\n\\nexport default siwaRoutes;\"}]\n34:[\"$\",\"div\",null,{\"className\":\"mt-6 mb-3\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"Verify Endpoint Examples\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mt-1\",\"children\":\"Verify the signed message and issue a receipt.\"}]]}]\n62:T5a5,"])</script>
120<script>self.__next_f.push([1,"// app/api/siwa/verify/route.ts\nimport { verifySIWA } from \"@buildersgarden/siwa\";\nimport { createReceipt } from \"@buildersgarden/siwa/receipt\";\nimport { corsJson, siwaOptions } from \"@buildersgarden/siwa/next\";\nimport { createPublicClient, http } from \"viem\";\nimport { baseSepolia } from \"viem/chains\";\n\nconst client = createPublicClient({\n  chain: baseSepolia,\n  transport: http(process.env.RPC_URL),\n});\n\n// Simple in-memory nonce store (use Redis in production)\nconst nonceStore = new Map\u003cstring, number\u003e();\n\nexport async function POST(req: Request) {\n  const { message, signature } = await req.json();\n\n  const result = await verifySIWA(\n    message,\n    signature,\n    \"api.example.com\",\n    (nonce) =\u003e {\n      if (!nonceStore.has(nonce)) return false;\n      nonceStore.delete(nonce); // consume nonce\n      return true;\n    },\n    client,\n    {\n      allowedSignerTypes: [\"eoa\", \"sca\"],\n      mustBeActive: true,\n      requiredServices: [\"llm\"],\n    }\n  );\n\n  if (!result.valid) {\n    return corsJson({ error: result.error }, { status: 401 });\n  }\n\n  // Issue receipt for authenticated requests\n  const { receipt } = createReceipt({\n    address: result.address,\n    agentId: result.agentId,\n    agentRegistry: result.agentRegistry,\n    chainId: result.chainId,\n    signerType: result.signerType,\n  }, { secret: process.env.RECEIPT_SECRET! });\n\n  return corsJson({ receipt, agentId: result.agentId });\n}\n\nexport { siwaOptions as OPTIONS };"])</script>
120<script>self.__next_f.push([1,"35:[\"$\",\"$L1a\",null,{\"title\":\"Next.js Verify Endpoint\",\"language\":\"typescript\",\"children\":\"$62\"}]\n63:T5b8,"])</script>
120<script>self.__next_f.push([1,"// routes/siwa.ts (add to same router as nonce)\nimport { verifySIWA } from \"@buildersgarden/siwa\";\nimport { createReceipt } from \"@buildersgarden/siwa/receipt\";\nimport { siwaCors, siwaJsonParser } from \"@buildersgarden/siwa/express\";\nimport { createPublicClient, http } from \"viem\";\nimport { baseSepolia } from \"viem/chains\";\n\nconst router = express.Router();\nrouter.use(siwaJsonParser());\nrouter.use(siwaCors());\n\nconst client = createPublicClient({\n  chain: baseSepolia,\n  transport: http(process.env.RPC_URL),\n});\n\n// Simple in-memory nonce store (use Redis in production)\nconst nonceStore = new Map\u003cstring, number\u003e();\n\nrouter.post(\"/verify\", async (req, res) =\u003e {\n  const { message, signature } = req.body;\n\n  const result = await verifySIWA(\n    message,\n    signature,\n    \"api.example.com\",\n    (nonce) =\u003e {\n      if (!nonceStore.has(nonce)) return false;\n      nonceStore.delete(nonce);\n      return true;\n    },\n    client,\n    {\n      allowedSignerTypes: [\"eoa\", \"sca\"],\n      mustBeActive: true,\n      requiredServices: [\"llm\"],\n    }\n  );\n\n  if (!result.valid) {\n    return res.status(401).json({ error: result.error });\n  }\n\n  const { receipt } = createReceipt({\n    address: result.address,\n    agentId: result.agentId,\n    agentRegistry: result.agentRegistry,\n    chainId: result.chainId,\n    signerType: result.signerType,\n  }, { secret: process.env.RECEIPT_SECRET! });\n\n  res.json({ receipt, agentId: result.agentId });\n});\n\nexport default router;"])</script>
120<script>self.__next_f.push([1,"36:[\"$\",\"$L1a\",null,{\"title\":\"Express Verify Endpoint\",\"language\":\"typescript\",\"children\":\"$63\"}]\n64:T57f,"])</script>
120<script>self.__next_f.push([1,"// src/routes/siwa.ts (add to same app as nonce)\nimport { verifySIWA } from \"@buildersgarden/siwa\";\nimport { createReceipt } from \"@buildersgarden/siwa/receipt\";\nimport { createPublicClient, http } from \"viem\";\nimport { baseSepolia } from \"viem/chains\";\n\nconst app = new Hono();\n\napp.use(\"*\", cors({\n  origin: \"*\",\n  allowHeaders: [\"Content-Type\", \"X-SIWA-Receipt\", \"Signature\", \"Signature-Input\", \"Content-Digest\"],\n}));\n\nconst client = createPublicClient({\n  chain: baseSepolia,\n  transport: http(process.env.RPC_URL),\n});\n\nconst nonceStore = new Map\u003cstring, number\u003e();\n\napp.post(\"/verify\", async (c) =\u003e {\n  const { message, signature } = await c.req.json();\n\n  const result = await verifySIWA(\n    message,\n    signature,\n    \"api.example.com\",\n    (nonce) =\u003e {\n      if (!nonceStore.has(nonce)) return false;\n      nonceStore.delete(nonce);\n      return true;\n    },\n    client,\n    {\n      allowedSignerTypes: [\"eoa\", \"sca\"],\n      mustBeActive: true,\n      requiredServices: [\"llm\"],\n    }\n  );\n\n  if (!result.valid) {\n    return c.json({ error: result.error }, 401);\n  }\n\n  const { receipt } = createReceipt({\n    address: result.address,\n    agentId: result.agentId,\n    agentRegistry: result.agentRegistry,\n    chainId: result.chainId,\n    signerType: result.signerType,\n  }, { secret: process.env.RECEIPT_SECRET! });\n\n  return c.json({ receipt, agentId: result.agentId });\n});\n\nexport default app;"])</script>
120<script>self.__next_f.push([1,"37:[\"$\",\"$L1a\",null,{\"title\":\"Hono Verify Endpoint\",\"language\":\"typescript\",\"children\":\"$64\"}]\n65:T58c,"])</script>
120<script>self.__next_f.push([1,"// src/routes/siwa.ts (add to same plugin as nonce)\nimport { verifySIWA } from \"@buildersgarden/siwa\";\nimport { createReceipt } from \"@buildersgarden/siwa/receipt\";\nimport { createPublicClient, http } from \"viem\";\nimport { baseSepolia } from \"viem/chains\";\n\nconst client = createPublicClient({\n  chain: baseSepolia,\n  transport: http(process.env.RPC_URL),\n});\n\nconst nonceStore = new Map\u003cstring, number\u003e();\n\nconst siwaRoutes: FastifyPluginAsync = async (fastify) =\u003e {\n  fastify.post(\"/verify\", async (req, reply) =\u003e {\n    const { message, signature } = req.body as { message: string; signature: string };\n\n    const result = await verifySIWA(\n      message,\n      signature,\n      \"api.example.com\",\n      (nonce) =\u003e {\n        if (!nonceStore.has(nonce)) return false;\n        nonceStore.delete(nonce);\n        return true;\n      },\n      client,\n      {\n        allowedSignerTypes: [\"eoa\", \"sca\"],\n        mustBeActive: true,\n        requiredServices: [\"llm\"],\n      }\n    );\n\n    if (!result.valid) {\n      return reply.status(401).send({ error: result.error });\n    }\n\n    const { receipt } = createReceipt({\n      address: result.address,\n      agentId: result.agentId,\n      agentRegistry: result.agentRegistry,\n      chainId: result.chainId,\n      signerType: result.signerType,\n    }, { secret: process.env.RECEIPT_SECRET! });\n\n    return { receipt, agentId: result.agentId };\n  });\n};\n\nexport default siwaRoutes;"])</script>
120<script>self.__next_f.push([1,"38:[\"$\",\"$L1a\",null,{\"title\":\"Fastify Verify Endpoint\",\"language\":\"typescript\",\"children\":\"$65\"}]\n"])</script>
120<script>self.__next_f.push([1,"39:[\"$\",\"div\",null,{\"id\":\"verify-erc8128\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"ERC-8128 Request Verification\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Verify incoming ERC-8128 signed requests from authenticated agents.\"}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Function\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Function\"}],[\"$\",\"th\",\"Returns\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Returns\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"verifyAuthenticatedRequest(req, options)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"AuthResult\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Verify incoming signed request.\"}]]}]]}]]}]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/erc8128\"}],\". Options accept \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"allowedSignerTypes\"}],\" for policy enforcement. The verified agent includes a \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"signerType\"}],\" field.\"]}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"3a:[\"$\",\"div\",null,{\"id\":\"verify-receipts\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Receipts\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Stateless HMAC-signed tokens issued after successful SIWA verification. The agent includes the receipt in subsequent requests, and the server verifies it.\"}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Function\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Function\"}],[\"$\",\"th\",\"Returns\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Returns\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"createReceipt(payload, options)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"{ receipt, expiresAt }\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Create an HMAC-signed receipt.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"verifyReceipt(receipt, secret)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"ReceiptPayload | null\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Verify and decode. Returns null if invalid.\"}]]}]]}]]}]}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Payload Field\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Payload Field\"}],[\"$\",\"th\",\"Type\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Type\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"address\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Agent wallet address.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"agentId\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"number\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"ERC-8004 token ID.\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"signerType\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"SignerType?\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Optional: 'eoa' or 'sca'.\"}]]}]]}]]}]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/receipt\"}],\".\"]}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"3b:[\"$\",\"div\",null,{\"id\":\"verify-wrappers\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Server Middleware\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Drop-in middleware for popular frameworks. Each handles ERC-8128 verification, receipt checking, and CORS.\"}],[\"$\",\"div\",null,{\"className\":\"rounded-lg border border-accent/30 bg-accent/5 px-4 py-3 mb-6\",\"children\":[\"$\",\"p\",null,{\"className\":\"text-sm text-muted leading-relaxed\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent\",\"children\":\"Note:\"}],\" \",\"ERC-8004 criteria (reputation, services, trust models) are checked during SIWA sign-in via\",\" \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"verifySIWA()\"}],\". The middleware below verifies ERC-8128 signatures on subsequent requests — it accepts\",\" \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"allowedSignerTypes\"}],\" and \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"verifyOnchain\"}],\" options for per-request policy.\"]}]}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Option\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Option\"}],[\"$\",\"th\",\"Type\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Type\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"receiptSecret\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"HMAC secret for receipt verification. Defaults to RECEIPT_SECRET env.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"allowedSignerTypes\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"('eoa' | 'sca')[]\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Restrict to EOA-only or SCA-only agents.\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"verifyOnchain\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"boolean\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Re-check ownerOf on every request (slower but more secure).\"}]]}],[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"rpcUrl\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"RPC URL for onchain verification.\"}]]}],[\"$\",\"tr\",\"4\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"publicClient\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"PublicClient\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"viem PublicClient for ERC-1271 smart account signatures.\"}]]}]]}]]}]}],[\"$\",\"div\",null,{\"id\":\"verify-wrappers-next\",\"className\":\"scroll-mt-20 mt-8 mb-2\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"Next.js (App Router)\"}],\"$L66\"]}],\"$L67\",\"$L68\",\"$L69\",\"$L6a\",\"$L6b\",\"$L6c\",\"$L6d\"]]}]\n"])</script>
120<script>self.__next_f.push([1,"3c:[\"$\",\"div\",null,{\"id\":\"nonce-store\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Nonce Store\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Pluggable server-side nonce tracking for replay protection. The SDK ships built-in adapters for Memory, Redis, Cloudflare KV, and any SQL database — no extra dependencies, you bring your own client.\"}]]}]\n"])</script>
120<script>self.__next_f.push([1,"3d:[\"$\",\"div\",null,{\"id\":\"nonce-why\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Why Nonces Matter\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"A SIWA message is valid for its entire TTL window (default 5 minutes). Without server-side tracking, an attacker who intercepts a signed message can \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"replay\"}],\" it — submitting the same signature multiple times to authenticate as the agent.\"]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"A nonce store solves this by recording every issued nonce and consuming it on first use. Once consumed, the nonce is deleted and any replay attempt is rejected.\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"The SDK provides three nonce validation strategies:\"}],[\"$\",\"ul\",null,{\"className\":\"space-y-2 mb-6 text-sm leading-relaxed text-muted list-none\",\"children\":[[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"•\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Callback\"}],\" — \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"(nonce) =\u003e boolean\"}],\": you manage nonce storage yourself\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"•\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Stateless token\"}],\" — \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"{ nonceToken, secret }\"}],\": HMAC-signed token, no server storage needed (but replayable within TTL)\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"•\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Nonce store\"}],\" — \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"{ nonceStore }\"}],\": server-side tracking with exactly-once consumption (recommended for production)\"]}]]}]]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"The \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"SIWANonceStore\"}],\" interface:\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"interface SIWANonceStore {\\n  /** Store an issued nonce. Returns true on success, false if already exists. */\\n  issue(nonce: string, ttlMs: number): Promise\u003cboolean\u003e;\\n  /** Atomically check-and-delete a nonce. Returns true if it existed. */\\n  consume(nonce: string): Promise\u003cboolean\u003e;\\n}\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Wire the store into both \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"createSIWANonce\"}],\" (issue) and \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"verifySIWA\"}],\" (consume):\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"import { createSIWANonce, verifySIWA } from \\\"@buildersgarden/siwa\\\";\\nimport { createMemorySIWANonceStore } from \\\"@buildersgarden/siwa/nonce-store\\\";\\n\\nconst nonceStore = createMemorySIWANonceStore();\\n\\n// Nonce endpoint — issue\\nconst result = await createSIWANonce(params, client, { nonceStore });
120\\n\\n// Verify endpoint — consume\\nconst verification = await verifySIWA(\\n  message, signature, domain,\\n  { nonceStore },\\n  client,\\n);\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"3e:[\"$\",\"div\",null,{\"id\":\"nonce-memory\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Memory (Default)\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"In-memory store using a \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"Map\"}],\" with TTL-based expiry. Suitable for single-process servers. Nonces are lost on restart.\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"import { createMemorySIWANonceStore } from \\\"@buildersgarden/siwa/nonce-store\\\";\\n\\nconst nonceStore = createMemorySIWANonceStore();\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"3f:[\"$\",\"div\",null,{\"id\":\"nonce-redis\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Redis\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Redis-backed store using \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"SET ... PX ttl NX\"}],\" for atomic issue and \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"DEL\"}],\" for atomic consume. Works with any Redis client that implements \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"set()\"}],\" and \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"del()\"}],\".\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"import { createRedisSIWANonceStore } from \\\"@buildersgarden/siwa/nonce-store\\\";\\n\\n// ioredis (works out of the box)\\nimport Redis from \\\"ioredis\\\";\\nconst redis = new Redis();\\nconst nonceStore = createRedisSIWANonceStore(redis);\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"For \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"node-redis v4\"}],\", wrap with a small adapter since its \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"set()\"}],\" signature differs:\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"import { createClient } from \\\"redis\\\";\\nimport { createRedisSIWANonceStore } from \\\"@buildersgarden/siwa/nonce-store\\\";\\n\\nconst client = createClient(); await client.connect();\\n\\nconst nonceStore = createRedisSIWANonceStore({\\n  set: (...args: unknown[]) =\u003e\\n    client\\n      .set(args[0] as string, args[1] as string, {\\n        PX: args[3] as number,\\n        NX: true,\\n      })\\n      .then((r) =\u003e r ?? null),\\n  del: (key: unknown) =\u003e client.del(key as string),\\n});\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"40:[\"$\",\"div\",null,{\"id\":\"nonce-kv\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Cloudflare KV\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Cloudflare Workers KV-backed store. Uses \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"put\"}],\" with \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"expirationTtl\"}],\" for auto-expiry. The consume path does a \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"get\"}],\" + \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"delete\"}],\" — not fully atomic, but acceptable for random nonces.\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"import { createKVSIWANonceStore } from \\\"@buildersgarden/siwa/nonce-store\\\";\\n\\n// In a Cloudflare Worker\\nexport default {\\n  async fetch(request: Request, env: Env) {\\n    const nonceStore = createKVSIWANonceStore(env.SIWA_NONCES);\\n    // use with createSIWANonce / verifySIWA\\n  },\\n};\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Bind a KV namespace called \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"SIWA_NONCES\"}],\" in your \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"wrangler.toml\"}],\":\"]}],[\"$\",\"$L19\",null,{\"language\":\"text\",\"children\":\"[[kv_namespaces]]\\nbinding = \\\"SIWA_NONCES\\\"\\nid = \\\"\u003cyour-kv-namespace-id\u003e\\\"\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"41:[\"$\",\"div\",null,{\"id\":\"nonce-database\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Database\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"For databases, implement \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"SIWANonceStore\"}],\" directly — it's just two methods. No factory needed.\"]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Schema\"}],\" — create a table with a unique nonce column and an expiry timestamp:\"]}],[\"$\",\"$L19\",null,{\"language\":\"text\",\"children\":\"CREATE TABLE siwa_nonces (\\n  nonce      VARCHAR(64) PRIMARY KEY,\\n  expires_at TIMESTAMPTZ NOT NULL\\n);\\n-- Optional: periodic cleanup of expired rows\\n-- DELETE FROM siwa_nonces WHERE expires_at \u003c NOW();\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Prisma\"}],\":\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"import type { SIWANonceStore } from \\\"@buildersgarden/siwa/nonce-store\\\";
120\\n\\nconst nonceStore: SIWANonceStore = {\\n  async issue(nonce, ttlMs) {\\n    try {\\n      await prisma.siwaNonce.create({\\n        data: { nonce, expiresAt: new Date(Date.now() + ttlMs) },\\n      });\\n      return true;\\n    } catch (e: any) {\\n      if (e.code === \\\"P2002\\\") return false; // unique constraint\\n      throw e;\\n    }\\n  },\\n  async consume(nonce) {\\n    try {\\n      await prisma.siwaNonce.delete({ where: { nonce } });\\n      return true;\\n    } catch {\\n      return false;\\n    }\\n  },\\n};\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Drizzle\"}],\":\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"import type { SIWANonceStore } from \\\"@buildersgarden/siwa/nonce-store\\\";\\nimport { eq, and, gt } from \\\"drizzle-orm\\\";\\nimport { siwaNonces } from \\\"./schema\\\";\\n\\nconst nonceStore: SIWANonceStore = {\\n  async issue(nonce, ttlMs) {\\n    try {\\n      await db.insert(siwaNonces).values({\\n        nonce,\\n        expiresAt: new Date(Date.now() + ttlMs),\\n      });\\n      return true;\\n    } catch (e: any) {\\n      if (e.code === \\\"23505\\\") return false; // unique violation\\n      throw e;\\n    }\\n  },\\n  async consume(nonce) {\\n    const result = await db\\n      .delete(siwaNonces)\\n      .where(\\n        and(\\n          eq(siwaNonces.nonce, nonce),\\n          gt(siwaNonces.expiresAt, new Date()),\\n        ),\\n      );\\n    return (result.rowCount ?? 0) \u003e 0;\\n  },\\n};\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"42:[\"$\",\"div\",null,{\"id\":\"captcha-how\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Captcha (Reverse CAPTCHA)\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"SIWA includes a \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"reverse CAPTCHA\"}],\" — inspired by \",[\"$\",\"a\",null,{\"href\":\"https://github.com/MoltCaptcha/MoltCaptcha\",\"className\":\"text-accent hover:underline\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"children\":\"MoltCaptcha\"}],\" — that proves an entity \",[\"$\",\"em\",null,{\"children\":\"is\"}],\" an AI agent, not a human. Challenges exploit how LLMs generate text in a single autoregressive pass, satisfying multiple constraints simultaneously, while humans must iterate.\"]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"The server generates a challenge with constraints the agent must satisfy in its response text — line count, sum of ASCII values of first characters, word count, character at a specific position, and total character count. Higher difficulty levels add more constraints with tighter time limits.\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Two integration points:\"}],[\"$\",\"ul\",null,{\"className\":\"space-y-2 mb-6 text-sm leading-relaxed text-muted list-none\",\"children\":[[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"•\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Sign-in flow\"}],\" — server requires captcha before issuing a nonce\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"•\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Per-request\"}],\" — middleware randomly challenges agents during authenticated API calls (server-defined policy/probability)\"]}]]}]]}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"43:[\"$\",\"div\",null,{\"id\":\"captcha-signin\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Sign-In Captcha\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Add \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"captchaPolicy\"}],\" and \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"captchaOptions\"}],\" to your nonce endpoint. The policy function receives the agent's identity and returns a difficulty level or \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"null\"}],\" to skip.\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"import { createSIWANonce } from \\\"@buildersgarden/siwa\\\";\\n\\nconst result = await createSIWANonce(\\n  { address, agentId, agentRegistry, challengeResponse },\\n  client,\\n  {\\n    secret: SIWA_SECRET,\\n    captchaPolicy: async ({ address }) =\u003e {\\n      const known = await db.agents.exists(address);\\n      return known ? null : 'medium'; // challenge unknown agents\\n    },\\n    captchaOptions: { secret: SIWA_SECRET },\\n  },\\n);\\n\\n// result.status is 'captcha_required' | 'nonce_issued' | SIWAResponse\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Agent-side: use \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"solveCaptchaChallenge()\"}],\" to detect and solve in one step.\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"import { solveCaptchaChallenge } from \\\"@buildersgarden/siwa/captcha\\\";\\n\\nconst res = await fetch(\\\"/api/siwa/nonce\\\", {\\n  method: \\\"POST\\\",\\n  body: JSON.stringify({ address, agentId, agentRegistry }),\\n});\\nconst data = await res.json();\\n\\nconst captcha = await solveCaptchaChallenge(data, async (challenge) =\u003e {\\n  // LLM generates text satisfying all constraints in a single pass\\n  // Your LLM generates text satisfying all constraints in one pass.\\n  // Use any provider (Anthropic, OpenAI, etc.) — just return a string.\\n  return await generateText(challenge);\\n});\\n\\nif (captcha.solved) {\\n  // Retry with challengeResponse\\n  await fetch(\\\"/api/siwa/nonce\\\", {\\n    method: \\\"POST\\\",\\n    body: JSON.stringify({ ...params, challengeResponse: captcha.challengeResponse }),\\n  });\\n}\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"44:[\"$\",\"div\",null,{\"id\":\"captcha-perrequest\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Per-Request Captcha\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Add \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"captchaPolicy\"}],\" to middleware for random spot-checks on authenticated requests.\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"// Next.js\\nexport const POST = withSiwa(handler, {\\n  captchaPolicy: ({ request }) =\u003e {\\n    if (request?.url.includes('/transfer') \u0026\u0026 Math.random() \u003c 0.05)\\n      return 'hard';\\n    return null;\\n  },\\n  captchaOptions: { secret: process.env.SIWA_SECRET! },\\n});\\n\\n// Express\\napp.use(siwaMiddleware({\\n  captchaPolicy: () =\u003e Math.random() \u003c 0.05 ? 'easy' : null,\\n  captchaOptions: { secret: SIWA_SECRET },\\n}));\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Agent-side: use \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"retryWithCaptcha()\"}],\" to detect a 401 captcha challenge, solve it, re-sign with ERC-8128, and get a ready-to-send retry request.\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"import { signAuthenticatedRequest, retryWithCaptcha } from \\\"@buildersgarden/siwa/erc8128\\\";\\n\\nconst url = \\\"https://api.example.com/action\\\";\\nconst body = JSON.stringify({ key: \\\"value\\\" });\\n\\n// Sign and send\\nconst signed = await signAuthenticatedRequest(\\n  new Request(url, { method: \\\"POST\\\", body }), receipt, signer, chainId,\\n);\\nconst response = await fetch(signed);\\n\\n// Detect + solve + re-sign if captcha required\\nconst result = await retryWithCaptcha(\\n  response,\\n  new Request(url, { method: \\\"POST\\\", body }), // fresh request\\n  receipt, signer, chainId,\\n  async (challenge) =\u003e generateText(challenge), // your LLM solver\\n);\\n\\nif (result.retry) {\\n  const retryResponse = await fetch(result.request);\\n}\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"45:[\"$\",\"div\",null,{\"id\":\"captcha-difficulty\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Difficulty Levels \u0026 Configuration\"}],[[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Level\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Level\"}],[\"$\",\"th\",\"Time Limit\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Time Limit\"}],[\"$\",\"th\",\"Constraints\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Constraints\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"easy\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"30s\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Line count + ASCII sum of first chars\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"medium\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"20s\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"+ word count\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"hard\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"15s\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"+ character at specific position\"}]]}],[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"extreme\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"10s\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"+ total character count\"}]]}]]}]]}]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"All verification behavior is configurable via \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"captchaOptions.verify\"}],\":\"]}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Option\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Option\"}],[\"$\",\"th\",\"Default\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Default\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"useServerTiming\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"true\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Use server wall-clock time instead of trusting the agent's solvedAt.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"timingToleranceSeconds\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"2\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Extra seconds added to time limit for network latency.\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"asciiTolerance\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"0\"}],\"$L6e\"]}],\"$L6f\",\"$L70\"]}]]}]}],\"$L71\",\"$L72\",\"$L73\",\"$L74\"]]}]\n"])</script>
120<script>self.__next_f.push([1,"46:[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"Payment-Required\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Server to Agent\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Base64-encoded JSON with accepted payment options. Sent with 402 responses.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"Payment-Signature\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Agent to Server\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Base64-encoded signed payment payload from the agent.\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"Payment-Response\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Server to Agent\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Base64-encoded settlement result with transaction hash.\"}]]}]]}]\n"])</script>
120<script>self.__next_f.push([1,"47:[\"$\",\"div\",null,{\"id\":\"x402-server\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Server Setup\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Three things are needed to enable x402 on a route: a \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"facilitator client\"}],\" (verifies and settles payments), a \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"resource description\"}],\", and an \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"accepts array\"}],\" listing payment options.\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"import {\\n  createFacilitatorClient,\\n  type X402Config,\\n} from \\\"@buildersgarden/siwa/x402\\\";\\n\\n// 1. Create facilitator client\\nconst facilitator = createFacilitatorClient({\\n  url: \\\"https://x402-facilitator.example.com\\\",\\n});\\n\\n// 2. Define x402 config\\nconst x402: X402Config = {\\n  facilitator,\\n  resource: {\\n    url: \\\"/api/premium\\\",\\n    description: \\\"Premium data access\\\",\\n  },\\n  accepts: [\\n    {\\n      scheme: \\\"exact\\\",\\n      network: \\\"eip155:84532\\\",      // Base Sepolia\\n      amount: \\\"1000000\\\",             // 1 USDC (6 decimals)\\n      asset: \\\"0x036CbD53842c5426634e7929541eC2318f3dCF7e\\\",\\n      payTo: \\\"0xYourAddress\\\",\\n      maxTimeoutSeconds: 60,\\n    },\\n  ],\\n};\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Pass the \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"x402\"}],\" config to any framework middleware. Routes without \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"x402\"}],\" remain SIWA-only (free).\"]}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"48:[\"$\",\"div\",null,{\"id\":\"x402-sessions\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Sessions (Pay-Once)\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"By default, every request requires a new payment. Add \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"session\"}],\" to the x402 config to enable \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"pay-once mode\"}],\": the agent pays on the first request and subsequent requests within the TTL window pass through without payment.\"]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Sessions are keyed by \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"(address, resource.url)\"}],\" — different agents and different routes are isolated from each other.\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"import {\\n  createFacilitatorClient,\\n  createMemoryX402SessionStore,\\n} from \\\"@buildersgarden/siwa/x402\\\";\\n\\nconst facilitator = createFacilitatorClient({\\n  url: process.env.X402_FACILITATOR_URL!,\\n});\\n\\n// In-memory store (use Redis/DB in production)\\nconst sessionStore = createMemoryX402SessionStore();\\n\\n// Pass to any middleware\\nconst x402Config = {\\n  facilitator,\\n  resource: { url: \\\"/api/premium\\\", description: \\\"Premium access\\\" },\\n  accepts: [/* ... */],\\n  session: {\\n    store: sessionStore,\\n    ttl: 3600_000,  // 1 hour\\n  },\\n};\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"On the first request, the agent pays and the middleware stores a session. On subsequent requests from the same agent to the same resource, the session is found and payment is skipped. After TTL expiry, payment is required again.\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"For production, implement the \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"X402SessionStore\"}],\" interface with a shared store:\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"interface X402SessionStore {\\n  get(address: string, resource: string): Promise\u003cX402Session | null\u003e;\\n  set(address: string, resource: string, session: X402Session, ttlMs: number): Promise\u003cvoid\u003e;\\n}\\n\\ninterface X402Session {\\n  paidAt: number;\\n  txHash?: string;\\n}\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"49:[\"$\",\"div\",null,{\"id\":\"x402-config\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Config Reference\"}],[[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Field\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Field\"}],[\"$\",\"th\",\"Type\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Type\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"facilitator\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"FacilitatorClient\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Client for payment verification and settlement.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"resource\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"ResourceInfo\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"The resource being paid for: { url, description? }.\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"accepts\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"PaymentRequirements[]\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Array of accepted payment options.\"}]]}],[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"session?\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"X402SessionConfig\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Optional pay-once session: { store, ttl }.\"}]]}]]}]]}]}],[\"$\",\"div\",null,{\"className\":\"mt-6 mb-3\",\"children\":[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"PaymentRequirements\"}]}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Field\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Field\"}],[\"$\",\"th\",\"Type\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Type\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"sc
120heme\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"Payment scheme (e.g. \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"\\\"exact\\\"\"}],\").\"]}]]}],\"$L75\",\"$L76\",\"$L77\",\"$L78\",\"$L79\"]}]]}]}],\"$L7a\",\"$L7b\",\"$L7c\",\"$L7d\",\"$L7e\"]]}]\n"])</script>
120<script>self.__next_f.push([1,"4a:[\"$\",\"div\",null,{\"id\":\"x402-middleware\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Middleware\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Each framework wrapper accepts an optional \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"x402\"}],\" field. When set, both SIWA authentication \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"and\"}],\" a valid payment are required. The verified payment is available in the handler.\"]}],[\"$\",\"div\",null,{\"id\":\"x402-express\",\"className\":\"scroll-mt-20 mt-8 mb-2\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"Express\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mb-3\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/express\"}],\". Payment is available on \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"req.payment\"}],\".\"]}]]}],[\"$\",\"$L1a\",null,{\"title\":\"Express x402 Example\",\"language\":\"typescript\",\"children\":\"import express from \\\"express\\\";\\nimport { siwaMiddleware, siwaJsonParser, siwaCors } from \\\"@buildersgarden/siwa/express\\\";\\nimport { createFacilitatorClient } from \\\"@buildersgarden/siwa/x402\\\";\\n\\nconst app = express();\\napp.use(siwaJsonParser());\\napp.use(siwaCors({ x402: true }));  // expose x402 headers in CORS\\n\\nconst facilitator = createFacilitatorClient({\\n  url: process.env.X402_FACILITATOR_URL!,\\n});\\n\\napp.post(\\n  \\\"/api/premium\\\",\\n  siwaMiddleware({\\n    x402: {\\n      facilitator,\\n      resource: { url: \\\"/api/premium\\\", description: \\\"Premium endpoint\\\" },\\n      accepts: [\\n        {\\n          scheme: \\\"exact\\\",\\n          network: \\\"eip155:84532\\\",\\n          amount: \\\"1000000\\\",\\n          asset: \\\"0x036CbD53842c5426634e7929541eC2318f3dCF7e\\\",\\n          payTo: \\\"0xYourAddress\\\",\\n        },\\n      ],\\n    },\\n  }),\\n  (req, res) =\u003e {\\n    // req.agent — verified SIWA identity\\n    // req.payment — { scheme, network, amount, asset, payTo, txHash }\\n    res.json({ agent: req.agent, txHash: req.payment?.txHash });\\n  },\\n);\"}],[\"$\",\"div\",null,{\"id\":\"x402-next\",\"className\":\"scroll-mt-20 mt-8 mb-2\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"Next.js\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mb-3\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/next\"}],\". Payment is the 3rd argument to the handler.\"]}]]}],[\"$\",\"$L1a\",null,{\"title\":\"Next.js x402 Example\",\"language\":\"typescript\",\"children\":\"// app/api/premium/route.ts\\nimport { withSiwa, siwaOptions } from \\\"@buildersgarden/siwa/next\\\";\\nimport { createFacilitatorClient } from \\\"@buildersgarden/siwa/x402\\\";\\n\\nconst facilitator = createFacilitatorClient({\\n  url: process.env.X402_FACILITATOR_URL!,\\n});\\n\\nexport const POST = withSiwa(\\n  async (agent, req, payment) =\u003e {\\n    // agent — verified SIWA identity\\n    // payment — { scheme, network, amount, asset, payTo, txHash } or undefined\\n    return { agent, txHash: payment?.txHash };\\n  },\\n  {\\n    x402: {\\n      facilitator,\\n      resource: { url: \\\"/api/premium\\\", description: \\\"Premium endpoint\\\" },\\n      accepts: [\\n        {\\n          scheme: \\\"exact\\\",\\n          network: \\\"eip155:84532\\\",\\n          amount: \\\"1000000\\\",\\n          asset: \\\"0x036CbD53842c5426634e7929541eC2318f3dCF7e\\\",\\n          payTo: \\\"0xYourAddress\\\",\\n        },\\n      ],\\n    },\\n  },\\n);
120\\n\\n// OPTIONS handler with x402 CORS headers\\nexport const OPTIONS = () =\u003e siwaOptions({ x402: true });\"}],\"$L7f\",\"$L80\",\"$L81\",\"$L82\"]}]\n"])</script>
120<script>self.__next_f.push([1,"83:T588,"])</script>
120<script>self.__next_f.push([1,"import {\n  encodeX402Header,\n  decodeX402Header,\n  type PaymentRequired,\n  type PaymentPayload,\n} from \"@buildersgarden/siwa/x402\";\nimport { signAuthenticatedRequest } from \"@buildersgarden/siwa/erc8128\";\n\n// 1. Make initial request (will get 402)\nconst signedRequest = await signAuthenticatedRequest(\n  new Request(\"https://api.example.com/premium\", { method: \"POST\" }),\n  receipt,\n  signer,\n  84532,\n);\n\nconst res = await fetch(signedRequest);\n\nif (res.status === 402) {\n  // 2. Decode payment requirements\n  const header = res.headers.get(\"Payment-Required\");\n  const { accepts, resource } = decodeX402Header\u003cPaymentRequired\u003e(header!);\n\n  // 3. Pick a payment option and construct payload\n  const option = accepts[0];\n  const payload: PaymentPayload = {\n    signature: \"0x...\",  // sign the payment with your wallet\n    payment: {\n      scheme: option.scheme,\n      network: option.network,\n      amount: option.amount,\n      asset: option.asset,\n      payTo: option.payTo,\n    },\n    resource,\n  };\n\n  // 4. Retry with payment header\n  const retryRequest = await signAuthenticatedRequest(\n    new Request(\"https://api.example.com/premium\", {\n      method: \"POST\",\n      headers: {\n        \"Payment-Signature\": encodeX402Header(payload),\n      },\n    }),\n    receipt,\n    signer,\n    84532,\n  );\n\n  const paidRes = await fetch(retryRequest);\n  // paidRes.headers.get(\"Payment-Response\") contains { txHash, ... }\n}"])</script>
120<script>self.__next_f.push([1,"4b:[\"$\",\"div\",null,{\"id\":\"x402-agent\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Agent-Side\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"When an agent receives a \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"402\"}],\" response, it should:\"]}],[\"$\",\"ol\",null,{\"className\":\"space-y-2 mb-4 text-sm leading-relaxed text-muted list-none\",\"children\":[[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"1.\"}],[\"$\",\"span\",null,{\"children\":[\"Read the \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"Payment-Required\"}],\" header and decode the payment options.\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"2.\"}],[\"$\",\"span\",null,{\"children\":[\"Construct a \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"PaymentPayload\"}],\" with the signed payment.\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"3.\"}],[\"$\",\"span\",null,{\"children\":[\"Encode it as a \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"Payment-Signature\"}],\" header and retry the request.\"]}]]}]]}],[\"$\",\"$L1a\",null,{\"title\":\"Agent Payment Flow\",\"language\":\"typescript\",\"children\":\"$83\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"4c:[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"getReputation(agentId, options)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"ReputationSummary\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Read agent reputation.\"}]]}]\n4d:[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/registry\"}],\".\"]}]\n4e:[\"$\",\"tr\",\"7\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"chainId\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Yes\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"EIP-155 chain ID (numeric). Must match the chain in agentRegistry.\"}]]}]\n4f:[\"$\",\"tr\",\"8\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"nonce\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Yes\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Server-generated, \u003e= 8 alphanumeric chars.\"}]]}]\n50:[\"$\",\"tr\",\"9\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"issuedAt\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Yes\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"RFC 3339 datetime.\"}]]}]\n51:[\"$\",\"tr\",\"10\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"expirationTime\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"No\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"RFC 3339 datetime.\"}]]}]\n52:[\"$\",\"tr\",\"11\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"notBefore\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"No\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"RFC 3339 datetime.\"}]]}]\n53:[\"$\",\"tr\",\"12\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"requestId\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"No\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Opaque request identifier.\"}]]}]\n54:[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"See \",[\"$\",\"a\",null,{\"href\":\"#contracts-format\",\"className\":\"text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200\",\"children\":\"Address Formatting Standards\"}],\" for details on CAIP-10, EIP-55, and EIP-155.\"]}]\n"])</script>
120<script>self.__next_f.push([1,"55:[\"$\",\"div\",null,{\"id\":\"protocol-vs-siwe\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"SIWA vs SIWE\"}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Aspect\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Aspect\"}],[\"$\",\"th\",\"SIWE (EIP-4361)\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"SIWE (EIP-4361)\"}],[\"$\",\"th\",\"SIWA\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"SIWA\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Purpose\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Human wallet auth\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Agent identity auth\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Identity proof\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Owns an Ethereum address\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Owns an ERC-8004 agent NFT\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Onchain check\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"None required\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"ownerOf(agentId) REQUIRED\"}]]}],[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Extra fields\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"None\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"agentId, agentRegistry\"}]]}],[\"$\",\"tr\",\"4\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Signing\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"EIP-191\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"EIP-191 (same)\"}]]}],[\"$\",\"tr\",\"5\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Message prefix\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"...your Ethereum account\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"...your Agent account\"}]]}]]}]]}]}]]}]\n"])</script>
120<script>self.__next_f.push([1,"57:[\"$\",\"div\",null,{\"id\":\"contracts-format\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Address Formatting Standards\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"SIWA uses standardized address formats from the blockchain ecosystem:\"}],[\"$\",\"div\",null,{\"className\":\"mt-4 mb-2\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"CAIP-10: Agent Registry Reference\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mt-1 mb-3\",\"children\":[[\"$\",\"a\",null,{\"href\":\"https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-10.md\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"className\":\"text-accent hover:underline\",\"children\":\"CAIP-10\"}],\" (Chain Agnostic Improvement Proposal) defines a standard way to reference blockchain accounts across different networks.\"]}]]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"The \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"agentRegistry\"}],\" field uses CAIP-10 format to uniquely identify the ERC-8004 Identity Registry contract on a specific chain:\"]}],[\"$\",\"$L19\",null,{\"language\":\"text\",\"children\":\"{namespace}:{chainId}:{contractAddress}\\n\\nFormat breakdown:\\n  namespace       = \\\"eip155\\\" (EVM-compatible chains per EIP-155)\\n  chainId         = numeric chain identifier (e.g., 8453 for Base)\\n  contractAddress = EIP-55 checksummed contract address\\n\\nExamples:\\n  eip155:8453:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432    (Base mainnet)\\n  eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e   (Base Sepolia)\\n  eip155:1:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432      (Ethereum mainnet)\"}],[\"$\",\"div\",null,{\"className\":\"mt-6 mb-2\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"EIP-55: Checksummed Addresses\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mt-1 mb-3\",\"children\":[[\"$\",\"a\",null,{\"href\":\"https://eips.ethereum.org/EIPS/eip-55\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"className\":\"text-accent hover:underline\",\"children\":\"EIP-55\"}],\" defines mixed-case checksum encoding for Ethereum addresses.\"]}]]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"All wallet addresses (\",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"address\"}],\" field) must be EIP-55 checksummed. This provides error detection for typos:\"]}],[\"$\",\"$L19\",null,{\"language\":\"text\",\"children\":\"Correct (checksummed):   0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0\\nIncorrect (lowercase):   0x742d35cc6634c0532925a3b844bc9e7595f0beb0\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Most libraries (viem, ethers.js) automatically return checksummed addresses. You can use \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"getAddress()\"}],\" from viem to ensure proper formatting.\"]}],[\"$\",\"div\",null,{\"className\":\"mt-6 mb-2\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"EIP-155: Chain IDs\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mt-1 mb-3\",\"children\":[[\"$\",\"a\",null,{\"href\":\"https://eips.ethereum.org/EIPS/eip-155\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"className\":\"text-accent hover:underline\",\"children\":\"EIP-155\"}],\" introduced chain IDs to prevent replay attacks across different networks.\"]}]]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"The \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"chainId\"}],\" field identifies which blockchain network the agent is registered on. Common chain IDs:\"]}],\"$L84\"]]}]\n"])</script>
120<script>self.__next_f.push([1,"58:[\"$\",\"div\",null,{\"id\":\"contracts-rpc\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Public RPC Endpoints\"}],[[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Chain\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Chain\"}],[\"$\",\"th\",\"RPC URL\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"RPC URL\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Base\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"https://mainnet.base.org\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Ethereum Sepolia\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"https://rpc.sepolia.org\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Base Sepolia\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"https://sepolia.base.org\"}]]}],[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Linea Sepolia\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"https://rpc.sepolia.linea.build\"}]]}],[\"$\",\"tr\",\"4\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Polygon Amoy\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"https://rpc-amoy.polygon.technology\"}]]}]]}]]}]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"For production, use a provider like Alchemy or Infura with your own API key.\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"59:[\"$\",\"div\",null,{\"id\":\"contracts-explorer\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Explorer\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"View registered agents at\",\" \",[\"$\",\"a\",null,{\"href\":\"https://www.8004scan.io/\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"className\":\"text-accent hover:text-blue-400 transition-colors duration-200 underline underline-offset-4 cursor-pointer\",\"children\":\"8004scan.io\"}]]}]]}]\n"])</script>
120<script>self.__next_f.push([1,"66:[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mb-3\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/next\"}],\" — exports: withSiwa, siwaOptions, corsJson\"]}]\n67:[\"$\",\"$L1a\",null,{\"title\":\"Next.js Example\",\"language\":\"typescript\",\"children\":\"// app/api/protected/route.ts\\nimport { withSiwa, siwaOptions } from \\\"@buildersgarden/siwa/next\\\";\\n\\nexport const POST = withSiwa(\\n  async (agent, req) =\u003e {\\n    // agent.address, agent.agentId, agent.chainId, agent.signerType\\n    const body = await req.json();\\n    return { received: body, agent };\\n  },\\n  {\\n    // Optional: restrict to EOA-only agents\\n    allowedSignerTypes: [\\\"eoa\\\"],\\n    // Optional: re-verify onchain ownership on every request\\n    verifyOnchain: true,\\n    rpcUrl: process.env.RPC_URL,\\n  }\\n);\\n\\nexport { siwaOptions as OPTIONS };\"}]\n68:[\"$\",\"div\",null,{\"id\":\"verify-wrappers-express\",\"className\":\"scroll-mt-20 mt-8 mb-2\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"Express\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mb-3\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/express\"}],\" — exports: siwaMiddleware, siwaJsonParser, siwaCors\"]}]]}]\n69:[\"$\",\"$L1a\",null,{\"title\":\"Express Example\",\"language\":\"typescript\",\"children\":\"import express from \\\"express\\\";\\nimport { siwaMiddleware, siwaJsonParser, siwaCors } from \\\"@buildersgarden/siwa/express\\\";\\nimport { createPublicClient, http } from \\\"viem\\\";\\nimport { baseSepolia } from \\\"viem/chains\\\";\\n\\nconst app = express();\\napp.use(siwaJsonParser());\\napp.use(siwaCors());\\n\\n// Optional: create a public client for ERC-1271 smart account support\\nconst publicClient = createPublicClient({\\n  chain: baseSepolia,\\n  transport: http(process.env.RPC_URL),\\n});\\n\\napp.post(\\n  \\\"/api/protected\\\",\\n  siwaMiddleware({\\n    // Optional: allow both EOA and smart contract accounts\\n    allowedSignerTypes: [\\\"eoa\\\", \\\"sca\\\"],\\n    // Optional: pass publicClient for ERC-1271 signature verification\\n    publicClient,\\n    // Optional: re-verify onchain on every request\\n    verifyOnchain: false,\\n  }),\\n  (req, res) =\u003e {\\n    // req.agent contains { address, agentId, chainId, agentRegistry, signerType }\\n    res.json({ agent: req.agent });\\n  }\\n);\"}]\n6a:[\"$\",\"div\",null,{\"id\":\"verify-wrappers-hono\",\"className\":\"scroll-mt-20 mt-8 mb-2\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"Hono\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mb-3\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/hono\"}],\" — exports: siwaMiddleware, siwaCors\"]}]]}]\n85:T42e,import { Hono } from \"hono\";\nimport { siwaMiddleware, siwaCors } from \"@buildersgarden/siwa/hono\";\nimport { createPublicClient, http } from \"viem\";\nimport { baseSepolia } from \"viem/chains\";\n\nconst app = new Hono();\n\n// CORS with SIWA headers (handles preflight automatically)\napp.use(\"*\", siwaCors());\n\n// Optional: public client for ERC-1271 smart account support\nconst publicClient = createPublicClient({\n  chain: baseSepolia,\n  transport: http(process.env.RPC_URL),\n});\n\n// Route with EOA-only policy\napp.post(\n  \"/api/eoa-only\",\n  siwaMiddleware({ allowedSignerTypes: [\"eoa\"] }),\n  (c) =\u003e c.json({ agent: c.get(\"agent\") }),\n);\n\n// Route allowing smart accounts with ERC-1271 verification\napp.post(\n  \"/api/with-sca\",\n  siwaMiddleware({ publicClient, allowedSignerTypes: [\"eoa\", \"sca\"] }),\n  (c) =\u003e c.json({ agent: c.get(\"agent\") }),\n);\n\n// Route with onchain re-verification on every request\napp.post(\n  \"/api/high-security\",\n  siwaMiddleware({ verifyOnchain: true, rpcUrl: process.env.RPC_URL }),\n  (c) =\u003e c.json({ agent: c.get(\"agent\") }),\n);\n\nexport default app;6b:[\"$\",\"$L1a\",null,{\"title\":\"Hono Example\",\"language\":\"typescript\",\"children\":\"$85\"}]\n6c:[\"$\",\"div"])</script>
120<script>self.__next_f.push([1,"\",null,{\"id\":\"verify-wrappers-fastify\",\"className\":\"scroll-mt-20 mt-8 mb-2\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"Fastify\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mb-3\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/fastify\"}],\" — exports: siwaPlugin, siwaAuth\"]}]]}]\n86:T453,import Fastify from \"fastify\";\nimport { siwaPlugin, siwaAuth } from \"@buildersgarden/siwa/fastify\";\nimport { createPublicClient, http } from \"viem\";\nimport { baseSepolia } from \"viem/chains\";\n\nconst fastify = Fastify();\n\n// Register CORS plugin with SIWA headers (handles preflight automatically)\nawait fastify.register(siwaPlugin);\n\n// Optional: public client for ERC-1271 smart account support\nconst publicClient = createPublicClient({\n  chain: baseSepolia,\n  transport: http(process.env.RPC_URL),\n});\n\n// Route with EOA-only policy\nfastify.post(\n  \"/api/eoa-only\",\n  { preHandler: siwaAuth({ allowedSignerTypes: [\"eoa\"] }) },\n  async (req) =\u003e ({ agent: req.agent }),\n);\n\n// Route allowing smart accounts\nfastify.post(\n  \"/api/with-sca\",\n  { preHandler: siwaAuth({ publicClient, allowedSignerTypes: [\"eoa\", \"sca\"] }) },\n  async (req) =\u003e ({ agent: req.agent }),\n);\n\n// Route with onchain re-verification\nfastify.post(\n  \"/api/high-security\",\n  { preHandler: siwaAuth({ verifyOnchain: true, rpcUrl: process.env.RPC_URL }) },\n  async (req) =\u003e ({ agent: req.agent }),\n);\n\nawait fastify.listen({ port: 3000 });6d:[\"$\",\"$L1a\",null,{\"title\":\"Fastify Example\",\"language\":\"typescript\",\"children\":\"$86\"}]\n6e:[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Allow ±N tolerance on ASCII sum comparison.\"}]\n6f:[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"revealConstraints\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"true\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Include actual vs target values in verification results.\"}]]}]\n70:[\"$\",\"tr\",\"4\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"consumeChallenge\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"—\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Callback for one-time-use tokens. Return false to reject replays.\"}]]}]\n71:[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Override difficulty settings per tier with \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"captchaOptions.difficulties\"}],\":\"]}]\n72:[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"captchaOptions: {\\n  secret: SIWA_SECRET,\\n  verify: {\\n    useServerTiming: true,\\n    timingToleranceSeconds: 5,\\n    revealConstraints: false,\\n    consumeChallenge: (token) =\u003e redis.set(`captcha:${token}`, '1', 'NX', 'EX', 60).then(r =\u003e r === 'OK'),\\n  },\\n  difficulties: {\\n    easy: { timeLimitSeconds: 45 },\\n    extreme: { timeLimitSeconds: 8 },\\n  },\\n}\"}]\n73:[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/captcha\"}],\".\"]}]\n"])</script>
120<script>self.__next_f.push([1,"74:[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Export\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Export\"}],[\"$\",\"th\",\"Side\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Side\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"solveCaptchaChallenge(nonceResponse, solver)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Agent\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Detect + solve captcha from nonce response.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"retryWithCaptcha(response, request, ...)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Agent\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Detect captcha in 401, solve, re-sign, return retry request. (from erc8128 module)\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"packCaptchaResponse(token, text)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Agent\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Package solution for submission.\"}]]}],[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"createCaptchaChallenge(difficulty, opts)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Server\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Generate challenge + HMAC-signed token.\"}]]}],[\"$\",\"tr\",\"4\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"verifyCaptchaSolution(token, solution, secret, verifyOpts?)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Server\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Verify all constraints + timing. Async.\"}]]}],[\"$\",\"tr\",\"5\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"unpackCaptchaResponse(packed)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Server\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Unpack agent response.\"}]]}]]}]]}]}]\n"])</script>
120<script>self.__next_f.push([1,"75:[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"network\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"Chain identifier (e.g. \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"\\\"eip155:84532\\\"\"}],\").\"]}]]}]\n76:[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"amount\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Payment amount in smallest unit (e.g. wei, USDC base units).\"}]]}]\n77:[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"asset\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Token contract address.\"}]]}]\n78:[\"$\",\"tr\",\"4\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"payTo\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Recipient address.\"}]]}]\n79:[\"$\",\"tr\",\"5\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"maxTimeoutSeconds?\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"number\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Maximum time for settlement.\"}]]}]\n7a:[\"$\",\"div\",null,{\"className\":\"mt-6 mb-3\",\"children\":[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"X402Payment (verified payment on request)\"}]}]\n"])</script>
120<script>self.__next_f.push([1,"7b:[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Field\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Field\"}],[\"$\",\"th\",\"Type\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Type\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"scheme\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Payment scheme.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"network\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Chain identifier.\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"amount\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Amount paid.\"}]]}],[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"asset\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Token address.\"}]]}],[\"$\",\"tr\",\"4\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"payTo\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Recipient address.\"}]]}],[\"$\",\"tr\",\"5\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"txHash?\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"On-chain transaction hash from settlement.\"}]]}]]}]]}]}]\n"])</script>
120<script>self.__next_f.push([1,"7c:[\"$\",\"div\",null,{\"className\":\"mt-6 mb-3\",\"children\":[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"FacilitatorClient\"}]}]\n"])</script>
120<script>self.__next_f.push([1,"7d:[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Method\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Method\"}],[\"$\",\"th\",\"Returns\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Returns\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"verify(payload, requirements)\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"VerifyResponse\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Validate a payment signature.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"settle(payload, requirements)\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"SettleResponse\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Execute on-chain settlement. Returns txHash on success.\"}]]}]]}]]}]}]\n"])</script>
120<script>self.__next_f.push([1,"7e:[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Use \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":[\"createFacilitatorClient(\",\"{ url }\",\")\"]}],\" to create a client that POSTs to \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"/verify\"}],\" and \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"/settle\"}],\" endpoints on the facilitator. Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/x402\"}],\".\"]}]\n7f:[\"$\",\"div\",null,{\"id\":\"x402-hono\",\"className\":\"scroll-mt-20 mt-8 mb-2\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"Hono\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mb-3\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/hono\"}],\". Payment is available via \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"c.get(\\\"payment\\\")\"}],\".\"]}]]}]\n80:[\"$\",\"$L1a\",null,{\"title\":\"Hono x402 Example\",\"language\":\"typescript\",\"children\":\"import { Hono } from \\\"hono\\\";\\nimport { siwaMiddleware, siwaCors } from \\\"@buildersgarden/siwa/hono\\\";\\nimport { createFacilitatorClient } from \\\"@buildersgarden/siwa/x402\\\";\\n\\nconst app = new Hono();\\napp.use(\\\"*\\\", siwaCors({ x402: true }));\\n\\nconst facilitator = createFacilitatorClient({\\n  url: process.env.X402_FACILITATOR_URL!,\\n});\\n\\napp.post(\\n  \\\"/api/premium\\\",\\n  siwaMiddleware({\\n    x402: {\\n      facilitator,\\n      resource: { url: \\\"/api/premium\\\", description: \\\"Premium endpoint\\\" },\\n      accepts: [\\n        {\\n          scheme: \\\"exact\\\",\\n          network: \\\"eip155:84532\\\",\\n          amount: \\\"1000000\\\",\\n          asset: \\\"0x036CbD53842c5426634e7929541eC2318f3dCF7e\\\",\\n          payTo: \\\"0xYourAddress\\\",\\n        },\\n      ],\\n    },\\n  }),\\n  (c) =\u003e {\\n    const agent = c.get(\\\"agent\\\");\\n    const payment = c.get(\\\"payment\\\");\\n    return c.json({ agent, txHash: payment?.txHash });\\n  },\\n);\"}]\n81:[\"$\",\"div\",null,{\"id\":\"x402-fastify\",\"className\":\"scroll-mt-20 mt-8 mb-2\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"Fastify\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mb-3\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/fastify\"}],\". Payment is available on \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"req.payment\"}],\".\"]}]]}]\n82:[\"$\",\"$L1a\",null,{\"title\":\"Fastify x402 Example\",\"language\":\"typescript\",\"children\":\"import Fastify from \\\"fastify\\\";\\nimport { siwaPlugin, siwaAuth } from \\\"@buildersgarden/siwa/fastify\\\";\\nimport { createFacilitatorClient } from \\\"@buildersgarden/siwa/x402\\\";\\n\\nconst fastify = Fastify();\\nawait fastify.register(siwaPlugin, { x402: true });\\n\\nconst facilitator = createFacilitatorClient({\\n  url: process.env.X402_FACILITATOR_URL!,\\n});\\n\\nfastify.post(\\n  \\\"/api/premium\\\",\\n  {\\n    preHandler: siwaAuth({\\n      x402: {\\n        facilitator,\\n        resource: { url: \\\"/api/premium\\\", description: \\\"Premium endpoint\\\" },\\n        accepts: [\\n          {\\n            scheme: \\\"exact\\\",\\n            network: \\\"eip155:84532\\\",\\n            amount: \\\"1000000\\\",\\n            asset: \\\"0x036CbD53842c5426634e7929541eC2318f3dCF7e\\\",\\n            payTo: \\\"0xYourAddress\\\",\\n          },\\n        ],\\n      },\\n    }),\\n  },\\n  async (req) =\u003e {\\n    // req.agent — verified SIWA identity\\n    // req.payment — { scheme, network, amount, asset, payTo, txHash }\\n    return { agent: req.agent, txHash: req.payment?.txHash };\\n  },\\n);\"}]\n"])</script>
120<script>self.__next_f.push([1,"84:[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Network\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Network\"}],[\"$\",\"th\",\"Chain ID\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Chain ID\"}],[\"$\",\"th\",\"Type\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Type\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Ethereum\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"1\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Mainnet\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Base\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"8453\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Mainnet\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Base Sepolia\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"84532\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Testnet\"}]]}],[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Ethereum Sepolia\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"11155111\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Testnet\"}]]}]]}]]}]}]\n"])</script>
120<script>self.__next_f.push([1,"5e:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n"])</script>
120<script>self.__next_f.push([1,"87:I[20414,[\"/_next/static/chunks/33074d3ff5d0cd2d.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/4141b86737d3d211.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"IconMark\"]\n5c:null\n60:[[\"$\",\"title\",\"0\",{\"children\":\"Docs — SIWA\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"Documentation for SIWA (Sign In With Agent) — getting started, API reference, wallet integration, and contract addresses.\"}],[\"$\",\"meta\",\"2\",{\"property\":\"og:title\",\"content\":\"SIWA — Sign In With Agent\"}],[\"$\",\"meta\",\"3\",{\"property\":\"og:description\",\"content\":\"Trustless identity and authentication for AI agents. An open standard built on ERC-8004 and ERC-8128.\"}],[\"$\",\"meta\",\"4\",{\"property\":\"og:image\",\"content\":\"https://siwa.id/og.png\"}],[\"$\",\"meta\",\"5\",{\"property\":\"og:image:width\",\"content\":\"1200\"}],[\"$\",\"meta\",\"6\",{\"property\":\"og:image:height\",\"content\":\"630\"}],[\"$\",\"meta\",\"7\",{\"property\":\"og:image:alt\",\"content\":\"SIWA — Sign In With Agent\"}],[\"$\",\"meta\",\"8\",{\"property\":\"og:type\",\"content\":\"website\"}],[\"$\",\"meta\",\"9\",{\"name\":\"twitter:card\",\"content\":\"summary_large_image\"}],[\"$\",\"meta\",\"10\",{\"name\":\"twitter:title\",\"content\":\"SIWA — Sign In With Agent\"}],[\"$\",\"meta\",\"11\",{\"name\":\"twitter:description\",\"content\":\"Trustless identity and authentication for AI agents. An open standard built on ERC-8004 and ERC-8128.\"}],[\"$\",\"meta\",\"12\",{\"name\":\"twitter:image\",\"content\":\"https://siwa.id/og.png\"}],[\"$\",\"link\",\"13\",{\"rel\":\"icon\",\"href\":\"/favicon.ico?favicon.4c82eb06.ico\",\"sizes\":\"32x32\",\"type\":\"image/x-icon\"}],[\"$\",\"$L87\",\"14\",{}]]\n"])</script>
120</body></html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.