BaseLive

Xona Agent

Live on x402 — age-gated AI image generation.

Xona Agent serves premium AI image and video generation through x402 micro-payments. zkRune adds a privacy-preserving eligibility gate in front of Xona's image endpoint: callers prove they are 18+ on Base mainnet without exposing the underlying birth year. Deployed at api.xona-agent.com/zkrune/image/flux-2-flex — every request hits the live gate.

What this demo shows

Three real steps, end to end. The gate is deployed on Xona's live x402 endpoint — every real request to api.xona-agent.com/zkrune/image/flux-2-flex runs through the on-chain verifier before the image is served.

01Live

Real ZK proof, in your browser

snarkjs runs the production age-verification circuit on your input. ~0.5s. Your birth year never leaves the page — only the boolean 'age ≥ 18' is exposed.

02Live

Real on-chain verification on Base

The proof is checked against the deployed zkRune verifier on Base mainnet via verifyProofStatic. View call — no wallet, no gas. Anyone can replay it.

03Live

Live on Xona's x402 endpoint

The same gate runs in production at api.xona-agent.com/zkrune/image/flux-2-flex. Missing proof → 403 challenge. Valid proof → handed off to x402 for payment. Try the curl evidence below.

Try the gate

Live ZK · Live Base

Stays in the browser. Only the boolean "age ≥ 18" is exposed on-chain.

  1. Groth16 proof generated client-side

  2. On-chain verification on Base

  3. x402 image-gen call to Xona

x402 request

Simulated
{
  "method": "POST",
  "url": "https://api.xona-agent.com/v1/x402/image/generate",
  "headers": {
    "Content-Type": "application/json",
    "X-Payment": "<base64(x402-v1 USDC transfer · $0.04)>",
    "X-zkRune-Proof": "0x<groth16-proof-hash>",
    "X-zkRune-Circuit": "age-verification",
    "X-zkRune-Verifier": "base:0xa03A353d…"
  },
  "body": {
    "prompt": "A neon-lit Solana validator at midnight, cinematic, photorealistic",
    "model": "xona-image-v1",
    "ratio": "1:1"
  }
}

Endpoint URL is illustrative. The X-zkRune-Proof header and verifier reference show how a partner could enforce both payment and eligibility at the HTTP layer.

Output preview

Simulated

Output appears once the gate passes.

Live on Xona today

Production

The gate is deployed on Xona's x402 endpoint. Every real request to api.xona-agent.com/zkrune/image/flux-2-flex runs through @zkrune/x402-verify before the image is served. Three cases, copy-pasteable.

No proofHTTP 403

Request

curl -X POST https://api.xona-agent.com/zkrune/image/flux-2-flex \
  -H "Content-Type: application/json" \
  -d '{"prompt":"x"}'

Response

{
  "error": "zkrune_eligibility_required",
  "reason": "missing_headers",
  "circuit": "age-verification",
  "verifier": "base:0xa03A353d…9E849EA",
  "generateProofAt": "https://zkrune.com",
  "message": "This endpoint requires a zkRune age-verification proof..."
}

Gate emits the 403 challenge — same shape as x402's 402, self-describing so the caller knows exactly which proof to generate.

Valid proofHTTP 402

Request

curl -X POST https://api.xona-agent.com/zkrune/image/flux-2-flex \
  -H "X-zkRune-Proof: <base64 envelope>" \
  -H "X-zkRune-Circuit: age-verification" \
  -d '{"prompt":"a cyberpunk fox holding a zk rune"}'

Response

{
  "x402Version": 2,
  "error": "Payment Required",
  "resource": {
    "url": "https://api.xona-agent.com/zkrune/image/flux-2-flex",
    "description": "...ZK age-verified, Base Mainnet."
  },
  "accepts": [{
    "scheme": "exact",
    "network": "eip155:8453",
    "amount": "60000",
    "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
  }]
}

Proof passed on-chain verification — control handed to x402, which now asks for 0.06 USDC on Base. Both gates run in production; only the success path needs a paying wallet.

Tampered proofHTTP 403

Request

curl -X POST https://api.xona-agent.com/zkrune/image/flux-2-flex \
  -H "X-zkRune-Proof: not-a-real-proof" \
  -H "X-zkRune-Circuit: age-verification" \
  -d '{"prompt":"x"}'

