Agent paywall (Mastra + JPYC)
The examples/agent-x402-jpyc workspace is the canonical end-to-end demo
of kawasekit on Polygon Amoy. It pairs a Mastra
agent (Anthropic Claude under the hood) with a Hono
server. The agent calls GET /weather/:city; the server gates the route
behind a JPYC v2 x402 v2 paywall; the agent pays automatically and gets
its answer.
Architecture
agent EOA ──signs EIP-3009──▶ facilitator EOA ──broadcasts──▶ JPYC contract │ │ │ │ pays POL │ │ │ └────────────────────── 0.001 JPYC ───────────────────────────▶ recipientThree on-chain identities, all separate by design:
- Agent payer EOA — signs EIP-3009
transferWithAuthorizationoff-chain. Holds JPYC. - Facilitator EOA — pays POL for gas and broadcasts the settlement transaction. Holds POL. Never sees user JPYC.
- Recipient EOA — receives the JPYC. Any address you control.
The two Node processes (server + agent) talk only over HTTP. The agent’s
sole x402 surface is wrapFetch; everything else is plain Mastra +
Anthropic SDK.
Prerequisites
- Node 22+ / pnpm 11+
- Polygon Amoy POL in the facilitator EOA — faucet: https://faucet.polygon.technology/
- Polygon Amoy JPYC in the agent payer EOA — faucet: https://faucet.jpyc.co.jp/. 0.1 JPYC supports roughly 100 calls.
- An Anthropic API key. A three-city
run on
claude-sonnet-4-5costs about $0.02–$0.05.
Run it
From the repository root:
pnpm installpnpm --filter kawasekit buildThen in the example workspace:
cd examples/agent-x402-jpyccp .env.example .env# Fill in: OWNER_PRIVATE_KEY, X402_PAYER_PRIVATE_KEY,# X402_FACILITATOR_PRIVATE_KEY, X402_RECIPIENT, ANTHROPIC_API_KEYTwo terminals:
pnpm dev:server# → listening on http://127.0.0.1:8787# → paywalled route: GET /weather/:citypnpm dev:agent# Claude reads the prompt, calls fetch_weather 3 times,# pays for each call. Final output is a one-line summary# per city plus a wrap-up.What you should see
Each call lands one tx on Polygon Amoy. The agent logs the Polygonscan URL on the way out — open it to see real JPYC settle.
The session-key sidecar
pnpm dev:session-demo is a separate, smaller script that demonstrates
the M3-2 envelope flow: owner-side issuance, serialize → parse round
trip, agent-side restore on a fresh PublicClient. It does not need the
LLM API key and is the fastest way to see kawasekit’s session-key
plumbing in isolation.
Gotchas this example surfaces
- Concurrent settle requires
nonceManager. The agent fans out three parallelfetch_weathercalls; the facilitator must serialise its on-chain nonces or only one tx lands. The fix is to construct the facilitator account with viem’snonceManager. Seeserver/index.tsfor the wiring. - EIP-3009 cannot be signed by a smart account. JPYC v2’s
transferWithAuthorizationis pureecrecover, so the agent’s signer must be an EOA. The kawasekittransferJpyc()UserOp path is what smart-account-held JPYC uses. - The owner / agent / facilitator split is enforced operationally. kawasekit does not stop you from collapsing them, but the threat model (and the example) treat them as three independent identities.
Going further
- Switch the facilitator to mainnet by changing
--chain polygonAmoyto--chain polygoneverywhere and settingKAWASEKIT_ALLOW_MAINNET=1. - Wire the observability adapter into the
facilitator’s
hooksto get a Grafana dashboard over the settlements. - Read the threat model for what each EOA can and cannot do if compromised.