{
  "schemaVersion": "1.0",
  "item": {
    "slug": "siwa",
    "name": "Sign-in with Agent",
    "source": "tencent",
    "type": "skill",
    "category": "AI 智能",
    "sourceUrl": "https://clawhub.ai/buildersgarden/siwa",
    "canonicalUrl": "https://clawhub.ai/buildersgarden/siwa",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/siwa",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=siwa",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "package.json",
      "skill.md",
      "CLAUDE.md",
      "bankr/skill.md",
      "assets/registration-template.json",
      "assets/SIWA_IDENTITY.template.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-30T16:55:25.780Z",
      "expiresAt": "2026-05-07T16:55:25.780Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
        "contentDisposition": "attachment; filename=\"network-1.0.0.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/siwa"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/siwa",
    "agentPageUrl": "https://openagent3.xyz/skills/siwa/agent",
    "manifestUrl": "https://openagent3.xyz/skills/siwa/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/siwa/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "SIWA SDK",
        "body": "Sign-In With Agent (SIWA) lets AI agents authenticate with services using their ERC-8004 onchain identity."
      },
      {
        "title": "Install",
        "body": "npm install @buildersgarden/siwa"
      },
      {
        "title": "Agent-Side (Signing)",
        "body": "Choose based on your wallet provider:\n\nBankr — Bankr Agent API wallets\nCircle — Circle developer-controlled wallets\nPrivy — Privy server wallets\nPrivate Key — Raw private key (viem LocalAccount)\nKeyring Proxy — Self-hosted proxy with optional 2FA"
      },
      {
        "title": "Server-Side (Verification)",
        "body": "Server-Side Verification — Next.js, Express, Hono, Fastify"
      },
      {
        "title": "SDK Modules",
        "body": "ImportDescription@buildersgarden/siwaCore: signSIWAMessage, verifySIWA, createSIWANonce, parseSIWAMessage, buildSIWAMessage, createClientResolver, parseChainId@buildersgarden/siwa/signerSigner factories (see wallet-specific skills above)@buildersgarden/siwa/erc8128ERC-8128 HTTP signing/verification@buildersgarden/siwa/receiptHMAC receipt helpers@buildersgarden/siwa/nonce-storeNonce stores (Memory, Redis, KV)@buildersgarden/siwa/identitySIWA_IDENTITY.md helpers@buildersgarden/siwa/registryOnchain agent registration@buildersgarden/siwa/client-resolverDynamic PublicClient resolution for multi-chain servers@buildersgarden/siwa/nextNext.js middleware (withSiwa, siwaOptions)@buildersgarden/siwa/expressExpress middleware (siwaMiddleware, siwaJsonParser, siwaCors)@buildersgarden/siwa/honoHono middleware (siwaMiddleware, siwaCors)@buildersgarden/siwa/fastifyFastify middleware (siwaPlugin, siwaAuth)@buildersgarden/siwa/x402x402 payment helpers@buildersgarden/siwa/captchaReverse CAPTCHA (prove you're an AI)"
      },
      {
        "title": "x402 Payments (Agent-Side)",
        "body": "When an API requires payment, it returns HTTP 402 with a Payment-Required header. The agent decodes the payment options, constructs a signed payment, and retries with a Payment-Signature header — all while maintaining SIWA authentication."
      },
      {
        "title": "Handling a 402 Response",
        "body": "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 authenticated request (may 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 from header\n  const header = res.headers.get(\"Payment-Required\");\n  const { accepts, resource } = decodeX402Header<PaymentRequired>(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 both SIWA auth + 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}"
      },
      {
        "title": "x402 Headers",
        "body": "HeaderDirectionDescriptionPayment-RequiredServer → AgentBase64-encoded JSON with accepted payment options. Sent with 402.Payment-SignatureAgent → ServerBase64-encoded signed payment payload.Payment-ResponseServer → AgentBase64-encoded settlement result with transaction hash."
      },
      {
        "title": "Pay-Once Sessions",
        "body": "Some endpoints use pay-once mode: the first request requires payment, subsequent requests from the same agent to the same resource pass through without payment until the session expires. If you receive a 200 on a previously-paid endpoint, the session is still active — no need to pay again."
      },
      {
        "title": "Captcha (Reverse CAPTCHA)",
        "body": "SIWA includes a \"reverse CAPTCHA\" mechanism — inspired by MoltCaptcha — that proves an entity 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.\n\nTwo integration points:\n\nSign-in flow — server requires captcha before issuing a nonce\nPer-request — middleware randomly challenges agents during authenticated API calls"
      },
      {
        "title": "Agent-Side: Handling a Captcha Challenge",
        "body": "The SDK provides two convenience wrappers for the captcha retry pattern:\n\nSign-In Captcha: solveCaptchaChallenge()\n\nimport { solveCaptchaChallenge } from \"@buildersgarden/siwa/captcha\";\n\n// 1. Request nonce\nconst nonceRes = await fetch(\"/api/siwa/nonce\", {\n  method: \"POST\",\n  headers: { \"Content-Type\": \"application/json\" },\n  body: JSON.stringify({ address, agentId, agentRegistry }),\n});\nconst data = await nonceRes.json();\n\n// 2. Detect + solve captcha if required\nconst captcha = await solveCaptchaChallenge(data, async (challenge) => {\n  // LLM generates text satisfying all constraints in a single pass\n  // challenge: { topic, format, lineCount, asciiTarget, wordCount?, timeLimitSeconds, ... }\n  // Your LLM generates text satisfying all constraints in one pass.\n  // Use any provider (Anthropic, OpenAI, etc.) — the solver just returns a string.\n  return await generateText(challenge);\n});\n\nif (captcha.solved) {\n  // 3. Retry with challenge response\n  const retryRes = await fetch(\"/api/siwa/nonce\", {\n    method: \"POST\",\n    headers: { \"Content-Type\": \"application/json\" },\n    body: JSON.stringify({ address, agentId, agentRegistry, challengeResponse: captcha.challengeResponse }),\n  });\n}\n\nPer-Request Captcha: retryWithCaptcha()\n\nimport { signAuthenticatedRequest, retryWithCaptcha } from \"@buildersgarden/siwa/erc8128\";\n\nconst url = \"https://api.example.com/action\";\nconst body = JSON.stringify({ key: \"value\" });\n\n// 1. Sign and send\nconst signed = await signAuthenticatedRequest(\n  new Request(url, { method: \"POST\", body }),\n  receipt, signer, chainId,\n);\nconst response = await fetch(signed);\n\n// 2. Detect + solve captcha, re-sign, and get retry request\nconst result = await retryWithCaptcha(\n  response,\n  new Request(url, { method: \"POST\", body }), // fresh request (original body consumed)\n  receipt, signer, chainId,\n  async (challenge) => generateText(challenge), // your LLM solver\n);\n\nif (result.retry) {\n  const retryResponse = await fetch(result.request);\n}\n\nNote: Pass a fresh, unconsumed Request to retryWithCaptcha — the original is consumed after signing/sending."
      },
      {
        "title": "Difficulty Levels",
        "body": "LevelTime LimitConstraintseasy30sLine count + ASCII sum of first charsmedium20s+ word counthard15s+ character at specific positionextreme10s+ total character count"
      },
      {
        "title": "Links",
        "body": "Documentation\nERC-8004\nERC-8128"
      }
    ],
    "body": "SIWA SDK\n\nSign-In With Agent (SIWA) lets AI agents authenticate with services using their ERC-8004 onchain identity.\n\nInstall\nnpm install @buildersgarden/siwa\n\nSkills\nAgent-Side (Signing)\n\nChoose based on your wallet provider:\n\nBankr — Bankr Agent API wallets\nCircle — Circle developer-controlled wallets\nPrivy — Privy server wallets\nPrivate Key — Raw private key (viem LocalAccount)\nKeyring Proxy — Self-hosted proxy with optional 2FA\nServer-Side (Verification)\nServer-Side Verification — Next.js, Express, Hono, Fastify\nSDK Modules\nImport\tDescription\n@buildersgarden/siwa\tCore: signSIWAMessage, verifySIWA, createSIWANonce, parseSIWAMessage, buildSIWAMessage, createClientResolver, parseChainId\n@buildersgarden/siwa/signer\tSigner factories (see wallet-specific skills above)\n@buildersgarden/siwa/erc8128\tERC-8128 HTTP signing/verification\n@buildersgarden/siwa/receipt\tHMAC receipt helpers\n@buildersgarden/siwa/nonce-store\tNonce stores (Memory, Redis, KV)\n@buildersgarden/siwa/identity\tSIWA_IDENTITY.md helpers\n@buildersgarden/siwa/registry\tOnchain agent registration\n@buildersgarden/siwa/client-resolver\tDynamic PublicClient resolution for multi-chain servers\n@buildersgarden/siwa/next\tNext.js middleware (withSiwa, siwaOptions)\n@buildersgarden/siwa/express\tExpress middleware (siwaMiddleware, siwaJsonParser, siwaCors)\n@buildersgarden/siwa/hono\tHono middleware (siwaMiddleware, siwaCors)\n@buildersgarden/siwa/fastify\tFastify middleware (siwaPlugin, siwaAuth)\n@buildersgarden/siwa/x402\tx402 payment helpers\n@buildersgarden/siwa/captcha\tReverse CAPTCHA (prove you're an AI)\nx402 Payments (Agent-Side)\n\nWhen an API requires payment, it returns HTTP 402 with a Payment-Required header. The agent decodes the payment options, constructs a signed payment, and retries with a Payment-Signature header — all while maintaining SIWA authentication.\n\nHandling a 402 Response\nimport {\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 authenticated request (may 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 from header\n  const header = res.headers.get(\"Payment-Required\");\n  const { accepts, resource } = decodeX402Header<PaymentRequired>(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 both SIWA auth + 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}\n\nx402 Headers\nHeader\tDirection\tDescription\nPayment-Required\tServer → Agent\tBase64-encoded JSON with accepted payment options. Sent with 402.\nPayment-Signature\tAgent → Server\tBase64-encoded signed payment payload.\nPayment-Response\tServer → Agent\tBase64-encoded settlement result with transaction hash.\nPay-Once Sessions\n\nSome endpoints use pay-once mode: the first request requires payment, subsequent requests from the same agent to the same resource pass through without payment until the session expires. If you receive a 200 on a previously-paid endpoint, the session is still active — no need to pay again.\n\nCaptcha (Reverse CAPTCHA)\n\nSIWA includes a \"reverse CAPTCHA\" mechanism — inspired by MoltCaptcha — that proves an entity 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.\n\nTwo integration points:\n\nSign-in flow — server requires captcha before issuing a nonce\nPer-request — middleware randomly challenges agents during authenticated API calls\nAgent-Side: Handling a Captcha Challenge\n\nThe SDK provides two convenience wrappers for the captcha retry pattern:\n\nSign-In Captcha: solveCaptchaChallenge()\nimport { solveCaptchaChallenge } from \"@buildersgarden/siwa/captcha\";\n\n// 1. Request nonce\nconst nonceRes = await fetch(\"/api/siwa/nonce\", {\n  method: \"POST\",\n  headers: { \"Content-Type\": \"application/json\" },\n  body: JSON.stringify({ address, agentId, agentRegistry }),\n});\nconst data = await nonceRes.json();\n\n// 2. Detect + solve captcha if required\nconst captcha = await solveCaptchaChallenge(data, async (challenge) => {\n  // LLM generates text satisfying all constraints in a single pass\n  // challenge: { topic, format, lineCount, asciiTarget, wordCount?, timeLimitSeconds, ... }\n  // Your LLM generates text satisfying all constraints in one pass.\n  // Use any provider (Anthropic, OpenAI, etc.) — the solver just returns a string.\n  return await generateText(challenge);\n});\n\nif (captcha.solved) {\n  // 3. Retry with challenge response\n  const retryRes = await fetch(\"/api/siwa/nonce\", {\n    method: \"POST\",\n    headers: { \"Content-Type\": \"application/json\" },\n    body: JSON.stringify({ address, agentId, agentRegistry, challengeResponse: captcha.challengeResponse }),\n  });\n}\n\nPer-Request Captcha: retryWithCaptcha()\nimport { signAuthenticatedRequest, retryWithCaptcha } from \"@buildersgarden/siwa/erc8128\";\n\nconst url = \"https://api.example.com/action\";\nconst body = JSON.stringify({ key: \"value\" });\n\n// 1. Sign and send\nconst signed = await signAuthenticatedRequest(\n  new Request(url, { method: \"POST\", body }),\n  receipt, signer, chainId,\n);\nconst response = await fetch(signed);\n\n// 2. Detect + solve captcha, re-sign, and get retry request\nconst result = await retryWithCaptcha(\n  response,\n  new Request(url, { method: \"POST\", body }), // fresh request (original body consumed)\n  receipt, signer, chainId,\n  async (challenge) => generateText(challenge), // your LLM solver\n);\n\nif (result.retry) {\n  const retryResponse = await fetch(result.request);\n}\n\n\nNote: Pass a fresh, unconsumed Request to retryWithCaptcha — the original is consumed after signing/sending.\n\nDifficulty Levels\nLevel\tTime Limit\tConstraints\neasy\t30s\tLine count + ASCII sum of first chars\nmedium\t20s\t+ word count\nhard\t15s\t+ character at specific position\nextreme\t10s\t+ total character count\nLinks\nDocumentation\nERC-8004\nERC-8128"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/buildersgarden/siwa",
    "publisherUrl": "https://clawhub.ai/buildersgarden/siwa",
    "owner": "buildersgarden",
    "version": "0.0.4",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/siwa",
    "downloadUrl": "https://openagent3.xyz/downloads/siwa",
    "agentUrl": "https://openagent3.xyz/skills/siwa/agent",
    "manifestUrl": "https://openagent3.xyz/skills/siwa/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/siwa/agent.md"
  }
}