Response

{
  "error": "zkrune_eligibility_required",
  "reason": "malformed_proof",
  "circuit": "age-verification",
  "message": "The X-zkRune-Proof header is not a valid base64-encoded proof envelope."
}

Garbage rejected at the gate — never reaches the verifier or the payment layer.

Why a ZK gate?

x402 makes payment permissionless. Eligibility — age, jurisdiction, license, brand-safety tier — is a separate question, and it has not been answered well in the agent economy. The options today all either leak data or break the agent flow.

Without zkRune

  • Trust the caller's word. Operator carries legal liability for any false claim. Not a real option for regulated content.
  • Demand ID upload. Kills agent UX. Storing PII opens a separate compliance burden — data-minimization issues, breach exposure.
  • Plug in a hosted KYC vendor. Per-check cost, redirect flows that break agent loops, mostly built for human verification — not headless agents.
  • Token-only gating. Proves the wallet paid. Proves nothing about who is calling, where, or under what license.

With zkRune

  • 200-byte proof, ~0.5s, fully client-side. No upload, no redirect, no third-party round-trip. The math runs in the user's browser.
  • Zero raw PII transmitted. Not to Xona, not to zkRune, not to any RPC. Only the boolean claim and a Groth16 proof.
  • Same primitive for humans and agents. Browser SDK for users on a webpage; Node SDK or plain HTTP for headless agents calling x402 endpoints.
  • On-chain verifier, audit trail by default. Every match leaves a cryptographic record on Base mainnet — regulator-shaped, no extra logging stack.

Same x402 endpoint, same payment flow — just one extra header carrying a proof a verifier already trusts.

Architecture

01Live

User submits private input

Birth year stays in the browser. Never sent to any server, never written to logs.

02Live

Groth16 proof generated client-side

snarkjs runs in the browser against the age-verification circuit. Output: a 200-byte SNARK plus public signals (currentYear, minimumAge).

03Live

Verified on Base mainnet

verifyProofStatic view call against the deployed zkRune verifier. No wallet, no gas, no off-chain trust.

04Live

x402 image-gen call to Xona

Live at api.xona-agent.com/zkrune/image/flux-2-flex. The endpoint runs the same gate behind every real request.

Endpoint integration

The gate ships as a published npm package — @louisstein/x402-verify. It reads HTTP headers only, never the request body, so it drops in front of any x402 endpoint regardless of stack. Xona's handler added three lines; the payment middleware and the handler stayed unchanged. Same code is now running in their production endpoint.

// Xona's x402 image endpoint — add the zkRune gate in three lines.
// @louisstein/x402-verify · reads headers only, never the request body.
import { Hono } from "hono";
import { zkRuneHonoMiddleware } from "@louisstein/x402-verify";

app.post(
  "/image/flux-2-flex",

  // zkRune eligibility gate — rejects callers who have not proven 18+.
  // A missing or invalid proof gets a 403 challenge that mirrors x402's 402.
  zkRuneHonoMiddleware({
    requiredCircuit: "age-verification",
    validatePublicSignals: (s) => {
      const [isValid, year, minAge] = s.map(Number);
      return isValid === 1 &&
             year >= new Date().getUTCFullYear() - 1 &&
             minAge >= 18;
    },
  }),

  x402(),        // existing payment middleware — unchanged
  fluxHandler,   // existing handler — unchanged
);

Deployed. Live on Xona's production endpoint — api.xona-agent.com/zkrune/image/flux-2-flex. The package is on npm with a comprehensive smoke test (13/13 checks against the live Base verifier) — both sides shipped.

Why it fits

Same chain footprint

Xona ships on SKALE on Base. zkRune's Base verifier (0xa03A353d…) is already live on mainnet — no new infra to deploy.

Orthogonal to x402

x402 answers who paid. zkRune answers who is allowed. Together they enforce payment and eligibility at the HTTP layer, with no shared state.

Compliance-ready

Age, jurisdiction, and license proofs map directly to the regulatory pressure shaping AI generation. Zero raw PII retained.

Already live — call it now

The integration is deployed on both sides: gate on Xona's production endpoint, package on npm. If you run an x402 service and want the same drop-in eligibility layer, the codepath is now a reference customers can verify themselves with a single curl.