spawnpay-paywall
v0.1.0
Published
Charge AI agents per-call for any function. Drop-in wrapper for MCP tools, REST endpoints, or any async function. Settles in USDC on Base L2.
Downloads
214
Maintainers
Readme
spawnpay-paywall
Charge AI agents per-call for any async function. Drop-in wrapper for MCP tools, REST handlers, or any function the agent might call. Settles in USDC on Base L2.
Why
You shipped an MCP server. Agents are calling it. You're eating LLM costs, scraping costs, or just compute, and there's no way to charge for it without forcing every user to sign up for Stripe and paste a credit card. Paywall solves that. Calling agents already have wallets, you just declare a price.
Install
npm install spawnpay-paywallUse
import { paywall } from 'spawnpay-paywall';
// Your existing tool implementation
async function fetchTweet({ url }) {
const r = await fetch(url);
return await r.text();
}
// Wrap it. Done.
export const fetchTweetPaid = paywall(
{
price: 0.01, // USDC per call
vendor: 'SP_yourCode', // your spawnpay referral code (or 0x wallet)
description: 'fetch_tweet',
},
fetchTweet,
);The calling agent needs SPAWNPAY_API_KEY in its env. Every call charges them 0.01 USDC, sends it to your wallet, then runs the original function. If the charge fails, the original never runs.
In an MCP server
Wrap each paid tool's handler. The MCP framework doesn't know paywall exists.
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
import { paywall } from 'spawnpay-paywall';
const server = new Server({ name: 'my-mcp', version: '1.0.0' }, { capabilities: { tools: {} } });
const decompile = paywall(
{ price: 0.10, vendor: 'SP_yourCode', description: 'decompile_binary' },
async ({ binary_path }) => {
/* ... real work ... */
return { code: '...', symbols: [...] };
},
);
server.setRequestHandler(CallToolRequestSchema, async (req) => {
if (req.params.name === 'decompile') {
const result = await decompile(req.params.arguments);
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
}
});Caller side
The agent calling your MCP needs a spawnpay key. Cheapest path: install spawnpay-mcp, run spawnpay_signup once, get $5 USDC credit free.
{
"mcpServers": {
"spawnpay": { "command": "npx", "args": ["-y", "spawnpay-mcp"] },
"your-mcp": {
"command": "npx",
"args": ["-y", "your-mcp"],
"env": { "SPAWNPAY_API_KEY": "spk_caller_key_here" }
}
}
}Errors
Paywall throws PaywallError with a .code you can branch on:
| Code | Means |
|------|-------|
| NO_API_KEY | Caller didn't set SPAWNPAY_API_KEY |
| INSUFFICIENT_BALANCE | Caller's wallet is empty |
| CREDIT_LOCKED | Signup credit not yet unlocked |
| DAILY_LIMIT | Caller hit their daily spend ceiling |
| BAD_VENDOR | Your vendor SP_ code isn't registered |
| NETWORK | Spawnpay backend unreachable |
| BACKEND | 5xx from spawnpay |
| CHARGE_FAILED | Catch-all 4xx |
Each error has .message and an optional .hint you can show the user.
Idempotency
Paywall auto-generates an idempotency key per (description, input, ~minute) — re-runs of the same call within ~60s don't double-charge, but a distinct call later does. Override via your own retry layer if you need a different policy.
Receipts
Every successful charge calls your onCharge hook (if provided) and passes a receipt object to the wrapped function as the second argument:
const myTool = paywall(
{ price: 0.01, vendor: 'SP_x', onCharge: (r) => console.log('paid:', r.txHash) },
async (input, ctx) => {
// ctx.receipt = { txHash, amount, vendor, currency, status, deduplicated }
return doWork(input);
},
);Pricing your tool
| Cost shape | Suggested price | |------------|-----------------| | Calls a paid LLM API | LLM cost × 1.2 | | Scrape / API proxy | $0.001 – $0.01 | | Compute-heavy (decompile, parse, transcribe) | $0.05 – $1.00 | | Curated data lookup | $0.01 – $0.10 |
Spawnpay takes 0.5%. You keep 99.5%.
Examples
| Example | Tool | Price |
|---------|------|-------|
| paid-search-mcp | web_search (Wikipedia + HN, swap to Brave/Tavily/Serper) | $0.005 |
| tweet-fetcher-mcp | fetch_tweet (fxtwitter API) | $0.001 |
License
MIT
