how surp.ivc.lol is built · what we chose · what we'd change · v2 proposal
surp is an x402-paywalled LLM gateway: an OpenAI-compatible HTTP API where every request is a USDC micro-payment settled on Base, and the model behind each request is chosen from the live cheapest listing on the Surplus Intelligence marketplace. This page documents the real architecture, the design decisions that make it cheap and honest, the numbers, and a proposed v2 that batches settlements so heavy users pay gas once, not per request.
POST /v1/chat/completions with a combo like surp/best-chat.| step | what happens | why it matters |
|---|---|---|
| 1 | Client calls with model: surp/best-chat. Gateway checks the exact-response cache first. |
Cache hits are 0.1¢ instead of 1¢ — the flywheel. |
| 2 | No payment header → gateway returns 402 + PAYMENT-REQUIRED with the exact USDC amount (spot price + 5% markup, floored at 1¢) and the EIP-712 domain. | Price is disclosed before the wallet signs. No surprise billing. |
| 3 | Client signs a TransferWithAuthorization (EIP-3009) with their wallet and retries with PAYMENT-SIGNATURE. |
Per-request signature — no standing allowance, no unlimited-spend risk. |
| 4 | Gateway decodes the payload, verifies it, settles on Base via the PayAI facilitator (retry ×5 backoff), then streams the response. | Settle-then-serve: generation never runs unpaid. |
| 5 | Post-response: stats logged, health sample recorded, affinity hash recorded, metrics sample enqueued. | Every layer records to its own store, fault-isolated. |
| decision | choice | trade-off |
|---|---|---|
| Payments | per-request EIP-3009 signatures, no approve-and-pull | safer (Surplus's own docs call this the better pattern) but every request needs a wallet sign; standing approvals save gas at unlimited-spend risk. |
| Routing | resolve combo → live cheapest on the marketplace + 5% fixed markup | we're a router, not a provider: no inventory risk, but margin is thin and depends on market liquidity. |
| Cache | exact-response cache at 0.1¢ + sticky routing (30% tolerance) preserving KV-prefix cache | massive cost savings on repeated prompts; cache only works for deterministic responses. |
| Data stores | one sqlite file per concern, WAL mode | zero ops, perfect for this scale; single-writer contention becomes a ceiling at higher QPS (v2 addresses this). |
| Fault isolation | every side-effect wrapped: a locked DB or dead metrics writer never breaks a paid stream | metrics are best-effort by design; a crash in telemetry is invisible to the money path. |
| Deployment | single Hetzner VPS, systemd, nginx | cheap and simple; single point of failure, single region (v2: multi-region or at least a standby). |
| Free tier | treasury-sponsored pool with per-class price ceilings and daily budgets | acquires users without a wallet; costs us real money, capped by budgets and conversion tracking. |
| number | value |
|---|---|
| requests served (lifetime) | 343 |
| requests (24h) | 0 |
| USDC settled | $337.6000 |
| unique wallets | 13 |
| cache hits | see /status (live cache metrics) |
| typical p50 output TPS | ~100 (deepseek-v4-flash-0731, verified) |
| markup | 500 bps (5%) over spot, 1¢ floor |
| cache-hit price | 0.1¢ (90% off the floor) |
Numbers come from the live /api/stats feed; latency and TPS from the verified benchmark runner and the metrics feed.
Every request = one on-chain EIP-3009 transfer. At Base's current ~0.01 gwei that's fractions of a cent, so it's fine today. But the moment a real agent makes thousands of calls an hour, gas + wallet-sign latency become the bottleneck, and per-request signing stops being "safer" and starts being "annoying." The fix is not a standing allowance — it's batching with a per-user credit ledger.
| option | verdict |
|---|---|
| standing allowance (Surplus SettlementV2 style) | rejected — unlimited-spend risk, and their own docs want to move away from it |
| per-request x402 forever | safe but doesn't scale to agent workloads; wallet-sign latency per call |
| credit ledger + batched settlement | one signature per batch, collateral-backed, opt-in, same EIP-3009 rails, no unlimited spend |
Status: proposal only. Community vote at /proposal/srp is about the SRP token; this v2 is the next design conversation after that. Want it sooner? Say so.
Structure inspired by donnemartin/system-design-primer (CC BY 4.0). The architecture documented here is the live system — read the code at github.com/ivcained/surp-router.