SecretPay

x402 payment gateway for AI agents private burner wallets via Unlink ZK pool + Ledger human approval

SecretPay

Created At

ETHGlobal Cannes 2026

Project Description

SecretPay is a Node.js/TypeScript middleware that intercepts HTTP requests from AI agents to paid APIs using the x402 protocol (HTTP 402 Payment Required). Here is the exact flow:

  1. The AI agent sends a request through SecretPay's gateway (POST /agent/request)
  2. SecretPay proxies the request to the target API
  3. If the API returns a 402, SecretPay parses the PAYMENT-REQUIRED header (base64 JSON) to extract the USDC amount and recipient address
  4. The policy engine evaluates the request: auto-approve if below $5, escalate to Ledger if above, deny if recipient is blacklisted
  5. If Ledger approval is needed, the operator physically approves/rejects on the hardware device
  6. SecretPay withdraws the exact amount from a shared Unlink ZK privacy pool to a freshly generated one-time burner wallet — breaking the on-chain link between the agent's identity and the payment
  7. The x402 fetch wrapper signs the payment challenge with the burner key and retries the original request
  8. The API serves the data, the burner wallet is discarded, and the transaction hash is recorded

Users onboard by connecting their Ethereum wallet, signing a message to deterministically derive their Unlink vault credentials (no database, no stored mnemonics), depositing USDC into the shared privacy pool, and whitelisting one or multiple AI agent addresses with custom per-agent spending limits (max per transaction, max per day). All built on Base Sepolia using viem, @unlink-xyz/sdk, @x402/fetch, and @ledgerhq/device-management-kit.

How it's Made

SecretPay is built in Node.js/TypeScript with Express on port 3000. Here is how each technology integrates:

x402 Protocol (Coinbase/Circle): We use @x402/fetch and @x402/evm to handle the full payment challenge-response cycle. When a 402 is detected, we decode the base64 PAYMENT-REQUIRED header, extract the raw USDC amount (6 decimal units), convert it to human-readable format, then use @x402/fetch's wrapFetch() with a burner private key to automatically sign the payment challenge and retry the request. The mock x402 server uses @x402/express paymentMiddleware to simulate paid APIs on port 4021.

Unlink Privacy Pool: We use @unlink-xyz/sdk with a single shared pool at 0x647f9b99af97e4b79DD9Dd6de3b583236352f482 on Base Sepolia. Every payment triggers a fresh burner wallet (generated via viem's generatePrivateKey), and the exact payment amount is withdrawn from the pool to that burner using a ZK proof — permanently breaking the on-chain link between the depositor identity and the spender. We poll transaction status until "relayed" or "processed" before proceeding.

Vault derivation without a database: Instead of storing mnemonics, users sign a deterministic message ("SecretPay vault access for 0x...") with MetaMask. We run keccak256 on the signature, take the first 16 bytes as BIP-39 entropy, and derive a 12-word mnemonic via @scure/bip39. Same wallet always derives the same Unlink vault — zero database required.

Ledger Hardware: @ledgerhq/device-management-kit connects to the physical device. Payments above the policy threshold pause the gateway flow and wait for a physical approve/reject on the Ledger screen before any funds move.

Multi-agent architecture: A single user vault can power N simultaneous AI agents, each with independent per-tx and per-day spending limits tracked in-memory with daily UTC resets. Agents are identified via the X-Agent-Address request header.

background image mobile

Join the mailing list

Get the latest news and updates

SecretPay | ETHGlobal