CLASP SDK
Let AI agents pay for any API. 3 lines of code. Sub-cent micropayments on XRP payment channels.
Installation
# Core SDK (agent-side)
pip install clasp-sdk
# With server/middleware support (provider-side)
pip install clasp-sdk[server]
Requires Python 3.10+. Dependencies: httpx, xrpl-py, pydantic.
npm install @clasp-sdk/node
Requires Node.js 18+. Dependencies: axios, xrpl.
go get github.com/symplesolutions/clasp-go
Requires Go 1.22+.
Quick Start — 5 Minutes to First Payment
1 Get a Testnet Wallet
You need an XRP wallet with testnet funds. The fastest way:
# Python — generate and fund a wallet
from xrpl.wallet import generate_faucet_wallet
from xrpl.clients import JsonRpcClient
client = JsonRpcClient("https://s.altnet.rippletest.net:51234")
wallet = generate_faucet_wallet(client)
print(f"Address: {wallet.address}")
print(f"Seed: {wallet.seed}")
# Save your seed — you'll need it below
2 Make a Paid API Call (Agent)
import asyncio
from clasp import CLASPAgent
async def main():
agent = CLASPAgent(
wallet_seed="sEd...", # Your testnet seed
clasp_api_url="http://localhost:8000",
)
# This handles 402 → open channel → pay → get data
response = await agent.call("http://localhost:9000/weather?city=Toronto")
print(response.json())
await agent.close()
asyncio.run(main())
import { CLASPAgent } from "@clasp-sdk/node";
const agent = new CLASPAgent({
walletSeed: "sEd...",
claspApiUrl: "http://localhost:8000",
});
const data = await agent.call("http://localhost:9000/weather?city=Toronto");
console.log(data);
package main
import (
"fmt"
clasp "github.com/symplesolutions/clasp-go"
)
func main() {
agent := clasp.NewAgent(clasp.AgentConfig{
WalletSeed: "sEd...",
CLASPApiURL: "http://localhost:8000",
})
resp, err := agent.Call("http://localhost:9000/weather?city=Toronto")
if err != nil { panic(err) }
fmt.Println(string(resp))
}
3 Monetize Your API (Provider)
from fastapi import FastAPI, Request
from clasp import CLASPServer
app = FastAPI()
clasp = CLASPServer(
provider_address="rYour...",
clasp_api_url="http://localhost:8000",
)
@app.get("/weather")
@clasp.require_payment(price_drops=1000) # 0.001 XRP
async def weather(request: Request):
return {"temp": 22, "condition": "sunny", "city": "Toronto"}
import express from "express";
import { CLASPServer } from "@clasp-sdk/node";
const app = express();
const clasp = new CLASPServer({
providerAddress: "rYour...",
claspApiUrl: "http://localhost:8000",
});
app.get("/weather", clasp.requirePayment(1000), (req, res) => {
res.json({ temp: 22, condition: "sunny", city: "Toronto" });
});
app.listen(9000);
package main
import (
"net/http"
"encoding/json"
clasp "github.com/symplesolutions/clasp-go"
)
func main() {
mw := clasp.NewMiddleware(clasp.MiddlewareConfig{
ProviderAddress: "rYour...",
CLASPApiURL: "http://localhost:8000",
PriceDrops: 1000,
})
http.Handle("/weather", mw.RequirePayment(
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]any{
"temp": 22, "condition": "sunny",
})
}),
))
http.ListenAndServe(":9000", nil)
}
How It Works
CLASP uses XRP Payment Channels — a built-in XRPL feature for off-ledger micropayments.
Key insight: Only 2 on-chain transactions are needed — one to open the channel, one to settle. Everything in between is free, instant, and unlimited.
| Metric | CLASP | Stripe x402 | Coinbase x402 |
|---|---|---|---|
| Cost per 10K calls | $0.0004 | $3,000 | $5.00 |
| On-chain transactions | 2 total | 10,000 | 10,000 |
| Settlement latency | Instant (off-chain) | ~3 sec | ~15 sec |
| Minimum payment | 1 drop ($0.0000005) | $0.30 | $0.01 |
Guide: Build an AI Agent
An AI agent using CLASP can autonomously discover, evaluate, and pay for APIs without human intervention.
Discovery — Find APIs
endpoints = await agent.discover("sentiment analysis")
for ep in endpoints:
print(f"{ep.url} — {ep.price_drops} drops — {ep.description}")
Automatic Payment Flow
When you call agent.call(url), the SDK handles everything:
- Sends the HTTP request to the target URL
- If the response is
402withtype: clasp-payment-required, extracts price and provider address - Opens a payment channel if none exists for that provider (configurable via
auto_open_channel) - Creates a cryptographic claim (off-chain signature)
- Retries the request with
X-CLASP-*headers - Returns the successful response
Budget Control
# Check spending
print(f"Total spent: {agent.total_spent_drops} drops")
print(f"Channel remaining: {agent.channel_remaining(channel_id)} drops")
# Set channel funding limit
agent = CLASPAgent(
wallet_seed="sEd...",
default_channel_drops=5_000_000, # Max 5 XRP per channel
)
Guide: Monetize Your API
Turn any existing API into a paid service with 3 lines of code. No signup, no billing integration, no invoicing.
Option A: Decorator (per-route)
@clasp.require_payment(price_drops=1000)
async def my_endpoint(request: Request):
# Access claim info
claim = request.state.clasp_claim
print(f"Paid: {claim['amount_drops']} drops")
print(f"Remaining: {claim['remaining_drops']} drops")
return {"data": "premium content"}
Option B: Middleware (entire API)
from clasp import CLASPMiddleware
app = CLASPMiddleware(
app,
provider_address="rYour...",
clasp_api_url="http://localhost:8000",
default_price_drops=1000,
skip_paths={"/docs", "/health", "/openapi.json"},
)
Revenue Collection
CLASP accumulates claims off-chain. To collect your XRP:
- Automatic: The CLASP backend settles channels when claims reach a threshold
- Manual: Trigger settlement via
POST /api/v1/settlements/trigger - On-chain: Provider can submit the latest claim to XRPL at any time
Discovery
The CLASP Discovery API lets agents find APIs that accept CLASP payments. Think of it as a marketplace where APIs list themselves.
Search
# By keyword
endpoints = await agent.discover("weather")
# Via the API directly
GET /api/v1/discover?q=weather&category=data&max_price=5000
Register Your API
POST /api/v1/endpoints/register
{
"url": "https://api.example.com/weather",
"description": "Real-time weather data for any city",
"price_drops": 1000,
"category": "data",
"tags": ["weather", "location", "forecast"]
}
Channel Management
Opening Channels
# Auto: agent.call() opens channels automatically on first 402
# Manual: explicit channel with custom funding
channel = await agent.open_channel(
provider_address="rProvider...",
amount_drops=50_000_000, # 50 XRP
)
print(f"Channel ID: {channel.channel_id}")
print(f"Funded: {channel.amount_drops} drops")
Channel Lifecycle
- Open — Agent creates
PaymentChannelCreateon XRPL (funds locked) - Active — Agent sends signed claims, provider verifies and serves data
- Settling — Provider submits highest claim to XRPL
- Closed — Remaining funds returned to agent (after dispute window)
API Reference: CLASPAgent
CLASPAgent(
wallet_seed: str, # XRPL wallet seed
clasp_api_url: str = "...", # CLASP backend URL
xrpl_node_wss: str = "...", # XRPL WebSocket node
auto_open_channel: bool = True,# Auto-open on 402
default_channel_drops: int = 10_000_000,
)
| Method | Returns | Description |
|---|---|---|
call(url, method, ...) | Response | Make paid HTTP request. Handles 402 flow automatically |
discover(query) | list[EndpointInfo] | Search for CLASP-enabled APIs |
open_channel(addr, drops) | ChannelInfo | Open an XRP payment channel on XRPL |
create_claim(ch_id, price) | Claim | Create a signed micropayment claim |
close() | None | Clean up HTTP client resources |
.total_spent_drops | int | Total drops spent across all channels |
channel_remaining(id) | int | None | Remaining drops in a channel |
API Reference: CLASPServer
CLASPServer(
provider_address: str, # Your XRPL address
clasp_api_url: str = "...", # CLASP backend URL
)
| Method | Returns | Description |
|---|---|---|
require_payment(price_drops) | decorator | Route decorator requiring CLASP payment |
API Reference: CLASPMiddleware
CLASPMiddleware(
app, # Your ASGI application
provider_address: str, # Your XRPL address
clasp_api_url: str = "...", # CLASP backend URL
default_price_drops: int = 1000,# Price per request
skip_paths: set[str] = {...}, # Paths to skip
verify_via_api: bool = True, # Verify claims via backend
)
ASGI middleware that enforces CLASP payments on all requests except skip_paths (/docs, /health, /openapi.json, etc).
API Reference: Claims
# Low-level claim creation
from clasp import create_claim, verify_claim
claim = create_claim(
channel_id="ABC123...", # 64-char hex channel ID
amount_drops=5000, # Cumulative total
private_key="ED...", # Hex-encoded private key
)
valid = verify_claim(claim, public_key="ED...")
API Reference: Types
# All types are frozen dataclasses
@dataclass(frozen=True)
class Claim:
channel_id: str # 64-char hex
amount_drops: int # Cumulative total drops
signature: str # ECDSA signature
@dataclass(frozen=True)
class ChannelInfo:
channel_id: str
amount_drops: int # Total funded
balance_drops: int # Currently claimed
status: str # "open", "settling", "closed"
@dataclass(frozen=True)
class EndpointInfo:
url: str
description: str
price_drops: int
tags: list[str] | None
category: str | None
Protocol: HTTP 402 Flow
CLASP extends the HTTP 402 status code (Payment Required) with a structured JSON response:
# 1. Agent sends request without payment
GET /weather?city=Toronto HTTP/1.1
Host: api.example.com
# 2. Provider responds with 402
HTTP/1.1 402 Payment Required
Content-Type: application/json
X-CLASP-Price: 1000
{
"type": "clasp-payment-required",
"version": "1.0",
"provider_address": "rProvider123...",
"price_drops": 1000,
"clasp_api": "http://localhost:8000"
}
# 3. Agent retries with payment claim
GET /weather?city=Toronto HTTP/1.1
X-CLASP-Channel-Id: ABC123...
X-CLASP-Amount: 1000
X-CLASP-Signature: 3045022100...
# 4. Provider verifies claim and responds
HTTP/1.1 200 OK
X-CLASP-Remaining: 9999000
X-CLASP-Channel-Id: ABC123...
{"temp": 22, "condition": "sunny"}
Protocol: Headers
| Header | Direction | Description |
|---|---|---|
X-CLASP-Channel-Id | Request & Response | 64-char hex payment channel ID |
X-CLASP-Amount | Request | Cumulative drops claimed (integer) |
X-CLASP-Signature | Request | ECDSA signature over claim payload |
X-CLASP-Price | Response (402) | Required drops for this request |
X-CLASP-Remaining | Response (200) | Remaining drops in channel |
Protocol: Payment Channels
CLASP uses native XRPL Payment Channels. Key properties:
- Trustless: Funds locked on-chain, only claimable with valid signatures
- Instant: Claims are verified off-chain — no block confirmation needed
- Cheap: Only 2 on-chain transactions (open + close) regardless of usage
- Dispute-safe: 24-hour settle delay allows agents to contest invalid claims
Claim Payload Format
# 44-byte canonical payload
CLM\x00 # 4 bytes: prefix
+ channel_id # 32 bytes: hex-decoded channel ID
+ amount_drops # 8 bytes: big-endian uint64
# Signed with secp256k1 ECDSA (same as XRPL transactions)
Examples
Weather API (Full Example)
# provider.py — Monetized weather API
from fastapi import FastAPI, Request
from clasp import CLASPServer
import httpx
app = FastAPI()
clasp = CLASPServer(provider_address="rYour...", clasp_api_url="http://localhost:8000")
@app.get("/weather")
@clasp.require_payment(price_drops=1000)
async def weather(request: Request, city: str = "Toronto"):
# Fetch real weather data
async with httpx.AsyncClient() as client:
resp = await client.get(f"https://wttr.in/{city}?format=j1")
data = resp.json()
current = data["current_condition"][0]
return {
"city": city,
"temp_c": int(current["temp_C"]),
"condition": current["weatherDesc"][0]["value"],
"humidity": int(current["humidity"]),
"paid_drops": request.state.clasp_claim["amount_drops"],
}
# Run: uvicorn provider:app --port 9000
# agent.py — AI agent that pays for weather
import asyncio
from clasp import CLASPAgent
async def main():
agent = CLASPAgent(wallet_seed="sEd...")
cities = ["Toronto", "Tokyo", "London", "Sydney"]
for city in cities:
resp = await agent.call(f"http://localhost:9000/weather?city={city}")
data = resp.json()
print(f"{data['city']}: {data['temp_c']}°C, {data['condition']}")
print(f"\nTotal spent: {agent.total_spent_drops} drops")
await agent.close()
asyncio.run(main())
FAQ
How much does it cost?
CLASP itself is free and open source. The only costs are XRP transaction fees (~0.00001 XRP to open/close channels) and the micropayments themselves (set by API providers, typically 0.001 XRP per call).
Is this on mainnet?
Currently testnet only. Mainnet launch planned for Q2 2026. The SDK defaults to the XRPL testnet — just change xrpl_node_wss to a mainnet node when ready.
What if the provider goes offline?
Your funds are safe. XRP is locked in a payment channel on XRPL. If the provider never settles, you can close the channel after the dispute window (24h) and get all your XRP back.
Can I set spending limits?
Yes. Control spending via default_channel_drops (max per channel) and auto_open_channel=False (require explicit channel opening). The SDK tracks cumulative spending per channel.
How is this different from Stripe x402 / Coinbase x402?
Stripe x402 uses Base (Ethereum L2) — each payment is an on-chain transaction ($0.30+ fees). Coinbase x402 uses USDC on Base. CLASP uses XRP payment channels — unlimited off-chain micropayments after one on-chain channel open. Up to 2,500x cheaper at scale.
Can I use this with LangChain / LlamaIndex / CrewAI?
Yes. CLASPAgent.call() is a standard async HTTP call. Wrap it as a tool in any agent framework. Example with LangChain coming soon.