Inspiration
With great power comes great responsibility. AI agents are starting to pay for things on our behalf, and to be comfortable with that we need to see and limit what they can do. Already today many people don't know which subscriptions and autopay setups they have with which vendors. When I went through my own PayPal history, Lupa found 20 payment permissions, and one of them had not charged anything in over a year but was still allowed to. Add autonomous agents on top of that and nobody knows anymore who may pay for what.
The payment APIs are built for the merchant. A merchant can create an order, a subscription or a billing agreement. The buyer gets a settings page, and there is no API for the buyer's side. So the tools that would watch over these permissions, or give an agent a safe slice of them, can't be built. Instead of weeping over the missing functionality, I wrote down what such an API could look like and made it run on the PayPal sandbox.
What it does
Lupa is a proposed Consumer Payment Authorization API. The proposal is the API. The portal is one example of a tool using it, and the MCP server is another.
Through the API a person, or an app working for them, can:
- list the payment permissions on their account (rebuilt from payment history, because PayPal does not list them)
- set a policy per permission: a limit, what to do with recurring charges, price increases or a new merchant, a monthly cap
- write the policy as one sentence ("Anything recurring over 20 euros needs me.") and let a model draft it
- delegate part of a permission to an AI agent: max amount, no subscriptions, how sure it must be, until when
- receive payment requests from merchants or agents, and get ALLOW, HOLD or BLOCK back in the same call
- approve or reject what was held
- read the audit trail of every step
Every decision runs on real PayPal sandbox money movement. ALLOW creates an order with intent: AUTHORIZE, authorizes and captures. HOLD authorizes only, and the money waits for the person. Approving captures it, rejecting voids it. Revoking a sandbox subscription cancels it at PayPal.
The portal looks a lot like normal payment history, and that is on purpose. The customer experience does not need to change much. The new part is what developers can build on the API: a budgeting app, a parental control, a company card policy, another agent framework.
How I built it
Python and FastAPI for the API, SQLite as the ledger, plain HTML and JavaScript for the portal, the mcp Python SDK for the agent tools. PayPal Orders v2, Payments v2, Subscriptions v1, Transaction Search and Webhooks in the sandbox. The model is openai/gpt-5.6-luna through OpenRouter. I wrote the spec and Claude Code did most of the typing.
One rule shaped everything. The model proposes, code decides. The policy engine is plain Python with no IO, and it is the only thing that can say ALLOW. An AI verdict, whether from Lupa's own model or from the agent itself, can turn ALLOW into HOLD but never the other way. A test checks that on 1000 random cases on every push. The model's own text is never shown either: the UI shows fixed sentences whose numbers come from the ledger.
Every response says where its parts came from: ● a real PayPal sandbox call ◇ the proposed API ◆ AI ■ policy. So it is always visible what is real and what is proposed.
Challenges I ran into
- There is no buyer-side data at all, so permissions had to be rebuilt from a payment activity export and Transaction Search. My real export is in the repo, anonymized: merchant aliases, keyed hashes, shifted dates, real amounts.
- Transaction Search returned 403 until the feature was enabled on the app, and new transactions show up only after up to 3 hours. A search window that starts too close to now returns 404 "Data for the given start date is not available".
- Card orders came back as PAYER_ACTION_REQUIRED (3DS), but authorize still went through, so the flow works without a browser.
- Approving sandbox subscriptions failed once because the browser still had the merchant account's cookies. Private window for the personal account fixed it.
Accomplishments that I'm proud of
Building a realistic API from scratch outside of PayPal was a challenge. How to make it seamlessly with real Sandbox api and webhooks in a test portal. In the end it was quite painless and I hope the little test site demonstrates the benefits of having such an API. That of course in the end is a strategic decision from PayPal if they want to open such endpoints to be used externally.
What I learned
I learned quite a bit of the internal processes of PayPal and also about the many merchant features, although they were not utilized in this project.
What's next for Lupa
The prototype has no authentication. A real version would use buyer OAuth scopes, where an agent can request payments but can never hold the scope to approve them, and per-agent credentials. The event trail would go out as buyer-side webhooks, so a wallet, a bank app or a family member's phone could subscribe. And PayPal would know the permissions directly, so nothing would need rebuilding from history.
Built With
- fastapi
- javascript
- mcp
- openrouter
- paypal-orders-api
- paypal-subscriptions-api
- paypal-transaction-search
- paypal-webhooks
- python
- sqlite
Log in or sign up for Devpost to join the conversation.