Skip to main content

Overview

The Hello EOA A2A demo is a minimal merchant/client example using the official A2A JS SDK with the x402 payments extension. This example demonstrates a fully functional payment flow where a client signs an EIP-3009 authorization and a server verifies and settles it on-chain.

What It Does

Server (Merchant)

  • Advertises the x402 extension in its AgentCard
  • On first message: returns a Task with input-required and x402.payment.required (payment terms)
  • On payment submission: verifies EIP-712 signature, publishes payment-pending, calls transferWithAuthorization, then publishes payment-completed and appends to x402.payment.receipts

Client (Buyer)

  • Fetches AgentCard and sends a message
  • Receives payment terms
  • Signs EIP-3009 using a wallet
  • Submits x402.payment.payload with the original taskId

Prerequisites

  • Node.js 18+

Installation

cd examples/javascript/adk
npm install

Configuration

Set these environment variables. You can place them in a local .env file and use export $(grep -v '^#' .env | xargs) to load them into your shell before running the scripts.
VariableDescription
RPC_URLJSON-RPC endpoint for your network (Base / Base Sepolia)
MERCHANT_PRIVATE_KEYMerchant signer (submits settlement)
CLIENT_PRIVATE_KEYClient signer (signs EIP-3009)
ASSET_ADDRESSToken contract (USDC) for your network
X402_NETWORK”base” or “base-sepolia” (placed in payment requirements)
PRICE_USDCHuman-readable price (e.g., 1 or 1.50)
PRICE_ATOMIC(Optional) Exact smallest-units string; overrides PRICE_USDC
MAX_TIMEOUT_SECONDS(Optional) Default 600

Notes

  • Merchant address is derived from MERCHANT_PRIVATE_KEY
  • Token decimals are read from the ASSET_ADDRESS at runtime
  • The server includes a precise EIP-712 domain in accepts[0].extra.domain; the client uses it for signing

Running the Demo

1. Start the Merchant Server

npm run server
The server will start at http://localhost:10000
  • AgentCard: http://localhost:10000/.well-known/agent-card.json

2. Run the Client

npm run client

Expected Output

The client will display:
Created Task: <id> input-required
After payment submission, task state: completed
Payment status: payment-completed
You’ll also see a receipt object with transaction hash and payer details.

Verifying Transactions

You can verify a transaction’s logs using:
# Optional filter: export ASSET_ADDRESS=<token>
npm run verify -- <txHash>
This prints:
  • Network information
  • Method (e.g., transferWithAuthorization)
  • Decoded arguments
  • Token Transfer/Authorization events

Files

FilePurpose
server.jsMerchant A2A server + x402 settlement (EIP-3009)
client.jsBuyer that signs EIP-712/EIP-3009 and submits the payload
verify.jsHelper to decode ERC-20 Transfer and EIP-3009 events
package.jsonScripts (server, client, verify)

Spec Compliance

  • Activation header: Server echoes X-A2A-Extensions, client attaches it to all requests
  • Metadata keys: Per spec - x402.payment.status, x402.payment.required, x402.payment.payload, x402.payment.receipts

Technical Details

EIP-3009 Payment Flow

  1. Client receives payment requirements from server
  2. Client signs EIP-712 typed data containing payment details
  3. Server verifies the signature matches expected parameters
  4. Server calls transferWithAuthorization on the USDC contract
  5. On-chain transfer occurs, emitting Transfer and Authorization events
  6. Server returns receipt with transaction hash

Signature Format

The signature uses EIP-712 typed data signing, which provides:
  • Human-readable structured data
  • Domain separation for security
  • Replay protection via nonces
  • Type safety for signed parameters

References

  • A2A JS SDK - Official Agent-to-Agent JavaScript SDK
  • x402 Protocol - Payment protocol specification
  • EIP-3009 - Transfer With Authorization standard
  • EIP-712 - Typed structured data hashing and signing

Build docs developers (and LLMs) love