Production-ready AI agent template with x402 payments, A2A protocol, and ERC-8004 on-chain identity. Deploys to AWS Lambda via Terraform.
a2a-x402-agent-template is an early-stage TypeScript project in the AI payments / x402 ecosystem, focused on a2a, aws-lambda, erc8004, hono. It currently has 2 GitHub stars and 0 forks, and sits alongside related tools like internet-court-skill, daydreams, machi, lucid-agents, os-moda, a2a-x402-typescript.
A production-ready template for building AI agents that accept on-chain payments. Combines Hono (web framework), x402 (HTTP 402 payment protocol), A2A (Agent-to-Agent protocol), and ERC-8004 (on-chain agent identity) into a serverless agent that deploys to AWS Lambda in one command.
Pre-configured for Base Sepolia (testnet) — switch to Base Mainnet by changing two env vars (see Network Switching). Designed to be consumed by AI agents: ships with AGENT.md so tools like OpenClaw can index and interact with this repo out of the box.
flowchart LR
Client -->|HTTPS| FnURL["Lambda Function URL"]
subgraph AWS["AWS (Terraform-managed)"]
FnURL --> Lambda["Lambda<br/>(arm64, Docker)"]
Lambda --> SM["Secrets Manager<br/>(private key)"]
Lambda -.-> CW["CloudWatch Logs"]
ECR["ECR"] -.->|image source| Lambda
end
subgraph Hono["Hono App"]
Free["/health<br/>/.well-known/agent-card.json<br/>/.well-known/agent-registration.json"]
Paid["/api/*   /a2a"]
end
Lambda --> Hono
Paid -->|verify payment| Facilitator["x402 Facilitator"]
Facilitator -->|settle| Blockchain["Base (USDC)"]
Terraform manages all AWS infrastructure: Lambda function, ECR image repository, Secrets Manager (private key), IAM roles, CloudWatch log group, and the Function URL endpoint. Endpoints split into free (/health, agent card, read-only A2A methods) and paid (/api/*, A2A message/send and message/stream) — see How Payments Work for the full x402 sequence.
| Library | Package | What it does |
|---|---|---|
| Hono | hono |
Ultrafast web framework. Runs on Node.js, AWS Lambda, Deno, Bun, Cloudflare Workers — same code everywhere. |
| x402 | @x402/hono @x402/core @x402/evm @coinbase/x402 |
HTTP 402 payment protocol. Uses Coinbase CDP facilitator for payment verification and settlement. |
| A2A | @a2a-js/sdk |
Google's Agent-to-Agent protocol. Standardized JSON-RPC interface so agents can discover and talk to each other. |
| ERC-8004 | agent0-sdk erc-8004-js |
On-chain agent identity. Mints an NFT with IPFS metadata pointing to your agent's live endpoint. Supports update-or-create registration flow. |
| Zod | zod |
TypeScript-first schema validation. Used to validate API route inputs. |
aws configure)git clone https://github.com/wgopar/a2a-x402-agent-template.git
cd a2a-x402-agent-template
npm install
npm run create-wallet -- my-agent
This generates a new Ethereum wallet and writes the address + private key to both .env (local dev) and infra/terraform.tfvars (Lambda deploy). It also sets function_name in tfvars, which names all AWS resources (Lambda, ECR, IAM roles). Use a unique name per agent to prevent resource collisions. Both files are gitignored.
Next: Fund the wallet with testnet ETH from a Base Sepolia faucet.
The wallet script pre-fills most values. Review .env and adjust if needed:
# .env (auto-generated, gitignored)
WALLET_ADDRESS=0x... # from create-wallet
PRIVATE_KEY=0x... # from create-wallet
NETWORK=eip155:84532 # Base Sepolia (testnet)
RPC_URL=https://sepolia.base.org
BYPASS_PAYMENTS=true # skip x402 for local dev (auto-disabled in production)
AGENT_NAME=Hello Agent
AGENT_URL=http://localhost:3000
PORT=3000
# CDP Facilitator (required when BYPASS_PAYMENTS=false)
CDP_API_KEY_ID=your-cdp-key-id
CDP_API_KEY_SECRET=your-cdp-key-secret
See Configuration Reference for all available variables.
npm run dev
# Health check (always free)
curl http://localhost:3000/health
# Agent card with structured entrypoints (always free)
curl http://localhost:3000/.well-known/agent-card.json
# Agent registration linkage (always free)
curl http://localhost:3000/.well-known/agent-registration.json
# API endpoint — returns 200 with BYPASS_PAYMENTS=true, or 402 with payment terms
curl http://localhost:3000/api/hello
With BYPASS_PAYMENTS=true (default for local dev), all endpoints return responses directly. When payments are enabled, unpaid requests return 402 Payment Required with payment terms in the x-payment-required header.
Make sure you've run npm run create-wallet -- <name> first — it sets function_name in terraform.tfvars, which is required and names all AWS resources.
cd infra && terraform init
terraform apply -target=aws_ecr_repository.agent # create ECR repo
cd ..
npm run deploy
This builds a Docker image, pushes to ECR, and runs terraform apply — your agent is live. Terraform stores your private key in AWS Secrets Manager (not as a Lambda environment variable), so it's encrypted at rest and accessed via IAM at runtime.
flowchart LR
Build["docker build<br/>(esbuild bundle)"] --> Push["docker push<br/>(ECR)"]
Push --> Apply["terraform apply<br/>(Lambda + IAM + Secrets)"]
Apply --> Live["Function URL<br/>(public HTTPS)"]
# Get your Function URL from terraform output
cd infra && terraform output function_url
# Test it
curl https://<your-function-url>/health
curl https://<your-function-url>/.well-known/agent-card.json
ERC-8004 registration mints an NFT that points to your agent's live endpoint via IPFS metadata. This enables on-chain agent discovery. If assets/icon.png exists, it's automatically uploaded to IPFS and included in the metadata.
The register script uses an update-or-create flow: it auto-detects if the wallet already owns an agent on the registry and updates its metadata instead of minting a new token. You can also set AGENT_ID in .env to target a specific token.
Sign up at pinata.cloud, create an API key, and add the JWT to .env:
PINATA_JWT=your-pinata-jwt
Point AGENT_URL in .env to your deployed Lambda Function URL (not localhost):
AGENT_URL=https://<your-function-url>
Place a PNG image at assets/icon.png. It will be uploaded to IPFS and included in the on-chain metadata automatically. To use a different path, set AGENT_IMAGE_PATH in .env.
npm run register
flowchart LR
Icon["Upload icon<br/>(assets/icon.png)"] --> Meta["Build metadata<br/>(name, skills, endpoint, image)"]
Meta --> IPFS["Upload to IPFS<br/>(via Pinata)"]
IPFS --> Check{"Agent exists?"}
Check -->|No| Mint["Mint ERC-8004 NFT<br/>(on-chain)"]
Check -->|Yes| Update["Update token URI<br/>(on-chain)"]
Anyone can now discover your agent on-chain:
tokenURI(tokenId) → ipfs://... → metadata JSON → services[0].endpoint → your agent
The x402 protocol uses gasless payments. Clients never submit blockchain transactions — they sign an off-chain EIP-3009 transferWithAuthorization, and the facilitator settles on-chain on their behalf.
sequenceDiagram
participant Client
participant Agent
participant Facilitator
participant Blockchain
Client->>Agent: Request (no payment)
Agent-->>Client: 402 + payment terms
Note over Client: Sign EIP-3009<br/>transferWithAuthorization<br/>(gasless, off-chain)
Client->>Agent: Retry + signed authorization
Agent->>Facilitator: Verify + settle
Facilitator->>Blockchain: Submit transferWithAuthorization
Facilitator-->>Agent: Settlement proof
Agent-->>Client: Response + tx hash
| Endpoint | Payment |
|---|---|
GET /health |
Free |
GET /.well-known/agent-card.json |
Free |
GET /.well-known/agent-registration.json |
Free |
POST /a2a — tasks/get, tasks/cancel |
Free |
POST /a2a — message/send, message/stream |
$0.01 USDC |
GET /api/hello |
$0.01 USDC |
POST /api/hello |
$0.01 USDC |
Read-only A2A methods are always free. Only work-producing methods (message/send, message/stream) require payment.
Three files to edit:
src/agent/skills.ts — Define skillsexport const skills: AgentSkill[] = [
{
id: "my-skill",
name: "My Skill",
description: "What this skill does",
tags: ["tag1", "tag2"],
examples: ["Do the thing", "Another example"],
},
];
src/agent/executor.ts — Implement logicexport class MyExecutor implements AgentExecutor {
async execute(
requestContext: RequestContext,
eventBus: ExecutionEventBus,
): Promise<void> {
// Your agent logic here
const task: Task = {
kind: "task",
id: requestContext.taskId,
contextId: requestContext.contextId,
status: {
state: "completed",
message: {
kind: "message",
messageId: uuidv4(),
role: "agent",
parts: [{ kind: "text", text: "Your response" }],
contextId: requestContext.contextId,
},
},
};
eventBus.publish(task);
eventBus.publish({
kind: "status-update",
taskId: requestContext.taskId,
contextId: requestContext.contextId,
status: task.status,
final: true,
});
eventBus.finished();
}
}
src/routes/api.ts — Add HTTP endpointsapi.get("/my-endpoint", (c) => {
return c.json({ data: "your response" });
});
New routes under /api/* are automatically payment-gated. Update the price in src/app.ts if needed.
├── src/
│ ├── app.ts # Composition root — middleware chain + routes
│ ├── config.ts # Environment config (async for Secrets Manager)
│ ├── server.ts # Node.js entrypoint (local dev)
│ ├── lambda.ts # AWS Lambda entrypoint (lazy init)
│ ├── agent/
│ │ ├── card.ts # AgentCard builder
│ │ ├── entrypoints.ts # ★ Structured entrypoints (customize this)
│ │ ├── executor.ts # ★ Task execution logic (customize this)
│ │ └── skills.ts # ★ Skill definitions (customize this)
│ ├── a2a/
│ │ └── handler.ts # A2A JSON-RPC handler + agent card endpoint
│ ├── payments/
│ │ └── x402.ts # x402 payment middleware factory
│ ├── routes/
│ │ ├── api.ts # ★ Paid HTTP routes (customize this)
│ │ └── health.ts # Health check
│ └── identity/
│ └── erc8004.ts # ERC-8004 registration (agent0-sdk)
├── scripts/
│ ├── create-wallet.ts # Generate wallet + set function_name → .env + terraform.tfvars
│ ├── register-identity.ts# Register on-chain identity
│ └── deploy.sh # Build + push + terraform apply
├── infra/
│ ├── main.tf # Lambda, ECR, IAM, Secrets Manager
│ ├── variables.tf # Terraform variable definitions
│ ├── outputs.tf # Terraform outputs (function URL, etc.)
│ └── terraform.tfvars.example
├── assets/
│ └── icon.png # Agent icon (uploaded to IPFS during registration)
├── test/ # Vitest tests
├── .env.example # Environment template
├── Dockerfile # Multi-stage (lambda default, server for ECS)
└── tsconfig.json
Files marked with ★ are the ones you customize.
| Variable | Required | Default | Description |
|---|---|---|---|
WALLET_ADDRESS |
Yes | — | Ethereum wallet address |
PRIVATE_KEY |
Yes (local dev) | — | Private key for signing. Not needed on Lambda if PRIVATE_KEY_SECRET_ARN is set. |
PRIVATE_KEY_SECRET_ARN |
Yes (Lambda) | — | AWS Secrets Manager ARN. Lambda uses this instead of PRIVATE_KEY. |
NETWORK |
No | eip155:84532 |
Chain identifier (Base Sepolia) |
RPC_URL |
No | https://sepolia.base.org |
JSON-RPC endpoint |
CDP_API_KEY_ID |
When payments enabled | — | CDP API key ID for x402 facilitator authentication |
CDP_API_KEY_SECRET |
When payments enabled | — | CDP API key secret for x402 facilitator authentication |
BYPASS_PAYMENTS |
No | false |
Skip x402 payment enforcement. Throws if true in production (NODE_ENV=production). |
AGENT_NAME |
No | Hello Agent |
Agent display name (shown in agent card) |
AGENT_DESCRIPTION |
No | A simple Hello World agent |
Agent description (shown in agent card) |
AGENT_URL |
No | http://localhost:3000 |
Public URL. Set to Function URL when deploying to Lambda. |
PORT |
No | 3000 |
Local dev server port |
AGENT_ID |
No | — | ERC-8004 agent token ID. Set after first registration. Used by register script for updates. |
PINATA_JWT |
For registration | — | Pinata API JWT. Required only for npm run register (ERC-8004). |
AGENT_IMAGE_PATH |
No | assets/icon.png |
Path to agent icon. Uploaded to IPFS during registration if present. |
AGENT_PROVIDER_NAME |
No | — | Provider org name. Requires AGENT_PROVIDER_URL to also be set. |
AGENT_PROVIDER_URL |
No | — | Provider org URL |
AGENT_DOCS_URL |
No | — | Documentation URL (shown in agent card) |
AGENT_ICON_URL |
No | — | Icon URL (shown in agent card) |
The same wallet works on both testnet and mainnet. Switch by editing .env and infra/terraform.tfvars:
| Base Sepolia (testnet) | Base Mainnet | |
|---|---|---|
NETWORK |
eip155:84532 |
eip155:8453 |
RPC_URL |
https://sepolia.base.org |
https://mainnet.base.org |
The CDP facilitator (@coinbase/x402) handles both networks — no URL switching needed. Just set CDP_API_KEY_ID and CDP_API_KEY_SECRET.
After switching, redeploy (npm run deploy) and re-register identity (npm run register) on the new network.
npm test # Run all tests
npm run lint # TypeScript type check
25 tests cover app composition (including JSON-RPC error handling and Zod validation), agent card generation, executor event publishing, config loading (including bypass-payments safety), and Lambda handler setup.
The trust layer for agent-to-agent commerce — natural-language mandates, ERC-7710 delegated permissions, x402 payments, escrow, and dispute resolution as one open, catch-all Agent Skill / Claude Code plugin.
Daydreams is a set of tools for building agents for commerce
Agent behavior that compiles
Lucid Agents Commerce SDK. Bootstrap AI agents in 60 seconds that can pay, sell, and participate in agentic commerce supply chains. Our protocol agnostic SDK provides CLI-generated templates and drop-in adapters for Hono, Express, Next.js, and TanStack, giving you instant access to crypto/fiat payment rails (AP2, A2A, x402, ERC8004).
An operating system built for AI agents — talk to your NixOS server instead of SSH-ing in. Typed, audited tool access with atomic rollback on every change. Research-grade; run it on a disposable box, not production.
A complete TypeScript implementation of the Python x402 payment protocol extension for A2A (Agent-to-Agent) communication. Enable your AI agents to request, verify, and settle crypto payments seamlessly.
A local-first AI agent with persistent memory, emotional intelligence, and a peer-to-peer skills economy.
The A2A x402 Extension brings cryptocurrency payments to the Agent-to-Agent (A2A) protocol, enabling agents to monetize their services through on-chain payments. This extension revives the spirit of HTTP 402 "Payment Required" for the decentralized agent ecosystem.
Aser is a lightweight, self-assembling AI Agent frame.
Golang SDK for A2A Protocol
A small, powerful, open-source CLI coding agent that works with open models.
Beacon - agent-to-agent pings with optional RTC value attached (BoTTube/Moltbook/RustChain + UDP bus)