AI agents call APIs. A lot. And they do it on their own.
So a bug, a prompt injection, or just a greedy model can burn through thousands of dollars before anyone looks at a dashboard. Credit card limits and monthly budgets tell you what you already spent. That’s the wrong end of the problem.
I wanted the other end: a hard prepaid cap that says “no” at the microsecond the charge lands. Never overshoot. Not even under load.
That’s LedgerCap.
The one hard problem
Everything in LedgerCap is in service of a single trick - the balance can never go below its floor, no matter how many agents hammer it at once.
That’s a concurrency problem. The naive version (SELECT the balance, check it, UPDATE it) has a time-of-check/time-of-use hole you can drive a truck through. Two charges read the same balance, both think there’s room, both commit. Now you’re overdrawn.
The whole thing collapses into one atomic SQL statement:
WITH upd AS (
UPDATE balances
SET balance_nanos = balance_nanos - $amount::bigint
WHERE owner_id = $id
AND (balance_nanos - COALESCE(reserved_nanos, 0)) >= $amount::bigint -- hard floor
RETURNING balance_nanos
)
INSERT INTO ledger ...
SELECT ... FROM upd
Check and debit in the same breath. If the floor would break, zero rows update and the caller gets a 402. No window. No lock. No truck.
AWS DSQL did the scary part
I ran this on AWS DSQL - distributed Postgres-wire database, optimistic concurrency control. No SELECT FOR UPDATE, no row locks. Instead you design the write so the right concurrent callers collide on the hot row. DSQL raises a 40001, a retry wrapper replays it, and the caller sees a ~1ms blip instead of an error.
It made me think about concurrency completely backwards from how I’m used to. But once it clicked, the code came out smaller than the lock-based version I’d have written against normal Postgres. No coordination, no lock manager, scales sideways for free.
There are sharp edges (DDL can’t take column defaults, indexes build async, every numeric param needs a ::bigint cast or it 42725s on you) - but none of those touch the hot path. The money logic stayed clean.
Vercel did the boring part - which is the point
The whole app is Next.js on Vercel. Two planes, one codebase:
- Data plane (
/api/v1/*) - token-authed, built for machine-to-machine agent calls - Control plane (
/api/*) - session-authed, backs the dashboard
I never thought about servers. Pushed to Vercel on day one, deployed on every commit, let Fluid Compute handle the cold starts. The dashboard, the API, the docs - all the same deployment. No infra to babysit.
That’s the bit I keep coming back to. The interesting problem was the atomic charge. Everything around it - hosting, builds, routing, scaling - Vercel just absorbed. I got to spend my time on the one thing that mattered.
The build
Kicked off a base Next.js + DSQL site, shipped it to Vercel, then drove the rest with an AI harness (Claude Code mostly, a bit of Codex and Antigravity for fun). The agent wrote code, deployed, and ran the k6 load tests that proved the cap actually holds when you throw concurrent charges at it.
It does. That was a good moment.
So what
A prepaid cap that physically cannot overshoot, an atomic charge in one SQL statement, holds/capture/void, per-user wallets, model-based metering, idempotent writes, a live dashboard and built-in docs.
The headline though is how little of it was hard. Pick a database that lets the database be correct (DSQL). Pick a platform that lets the platform be the platform (Vercel). Then there’s exactly one interesting problem left, and you get to actually solve it.
Links:
- LedgerCap: https://ledgercap.dev
- API docs: https://ledgercap.dev/docs
- AWS DSQL: https://aws.amazon.com/rds/aurora/dsql/
- Vercel: https://vercel.com