Inspiration

During my internship, I submitted a reimbursement for a work expense. 2 weeks went by. My partner, at a different company, was going through the exact same thing: approvals stuck in someone's inbox, no visibility into where the claim even was. Neither of us had done anything wrong. The money just sat there because a human had to find time to manually check a receipt, decide if it looked legit, and push it through.

It's even worse for people who spend on a company's behalf without a company card: interview candidates, contractors abroad, guest speakers. They front the cost and wait.

That felt like a solvable problem. Not every claim needs the same level of scrutiny, as a $12 coffee receipt and a $4,000 conference invoice shouldn't go through the same slow, manual pipeline. We wanted to build something that could move fast on the obvious cases and still catch the ones that actually need a second look.

What it does

When a claim arrives (a receipt plus a business reason), Hold reserves the money right away in an on-chain escrow: an x402 auth-capture hold on Base Sepolia. Then it verifies the claim in seconds instead of weeks:

  • Claude reads the receipt and extracts the merchant, total, date, and card details. Hold then flags receipts that don't add up: line items that don't match the total, a date months away from the claim, a claim larger than the receipt.
  • Hold buys paid x402 verification checks (exchange rate, merchant match, company-card ledger, receipt forensics) from separate seller agents, each with its own wallet and price; one uses real ECB exchange-rate data. A bandit algorithm decides how much verification each claim is worth buying, and Hold learns from spot checks which sellers to trust.
  • A deterministic matcher makes the money call: pay, pay the correct amount (sometimes more than claimed, when someone under-converted currency), or void a duplicate the company card already paid, so nothing leaves escrow.
  • If Claude disagrees with the matcher, a claim breaks company policy, or the receipt looks off, it goes to a human with a severity, a one-line reason, and the receipt, instead of silently going through.

A deadline watcher makes sure no hold silently expires, and an auditor agent re-checks paid claims as late card charges post and refunds duplicates through the escrow (tested in simulation). Each company configures its own rules: approval threshold, category caps, required checks, and whether a business reason is required. Approved claims settle in testnet USDC on Base Sepolia.

How we built it

We split the system into layers on purpose, so no single piece had to be trusted blindly:

  • Claude (via the Anthropic API) handles anything that requires reading and judgment: reading receipt photos, noting visual red flags, and writing a plain-language justification for each decision. Haiku reads every receipt; when its numbers don't add up, Sonnet re-reads just the totals (a model cascade).
  • A LinUCB bandit is the only component that's actually trained. It learns which bundle of x402 verification checks is worth paying for on a given claim, balancing the cost of checking against the risk of not checking. We trained it in a multi-agent simulation against an adaptive fraud adversary.
  • A matcher and guardrails, written as plain code, make the actual financial decision (pay, void, or escalate) and control the dollar amount. They also check receipt arithmetic and dates, and enforce spending caps, pay-or-void exactly once, registered payees, and deadlines. We kept this deterministic on purpose, since it's the part that touches money.
  • Coinbase for Agents handles the money: x402 auth-capture escrow (hold, capture, partial capture, void, refund) through a facilitator we wrote ourselves, x402 exact payments for the checks, and CDP server wallets for the company, operator, sellers, and payees.
  • Reuse: our auth-capture facilitator as an installable package (hold-escrow), an MCP server so Claude, Cursor, or any agent can submit and approve claims, and an agent skill.

Challenges we ran into

Getting the layers to actually agree with each other was harder than building any one of them. Early on, Claude's review step and the matcher would sometimes reach different conclusions about the same claim, and we had to decide: does Claude's judgment override the code, or does the code override Claude? We landed on escalating to a human whenever they disagreed, instead of letting either one win by default. It felt like the only honest way to handle the conflict in a system that deals with payments.

Hold-then-capture didn't exist off the shelf. Coinbase's checkout captures automatically, and the server side of x402 auth-capture isn't packaged, so we wrote our own facilitator against the escrow contract and ran it live.

We also had to be careful with the payment side. Once we flipped the switch to live mode, a bug wasn't just a bug anymore; it could move money on-chain. An escrow hold locks the full claim amount, and testnet faucets only give a few USDC a day, so we built a scale-down setting: the UI keeps real-looking amounts while holds and payouts move 1/1000th on-chain. That let us test the full live payment path with trivial amounts and run the whole demo month live.

A real receipt photo exposed a misread: Haiku read a $44.46 total as $40.46. Code-side arithmetic plus a stronger-model re-read now catch that.

Accomplishments that we're proud of

  • A full demo month ran live on Base Sepolia: 10 holds, 33 paid x402 checks, payouts including a partial, and two on-chain voids (a dinner the company card already paid, and a reused hotel receipt).
  • The seller marketplace ran live: one claim bought 5 paid checks from 4 different seller agents on Base Sepolia.
  • We filled a gap Coinbase engineers pointed out (a self-hosted auth-capture facilitator) and packaged it for others.
  • Hold flagged a real receipt photo whose date was 11 months off.

What we learned

The biggest lesson was knowing where not to use AI. It would've been easy to let Claude make every decision, but the moment money is involved, you want a boring, predictable, auditable system making that final call, not a model's best guess. Claude is great at reading a messy receipt and explaining a decision in plain English. It's not the thing that should decide whether to send someone $400.

What's next for Hold

Mainnet with payouts swept to a bank (and ACH for people who don't want a wallet), real company-card feeds (Ramp, Brex, banks) instead of seeded data, sellers run by other companies, and importing a company's expense policy straight from its PDF.

Built With

  • agentic
  • ai
  • anthropic
  • api
  • base-sepolia
  • cdp-sdk
  • coinbase
  • coinbase-developer-program
  • crypto
  • css
  • finance
  • fintech
  • html
  • node.js
  • payments
  • python
  • reinforcement-learning
  • usdc
  • x402
Share this project:

Updates

Submission history