X402 Protocol
Technical documentation for the X402 micropayment protocol powering USIC's streaming payments.
Overview
X402 is a custom micropayment protocol designed specifically for streaming media. It enables instant, low-cost payments without requiring a blockchain transaction for every stream.
Instant Payments
Payments settle in real-time as content streams
Secure
Cryptographic signatures prevent fraud
Efficient
Batch multiple payments into one transaction
How It Works
1. Payment Channel Opening
When a listener starts streaming, they open a payment channel by signing a message authorizing payments up to a certain amount.
{
"listener": "0x1234...",
"maxAmount": "1000000", // 1 USDC
"nonce": 1,
"signature": "0xabcd..."
}2. Streaming & Payment Chunks
As the track plays, the client sends signed payment chunks to the server. Each chunk represents a portion of the stream (e.g., 30 seconds at the artist's set price).
{
"trackId": "abc123",
"chunkIndex": 5,
"amount": "10000", // 0.01 USDC (example, set by artist)
"timestamp": 1234567890,
"signature": "0xdef..."
}3. Settlement
When the stream ends or the payment channel closes, the server submits the final signed payment to the smart contract for settlement.
function settlePayment( address listener, address artist, uint256 amount, uint256 nonce, bytes signature ) external
Security Features
Signature Verification
All payment messages are signed by the listener's wallet. The smart contract verifies signatures on-chain to prevent fraud.
Nonce Protection
Each payment channel has a unique nonce to prevent replay attacks. Used nonces are tracked on-chain.
Amount Limits
Payment channels have maximum amounts to limit potential losses if a signature is compromised.
Timeout Protection
Payment channels expire after a set time period, requiring renewal for continued streaming.
API Integration
Client-Side Flow
1. Initialize Payment Channel
const signature = await wallet.signMessage({
message: JSON.stringify({
listener: address,
maxAmount: parseUnits("1", 6), // 1 USDC
nonce: Date.now()
})
})2. Send Payment Chunks
const response = await fetch('/api/x402/chunk', {
method: 'POST',
body: JSON.stringify({
trackId,
chunkIndex,
amount: parseUnits("0.01", 6), // Artist-set price
signature
})
})3. Close Channel
await fetch('/api/x402/settle', {
method: 'POST',
body: JSON.stringify({
trackId,
finalSignature
})
})Full Implementation
For a complete implementation example, check out our GitHub repository.
View on GitHub