Inspiration
AI agents can now buy products, pay invoices and manage subscriptions, but giving each agent its own unrestricted payment integration creates real risk. Three agents that each stay within their own limit can jointly overspend an organization's budget. An agent can change an order after a human approved it, or replay an old approval. And when merchant, user and organization rules conflict, nobody can say afterwards why a payment was allowed.
We wanted the missing layer between agents and payment providers: define financial authority once, enforce it consistently, and keep an auditable record of every decision.
What it does
PACT (Policy and Authorization Control Tower) is a financial governance runtime for AI agents. An agent such as Claude Code asks PACT for permission through MCP. PACT then:
- Evaluates policy. A deterministic, fail-closed engine composes system, organization, user, merchant and agent rules. It returns ALLOW, DENY or REQUIRE_APPROVAL with exact reason codes, never an LLM guess.
- Reserves a shared budget. All agents draw from one ledger with atomic reservations.
- Asks a human. The admin dashboard shows the exact transaction and every policy finding. Approval is bound to that order's hash.
- Issues a restricted grant. It is single-use, hashed, and bound to one merchant, order, amount and currency.
- Executes through PayPal Sandbox. Only the execution gateway can reach PayPal, and it re-checks the grant and the live order first.
- Records everything in a tamper-evident, hash-chained audit log.
No agent-facing tool can approve a payment. Replays and post-approval order changes are rejected and audited. We also built a Merchant Lab storefront where you can watch an agent's cart and each order's authorization timeline update live.
How we built it
- Core: Python with SQLAlchemy. Concurrency safety comes from
BEGIN IMMEDIATEand conditional SQL updates: a test with 20 contenders for room for exactly 5 lets exactly 5 win. - Interfaces: a FastAPI REST API, an MCP server that holds only an agent key (no database, no PayPal secrets, no approval rights), and an operator CLI (
pact demo,doctor,approve). - PayPal: an Orders v2 adapter limited to Sandbox URLs, plus a clearly labelled simulation adapter ("Simulation (not PayPal)").
- UI: React, Vite and Tailwind. The admin dashboard has Overview, Approval Centre, Policies and an Audit Explorer. The storefront has the catalogue, live cart and order pages.
- Quality: 1,256 tests, including end-to-end tests through the real PayPal adapter on a mock transport, a security test matrix with a threat model, and CI for both Python and the dashboard.
- Process: we built it with Claude Code, splitting independent work across parallel agents with disjoint file ownership.
Challenges we ran into
- PayPal Sandbox behaviour. INR is rejected for our account type, so we settle in USD. The checkout can show a guest card form that rejects test cards instead of a login. Buyers must use a Personal Sandbox account that differs from the business account.
- Payments that wait on a human. A payment can sit in checkout for a long time, hold budget, or fail permanently when the buyer clicks "Cancel and return". We hit each of these and tracked them as issues, fixing the gateway paths (order not found, capture recursion, non-terminal cancel, checkout timeout) before the demo.
- Provider timeouts. A timeout can't be treated as failure or success. The request moves to UNKNOWN and is reconciled against the provider, never retried blindly.
- Keeping the agent powerless. Every route, tool and log needed checking so that no agent path can approve, edit policy or read a secret. The security test matrix covers this.
Accomplishments that we're proud of
- A complete governed purchase on PayPal Sandbox: Claude requests a keyboard, PACT requires approval, a human approves, the grant is consumed once, PayPal captures the payment, and the request ends
EXECUTEDwith a real capture id. The audit chain verified across 459 events. - Shared budgets that hold up under concurrency, so the last request is denied by the global budget even when it is within its own agent's cap.
- Replay and modification attempts are rejected and visible in the audit explorer.
- An agent-facing surface with 16 tools, none of which can approve.
- A threat model with documented findings and a test for each, written alongside the code.
What we learned
- Authorization must be bound to the exact transaction, not just to an agent or a session.
- Money and approvals need explicit state machines. The "unknown outcome" state matters more than the happy path.
- Payment sandboxes have their own edge cases, and a simulation adapter is useful but must never be passed off as the real provider.
- Writing the threat model and tests early found real bugs, such as a public cancel link that could fail a live payment.
What's next for PACT
- Fix the remaining documented findings: the public cancel link, security headers and rate limiting on authentication.
- Deploy a hosted instance with PostgreSQL support and a hardened admin login.
- More payment providers behind the same adapter interface, and a policy editor with versioning, previews and diffs.
- Per-agent spending analytics and alerts, and SDKs beyond MCP.
- Complement agent payment protocols such as AP2 and PayPal Agent Ready: PACT governs the decision and the audit trail, and those protocols move the money.
PACT is a sandbox reference implementation, not a certified financial security product. It processes no real money.
Built With
- claude-code
- fastapi
- github-actions
- httpx
- mcp
- model-context-protocol
- node.js
- paypal
- paypal-orders-api
- paypal-sandbox
- pydantic
- pytest
- python
- react
- sqlalchemy
- sqlite
- tailwindcss
- typescript
- uv
- uvicorn
- vite