xSHADE

x402 · private payTo

Private x402 payments for AI agents.

xSHADE gives every x402 payment its own one-time address. Agents pay the way they already do. Nobody can add up what your API earns, and your server never holds a key that can spend it.

protocol
x402 v2
settles in
USDC, EIP-3009
server holds
public key only

Live x402 call

runs in this tab
The API's xSHADE Keypublic

…

→ GET /v1/weather
← 402 Payment Required
    payTo  … new
    price  0.01 USDC
→ PAYMENT-SIGNATURE (signed USDC)
← 200 OK

Each press is one paid call. Same key, a new payTo.

    0 paid calls0 payTo0 spend keys on server

    Network

    live
    network
    Sepolia
    chain id
    11155111
    block
    …
    shielded addresses
    …
    contract
    0xE6273F…7Dd619

    One paid call, four steps

    A normal x402 payment, except the address changes every time and the spend key never touches your server.

    1. 01agentCalls your APIAny x402 client. No SDK, no plugin, nothing new to learn.
    2. 02your serverAnswers 402 with a new payToMade from your public xSHADE Key. A different address for every call.
    3. 03facilitatorSettles the USDCThe agent signs, the facilitator settles, your API returns the data.
    4. 04you, offlineScan and sweepYour xSHADE Secret finds every payment. USDC moves out with no ETH needed.Scan in the browser

    Add it to your API

    One hook on your x402 server. xshade-x402 swaps your fixed payTo for a new shielded address and publishes the scan data in batches.

    Seller · your API

    import { Announcer, shieldedPayTo } from 'xshade-x402' const announcer = new Announcer({ contract, wallet, publicClient })const shield = shieldedPayTo({  xshadeKey: process.env.XSHADE_KEY, // public key only  onPaid: announcer.add,}) server.onAfterSettle(shield.onAfterSettle) app.use(paymentMiddleware({  'GET /v1/weather': {    accepts: { scheme: 'exact', network, price: '$0.01',               payTo: shield.payTo },   // new address per call  },}, server))

    Buyer · any agent

    import { wrapFetchWithPaymentFromConfig } from '@x402/fetch'import { ExactEvmScheme } from '@x402/evm' // A plain x402 client. It does not know xSHADE exists.const pay = wrapFetchWithPaymentFromConfig(fetch, {  schemes: [{ network, client: new ExactEvmScheme(account) }],}) const res = await pay('https://your-api.com/v1/weather')

    Nothing changes for the buyer. It sees a normal 402 with a payTo, pays it, and gets the data.

    Public, on chain

    • Your xSHADE Keyshareable
    • Each payment and its payTovisible, unlinked
    • Ephemeral point E, tagbatched, delayed

    Never on your server

    • xSHADE Secretstays offline
    • Which payTo addresses are yoursfound by scanning
    • Spend keysbuilt when you sweep

    Public reputation, private income

    List your agent in ERC-8004 with an xSHADE Key instead of a fixed wallet. Each payment returns a signed receipt, so buyers can leave reviews that prove they paid without showing where the money went.

    In the receipt

    • agentIdwhich agent was paid
    • reviewerthe one address that may use it
    • receiptIdrandom, so it counts once
    • issuedDaythe day, not the second

    Signed with EIP-712 by the receipt signer named in the agent's ERC-8004 profile.

    Left out on purpose

    • payTo addressnot included
    • tx hashnot included
    • amountnot included
    • exact timenot included

    Any of these would let someone match the review to a transfer. Copied, forged and missing receipts are rejected.

    Under the hood

    No pool, no mixer, no relayer. The payTo is plain elliptic-curve math that your server and your secret both compute.

    The math, all of it

    1. serverS = e · Kone-time key e per call, your public xSHADE Key K
    2. youS = k · Eyour secret k, the announced point E = e · G
    3. bothh = keccak256(S)first 2 bytes of S become the scan tag
    4. bothP = K + h · GpayTo is addr(P)
    5. youp = k + h mod nthe spend key only you can build

    Curve secp256k1. Source: xshade-x402/src/keys.ts and XShade-Main.sol.

    On chain now

    Sepolia
    Shielded addresses announced…

    No announcements yet. The first private payment on this contract shows up here.

    This is everything the contract stores: an ephemeral point and a 2-byte tag. No receiver.

    Or pay a person by hand

    The same shielded addresses work without an API. Send ETH or any token to someone's xSHADE Key from this app.

    1. Generate an addressCreate an xSHADE Key in your browser. Share the public key. Keep the secret file.Open wallets
    2. Send any token to itThe sender pastes your key. ETH or any ERC-20 lands on a fresh shielded address.Send privately
    3. Scan and withdrawYour secret finds every address that is yours. Withdraw to any wallet.Receive
    xSHADE is non-custodial. Your xSHADE Secret never leaves this browser.chain 11155111contract 0xE6273F340c7a78e076aeC8d23B38911cA67Dd619