Last week, Tempo and Stripe launched the Machine Payments Protocol. The idea: HTTP 402 (Payment Required) finally does something useful. An agent requests data, the server says “pay me first,” the agent pays in USDC, and the server delivers.
I wanted to see how fast I could build a real paid service on top of this. Turns out, pretty fast.
What I built
FinSight is a financial portfolio analytics API. AI agents send a portfolio (a list of assets with weights, returns, and volatility numbers), pay a small amount in USDC per call, and get structured analysis back.
Five paid endpoints:
-
Risk profiling scores each asset 0-100 based on volatility and max drawdown. Stablecoins get a flat 5. Everything else runs through
min(100, (vol * 80 + drawdown * 60) / 1.4). Portfolio risk is the weighted average. - Rebalance computes target allocation based on a risk profile. Conservative profiles push 60% toward stablecoins. Balanced does 30%. Aggressive does 10%. The rest gets distributed by scoring non-stable assets: conservative uses inverse volatility, balanced uses return/risk ratio, aggressive uses raw return.
-
Diversification calculates the Herfindahl-Hirschman Index.
sum(weight^2) * 10000. Grades from “excellent” to “critical.” Fires warnings when a single asset exceeds 50%, stable ratio drops below 5%, or HHI goes above 4000. - Stress test runs the portfolio through five scenarios: market crash (-40%), crypto winter (-60%), stablecoin depeg, volatility spike, and bull recovery (+80%). Reports portfolio value, percentage change, worst-hit and best-performing asset per scenario.
- Full report combines everything in one response.
Live at: finsight-mpp.finsight-mpp.workers.dev
The payment flow
Here is what happens when an agent calls a paid endpoint:
Agent --> POST /analyze/risk + portfolio data
Server --> 402 Payment Required + challenge
Agent --> POST /analyze/risk + payment credential
Server --> 200 OK + analysis + receipt
The mppx SDK handles steps 2-3 automatically. From the agent’s side, it looks like a single request. Payment settles in USDC on Tempo’s blockchain in under a second.
In code, adding payment to a route is one middleware call:
app.post('/analyze/risk', charge('0.01'), async (c) => {
const { error, portfolio } = await parsePortfolio(c)
if (error) return error
return c.json(analyzeRisk(portfolio!))
})
The charge function wraps mppx with lazy initialization. Cloudflare Workers does not have process.env, so secrets come through c.env at request time:
function charge(amount: string) {
return async (c: any, next: any) => {
if (!cachedMppx) {
cachedMppx = Mppx.create({
secretKey: c.env.MPP_SECRET_KEY,
methods: [
tempo({
chainId: 4217,
currency: '0x20C000000000000000000000b9537d11c60E8b50',
recipient: '0x45f7d1ef7fc50e054fb89a20e82485861ee91857',
}),
],
})
}
return cachedMppx.charge({ amount })(c, next)
}
}
That is the entire payment integration. No Stripe dashboard, no webhook endpoints, no subscription management.
The stack
Nothing exotic:
- Hono as the web framework. Lightweight, edge-native, first-class support in mppx SDK.
- mppx for the MPP payment layer. Tempo charge method, USDC on Tempo mainnet.
- Zod for input validation. Portfolio schema validates field types, ranges, and that weights sum to ~1.0.
- viem for blockchain interaction under the hood.
- Cloudflare Workers for hosting. Zero cold start, global edge network, generous free tier.
Project structure:
src/
index.ts # Routes + mppx setup
schemas.ts # Zod validation
types.ts # TypeScript interfaces
llms.txt # Agent discovery file
analyze/
risk-profile.ts # Risk scoring
rebalance.ts # Allocation targets
diversification.ts # HHI calculation
stress-test.ts # Scenario simulation
full-report.ts # Orchestrator
Each analysis module is a pure function. Portfolio in, structured JSON out. No side effects, no state, no database.
Input validation
All endpoints share one Zod schema:
const HoldingSchema = z.object({
asset: z.string().min(1).max(20),
weight: z.number().min(0).max(1),
avgReturn: z.number().min(-1).max(100).default(0),
volatility: z.number().min(0).max(100).default(0.3),
maxDrawdown: z.number().min(0).max(1).default(0.3),
isStable: z.boolean().default(false),
})
const PortfolioSchema = z.object({
holdings: z.array(HoldingSchema).min(1).max(100),
profile: z.enum(['conservative', 'balanced', 'aggressive']).default('balanced'),
benchmarkReturn: z.number().default(0.08),
})
Weights must sum to approximately 1.0 (0.98-1.02 tolerance). If validation fails, the server returns 400 before any payment happens. You only pay for valid requests.
Agent discovery
For agents to find your service, you need an llms.txt file. Think robots.txt but for AI agents. It describes your endpoints, input format, pricing, and how to pay.
I serve mine at GET /llms.txt:
app.get('/llms.txt', (c) => c.text(llmsTxt))
Any coding agent (Claude Code, Codex, Amp) pointed at this URL can read the full service description and start making paid requests without human intervention.
Stress testing the stress test
The stress test module was the most interesting to build. Each scenario applies a different multiplier to asset values based on their properties:
const SCENARIOS: ScenarioSpec[] = [
{
name: 'market_crash',
description: 'Broad market decline of 40%',
calcAssetChange: (h) => (h.isStable ? 0 : -(0.4 * h.volatility) / 0.5),
},
{
name: 'recovery_bull',
description: 'Strong bull market recovery of 80%',
calcAssetChange: (h) => {
if (h.isStable) return 0
return Math.min(2, (0.8 * Math.max(h.avgReturn, 0.05)) / 0.1)
},
},
// ... 3 more scenarios
]
Higher volatility assets get hit harder in crashes. Higher return assets gain more in bull runs. Stablecoins are unaffected except in the depeg scenario. The math is simplified (no correlation matrix), but it gives agents a useful signal about portfolio resilience.
Try it
npx mppx account create
npx mppx https://finsight-mpp.finsight-mpp.workers.dev/analyze/report \
--method POST \
--body '{
"holdings": [
{"asset":"ETH","weight":0.5,"avgReturn":0.15,"volatility":0.65,"maxDrawdown":0.55},
{"asset":"BTC","weight":0.3,"avgReturn":0.12,"volatility":0.55,"maxDrawdown":0.45},
{"asset":"USDC","weight":0.2,"isStable":true}
],
"profile":"balanced"
}'
First command creates a wallet. Second command calls the API and pays automatically.
What I learned
MPP is production-ready. The SDK works. Payment settles fast. The 402 flow is clean. If you have a computation that agents would pay for, you can ship a paid service in a day.
Stateless is the sweet spot. No database means no migrations, no backups, no state bugs. The service is a pure function. Trivially scalable and nearly impossible to break.
Discoverability matters more than code. Building the API was the easy part. Getting listed in the MPP service directory, writing an llms.txt file, and getting the service in front of agent developers is the actual work.
Cloudflare Workers + Hono is a good combo for this. Edge deployment, zero cold start, and the mppx SDK has first-class Hono middleware. The lazy initialization pattern for secrets was the only Workers-specific gotcha.
Source
Open source: github.com/dun999/finsight-mpp
If you want to build your own paid service on MPP, fork the repo, swap the recipient wallet address, deploy, and you are live.
Built by @ichbindun. MPP docs at mpp.dev.
United States
NORTH AMERICA
Related News

Open Harness: The Multi-Panel AI Powerhouse Revolutionizing Developer Workflows
10h ago
Firefox Announces Built-In VPN and Other New Features - and Introduces Its New Mascot
9h ago
50% of Consumers Prefer Brands That Avoid GenAI Content
9h ago
Officer Leaks Location of French Aircraft Carrier With Strava Run
9h ago
CBS News Shutters Radio Service After Nearly a Century
9h ago