Accept anything as payment! An x402 proxy where sponsors pay for user access in exchange for actions.
Payload Exchange is a proxy layer that intercepts x402 payment requests and introduces a third party: Sponsors. This expands the end users' experience to alternative payments other than stablecoins or other monetary currencies, by having sponsors cover the payment (fully or partially) in exchange for user actions or data.
Imagine a near future where quality content providers put their resources (APIs, articles, videos, data endpoints, digital goods...) behind x402 payment walls. Majority of them might be trivial tasks with small fees, some even consumed by AI agents. For better user experience and more sophisticated agentic workflows, these x402 payments can be sponsored in exchange for some minor action or data from the user—a really free way to pay with whatever you've got to offer.
- x402 Proxy Layer: Intercepts and manages x402 payment requests
- Sponsor Integration: Allows sponsors to cover payments in exchange for user actions
- Action Plugins: Flexible plugin system for different action types (email capture, surveys, GitHub stars, code verification)
- ChatGPT Integration: Built with OpenAI Apps SDK and Model Context Protocol (MCP) for native ChatGPT widget rendering
- Wallet Support: CDP (Coinbase Developer Platform) embedded wallets for seamless payments
- Resource Discovery: Search and browse available x402-protected resources
graph TB
subgraph "ChatGPT Client"
ChatGPT[ChatGPT Interface]
Widget[Widget Renderer]
end
subgraph "Payload Exchange"
MCP[MCP Server<br/>app/mcp/route.ts]
Proxy[Proxy Layer<br/>app/api/proxy]
Paywall[Paywall System<br/>app/paywall]
Resources[Resource Registry<br/>server/core/resources]
end
subgraph "Action System"
Registry[Action Registry<br/>server/core/actions]
Email[Email Capture Plugin]
Survey[Survey Plugin]
GitHub[GitHub Star Plugin]
Code[Code Verification Plugin]
end
subgraph "Payment Layer"
X402[x402 Client<br/>server/core/x402]
CDP[CDP Wallets<br/>components/cdp-provider]
Treasury[Treasury Wallet]
end
subgraph "External Services"
Upstream[Upstream x402 Resources]
Sponsor[Sponsors]
User[End Users]
end
ChatGPT -->|Tool Calls| MCP
MCP -->|Widget HTML| Widget
Widget -->|Renders| Paywall
User -->|Requests Resource| Proxy
Proxy -->|Intercepts| Upstream
Upstream -->|402 Payment Required| Proxy
Proxy -->|Shows| Paywall
Paywall -->|Lists Actions| Registry
Registry --> Email
Registry --> Survey
Registry --> GitHub
Registry --> Code
User -->|Completes Action| Paywall
Paywall -->|Validates| Registry
Registry -->|Reward Eligible| Sponsor
Sponsor -->|Covers Payment| X402
X402 -->|Pays| Upstream
Upstream -->|Returns Resource| Proxy
Proxy -->|Delivers| User
Paywall -->|Direct Payment| CDP
CDP -->|USDC Payment| X402
X402 -->|Settles| Treasury
MCP -->|Queries| Resources
Resources -->|Metadata| Paywall
payload-exchange/
├── app/
│ ├── (dashboard)/ # Dashboard routes
│ │ ├── sponsor/ # Sponsor management
│ │ └── user/ # User management
│ ├── api/
│ │ ├── payload/ # x402 proxy endpoints
│ │ └── proxy/ # General proxy routes
│ ├── mcp/
│ │ └── route.ts # MCP server for ChatGPT integration
│ ├── paywall/
│ │ └── paywall-client.tsx # Paywall UI component
│ └── resources/ # Resource discovery UI
│
├── components/
│ ├── paywall-widget.tsx # Main paywall component
│ ├── cdp-provider.tsx # CDP wallet provider
│ └── ui/ # Reusable UI components
│
├── server/
│ ├── core/
│ │ ├── actions/ # Action plugin system
│ │ │ ├── registry.ts # Plugin registry
│ │ │ └── plugins/ # Action plugins
│ │ ├── resources/ # Resource management
│ │ │ └── registry.ts # Resource registry
│ │ └── x402/ # x402 client implementation
│ ├── db/ # Database schema and queries
│ └── hono/ # Hono API routes
│
└── hooks/ # React hooks for app functionality
- Node.js 18+ or Bun
- PostgreSQL database (for production)
- CDP Project ID from Coinbase Developer Platform
# Install dependencies
npm install
# or
pnpm install
# or
bun installCopy .env.example to .env.local and configure:
# Application URL (required for iframe rendering)
TUNNEL_URL=http://localhost:3000
# Database connection
DATABASE_URL=postgresql://user:password@localhost:5432/payload_exchange
# CDP Configuration
NEXT_PUBLIC_CDP_PROJECT_ID=your-project-id
# Treasury wallet for receiving payments
TREASURY_WALLET_ADDRESS=0x...
TREASURY_PRIVATE_KEY=0x...
# x402 endpoint (optional, for custom x402 implementation)
X402_ENDPOINT=https://...
# VLayer configuration (for verification)
VLAYER_API_ENDPOINT=https://...
VLAYER_CLIENT_ID=...
VLAYER_BEARER_TOKEN=...-
Get your CDP Project ID:
- Sign up at CDP Portal
- Create a new project and copy your Project ID
-
Configure your domain:
- Navigate to Domains Configuration
- Add
http://localhost:3000for local development - Add your production domain when deploying
-
Set environment variable:
NEXT_PUBLIC_CDP_PROJECT_ID=your-actual-project-id
# Generate migrations
npm run db:generate
# Run migrations
npm run db:migrate
# Or push schema directly (development)
npm run db:push
# Open Drizzle Studio (optional)
npm run db:studionpm run dev
# or
pnpm devOpen http://localhost:3000 to see the app.
Payload Exchange integrates with ChatGPT through the OpenAI Apps SDK using Model Context Protocol (MCP).
The MCP server is available at /mcp and exposes:
Tools:
open_app- Open the Payload Exchange app widgetget_resource_by_url- Fetch a specific resource by URLlist_resources- List all available x402 resourcessearch_resources- Search resources by queryshow_paywall- Display paywall for a resource
Resources:
content-widget- Main app widget HTMLresource-widget- Resource viewer widget HTMLpaywall-widget- Paywall widget HTML
- Deploy your app to Vercel or another hosting provider
- In ChatGPT, navigate to Settings → Connectors → Create
- Add your MCP server URL:
https://your-app.vercel.app/mcp
Note: Connecting MCP servers to ChatGPT requires developer mode access. See the connection guide for setup instructions.
Payload Exchange uses a plugin-based system for different action types:
-
Email Capture (
email-capture)- Captures user email addresses
- Validates email format
-
Survey (
survey)- Collects user responses to custom surveys
- Configurable questions and response types
-
GitHub Star (
github-star)- Verifies GitHub repository stars
- OAuth integration for GitHub
-
Code Verification (
code-verification)- Verifies code snippets or solutions
- Uses VLayer for verification
Implement the ActionPlugin interface:
export interface ActionPlugin<Config = any> {
id: string;
name: string;
describe(config?: Config): {
humanInstructions: string;
schema?: any;
};
start(ctx: {
userId: string;
resourceId: string;
actionId: string;
config: Config;
}): Promise<{
instanceId: string;
instructions: string;
url?: string;
metadata?: Record<string, any>;
}>;
validate(ctx: {
instanceId: string;
userId: string;
resourceId: string;
actionId: string;
config: Config;
input: any;
}): Promise<{
status: ActionStatus;
reason?: string;
rewardEligible?: boolean;
}>;
}Register your plugin in server/core/actions/registry.ts.
- User requests a resource protected by x402
- Proxy intercepts the request and receives a 402 Payment Required response
- Paywall displays available payment options:
- Direct payment (USDC via CDP)
- Sponsored actions (complete an action instead)
- User chooses an action or direct payment
- Action validation occurs (if action chosen)
- Sponsor covers payment (if action completed successfully)
- x402 payment is made to upstream resource
- Resource is delivered to the user
The core MCP server implementation that exposes tools and resources to ChatGPT.
Key features:
- Tool registration with OpenAI-specific metadata
- Resource registration for HTML widget rendering
- Cross-linking between tools and resources via
templateUri
Critical: Set assetPrefix to ensure /_next/ static assets are fetched from the correct origin:
const nextConfig: NextConfig = {
assetPrefix: APP_BASE_URL, // Prevents 404s on /_next/ files in iframe
};Without this, Next.js will attempt to load assets from the iframe's URL, causing 404 errors.
The <NextChatSDKBootstrap> component patches browser APIs to work correctly within the ChatGPT iframe:
What it patches:
history.pushState/history.replaceState- Prevents full-origin URLs in historywindow.fetch- Rewrites same-origin requests to use the correct base URL<html>attribute observer - Prevents ChatGPT from modifying the root element
Required configuration:
<html lang="en" suppressHydrationWarning>
<head>
<NextChatSDKBootstrap baseUrl={APP_BASE_URL} />
</head>
<body>{children}</body>
</html>Note: suppressHydrationWarning is currently required because ChatGPT modifies the initial HTML before the Next.js app hydrates, causing hydration mismatches.
- OpenAI Apps SDK Documentation
- OpenAI Apps SDK - MCP Server Guide
- Model Context Protocol
- x402 Protocol
- Next.js Documentation
- CDP Embedded Wallets Documentation
- CDP Web SDK Reference
- ETHGlobal Showcase
This project is designed to work seamlessly with Vercel deployment. The baseUrl.ts configuration automatically detects Vercel environment variables and sets the correct asset URLs.
The configuration automatically handles:
- Production URLs via
VERCEL_PROJECT_PRODUCTION_URL - Preview/branch URLs via
VERCEL_BRANCH_URL - Asset prefixing for correct resource loading in iframes
Ensure all required environment variables are set in your Vercel project settings:
TUNNEL_URLorVERCEL_URL(auto-detected)DATABASE_URLNEXT_PUBLIC_CDP_PROJECT_IDTREASURY_WALLET_ADDRESSTREASURY_PRIVATE_KEYVLAYER_API_ENDPOINT(if using code verification)VLAYER_CLIENT_IDVLAYER_BEARER_TOKEN
# Development
npm run dev # Start development server
# Database
npm run db:generate # Generate Drizzle migrations
npm run db:migrate # Run migrations
npm run db:push # Push schema directly (dev)
npm run db:studio # Open Drizzle Studio
# Code Quality
npm run check # Run Biome linter
npm run fix # Fix linting issues
# Utilities
npm run create-account # Create a new account (script)Contributions are welcome! Please feel free to submit a Pull Request.
[Add your license here]
Built for ETHGlobal Buenos Aires 🚀