{"_id":"@castar/x402-verify","name":"@castar/x402-verify","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@castar/x402-verify","version":"0.1.0","description":"Castar wallet verification + attestation SDK — business API-key mode or account-less x402 payment mode, behind a one-liner.","license":"MIT","repository":{"type":"git","url":"git+ssh://git@github.com/Castar-Labs/castar-sdk-ts.git"},"bugs":{"url":"https://github.com/Castar-Labs/castar-sdk-ts/issues"},"homepage":"https://github.com/Castar-Labs/castar-sdk-ts#readme","type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"publishConfig":{"access":"public"},"sideEffects":false,"engines":{"node":">=18"},"scripts":{"build":"tsup","typecheck":"tsc --noEmit","test":"vitest run","test:watch":"vitest","prepublishOnly":"npm run build"},"keywords":["x402","attestation","wallet-verification","eas","castar","eip-3009"],"devDependencies":{"@types/node":"^20.0.0","tsup":"^8.0.0","typescript":"^5.7.0","viem":"^2.21.0","vitest":"^2.0.0"},"gitHead":"74b73ded18fbca38bfa1c22d8e5ec533ea0535ec","_id":"@castar/x402-verify@0.1.0","_nodeVersion":"26.4.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-hvt8V49Q5lhtUXAYuk4PjFs14WHb4AIqc17ag27ugyquXD9ADS/wKPiQL9awsHXuZ3WqFNIiA6l0OJML9K56Kg==","shasum":"3e1af926eff93a235d0fb129f004207e839a26c0","tarball":"https://registry.npmjs.org/@castar/x402-verify/-/x402-verify-0.1.0.tgz","fileCount":9,"unpackedSize":92818,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIAuL+d4tobyTo8elEeM2vJ9xQp1IsitITGYfd2nx+nCdAiEA1s2fwnBDpB34ZDBl9mzCVGIzCXB7mMpM9QECSwAwZMs="}]},"_npmUser":{"name":"antoonip","email":"antoni.pawlak@pm.me"},"directories":{},"maintainers":[{"name":"antoonip","email":"antoni.pawlak@pm.me"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/x402-verify_0.1.0_1782826139612_0.7780806242169986"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-30T13:28:59.421Z","0.1.0":"2026-06-30T13:28:59.745Z","modified":"2026-06-30T13:28:59.998Z"},"maintainers":[{"name":"antoonip","email":"antoni.pawlak@pm.me"}],"description":"Castar wallet verification + attestation SDK — business API-key mode or account-less x402 payment mode, behind a one-liner.","homepage":"https://github.com/Castar-Labs/castar-sdk-ts#readme","keywords":["x402","attestation","wallet-verification","eas","castar","eip-3009"],"repository":{"type":"git","url":"git+ssh://git@github.com/Castar-Labs/castar-sdk-ts.git"},"bugs":{"url":"https://github.com/Castar-Labs/castar-sdk-ts/issues"},"license":"MIT","readme":"# @castar/x402-verify\n\nTypeScript SDK for Castar wallet eligibility checks and attestation issuance.\n\nIt supports two request modes:\n\n- `apiKey`: business integration with a Castar API key.\n- `x402`: pay-per-request integration without a Castar account. The SDK performs the x402 quote/payment handshake, signs the wallet-ownership challenge, and returns the verification result.\n\n## Requirements\n\n- Node.js 18+.\n- A `fetch` implementation. Node 18+ provides one; otherwise pass `fetch` in `createClient`.\n- For `x402` mode, a payer signer that implements `signTypedData`. A `viem` local account satisfies this interface.\n\nThe package has no runtime dependencies.\n\n## Install\n\n```bash\nnpm install @castar/x402-verify\n```\n\n## API-key mode\n\nUse this mode when your application has a Castar business API key.\n\n```ts\nimport { createClient } from \"@castar/x402-verify\";\n\nconst client = createClient({\n  baseUrl: \"https://api.castar.xyz\",\n  mode: \"apiKey\",\n  apiKey: process.env.CASTAR_API_KEY!, // \"client_id:secret\"\n});\n\nconst result = await client.verify({\n  chain: 57073,\n  asset: \"0xTokenContract\",\n  wallet: \"0xWalletToCheck\",\n  minUnits: \"1000000\",\n});\n\nconsole.log(result.eligible, result.attestation?.uid);\n```\n\nIn `apiKey` mode the SDK uses Bearer auth and never calls the x402 endpoints.\n\n## x402 mode\n\nUse this mode when the caller pays per verification request.\n\n```ts\nimport { createClient } from \"@castar/x402-verify\";\nimport { privateKeyToAccount } from \"viem/accounts\";\n\nconst account = privateKeyToAccount(process.env.PAYER_KEY as `0x${string}`);\n\nconst client = createClient({\n  baseUrl: \"https://api.castar.xyz\",\n  mode: \"x402\",\n  payer: account,\n  maxSpend: \"100000\",\n  allowedNetworks: [\"eip155:57073\"],\n});\n\nconst result = await client.verify({\n  chain: 57073,\n  asset: \"0xTokenContract\",\n  wallet: account.address,\n  minUnits: \"1000000\",\n});\n```\n\nThe x402 flow is fail-closed:\n\n1. `quote()` fetches the server's payment requirements.\n2. `allowedNetworks` and `maxSpend` are checked before anything is signed.\n3. The payer signs the EIP-3009 payment authorization.\n4. The subject wallet signs the ownership challenge.\n5. The backend completes eligibility verification and, when eligible, settles and returns the attestation.\n\nIf the wallet is not eligible, `verify()` resolves with `eligible: false` and `attestation: null`.\n\n### Verifying a different wallet\n\nThe payer and verified wallet can be different. In that case, pass `subjectSigner` for the verified wallet:\n\n```ts\nconst client = createClient({\n  baseUrl: \"https://api.castar.xyz\",\n  mode: \"x402\",\n  payer,\n  subjectSigner,\n});\n\nawait client.verify({\n  chain: 57073,\n  asset: \"0xTokenContract\",\n  wallet: subjectSigner.address,\n  minUnits: \"1000000\",\n});\n```\n\nFor EVM wallets, a `viem` account can be used as `subjectSigner`. For Solana wallets, provide an adapter whose `address` is the base58 public key and whose `signMessage({ message })` returns a base58 ed25519 signature.\n\n## Client options\n\n```ts\ninterface ClientOptions {\n  baseUrl: string;\n  mode: \"apiKey\" | \"x402\";\n  apiKey?: string;\n  payer?: PaymentSigner;\n  subjectSigner?: ChallengeSigner;\n  maxSpend?: bigint | string;\n  allowedNetworks?: string[];\n  fetch?: typeof fetch;\n  onPaymentRequired?: (req: PaymentRequirements) => void | Promise<void>;\n}\n```\n\n`apiKey` is required in `apiKey` mode. `payer` is required in `x402` mode. `subjectSigner` is required when the wallet being verified is different from the payer.\n\n`onPaymentRequired` runs after the quote is received and after the local price/network guards pass, but before the payment authorization is signed.\n\n## Verification input\n\n```ts\ninterface VerifyParams {\n  chain: number;\n  asset: string;    // EVM token contract or Solana SPL mint\n  wallet: string;   // wallet being verified\n  minUnits: string; // minimum balance in atomic units\n}\n```\n\n## Verification result\n\n```ts\ninterface VerificationResult {\n  eligible: boolean;\n  balanceAt: string;\n  attestation: { uid: string; txHash: string; chainId: number } | null;\n  paymentId?: string;    // x402 only\n  settlementTx?: string; // x402 only, present when charged\n  raw: unknown;\n}\n```\n\n## Errors\n\nEvery SDK failure throws `CastarError` with a stable `.code`.\n\n| Error | Code | Notes |\n| --- | --- | --- |\n| `ConfigError` | `config_error` | Missing `baseUrl`, invalid mode, missing API key, missing signer, or signer/wallet mismatch. |\n| `MaxSpendExceededError` | `max_spend_exceeded` | Price is above `maxSpend`; thrown before signing. |\n| `UnsupportedNetworkError` | `unsupported_network` | Payment network is not in `allowedNetworks`; thrown before signing. |\n| `UserRejectedSigningError` | `user_rejected_signing` | Payment or challenge signing failed or was rejected. |\n| `BackendError` | server error code or `backend_error` | Backend/facilitator rejection. Includes `.status`. |\n\n```ts\nimport { MaxSpendExceededError, UserRejectedSigningError } from \"@castar/x402-verify\";\n\ntry {\n  await client.verify({ chain, asset, wallet, minUnits });\n} catch (e) {\n  if (e instanceof MaxSpendExceededError) {\n    // Price was above your configured cap. Nothing was signed.\n  } else if (e instanceof UserRejectedSigningError) {\n    // The signer rejected or failed. No complete request was sent.\n  } else {\n    throw e;\n  }\n}\n```\n\nKnown backend codes exported through `BackendError` include:\n\n```txt\npayment_required\npayment_invalid\nmalformed_payment\nfacilitator_unavailable\nsettlement_failed\nchallenge_invalid\nwallet_mismatch\npayment_expired\npayment_consumed\nx402_disabled\n```\n\n## Quote and low-level helpers\n\n`client.quote()` is available in both modes but is only useful for x402. It calls the x402 endpoint and returns the first accepted `PaymentRequirements` without signing or paying.\n\nAdvanced exports:\n\n```ts\nimport {\n  buildChallengeMessage,\n  buildPaymentSignatureHeader,\n  parsePaymentRequired,\n  randomNonce32,\n} from \"@castar/x402-verify\";\n```\n\nUse these helpers only when building a custom x402 flow around the same backend contract.\n\n## Local development\n\n```bash\nnpm run build      # build ESM, CJS, and .d.ts files\nnpm run typecheck  # TypeScript validation\nnpm test           # Vitest test suite\n```\n\nExample scripts live in `examples/`.\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-41c6a2dac173cdbf3131083d72a30e45"}