Real-time x402 payments over WebSockets
Pay once, stream requests continuously.
WebSocket relay lets agents reuse a single connection for multiple paid requests — faster, cheaper, and optimized for real-time workloads like AI agents, chat systems, and streaming APIs.
10-second example
import { RelaiWebSocketClient } from "@relai-fi/x402/ws"
const ws = new RelaiWebSocketClient({
url: "wss://api.relai.fi/api/ws/relay",
wallets: { solana: solanaWallet, evm: evmWallet }
})
await ws.connect()
// first call — triggers 402 → sign → retry automatically
const res = await ws.call({
apiId: "1769629274857",
path: "/v1/chat/completions",
body: { messages: [{ role: "user", content: "hello" }] }
})
// subsequent calls — no reconnect, no new handshake
const res2 = await ws.call({ apiId: "1769629274857", path: "/v1/chat/completions", ... })Why WebSocket?
Use WebSocket relay when:
How it works
WebSocket relay keeps the same x402 payment model. Only the transport changes — not the payment logic.
Shared endpoint
Each API has its own HTTP relay URL — WebSocket calls go through one shared gateway.
https://api.relai.fi/relay/{apiId}/...wss://api.relai.fi/api/ws/relayGiven the HTTP URL https://api.relai.fi/relay/1769629274857/v1/chat/completions?model=gpt-4o-mini, the WS parameters are:
Request format
Send a relay.call message with a unique id for response correlation:
{
"id": "req-42",
"method": "relay.call",
"params": {
"apiId": "1769629274857",
"path": "/v1/chat/completions?model=gpt-4o-mini",
"requestMethod": "POST",
"requestHeaders": {
"Content-Type": "application/json"
},
"requestBody": {
"messages": [{ "role": "user", "content": "Hello" }]
}
}
}Payment handshake
Same x402 flow as HTTP — just over WebSocket frames:
paymenterror.code = 402 and error.paymentRequiredpayment field addedresult and optional paymentResponsePersistent connections
For API providers
You don't need to change anything. Keep your existing HTTP relay integration — buyers can still access your paid endpoints over WebSocket automatically. The same x402 payment flow applies; only the transport is different.
Troubleshooting
Ensure every request has a unique id and your client matches responses by that id.
Verify the retry request contains a top-level payment field matching one of the accepted requirements.
Keep HTTP fallback enabled and set a shorter WS timeout so flows are not blocked by long retries.