Payment Channels
Payment channels are ideal for frequent API calls, allowing you to deposit once and make multiple requests without additional gas fees.
How it works & Architecture
v0.6.0+ Unified Approach (Recommended)
For API Consumers
import { withPaymentInterceptor, ClientInterceptor } from "pipegate-sdk";
// Create channel (same process as before)
const pipeGate = new ClientInterceptor();
const channel = await pipeGate.createPaymentChannel({
recipient: "0x...",
duration: 2592000,
tokenAddress: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
amount: "100",
});
// Single unified interceptor with automatic state management
const client = withPaymentInterceptor(
axios.create({ baseURL: "https://api.example.com" }),
PRIVATE_KEY,
{ channel: channel }
);
// Automatic payment and state updates
const response = await client.get("/endpoint");
For API Providers
use pipegate::middleware::{PaymentsLayer, PaymentsState, Scheme, SchemeConfig};
// Configure channel payments
let channel_config = SchemeConfig::new(
Scheme::PaymentChannels,
"https://base-sepolia-rpc.publicnode.com".to_string(), // Base Sepolia testnet
token_address, // USDC or other ERC-20 token address
recipient_address, // Provider's address to receive channel payments
"0.001".to_string(), // Price per API request in tokens
).await;
// Single middleware for all schemes
let app = Router::new()
.route("/api", get(handler))
.layer(PaymentsLayer::new(
PaymentsState::new(),
MiddlewareConfig::new(vec![channel_config])
));
Legacy Implementation
For API Users
Create Payment Channel
import { ClientInterceptor } from "pipegate-sdk";
const pipeGate = new ClientInterceptor();
// Update these params with what you get from the API provider
const channelParams = {
recipient: "0x...", // API provider's address
duration: 2592000, // 30 days
tokenAddress: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", // USDC
amount: "100", // 100 USDC
};
const channel = await pipeGate.createPaymentChannel(channelParams);
await pipeGate.addNewChannel(channel.channelId, channel);
or If you want to use the cast CLI tool, refer to the steps here
Setup API Client
const api = axios.create({
baseURL: "https://api.example.com",
});
api.interceptors.request.use(
pipeGate.createPaymentChannelRequestInterceptor(channelId).request
);
api.interceptors.response.use(
pipeGate.createPaymentChannelResponseInterceptor().response
);
Monitor Channel State
const channelState = pipeGate.getChannelState(channelId);
console.log("Balance:", channelState?.balance);
console.log("Expiration:", channelState?.expiration);
For API Providers
Configure Middleware
use pipegate::middleware::payment_channel::{channel::ChannelState, types::PaymentChannelConfig};
use pipegate::utils::{Address, Url, U256};
let rpc_url: Url = "https://base-rpc.publicnode.com".parse().unwrap();
let state = ChannelState::new();
let config = PaymentChannelConfig {
recipient: Address::from_str("YOUR_ADDRESS").unwrap(),
token_address: Address::from_str("USDC_ADDRESS").unwrap(),
amount: U256::from(1000), // 0.001 USDC in this case
rpc_url: rpc_url.to_string(),
};
Attach Middleware layer
use pipegate::middleware::payment_channel::{PaymentChannelMiddlewareLayer};
let app = Router::new()
.route("/", get(root))
.layer(PaymentChannelMiddlewareLayer::new(state, config));
Register Price in Channel Factory
Terminal
# Set your price per request (1000 = 0.001 USDC)
cast send $FACTORY_ADDRESS "register(uint256)" 1000 \
--rpc-url $RPC_URL \
--private-key $PRIVATE_KEY
Handle Channel Closure
// Close channel and withdraw funds
let tx_hash = close_channel(
rpc_url,
private_key.as_str(),
&payment_channel,
&signature,
raw_body,
);
or use CLI to close the channel
Terminal
# Close the channel to withdraw 1 USDC with a nonce of 1000, along with the signature received during the API calls
cast send $FACTORY_ADDRESS "close(uint256 channelBalance,uint256 nonce,bytes calldata rawBody,bytes calldata signature)" 1000 1000 0x0 $SIGNATURE \
--rpc-url $RPC_URL \
--private-key $PRIVATE_KEY
Example for channel closure can be found here
Best Practices
- Always monitor channel balance
- Set appropriate channel duration
- Handle channel expiration gracefully
- Implement proper error handling