Skip to content

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

Stream Flow

💡 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

  1. Provider Setup: API provider configures acceptable flow rates and token types
  2. Stream Creation: Consumer creates a Superfluid stream to provider's address
  3. Flow Verification: System verifies active stream and flow rate meets requirements
  4. 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:

  1. Use the Superfluid Dashboard to start a stream to the provider's address with your configured flow rate.

  2. Use Pipegate Hub to subscribe to a provider directly.

  3. For CLI users, create a stream using the cast command (requires wrapped or native streamable tokens):

terminal
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_KEY

Flow Rate Calculation

flowRate = "761035007610"; // 2 USDC per month

Setup 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