Inspiration
AI agents can now browse shops, fill carts and even call PayPal's own tools. But giving one a payment method is all or nothing: one poisoned product page, a wrong variant or a sneaky add-on, and it spends money you never meant to spend. Then the second problem starts: when the buyer disputes, nobody can prove what they actually authorised. Not the buyer, not the seller, not PayPal. We wanted both halves fixed: agents that can only spend what you approved, and proof that holds up in a dispute.
What it does
Buyer side: the agent proposes, you countersign.
- A signed permission, not your wallet. You tell the agent what to buy, the budget, which shops and until when, and approve it with your fingerprint (passkey / Touch ID).
- One door to pay. The agent can only pay through the Countersign gateway. The gateway prices the cart itself and runs plain-code rules (budget, quantity, allowed shops, expiry). AI checks then ask two questions: does the cart match what you asked for, and did the shop's page try to give the agent orders?
- Good carts pass, doubtful ones wait, bad ones stop. A held cart shows every line, why it was held and the AI's own words, and you approve that exact cart. A blocked cart shows a clear "Stopped" panel: your shops vs the shop it tried, your budget vs this cart, or the hidden text on the page and the gift card it slipped in.
- Works on ordinary websites. A checkout guard drives Chrome for the agent. You watch it shop, with a banner and each click highlighted. Payment shows " Payment locked" until you approve the exact cart it read from the shop, then unlocks by itself, and relocks if the cart changes.
- Guards PayPal's own agent tools. Countersign sits in front of PayPal's official MCP server. Read-only tools pass through. A refund, invoice or new product waits in your Inbox in plain words ("Give a customer 25 USD back", "Money moves if you say yes"), then runs once, exactly as approved.
- A fleet of agents, each in its own lane: separate keys, 30-day caps, and one-click "stop all agents".
Seller side: the receipt becomes evidence.
- Every purchase gets a signed receipt in a tamper-evident log, witnessed by a public timestamp authority.
- The Dispute Desk imports PayPal disputes and verifies the buyer's receipt on its own, without trusting the buyer's gateway. It builds the evidence packet and suggests fight or refund; staff choose, and the answer goes back to PayPal.
Judges can try it in 60 seconds: the live site's judge mode lets a demo agent try six carts while you decide.
How we built it
- Gateway: Python, FastAPI, MCP (the agent's only door), PostgreSQL. PayPal Orders v2 and Disputes APIs in the sandbox.
- AI checks: GroqCloud
openai/gpt-oss-20bfor typed JSON cart matching, andmeta-llama/llama-prompt-guard-2-86mfor injected instructions. If a check fails or times out, the cart is held, never approved. - Trust:
- Ed25519-signed permissions and receipts.
- WebAuthn passkey signatures over exactly what you saw.
- A hash-chained audit log witnessed by RFC 3161 timestamp authorities (DigiCert, FreeTSA).
- Shop-signed cart offers.
- A focused subset of AP2 v0.2 Checkout and Payment Mandates.
- Checkout guard: Playwright driving Chrome, exposed to the agent as an MCP server. Its banner lives in a closed shadow root, so the agent can't read or fake it.
- PayPal guard: an MCP proxy in front of PayPal's official MCP server (
@paypal/mcp, Agent Toolkit). Each approval is bound to a hash of the exact arguments. - Agent: Claude, through Claude Code and the Claude Agent SDK.
- Web app: React + TypeScript (buyer Inbox, approvals, audit log, receipts; seller Dispute Desk).
- Hosting: Render, with one Blueprint for the gateway, Dispute Desk, demo shops, web app and PostgreSQL.
- Evaluation: 167 labelled carts, 55 held out, with every model reply stored word for word.
Challenges we ran into
- Our agent was too good. A real Claude agent refused our poisoned product page, so the "fooled agent" scene had to be scripted. The gateway still has to stop a fooled agent, and it does.
- PayPal vault tokens belong to one merchant, so a third-party gateway can't pay at any shop. We made PayPal's own checkout the payment step and Countersign the gatekeeper in front of it.
- Same question, different answers. A language model can answer the same cart differently twice. We store every reply and measure on a held-out set instead of trusting one good run.
- Making safety visible. A block in a log means nothing to a normal user. We redesigned every "no" so it shows what you allowed vs what the agent tried, in plain words.
Accomplishments that we're proud of
- 0 of 114 carts that should have been stopped were paid without asking (95% CI 0–3%).
- All 15 held-out hidden-instruction attacks were caught.
- Pack sizes are counted in code: 13 of 13 new held-out pack cases right.
- Real sandbox disputes answered from the desk: a refund offer, and evidence accepted.
- Receipts anyone can check with public keys only: the gateway's signature, the buyer's device signature, the shop's signature and the outside timestamp.
- Approvals for PayPal's own agent tools that an everyday user can understand, and that run exactly once.
What we learned
- The model is the weakest link, so it never has the last word. Money rules are plain code, and doubt means "ask the person".
- Proof is worth more when the other side can check it. The seller verifies the buyer's receipt on its own, without trusting the buyer's gateway.
- Consent must be specific. "This exact cart, once" is easy to give and easy to prove. "My card, for anything" is neither.
What's next for Countersign
- Inside PayPal as a wallet feature, so saved consent is released only for countersigned carts, at any merchant.
- Structured agent checkouts (e.g. Shopify) instead of reading pages, plus more shops.
- Better-calibrated AI checks, and letting you edit a permission (budget, shops) before approving.
- Receipts as a standard, so any seller or PayPal itself can check an agent purchase in a dispute.
Built With
- claude
- fastapi
- paypal
- postgresql
- python
- react
- render