Docs · Reference · Markdown
Server SDK (@flying-money/server)
The seller side of the protocol. Put the middleware in front of paid routes; run the redeemer to collect.
Hono middleware
import { upstashStore } from '@flying-money/server'
import { flyingMoney } from '@flying-money/server/hono'
import { Hono } from 'hono'
import type { Hex } from 'viem'
const app = new Hono()
const paid = flyingMoney({
accepts: ['arbitrum-sepolia'],
payee: process.env.PAYEE_ADDRESS as Hex,
price: () => 10_000n, // 0.01 USDC per request
store: upstashStore({
url: process.env.UPSTASH_REDIS_REST_URL ?? '',
token: process.env.UPSTASH_REDIS_REST_TOKEN ?? '',
}),
})
app.use('/v1/*', paid)
app.get('/v1/tea-price', (c) => c.json({ price: 42, requestId: c.get('flyingMoney').requestId }))
What the middleware does for every paid request:
- No note →
402with aFlying-Money-Offerheader (price, chains, contract, token, payee). - Parses the note, checks the chain and contract, reads the certificate (cached), checks payee, lifetime, signature and face value.
- A
requestIdit has seen returns the stored outcome (replays are never charged twice). - Reserves the price atomically against the best note it holds (concurrent requests can't overspend).
- Runs your handler. A response with status ≥ 400 counts as a failed service: the price becomes credit for the buyer.
- Adds a
Flying-Money-Receiptheader with accepted / consumed / credit / remaining.
Your handler must be idempotent on requestId (c.get('flyingMoney').requestId). For side effects, use createIdempotency().
Stores
The store is the seller's authoritative ledger. It must be durable.
| Store | Use |
|---|---|
upstashStore({ url, token }) |
Serverless (Vercel), over HTTPS; Lua scripts make begin/finish atomic |
redisStore(url) |
Any Redis over TCP |
memoryStore() |
Tests and demos only; onCommit persists snapshots (the shop till uses IndexedDB) |
Redeemer
import { redisStore, startRedeemer } from '@flying-money/server'
import type { Hex } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
const redeemer = startRedeemer({
chains: ['arbitrum-sepolia'],
store: redisStore(process.env.REDIS_URL ?? 'redis://localhost:6379'),
redeemerAccount: privateKeyToAccount(process.env.REDEEMER_KEY as Hex), // needs gas only
policy: { minAmount: 100_000n, maxAgeSeconds: 3_600, safetyBeforeExpiry: 1_800 },
intervalMs: 60_000,
})
It redeems only served value, batches up to 20 notes into one redeemMany, records the transaction hash before broadcasting, and never rebroadcasts. Anyone may send the transaction; the money always goes to the payee.
Discovery
Sellers should serve /.well-known/flying-money.json with their accepts[] and price table, so agents can see prices without a 402 round trip. The Silk Road Oracle (apps/oracle) is a complete example, with /openapi.json.