Superfluid Streams
Superfluid streams enable continuous, real-time micropayments for subscription-based APIs through money streaming protocols. Instead of making individual payments for each API call, users create ongoing payment streams that flow continuously to API providers, enabling pay-per-second usage models without individual transactions.
How Superfluid Streams Work
Think of it like a financial "tap" that you turn on to start paying an API provider. Once activated, tokens flow continuously from your wallet to the provider's wallet in real-time. The API provider can verify your active stream and grant access to their services as long as the payment keeps flowing.
Best Use Cases
- Subscription-based APIs: Pay continuously for ongoing API access without monthly billing
- Real-time data feeds: Stream payments for live data consumption like market prices or IoT sensor data
- Usage-based billing: Automatic payment adjustment based on actual consumption
- Long-running processes: Pay for extended computational or storage services that run over time
- IoT and sensor networks: Continuous payments for device data streams and telemetry
How it Works & Architecture

💡 Implementation Details
Summary
Superfluid streams enable continuous, real-time micropayments for subscription-based APIs through money streaming protocols. Users create ongoing payment streams that flow continuously to API providers, allowing for pay-per-second usage models without individual transactions.
Stream Creation Flow
- Provider Setup: API provider configures acceptable flow rates and token types
- Stream Creation: Consumer creates a Superfluid stream to provider's address
- Flow Verification: System verifies active stream and flow rate meets requirements
- Continuous Access: API access granted as long as stream remains active
X-Payment Header Payload
Superfluid streams use the stream scheme with the x402 v1 format:
{
"x402Version": 1,
"network": "base",
"scheme": "stream",
"payload": {
"signature": "0x1234...",
"sender": "0x..sender_address"
}
}Key components:
- x402Version: Protocol version (1)
- network: Blockchain network with Superfluid support
- scheme: Payment method ("stream")
- signature: Consumer's cryptographic authorization proving stream ownership
- sender: Address of the stream creator (consumer)
Verification Process
The middleware performs stream verification in this order:
1. Header Validation
- Parse and validate X-Payment JSON structure
- Verify x402Version is 1 and scheme matches "stream"
- Extract sender address and signature from payload
2. Signature Verification
- Verify signature proves ownership of the sender address
- Ensure signature was created by the stream consumer
- Validate signature authenticity using ECDSA recovery
3. Stream State Validation
- Query Superfluid contracts to verify active stream exists
- Check stream flows from sender to configured recipient address
- Validate flow rate meets minimum requirements
- Ensure stream hasn't been terminated or cancelled
4. Cache Management
- Store verified stream information in local cache for performance
- WebSocket listeners monitor stream events for real-time cache invalidation
- No expiration-based cache - updates driven by stream events
State Management
Stream payments maintain state through a combination of on-chain data and local caching:
Server-Side State (Cached)
pub struct StreamState {
streams: HashMap<Address, StreamInfo>,
}Caching Strategy:
- Stream verification results cached for performance (sub-50ms response)
- Cache invalidated immediately when stream events detected via WebSocket
- Real-time event-driven updates ensure accuracy
On-Chain State (Authoritative)
- Superfluid protocol maintains authoritative stream state
- Real-time stream flow calculations
- Automatic flow rate adjustments and terminations
Performance Optimization:
- WebSocket listeners monitor stream events for real-time updates
- Local cache reduces verification latency significantly
- Event-driven cache invalidation ensures real-time accuracy
Settlement Process
Stream payments are inherently settled in real-time:
1. Continuous Flow
- Tokens flow continuously from consumer to provider
- No manual settlement required
- Real-time balance updates on-chain
2. Stream Management
- Consumers can modify or cancel streams anytime
- Providers receive immediate access to streamed funds
- Automatic termination when consumer balance is insufficient
Smart Contract Integration
Superfluid Protocol
- CFAv1 Contract: Manages constant flow agreements
- SuperToken: Streaming-enabled token wrapper
- Flow Rate: Continuous per-second payment rate
Network Support
- Available on all Superfluid-supported networks
- Base, Polygon, Optimism, and other L2 solutions
Security Features
- Real-time verification: Continuous stream monitoring
- Event-based updates: Immediate notification of stream changes
- Signature authentication: Cryptographic proof of stream ownership
v0.6.0+ Unified Approach (Recommended)
For API Consumers
import { withPaymentInterceptor } from "pipegate-sdk";
// Create stream first (same process as before)
const streamSender = "0x..."; // Your address with active stream
// Single unified interceptor
const client = withPaymentInterceptor(
axios.create({ baseURL: "https://api.example.com" }),
PRIVATE_KEY,
{ streamSender: streamSender }
);
// Automatic payment verification
const response = await client.get("/endpoint");For API Providers
use pipegate::middleware::{PaymentsLayer, PaymentsState, Scheme, SchemeConfig};
// Configure stream payments
let stream_config = SchemeConfig::new(
Scheme::SuperfluidStreams,
"https://base-rpc.publicnode.com".to_string(),
recipient_address,
super_token_address, // supertoken address like USDCx or token address like USDC
"2".to_string(), // 2 tokens per month
).await;
// Single middleware for all schemes
let app = Router::new()
.route("/api", get(handler))
.layer(PaymentsLayer::new(
PaymentsState::new(),
MiddlewareConfig::new(vec![stream_config])
));Legacy Implementation
For API Consumers
Create Stream
There are several ways to create a stream:
-
Use the Superfluid Dashboard to start a stream to the provider's address with your configured flow rate.
-
Use Pipegate Hub to subscribe to a provider directly.
-
For CLI users, create a stream using the
castcommand (requires wrapped or native streamable tokens):
cast send $CFA_FORWARDER_ADDRESS "createFlow(address, address, address, int96, bytes)" $TOKEN_ADDRESS $YOUR_ADDRESS $PROVIDER_ADDRESS $FLOW_RATE 0x --rpc-url $RPC_URL --private-key $PRIVATE_KEYFlow Rate Calculation
flowRate = "761035007610"; // 2 USDC per monthSetup API Client
Using axios interceptors:
import { ClientInterceptor } from "pipegate-sdk";
const pipeGate = new ClientInterceptor();
const api = axios.create({
baseURL: "https://api.example.com",
});
const streamSender = "0x..."; // Your address
api.interceptors.request.use(
pipeGate.createStreamRequestInterceptor(streamSender).request
);
const response = await api.get("/endpoint");Or Manually signing the request and adding the required headers in the request:
import { ClientInterceptor } from "pipegate-sdk";
const pipeGate = new ClientInterceptor();
const streamSender = "0x...SENDER_ADDRESS";
const signedHeaders = await pipegate.signStreamRequest(streamSender);
const response = await fetch("/endpoint", {
headers: {
"X-Sender": streamSender,
"X-Signature": signature,
},
});For API Providers
Configure Stream Settings
Configure the token you want to receive the streams in and the amount converted to flow rate ( /sec ).
use pipegate::middleware::stream_payment::types::StreamsConfig;
use pipegate::utils::{Address, Url, I96};
let rpc_url: Url = "https://base-rpc.publicnode.com".parse().unwrap();
let stream_payment_config = StreamsConfig {
recipient: Address::from_str("YOUR_ADDRESS").unwrap(),
token_address: Address::from_str("TOKEN_ADDRESS").unwrap(),
amount: "761035007610".parse::<I96>().unwrap(), // 2 USDC/month
cfa_forwarder: Address::from_str("CFA_ADDRESS").unwrap(),
rpc_url: rpc_url.to_string(),
cache_time: 86400, // 1 day
};Setup Middleware
use pipegate::middleware::stream_payment::{state::StreamState, StreamMiddlewareLayer};
let stream_state = StreamState::new();
let app = Router::new()
.route("/", get(root))
.layer(StreamMiddlewareLayer::new(
stream_payment_config,
stream_state
));Attach listener
Attach the stream listener to the server that will maintain a local cache of the streams verification and status, later invalidating the cache if the stream is terminated.
use pipegate::middleware::stream_payment::{types::StreamListenerConfig, StreamListner};
let stream_state_clone = stream_state.clone();
let stream_payment_config_clone = stream_payment_config.clone();
// create configuration for the stream listener
let stream_listener_config = StreamListenerConfig {
wss_url: "wss://base-sepolia-rpc.publicnode.com".to_string(),
cfa: Address::from_str("0x6836F23d6171D74Ef62FcF776655aBcD2bcd62Ef").unwrap(),
};
// start the stream listener
let _stream_listener = StreamListner::new(
stream_state_clone,
stream_payment_config_clone,
stream_listener_config,
).await;To check the current streams you are receiving, you can check the superfluid app for now
Best Practices
- Monitor stream health
- Handle stream termination
- Implement grace periods
- Cache stream status