Inspiration People don't want to browse twelve tabs anymore. They want to say "a USB-C hub and a keyboard with brown switches, under $240" and have it handled. PayPal has said plainly that this is where commerce is going, with agents shopping and paying on the consumer's behalf.

The missing piece is what happens in between. Today you either hand an AI your card and hope, or you do every checkout yourself. Neither is what people want. They want the assistant to do the boring part while a hard line stays around what it can spend, where, and on what.

PayPilot AI exists to hold that line. Not a polite agent that was asked to respect your budget — an agent that structurally cannot exceed it.

What it does PayPilot researches, compares, and buys inside a mandate you define. PayPal settles the payment. A human approves before money moves.

You give it two things. A mandate: total budget, per-item cap, allowed categories, blocked merchants, minimum rating, auto-approve threshold. And a mission, in plain language.

It gives you back a governed purchase. The agent searches agent-ready merchant catalogs through PayPal, filters candidates against your mandate, and proposes a cart with its reasoning attached — including what it rejected and why. Every cart passes the policy engine before it's eligible for checkout. You review, click through to PayPal, and approve. The agent never touches credentials.

Every decision is logged. Proposals, blocks, approvals, captures — all replayable after the fact.

The short version: the agent does the legwork, the mandate does the refusing, the human does the approving.

How we built it One design decision drove everything else: the model can reason, but it cannot spend.

We run Claude through the PayPal MCP server, but gave it exactly five tools — search_products, get_product, check_mandate, propose_cart, suggest_mandate_change. None can initiate a payment. The mandate lives in a separate TypeScript policy engine, and that engine alone can mark a cart eligible for checkout.

Layer Stack Why Agent runtime Claude via Anthropic API, orchestrated through PayPal's MCP server Natural-language access to PayPal order and cart operations Payment rail PayPal Orders v2 API (sandbox) + Cart API Explicit order/capture semantics; Cart API is the agent-facing checkout path Guardrail Custom mandate policy engine (TypeScript, Python port) Keeps authorization out of the model entirely Discovery PayPal Store Sync + agent-ready catalogs, plus a local demo catalog How products become visible to an assistant at all Approval UX Review console: proposed cart, mandate checks, rejected options, PayPal handoff Buyer keeps authentication and funding control Ledger SQLite, append-only Cheap, boring, replayable The flow: mandate created as structured data → agent researches → check_mandate gates every cart → user reviews and approves → PayPal captures → ledger records. Fixed request IDs throughout, so retries can't duplicate an order.

Challenges we ran into Order status is not payment status. PayPal's Orders v2 schema warns that an order can read COMPLETED while its capture is DECLINED. Our first ledger trusted order status, which meant the agent could announce a successful purchase on a payment that never happened. Rebuilt around capture status.

The model forgot things. Mandate started in the system prompt. Worked in testing, drifted in longer sessions — proposed a cart a few dollars over the per-item cap. Prompts are suggestions; mandates have to be code.

Human-in-the-loop is a UX problem. Bolting on a confirm dialog is easy. Making approval feel like a natural step rather than a second checkout is not. We landed on: the proposal, two or three rejections with reasons, one button.

The sandbox isn't production. Duplicate request IDs, stale carts, inconsistent catalog responses. Fixed idempotency keys, retry ceilings, and a demo mode on a curated local catalog.

MCP is a protocol, not a product. The MCP server gives models access to PayPal tools but ships no purchasing policy layer. We built the mandate engine, approval flow, and ledger ourselves, working across both the hosted MCP path and a direct Orders v2 path.

Scope at 48 hours, 16,000 registrants. We cut to one vertical slice: intent → discovery → mandate check → proposal → approval → capture → ledger. It runs end to end. Everything else went on the roadmap rather than half-built.

Accomplishments that we're proud of The guardrail actually holds. We tried to break it — missions engineered to talk the agent over budget, loosely worded mandates, tempting blocked products. It held, because the agent never had the authority to break it. There's a real difference between an agent that follows rules and one that can't violate them.

It's a real transaction. Real sandbox captures, real ledger reflecting what happened to the money. The capture-vs-order bug is invisible in any demo that fakes the payment step.

What we learned Don't ask a language model to be a policy engine. It looked fine until it didn't. Moving the mandate into deterministic code made the agent both more useful and less scary.

For agentic commerce, trust is the product. Convenience gets someone to try it; "it did what I said" is why they keep using it.

And build against the real sandbox. Half our best bugs came from schema corners nobody reads until something breaks.

What's next Near term: richer mandates without harder setup — recurring mandates, time windows, per-merchant budgets layered under the global one, and natural language that compiles to the same structured object as the form.

Then: coordination. Several agents working inside one mandate, each on a different category, drawing on the same budget and ledger. That's when the audit trail starts earning its keep, because no human can watch three agents at once.

Longer term: merchant adoption. Store Sync and agent-ready catalogs are the right direction, and the mandate layer is deliberately payment-rail independent — so as more catalogs open up, the same guardrail carries over.

Same goal we started with: an assistant that can shop for you without ever holding the wallet.

Built With

Share this project:

Updates

Submission history