oneie
Version:
Build apps, websites, and AI agents in English. Zero-interaction setup for AI agents (Claude Code, Cursor, Windsurf). Download to your computer, run in the cloud, deploy to the edge. Open source and free forever.
1,354 lines (1,168 loc) • 39.3 kB
Markdown
---
title: X402
dimension: connections
category: x402.md
tags: agent, ai, blockchain, protocol
related_dimensions: events, knowledge, people, things
scope: global
created: 2025-11-03
updated: 2025-11-03
version: 1.0.0
ai_context: |
This document is part of the connections dimension in the x402.md category.
Location: one/connections/x402.md
Purpose: Documents x402 protocol integration - http-native payments
Related dimensions: events, knowledge, people, things
For AI agents: Read this to understand x402.
---
# X402 Protocol Integration - HTTP-Native Payments
**Version:** 1.0.0
**Purpose:** Integrate X402 protocol for instant, frictionless digital payments across ONE platform agents and services
**Protocol:** https://www.x402.org/
**GitHub:** https://github.com/coinbase/x402
---
## Overview
**X402** is an open protocol for internet-native payments built around the HTTP 402 "Payment Required" status code. It enables instant digital transactions without complex registration processes, making it ideal for AI agent-to-agent payments, API monetization, and micropayments.
**Key Benefits:**
- ✅ **Zero fees** for customers and merchants
- ✅ **Instant settlement** (~2 seconds on blockchain)
- ✅ **Minimal integration** (1 line of middleware code)
- ✅ **Blockchain agnostic** (Solana, Ethereum, Base, etc.)
- ✅ **No account creation** required
- ✅ **Micropayments** as low as $0.001
- ✅ **HTTP-native** (works with existing web infrastructure)
**Use Cases in ONE Platform:**
1. AI agent API calls (pay-per-request)
2. External agent integrations (ElizaOS, AutoGen, etc.)
3. N8N workflow executions (pay-per-run)
4. Cloud storage access (pay-per-GB)
5. Content creator micropayments
6. Multi-agent collaboration billing
---
## Architecture: X402 + Effect.ts + Convex
```
┌─────────────────────────────────────────────────────────────────┐
│ FRONTEND (React + Astro) │
├─────────────────────────────────────────────────────────────────┤
│ Payment UI Components │
│ ├─ <PaymentPrompt> - Show 402 payment required │
│ ├─ <WalletConnect> - Connect crypto wallet │
│ ├─ <PaymentHistory> - View transaction history │
│ └─ <BalanceDisplay> - Show wallet balance │
└──────────────────┬──────────────────────────────────────────────┘
│
↓ X-PAYMENT HTTP Header
┌──────────────────┐
│ Astro API Route │
│ (X402 Handler) │
└────────┬─────────┘
│
↓
┌─────────────────────────────────────────────────────────────────┐
│ Convex Backend │
├─────────────────────────────────────────────────────────────────┤
│ X402PaymentService (Effect.ts) │
│ ├─ verifyPayment(paymentPayload) → boolean │
│ ├─ createPaymentRequest(resource, amount) → PaymentRequired │
│ ├─ settlePayment(paymentId) → Transaction │
│ └─ getPaymentHistory(userId) → Payment[] │
│ │
│ X402FacilitatorService (Effect.ts) │
│ ├─ POST /verify - Validate payment │
│ ├─ POST /settle - Execute blockchain transaction │
│ ├─ GET /supported - List supported schemes/networks │
│ └─ Integrates with blockchain providers │
└──────────────────┬──────────────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────────────┐
│ Blockchain Layer (Multi-Chain) │
├─────────────────────────────────────────────────────────────────┤
│ Base (Coinbase L2) │
│ ├─ USDC transfers │
│ ├─ Low gas fees │
│ └─ Fast settlement │
│ │
│ Ethereum Mainnet │
│ ├─ USDC, DAI, USDT │
│ └─ Permit-based transfers │
│ │
│ Solana │
│ ├─ USDC (SPL token) │
│ └─ Ultra-low fees │
└─────────────────────────────────────────────────────────────────┘
```
**Key Integration Points:**
1. Astro API routes handle X402 protocol (402 responses, X-PAYMENT headers)
2. Effect.ts services manage payment verification and settlement
3. Convex stores payment records and transaction history
4. Multi-chain support via Effect.ts providers (Base, Ethereum, Solana)
---
## Part 1: X402 Protocol Specification
### HTTP 402 Flow
**1. Client Requests Protected Resource**
```http
GET /api/agent/execute?taskId=123 HTTP/1.1
Host: one.ie
Authorization: Bearer user-token-123
```
**2. Server Responds with 402 Payment Required**
```http
HTTP/1.1 402 Payment Required
Content-Type: application/json
{
"x402Version": 1,
"accepts": [
{
"scheme": "permit",
"network": "base",
"maxAmountRequired": "0.01",
"resource": "/api/agent/execute?taskId=123",
"payTo": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"asset": "USDC",
"decimals": 6
},
{
"scheme": "permit",
"network": "ethereum",
"maxAmountRequired": "0.01",
"resource": "/api/agent/execute?taskId=123",
"payTo": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"asset": "USDC",
"decimals": 6
},
{
"scheme": "transfer",
"network": "solana",
"maxAmountRequired": "0.01",
"resource": "/api/agent/execute?taskId=123",
"payTo": "DYw8jCTfwHNRJhhmFcbXvVDTqWMEVFBX6ZKUmG5CNSKK",
"asset": "USDC",
"decimals": 6
}
],
"error": null
}
```
**3. Client Creates Payment and Retries Request**
```http
POST /api/agent/execute?taskId=123 HTTP/1.1
Host: one.ie
Authorization: Bearer user-token-123
X-PAYMENT: {"x402Version":1,"scheme":"permit","network":"base","payload":{"permit":{"..."},"signature":"0x..."}}
Content-Type: application/json
{
"parameters": {
"action": "analyze_metrics",
"userId": "user-123"
}
}
```
**4. Server Verifies Payment and Returns Resource**
```http
HTTP/1.1 200 OK
Content-Type: application/json
X-PAYMENT-ID: pay_1234567890
{
"result": {
"analysis": "...",
"metrics": {...}
}
}
```
### TypeScript Protocol Interfaces
**File:** `convex/protocols/x402.ts`
```typescript
import { v } from "convex/values";
/**
* X402 Protocol Version
*/
export const X402_VERSION = 1;
/**
* Payment Required Response (HTTP 402)
*/
export interface PaymentRequired {
x402Version: number;
accepts: PaymentRequirement[];
error?: string;
}
/**
* Payment Requirement for a specific scheme/network
*/
export interface PaymentRequirement {
scheme: PaymentScheme;
network: BlockchainNetwork;
maxAmountRequired: string; // Decimal string (e.g., "0.01")
resource: string; // API endpoint path
payTo: string; // Recipient address
asset: string; // Token symbol (e.g., "USDC")
decimals?: number; // Token decimals (default 6 for USDC)
facilitator?: string; // Facilitator server URL
metadata?: {
description?: string; // Payment description
invoiceId?: string; // Invoice reference
[key: string]: any;
};
}
/**
* Payment Schemes
*/
export type PaymentScheme =
| "permit" // ERC-2612 permit (gasless approval + transfer)
| "transfer" // Direct token transfer
| "signature" // Signature-based payment
| "invoice"; // Invoice-based payment
/**
* Supported Blockchain Networks
*/
export type BlockchainNetwork =
| "base" // Coinbase Base L2
| "ethereum" // Ethereum mainnet
| "solana" // Solana mainnet
| "arbitrum" // Arbitrum L2
| "optimism" // Optimism L2
| "polygon"; // Polygon PoS
/**
* Payment Payload (sent in X-PAYMENT header)
*/
export interface PaymentPayload {
x402Version: number;
scheme: PaymentScheme;
network: BlockchainNetwork;
payload: PermitPayload | TransferPayload | SignaturePayload | InvoicePayload;
}
/**
* Permit-based Payment (ERC-2612)
*/
export interface PermitPayload {
permit: {
owner: string; // Sender address
spender: string; // Facilitator contract address
value: string; // Amount (in token units)
nonce: number; // Permit nonce
deadline: number; // Unix timestamp
};
signature: string; // EIP-712 signature
transferData?: {
recipient: string; // Final recipient
amount: string; // Transfer amount
};
}
/**
* Direct Transfer Payment
*/
export interface TransferPayload {
txHash: string; // Transaction hash
from: string; // Sender address
to: string; // Recipient address
amount: string; // Amount transferred
token: string; // Token contract address
timestamp: number; // Transaction timestamp
}
/**
* Signature-based Payment
*/
export interface SignaturePayload {
message: string; // Signed message
signature: string; // Signature
signer: string; // Signer address
nonce: string; // Unique nonce
}
/**
* Invoice-based Payment
*/
export interface InvoicePayload {
invoiceId: string; // Invoice identifier
proof: string; // Payment proof
amount: string; // Amount paid
timestamp: number; // Payment timestamp
}
/**
* Facilitator Endpoints
*/
export interface FacilitatorEndpoints {
verify: string; // POST /verify - Validate payment
settle: string; // POST /settle - Execute settlement
supported: string; // GET /supported - List schemes/networks
}
/**
* Payment Verification Request
*/
export interface VerifyPaymentRequest {
paymentPayload: PaymentPayload;
requirement: PaymentRequirement;
resource: string;
timestamp: number;
}
/**
* Payment Verification Response
*/
export interface VerifyPaymentResponse {
valid: boolean;
paymentId?: string;
txHash?: string;
error?: string;
metadata?: {
blockNumber?: number;
confirmations?: number;
gasUsed?: string;
[key: string]: any;
};
}
/**
* Settlement Request
*/
export interface SettlePaymentRequest {
paymentId: string;
paymentPayload: PaymentPayload;
requirement: PaymentRequirement;
}
/**
* Settlement Response
*/
export interface SettlePaymentResponse {
settled: boolean;
txHash: string;
blockNumber?: number;
error?: string;
}
/**
* Supported Schemes Response
*/
export interface SupportedSchemesResponse {
schemes: Array<{
scheme: PaymentScheme;
networks: BlockchainNetwork[];
tokens: Array<{
symbol: string;
address: string;
decimals: number;
networks: BlockchainNetwork[];
}>;
}>;
}
/**
* Convex validators for X402 protocol
*/
export const paymentRequirementValidator = {
scheme: v.union(
v.literal("permit"),
v.literal("transfer"),
v.literal("signature"),
v.literal("invoice")
),
network: v.union(
v.literal("base"),
v.literal("ethereum"),
v.literal("solana"),
v.literal("arbitrum"),
v.literal("optimism"),
v.literal("polygon")
),
maxAmountRequired: v.string(),
resource: v.string(),
payTo: v.string(),
asset: v.string(),
decimals: v.optional(v.number()),
facilitator: v.optional(v.string()),
metadata: v.optional(v.any()),
};
export const paymentPayloadValidator = {
x402Version: v.number(),
scheme: v.union(
v.literal("permit"),
v.literal("transfer"),
v.literal("signature"),
v.literal("invoice")
),
network: v.union(
v.literal("base"),
v.literal("ethereum"),
v.literal("solana"),
v.literal("arbitrum"),
v.literal("optimism"),
v.literal("polygon")
),
payload: v.any(),
};
```
---
## Part 2: Effect.ts Service Implementation
### X402PaymentService
**File:** `convex/services/x402-payment.ts`
```typescript
import { Effect } from "effect";
import { ConvexDatabase } from "./convex-database";
import type { Id } from "../_generated/dataModel";
import type {
PaymentRequired,
PaymentRequirement,
PaymentPayload,
VerifyPaymentRequest,
VerifyPaymentResponse,
X402_VERSION,
} from "../protocols/x402";
/**
* X402PaymentService - Implements X402 protocol for HTTP-native payments
*/
export class X402PaymentService extends Effect.Service<X402PaymentService>()(
"X402PaymentService",
{
effect: Effect.gen(function* () {
const db = yield* ConvexDatabase;
return {
/**
* Create a 402 Payment Required response
*/
createPaymentRequest: (args: {
resource: string;
amount: string;
description?: string;
userId?: Id<"entities">;
}) =>
Effect.gen(function* () {
// Get platform payment addresses
const paymentConfig = yield* getPaymentConfig();
// Create payment requirements for all supported networks
const accepts: PaymentRequirement[] = [
// Base (Coinbase L2) - Preferred
{
scheme: "permit",
network: "base",
maxAmountRequired: args.amount,
resource: args.resource,
payTo: paymentConfig.base.address,
asset: "USDC",
decimals: 6,
facilitator: paymentConfig.facilitatorUrl,
metadata: {
description: args.description,
preferredNetwork: true,
},
},
// Ethereum mainnet
{
scheme: "permit",
network: "ethereum",
maxAmountRequired: args.amount,
resource: args.resource,
payTo: paymentConfig.ethereum.address,
asset: "USDC",
decimals: 6,
facilitator: paymentConfig.facilitatorUrl,
metadata: {
description: args.description,
},
},
// Solana
{
scheme: "transfer",
network: "solana",
maxAmountRequired: args.amount,
resource: args.resource,
payTo: paymentConfig.solana.address,
asset: "USDC",
decimals: 6,
metadata: {
description: args.description,
},
},
];
const paymentRequired: PaymentRequired = {
x402Version: X402_VERSION,
accepts,
error: null,
};
// Log payment request
yield* db.insert("events", {
type: "payment_requested",
actorId: args.userId,
targetId: null,
timestamp: Date.now(),
metadata: {
protocol: "x402",
resource: args.resource,
amount: args.amount,
networks: accepts.map((a) => a.network),
},
});
return paymentRequired;
}),
/**
* Verify payment from X-PAYMENT header
*/
verifyPayment: (args: {
paymentPayload: PaymentPayload;
requirement: PaymentRequirement;
resource: string;
userId?: Id<"entities">;
}) =>
Effect.gen(function* () {
// Validate payload version
if (args.paymentPayload.x402Version !== X402_VERSION) {
return {
valid: false,
error: `Unsupported X402 version: ${args.paymentPayload.x402Version}`,
} as VerifyPaymentResponse;
}
// Validate scheme matches
if (args.paymentPayload.scheme !== args.requirement.scheme) {
return {
valid: false,
error: `Payment scheme mismatch: expected ${args.requirement.scheme}, got ${args.paymentPayload.scheme}`,
} as VerifyPaymentResponse;
}
// Validate network matches
if (args.paymentPayload.network !== args.requirement.network) {
return {
valid: false,
error: `Network mismatch: expected ${args.requirement.network}, got ${args.paymentPayload.network}`,
} as VerifyPaymentResponse;
}
// Call facilitator to verify payment
const facilitatorUrl =
args.requirement.facilitator || process.env.X402_FACILITATOR_URL;
const verifyRequest: VerifyPaymentRequest = {
paymentPayload: args.paymentPayload,
requirement: args.requirement,
resource: args.resource,
timestamp: Date.now(),
};
const response = yield* Effect.tryPromise({
try: () =>
fetch(`${facilitatorUrl}/verify`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(verifyRequest),
}).then((res) => res.json()),
catch: (error) =>
new Error(`Facilitator verification failed: ${error}`),
});
const verifyResponse = response as VerifyPaymentResponse;
if (!verifyResponse.valid) {
// Log failed verification
yield* db.insert("events", {
type: "payment_failed",
actorId: args.userId,
targetId: null,
timestamp: Date.now(),
metadata: {
protocol: "x402",
resource: args.resource,
error: verifyResponse.error,
scheme: args.paymentPayload.scheme,
network: args.paymentPayload.network,
},
});
return verifyResponse;
}
// Store verified payment
const paymentId = yield* db.insert("entities", {
type: "payment",
name: `X402 Payment - ${args.resource}`,
properties: {
protocol: "x402",
scheme: args.paymentPayload.scheme,
network: args.paymentPayload.network,
amount: args.requirement.maxAmountRequired,
asset: args.requirement.asset,
resource: args.resource,
payTo: args.requirement.payTo,
txHash: verifyResponse.txHash,
paymentId: verifyResponse.paymentId,
status: "verified",
userId: args.userId,
verifiedAt: Date.now(),
metadata: verifyResponse.metadata,
},
status: "active",
createdAt: Date.now(),
updatedAt: Date.now(),
});
// Log successful payment
yield* db.insert("events", {
type: "payment_verified",
actorId: args.userId,
targetId: paymentId,
timestamp: Date.now(),
metadata: {
protocol: "x402",
resource: args.resource,
amount: args.requirement.maxAmountRequired,
scheme: args.paymentPayload.scheme,
network: args.paymentPayload.network,
txHash: verifyResponse.txHash,
},
});
return {
...verifyResponse,
paymentId: paymentId as string,
};
}),
/**
* Get payment history for a user
*/
getPaymentHistory: (args: { userId: Id<"entities">; limit?: number }) =>
Effect.gen(function* () {
const payments = yield* db.query("entities", {
filter: (q) =>
q.and(
q.eq(q.field("type"), "payment"),
q.eq(q.field("properties.protocol"), "x402"),
q.eq(q.field("properties.userId"), args.userId)
),
limit: args.limit || 100,
});
return payments;
}),
/**
* Get total amount paid by user
*/
getTotalPaid: (args: { userId: Id<"entities">; asset?: string }) =>
Effect.gen(function* () {
const payments = yield* db.query("entities", {
filter: (q) => {
const conditions = [
q.eq(q.field("type"), "payment"),
q.eq(q.field("properties.protocol"), "x402"),
q.eq(q.field("properties.userId"), args.userId),
];
if (args.asset) {
conditions.push(
q.eq(q.field("properties.asset"), args.asset)
);
}
return q.and(...conditions);
},
});
const total = payments.reduce((sum, payment) => {
const amount = parseFloat(payment.properties.amount as string);
return sum + amount;
}, 0);
return {
total: total.toFixed(6),
asset: args.asset || "USDC",
count: payments.length,
};
}),
};
}),
dependencies: [ConvexDatabase.Default],
}
) {}
/**
* Helper: Get payment configuration
*/
const getPaymentConfig = () =>
Effect.gen(function* () {
return {
facilitatorUrl:
process.env.X402_FACILITATOR_URL || "https://facilitator.x402.org",
base: {
address:
process.env.X402_BASE_ADDRESS ||
"0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
usdcContract: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC on Base
},
ethereum: {
address:
process.env.X402_ETHEREUM_ADDRESS ||
"0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
usdcContract: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC on Ethereum
},
solana: {
address:
process.env.X402_SOLANA_ADDRESS ||
"DYw8jCTfwHNRJhhmFcbXvVDTqWMEVFBX6ZKUmG5CNSKK",
usdcMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC on Solana
},
};
});
```
---
## Part 3: Astro API Route Integration
### X402 Middleware
**File:** `src/pages/api/x402/middleware.ts`
```typescript
import type { APIRoute } from "astro";
import { X402PaymentService } from "@/convex/services/x402-payment";
import type { PaymentPayload, PaymentRequired } from "@/convex/protocols/x402";
/**
* X402 Middleware - Handle payment verification for protected routes
*/
export async function x402Middleware(
request: Request,
resource: string,
amount: string,
userId?: string
): Promise<Response | null> {
const paymentHeader = request.headers.get("X-PAYMENT");
// If no payment header, return 402 Payment Required
if (!paymentHeader) {
const paymentService = new X402PaymentService();
const paymentRequired = await paymentService.createPaymentRequest({
resource,
amount,
description: `Access to ${resource}`,
userId,
});
return new Response(JSON.stringify(paymentRequired), {
status: 402,
headers: {
"Content-Type": "application/json",
"X-PAYMENT-REQUIRED": "true",
},
});
}
// Parse payment payload
let paymentPayload: PaymentPayload;
try {
paymentPayload = JSON.parse(paymentHeader);
} catch (error) {
return new Response(
JSON.stringify({ error: "Invalid X-PAYMENT header format" }),
{
status: 400,
headers: { "Content-Type": "application/json" },
}
);
}
// Verify payment
const paymentService = new X402PaymentService();
const verification = await paymentService.verifyPayment({
paymentPayload,
requirement: {
scheme: paymentPayload.scheme,
network: paymentPayload.network,
maxAmountRequired: amount,
resource,
payTo: process.env.X402_BASE_ADDRESS!,
asset: "USDC",
},
resource,
userId,
});
if (!verification.valid) {
return new Response(
JSON.stringify({
error: verification.error || "Payment verification failed",
}),
{
status: 402,
headers: {
"Content-Type": "application/json",
"X-PAYMENT-FAILED": "true",
},
}
);
}
// Payment verified - return null to continue processing
return null;
}
```
### Protected API Route Example
**File:** `src/pages/api/agent/execute.ts`
```typescript
import type { APIRoute } from "astro";
import { x402Middleware } from "./x402/middleware";
import { IntelligenceAgent } from "@/convex/services/intelligence-agent";
export const POST: APIRoute = async ({ request, locals }) => {
const resource = "/api/agent/execute";
const amount = "0.01"; // $0.01 per request
const userId = locals.user?.id;
// X402 payment check
const paymentResponse = await x402Middleware(
request,
resource,
amount,
userId
);
if (paymentResponse) {
return paymentResponse; // Return 402 or payment error
}
// Payment verified - execute agent task
const { taskId, parameters } = await request.json();
const intelligenceAgent = new IntelligenceAgent();
const result = await intelligenceAgent.executeTask({
taskId,
userId,
parameters,
});
return new Response(JSON.stringify(result), {
status: 200,
headers: {
"Content-Type": "application/json",
"X-PAYMENT-VERIFIED": "true",
},
});
};
```
---
## Multi-Tenancy & Groups
All entities, connections, and events in this protocol are scoped to a `groupId`:
```typescript
// Every entity
{
groupId: Id<"groups">, // Required for multi-tenancy
type: "payment" | "x402_service",
// ... rest of fields
}
// Every connection
{
groupId: Id<"groups">, // Required for multi-tenancy
fromEntityId: Id<"entities">,
toEntityId: Id<"entities">,
relationshipType: "paid_via" | "uses_service",
// ... rest of fields
}
// Every event
{
groupId: Id<"groups">, // Required for multi-tenancy
type: "payment_requested" | "payment_verified" | "payment_failed",
// ... rest of fields
}
```
## Part 4: Ontology Integration
### Entity Types
Uses existing types (no new types needed):
```typescript
// Payment entity (existing)
| 'payment'
```
**Payment Properties for X402:**
```typescript
{
protocol: 'x402',
scheme: 'permit' | 'transfer' | 'signature' | 'invoice',
network: 'base' | 'ethereum' | 'solana' | 'arbitrum' | 'optimism' | 'polygon',
amount: string, // Decimal amount (e.g., "0.01")
asset: string, // Token symbol (e.g., "USDC")
resource: string, // API endpoint
payTo: string, // Recipient address
txHash?: string, // Blockchain transaction hash
paymentId?: string, // X402 payment ID
status: 'pending' | 'verified' | 'settled' | 'failed',
userId?: Id<'entities'>, // Payer user ID
verifiedAt?: number, // Verification timestamp
settledAt?: number, // Settlement timestamp
metadata: {
blockNumber?: number,
confirmations?: number,
gasUsed?: string,
[key: string]: any,
},
}
```
### Event Types
Uses existing types:
```typescript
// Payment requested
{
type: 'payment_requested', // Existing type
actorId: userId,
targetId: null,
timestamp: Date.now(),
metadata: {
protocol: 'x402',
resource: '/api/agent/execute',
amount: '0.01',
networks: ['base', 'ethereum', 'solana'],
}
}
// Payment verified
{
type: 'payment_verified', // Existing type
actorId: userId,
targetId: paymentId,
timestamp: Date.now(),
metadata: {
protocol: 'x402',
resource: '/api/agent/execute',
amount: '0.01',
scheme: 'permit',
network: 'base',
txHash: '0x...',
}
}
// Payment failed
{
type: 'payment_failed', // Existing type
actorId: userId,
targetId: null,
timestamp: Date.now(),
metadata: {
protocol: 'x402',
resource: '/api/agent/execute',
error: 'Insufficient balance',
scheme: 'permit',
network: 'base',
}
}
```
---
## Part 5: Frontend Integration
### PaymentPrompt Component
**File:** `src/components/payment/PaymentPrompt.tsx`
```tsx
import React, { useState } from "react";
import type { PaymentRequired } from "@/convex/protocols/x402";
import {
Card,
CardHeader,
CardTitle,
CardDescription,
CardContent,
CardFooter,
} from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Wallet, Check, X } from "lucide-react";
interface PaymentPromptProps {
paymentRequired: PaymentRequired;
onPaymentComplete: (paymentPayload: any) => void;
onCancel: () => void;
}
export function PaymentPrompt({
paymentRequired,
onPaymentComplete,
onCancel,
}: PaymentPromptProps) {
const [selectedNetwork, setSelectedNetwork] = useState(
paymentRequired.accepts[0]
);
const [processing, setProcessing] = useState(false);
const [error, setError] = useState<string | null>(null);
const handlePayment = async () => {
setProcessing(true);
setError(null);
try {
// Connect wallet (using Web3 provider)
const provider = await getWeb3Provider(selectedNetwork.network);
// Create payment payload based on scheme
let paymentPayload;
if (selectedNetwork.scheme === "permit") {
paymentPayload = await createPermitPayload(provider, selectedNetwork);
} else if (selectedNetwork.scheme === "transfer") {
paymentPayload = await createTransferPayload(provider, selectedNetwork);
}
onPaymentComplete(paymentPayload);
} catch (err) {
setError(err instanceof Error ? err.message : "Payment failed");
} finally {
setProcessing(false);
}
};
return (
<Card className="w-full max-w-md">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Wallet className="h-5 w-5" />
Payment Required
</CardTitle>
<CardDescription>
This resource requires payment to access
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
{/* Payment amount */}
<div className="rounded-lg border bg-muted p-4">
<div className="text-sm text-muted-foreground">Amount</div>
<div className="text-2xl font-bold">
${selectedNetwork.maxAmountRequired} {selectedNetwork.asset}
</div>
<div className="text-sm text-muted-foreground">
{selectedNetwork.metadata?.description || selectedNetwork.resource}
</div>
</div>
{/* Network selection */}
<div className="space-y-2">
<div className="text-sm font-medium">Select Network</div>
<div className="grid gap-2">
{paymentRequired.accepts.map((requirement, i) => (
<button
key={i}
onClick={() => setSelectedNetwork(requirement)}
className={`flex items-center justify-between rounded-lg border p-3 transition-colors ${
selectedNetwork === requirement
? "border-primary bg-primary/10"
: "hover:border-primary/50"
}`}
>
<div>
<div className="font-medium capitalize">
{requirement.network}
</div>
<div className="text-xs text-muted-foreground">
{requirement.scheme}
</div>
</div>
{selectedNetwork === requirement && (
<Check className="h-4 w-4 text-primary" />
)}
</button>
))}
</div>
</div>
{/* Error display */}
{error && (
<Alert variant="destructive">
<X className="h-4 w-4" />
<AlertDescription>{error}</AlertDescription>
</Alert>
)}
</CardContent>
<CardFooter className="flex gap-2">
<Button variant="outline" onClick={onCancel} className="flex-1">
Cancel
</Button>
<Button
onClick={handlePayment}
disabled={processing}
className="flex-1"
>
{processing
? "Processing..."
: `Pay $${selectedNetwork.maxAmountRequired}`}
</Button>
</CardFooter>
</Card>
);
}
// Helper functions (implement with Web3 libraries)
async function getWeb3Provider(network: string) {
// Implementation depends on wallet provider (MetaMask, WalletConnect, etc.)
return {} as any;
}
async function createPermitPayload(provider: any, requirement: any) {
// Create ERC-2612 permit signature
return {} as any;
}
async function createTransferPayload(provider: any, requirement: any) {
// Create direct transfer transaction
return {} as any;
}
```
---
## Part 6: Use Cases
### 1. AI Agent Pay-Per-Request
```typescript
// Protected AI agent endpoint
// File: src/pages/api/agent/intelligence/analyze.ts
export const POST: APIRoute = async ({ request, locals }) => {
// Require $0.01 payment per analysis
const paymentCheck = await x402Middleware(
request,
"/api/agent/intelligence/analyze",
"0.01",
locals.user?.id
);
if (paymentCheck) return paymentCheck;
// Execute analysis (payment verified)
const { userId, metrics } = await request.json();
const result = await intelligenceAgent.analyzeMetrics({ userId, metrics });
return new Response(JSON.stringify(result), { status: 200 });
};
```
### 2. External Agent Integration (ElizaOS)
```typescript
// Charge for ElizaOS agent collaboration
// File: src/pages/api/eliza/send-message.ts
export const POST: APIRoute = async ({ request, locals }) => {
// Require $0.005 per message to ElizaOS agent
const paymentCheck = await x402Middleware(
request,
"/api/eliza/send-message",
"0.005",
locals.user?.id
);
if (paymentCheck) return paymentCheck;
// Send message (payment verified)
const { agentId, message } = await request.json();
const result = await elizaOSService.sendMessage({ agentId, message });
return new Response(JSON.stringify(result), { status: 200 });
};
```
### 3. N8N Workflow Execution
```typescript
// Charge for workflow execution
// File: src/pages/api/workflow/execute.ts
export const POST: APIRoute = async ({ request, locals }) => {
const { workflowId } = await request.json();
// Get workflow pricing
const workflow = await getWorkflow(workflowId);
const price = workflow.properties.price || "0.10";
const paymentCheck = await x402Middleware(
request,
`/api/workflow/execute?id=${workflowId}`,
price,
locals.user?.id
);
if (paymentCheck) return paymentCheck;
// Execute workflow (payment verified)
const result = await n8nService.executeWorkflow({ workflowId });
return new Response(JSON.stringify(result), { status: 200 });
};
```
### 4. Cloud Storage Access
```typescript
// Pay-per-GB storage
// File: src/pages/api/storage/upload.ts
export const POST: APIRoute = async ({ request, locals }) => {
const contentLength = request.headers.get("content-length");
const sizeGB = parseInt(contentLength || "0") / 1_000_000_000;
const price = (sizeGB * 0.05).toFixed(3); // $0.05 per GB
const paymentCheck = await x402Middleware(
request,
"/api/storage/upload",
price,
locals.user?.id
);
if (paymentCheck) return paymentCheck;
// Upload file (payment verified)
const result = await storageService.upload(request.body);
return new Response(JSON.stringify(result), { status: 200 });
};
```
---
## Benefits
### 1. Instant Micropayments
- Payments settle in ~2 seconds on blockchain
- No waiting for traditional payment processors
- Enables pay-per-use business models
### 2. Zero Fees
- No processing fees for merchants
- No transaction fees for customers (except gas)
- Better economics than Stripe, PayPal, etc.
### 3. Global Access
- No geographic restrictions
- No account verification needed
- Crypto wallets work worldwide
### 4. Privacy-Preserving
- No personal information required
- Blockchain addresses only
- GDPR-compliant by design
### 5. Agent-to-Agent Payments
- AI agents can autonomously pay for services
- Machine-to-machine transactions
- Programmable payment logic
---
## Summary
**X402 Protocol Integration:**
- ✅ HTTP-native payment protocol (402 status code)
- ✅ Effect.ts services (X402PaymentService)
- ✅ Astro API middleware (x402Middleware)
- ✅ Multi-chain support (Base, Ethereum, Solana)
- ✅ Frontend payment UI (PaymentPrompt component)
- ✅ Complete type safety (TypeScript protocols)
**Use Cases:**
- ✅ AI agent API monetization
- ✅ External agent integration billing
- ✅ N8N workflow pay-per-execution
- ✅ Cloud storage pay-per-GB
- ✅ Content creator micropayments
**Non-Breaking:**
- Uses existing `payment` entity type
- Uses existing event types
- No schema changes needed
- Append-only integration
🎉 **Result:** Instant, frictionless digital payments for the ONE platform with zero fees and global access.