Architecture
Preimage Research uses a stateless proxy-to-gateway pattern that keeps provider SDKs simple while centralizing payment logic in the Gateway.
System Overview
┌──────────────────────────────────────────────────────────────┐
│ Ecosystem Layer │
├──────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌──────────────────────────┐ │
│ │ Buyers │ │ API Providers │ │
│ │ │ │ │ │
│ │ - Web apps │ │ - Express APIs │ │
│ │ - Mobile │ │ - FastAPI services │ │
│ │ - CLI tools │ │ - Django apps │ │
│ │ - Scripts │ │ - Gin servers │ │
│ └──────┬──────┘ │ - Axum services │ │
│ │ └────────┬─────────────────┘ │
│ │ │ │
└─────────┼────────────────────────────┼────────────────────── ┘
│ │
│ │
┌─────────┼────────────────────────────┼──────────────────────┐
│ │ SDK Layer │ │
├─────────┼────────────────────────────┼──────────────────────┤
│ │ │ │
│ ┌──────▼────────┐ ┌────────▼───────────┐ │
│ │ @preimage/ │ │ Provider SDK │ │
│ │ client │ │ Middleware │ │
│ │ │ │ │ │
│ │ - Auto 402 │ │ - Forward requests │ │
│ │ - Sign USDC │ │ - Proxy to Gateway │ │
│ │ - Retry │ │ - Attach receipts │ │
│ └───────┬───────┘ └─────────┬──────────┘ │
│ │ │ │
└──────────┼────────────────────────────┼─────────────────────┘
│ │
│ HTTP/HTTPS │
│ │
┌──────────┼────────────────────────────┼─────────────────────┐
│ │ Core Infrastructure │ │
├──────────┼────────────────────────────┼─────────────────────┤
│ │ │ │
│ └────────────┬───────────────┘ │
│ │ │
│ ┌────────▼─────────────┐ │
│ │ Preimage Research Gateway │ │
│ │ │ │
│ │ - Generate challenges│ │
│ │ - Verify macaroons │ │
│ │ - Verify payments │ │
│ │ - Sign receipts │ │
│ │ - Manage providers │ │
│ └─────────┬────────────┘ │
│ │ │
│ │ │
│ ┌─────────▼────────────┐ │
│ │ x402 Facilitator │ │
│ │ │ │
│ │ - Submit USDC txs │ │
│ │ - Verify on-chain │ │
│ │ - Gas management │ │
│ └─────────┬────────────┘ │
│ │ │
└────────────────────────┼────────────────────────────────────┘
│
│
┌────────────────────────┼────────────────────────────────────┐
│ │ Blockchain Layer │
├────────────────────────┼────────────────────────────────────┤
│ │ │
│ ┌─────────▼────────────┐ │
│ │ Base / Ethereum / │ │
│ │ Polygon │ │
│ │ │ │
│ │ - USDC smart contract│ │
│ │ - EIP-3009 transfers │ │
│ │ - Settlement │ │
│ └──────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘Stateless Proxy Pattern
Why Proxy-to-Gateway?
Traditional payment systems require each API to:
- 🗄️ Maintain a database
- 🔐 Manage user accounts
- 💳 Process payments
- 📊 Track usage
- 🧾 Generate invoices
Preimage Research simplifies this: Provider SDKs are thin proxies that forward auth requests to the Gateway.
Benefits
| Aspect | Traditional | Preimage Research |
|---|---|---|
| Database | Required | Not needed |
| State | Stateful | Stateless |
| SDK Complexity | 1000+ LOC | 50-100 LOC |
| Payment Logic | Per-provider | Centralized |
| Updates | Manual deploy | Automatic |
| Consistency | Varies | Identical |
Stateless = Scalable. Your API can scale horizontally without worrying about session state or payment verification logic.
Component Breakdown
1. Client SDK (@preimage/client)
Purpose: Automatically handle 402 challenges for API consumers
Responsibilities:
- Detect
402 Payment Requiredresponses - Parse x402 challenges
- Sign USDC payments (EIP-3009)
- Retry requests with authorization
- Extract and return receipts
Example Flow:
const client = createClient({ ... });
// 1. Initial request → 402 response (handled internally)
// 2. Sign USDC payments (handled internally)
// 3. Retry with auth (handled internally)
// 4. Return data + receipt
const response = await client.request('/api/data');2. Provider SDKs
Purpose: Protect API endpoints with minimal code
Available SDKs:
- Express (Node.js)
- FastAPI (Python)
- Django (Python)
- Gin (Go)
- Axum (Rust)
Responsibilities:
- Intercept incoming requests
- Check for
Authorization: x402header - If missing → Forward to Gateway for challenge
- If present → Forward to Gateway for verification
- Attach receipt to response
- Pass request to API handler
Example (Express):
app.use('/api', createX402Middleware({
gatewayUrl: 'https://gateway.preimage.io',
providerId: 'prov_abc123',
pricing: { usdcPerUnit: 0.001 }
}));
app.get('/api/data', (req, res) => {
// Only called if payment verified!
res.json({ data: 'success' });
});3. Preimage Research Gateway
Purpose: Centralized payment logic and verification for Preimage Research
Responsibilities:
- Provider Management - Register providers, endpoints, wallets
- Challenge Generation - Create macaroons with pricing info
- Payment Verification - Validate signatures and amounts
- Facilitator Integration - Submit USDC transfers to blockchain
- Receipt Signing - Generate JWS receipts
- Rate Limiting - Prevent abuse
- Analytics - Track usage and revenue
API Endpoints:
POST /providers # Register provider
POST /providers/:id/endpoints # Add endpoint
POST /providers/:id/wallets # Add wallet
GET /challenge # Generate challenge
POST /verify # Verify payment
GET /receipts/:id # Get receiptThe Gateway is operated by Preimage Research. You don't need to deploy or maintain it.
4. x402 Facilitator
Purpose: Non-custodial blockchain transaction submission
Responsibilities:
- Receive signed USDC transfers
- Verify signatures
- Submit to blockchain
- Pay gas fees
- Return transaction hash
- Handle failures/retries
Supported Networks:
- Base (mainnet + sepolia)
- Ethereum (mainnet + sepolia)
- Polygon (mainnet + amoy)
Facilitators are non-custodial. They never hold funds - they only submit pre-signed transactions to the blockchain.
Request Flow (Detailed)
Challenge Phase
1. Client → Provider SDK
GET /api/data
2. Provider SDK → Gateway
POST /challenge
{
"providerId": "prov_abc",
"endpointId": "ep_xyz",
"pricing": { "usdcPerUnit": 0.001 }
}
3. Gateway → Provider SDK
200 OK
{
"macaroon": "...",
"accepts": [ ... ],
"requestId": "..."
}
4. Provider SDK → Client
402 Payment Required
{ x402 challenge }Payment Phase
5. Client (local)
- Parse challenge
- Sign USDC payment #1 (provider)
- Sign USDC payment #2 (platform)
- Build Authorization headerVerification Phase
6. Client → Provider SDK
GET /api/data
Authorization: x402 <macaroon>:<payload1>:<payload2>
7. Provider SDK → Gateway
POST /verify
{
"macaroon": "...",
"payloads": [ ... ],
"providerId": "...",
"endpointId": "..."
}
8. Gateway → Facilitator
POST /submit
{ signed USDC transfers }
9. Facilitator → Blockchain
transferWithAuthorization(...)
10. Blockchain → Facilitator
Transaction hash: 0x789...
11. Facilitator → Gateway
{ txHash: "0x789..." }
12. Gateway → Provider SDK
200 OK
{
"verified": true,
"receipt": "eyJ...", // JWS receipt
"paymentId": "pay_123"
}
13. Provider SDK → API Handler
req.x402 = { receipt, verified: true }
14. API Handler → Provider SDK
{ data: "response" }
15. Provider SDK → Client
200 OK
Preimage-Receipt: eyJ...
{ data: "response" }Data Flow
Macaroon Flow
Gateway
│
├─ Generate macaroon
│ ├─ Add caveat: provider-id
│ ├─ Add caveat: endpoint-id
│ ├─ Add caveat: expiry (5 min)
│ └─ Sign with Gateway secret
│
↓
Client
│
├─ Receive macaroon in 402 response
├─ Store temporarily
└─ Include in retry Authorization header
│
↓
Gateway
│
├─ Verify signature
├─ Check expiry caveat
├─ Check provider-id caveat
└─ Check endpoint-id caveatPayment Flow
Client Wallet
│
├─ Sign USDC transfer #1 (provider)
│ └─ EIP-712 signature
│
├─ Sign USDC transfer #2 (platform)
│ └─ EIP-712 signature
│
↓
Gateway
│
├─ Verify signatures
├─ Check amounts
└─ Submit to facilitator
│
↓
Facilitator
│
├─ Call USDC.transferWithAuthorization(...)
├─ Payment #1 → Provider wallet (98%)
└─ Payment #2 → Platform wallet (2%)
│
↓
Blockchain
│
├─ Verify signatures
├─ Check balances
├─ Execute transfers
└─ Emit eventsSecurity Model
Trust Boundaries
| Component | Trusted By | Trust Level |
|---|---|---|
| Client SDK | Buyer | Full (open source) |
| Provider SDK | Provider | Full (open source) |
| Gateway | Both | Verifiable (signed receipts) |
| Facilitator | Both | Non-custodial (can't steal funds) |
| Blockchain | Everyone | Trustless (EVM) |
What If Gateway Is Malicious?
Cannot:
- ❌ Steal USDC (non-custodial, signed transfers only)
- ❌ Forge receipts (public key verification)
- ❌ Charge wrong amount (client signs specific amounts)
Can (but detectable):
- ⚠️ Refuse to process payments (provider loses money)
- ⚠️ Return fake verification (receipt verification catches this)
Receipts provide accountability. Every payment has a cryptographically signed proof that can be independently verified.
What If Provider SDK Is Malicious?
Cannot:
- ❌ Steal USDC (never has access to private keys)
- ❌ Forge receipts (Gateway signature required)
Can:
- ⚠️ Not honor API requests (buyer wasted money - reputation damage)
Scalability
Gateway Scalability
- Horizontal scaling with load balancer
- Stateless (no session management)
- Cached macaroon secrets (fast verification)
- Async receipt signing (non-blocking)
Provider SDK Scalability
- Completely stateless
- No database required
- No session storage
- CDN-friendly (cache static responses)
Blockchain Scalability
| Network | TPS | Block Time | Finality |
|---|---|---|---|
| Base | ~1000 | 2s | 2s |
| Ethereum | ~15 | 12s | 12min |
| Polygon | ~7000 | 2s | 2s |
We recommend Base for production. It offers the best balance of speed, cost, and security for x402 payments.