Inspiration

AI agents can now shop and pay for people. But between the moment a purchase is approved and the moment PayPal captures it, prices drift, items get swapped, policies change, and retries double-charge. A well-formed LLM output is not proof that the payment matches what the owner approved. I wanted a way to prove it, for developers and companies putting an agent in front of a checkout.

Why PayPal

PayPact is built on PayPal Orders v2 because that is where the risk actually sits: between the moment a human approves a purchase and the moment PayPal captures it. PayPact fingerprints exactly what was approved (SHA-256 over item, quantity and amount), re-checks policy and amount before the order is created, and runs the same check again at capture. Order creation uses PayPal-Request-Id so retries cannot double-charge. PayPal webhook events (refunds, disputes) are reconciled into the same hash-chained audit ledger, so the record covers what happened after capture too. A merchant or platform that lets agents pay would put this gate between the agent and PayPal's order and capture calls. It needs no change to PayPal and no trust in the agent. The agent can search, propose and pay, but the MCP server has no approve tool, so only the owner can authorise spending.

What it does

PayPact is a deterministic gate between any AI agent and PayPal Orders v2. The model only proposes; money moves only if the exact proposal the owner approved still passes policy at the moment of capture.

  • A versioned spending policy and budget that the AI cannot change
  • Gemini turns the request into a proposal and picks the product through tool calls, but never approves anything
  • Every proposal gets a SHA-256 fingerprint of exactly what was approved
  • The gate re-checks policy, budget and fingerprint before the PayPal order is created and again at capture
  • Hidden fees, swapped items, revoked policies and prompt injections are blocked before PayPal is called
  • Every outcome goes into a hash-chained audit ledger with signed (HMAC) receipts; change one number and verification fails
  • An MCP server lets any outside agent search, propose and pay, but there is no approve tool. Only the owner can approve.

How I built it

A FastAPI backend with a deterministic policy engine and a guarded transaction state machine, a Next.js 14 dashboard, an MCP server, and the PayPal sandbox (Orders v2 with PayPal-Request-Id idempotency, capture-amount checks, timeout reconciliation, and webhook signature verification). Gemini 2.5 Flash handles intent parsing and product choice through function calling; it never sees PayPal credentials and has no network path to PayPal. The project has 297 backend tests and 98 frontend tests, and a lab of seven scripted failure scenarios. I built it with AI coding assistance (Claude Code), as the README discloses.

Challenges

  • Keeping the model's role narrow, so a Gemini pick is accepted only if a tool returned the SKU and it satisfies the request
  • Making approval mean something: owner-only, with one-time links bound to the proposal fingerprint
  • Reservations that lapse while a buyer leaves a PayPal popup open, which could let a late capture overspend the budget. A code review found it, and it's fixed with tests.
  • Being honest about what a benchmark of my own reference designs does and doesn't show

Accomplishments

  • A full live purchase in the PayPal sandbox, with real order and capture IDs
  • Three attacks blocked before PayPal is called: a hidden shipping fee, a swapped item, and a prompt injection
  • An MCP agent that is refused until the owner approves
  • Seven scripted scenarios, where PayPact passes all seven, against a no-gate baseline that passes one and a proposal-time-check baseline that passes four. Those baselines are simplified designs I wrote for the lab, so the result shows the gate does what it was built to do, not that it beats real systems.

What I learned

Authorization has to be re-checked at the moment money moves, not only when something is proposed. An LLM should propose, and something deterministic should decide.

What's next

Persistent storage for policies and the ledger, real merchant feeds instead of simulated drift, user accounts for owner approval, and independently verifiable receipts. It's a sandbox demo today: state is in memory and the catalogue is small. The README lists the limitations.

Built With

  • fastapi
  • gemini
  • gemini-2.5-flash
  • github-actions
  • hmac
  • httpx
  • mcp
  • model-context-protocol
  • next.js
  • ollama
  • paypal
  • paypal-js-sdk
  • paypal-orders-v2
  • pydantic
  • pytest
  • python
  • react
  • render
  • sha-256
  • typescript
  • vitest
Share this project:

Updates

Submission history