Inspiration
Online communities run on a host's money work: selling course seats and summit tickets, running memberships, and paying the instructors and partners who did the work. That work is usually spread across forms, spreadsheets, and manual transfers. Room Pass puts it in one place: a member types a plain-English request in a chat, and an AI agent does the money work through PayPal — while a human host approves anything that sends money out.
What it does
A member types a plain-English request in a chat. The agent finds the items in the host's catalog, checks seats, and creates ONE PayPal order for the whole basket (Orders v2); the member approves once at PayPal. For example, "I want the 4-week AI screenwriting course and a seat at the December summit" creates one $198.00 order ($149 + $49), and seats update only after the payment is captured.
Memberships: the agent creates the PayPal product and billing plan on the fly and starts a subscription (Subscriptions API), and can upgrade, downgrade (revise), or cancel it — for example, joining Pro at $25/month, then upgrading to Studio at $60/month.
Payouts: for a partnership sale the agent shows the split math — a 10% platform fee, then the partners' percentage split of the remainder — and only when the host presses Approve does it send a PayPal Payouts batch to the partners. For an $800 partnership sale split 60/40, that is an $80 fee, $720 net, and $432 / $288 to the partners. Invoicing drafts are supported too: a draft PayPal invoice for a company buying seats for staff, never auto-sent. Everything runs on the PayPal SANDBOX — test money only. All demo data (the community, courses, summit, members, instructor, and partners) is fictional.
How we built it
Room Pass is built with Node.js (zero dependencies, standard library only) and a plain HTML/CSS/JS front end. The server is plain node:http with the built-in fetch; there is no npm dependency to install beyond running npm install / npm start.
PayPal is the whole money layer, via src/paypal.js: OAuth2 client-credentials, Checkout Orders v2 (create/capture), Catalog Products v1, Subscriptions v1 (create/revise/cancel), Payouts v1, and Invoicing v2 (draft). The stack is: Runtime — Node.js (v18+, tested on v24); Front end — one static page (public/index.html), vanilla JS + fetch; Payments — PayPal REST APIs; Agent layer — src/agent.js, a deterministic planner that parses the member's plain-English message, runs catalog/seat tool calls, then the matching PayPal tool call; Demo mode — src/demo.js, which simulates the same response shapes when no credentials are set, clearly labeled everywhere; Data — src/catalog.js, the fictional Demo Community catalog, membership tiers, and the pure payout-math function (10% fee, split of the net, last recipient absorbs rounding). A demo-mode simulator was added so the app works with no credentials at all (IDs prefixed DEMO-, with a yellow banner shown the whole time), and an end-to-end local test (npm test) passes.
We deliberately made the agent deterministic: intent parsing is deterministic keyword matching (no LLM), with one named tool call per user request. Every money movement traces to a named intent and a named tool call, new PayPal API calls are added one at a time and tested raw, and payouts additionally require an explicit human host approval (/api/payout/approve is a separate step). Credentials are read only from environment variables / a local .env file and are never in the code, and the app is wired to the PayPal sandbox API base only — it cannot move real money.
Challenges we ran into
PayPal's sandbox flow needs two different accounts, and that was the first stumbling block: one sandbox Business account (the seller — the app) and one sandbox Personal account (the buyer). Switching the buyer to the right identity changed a confusing 402 PAYMENT_ISSUE into an immediate approval, while using the wrong identity showed a fallback card page instead of the normal approval flow. The wrong account also made it look like the approval had failed or not registered at all, which sent debugging down the wrong paths.
We deliberately built only for exact single-request order/capture matching — after the first successful capture there was no auto-capture, no refresh watcher, and no retry; the next approved order that's already in APPROVED state with an APPROVED confirm button needed a fresh browser reload to make it appear.
Other issues we had to work through: a missing slash between an environment base URL and its path swallowed the env var (caught with a tiny hard-coded test first, then the env plumbing fixed); a single approval for two items took as long to understand as the simple buy; an unread amount changed in one place and not in the other; the UI had a real bug — Add to cart on the main page used a wrong function name; and sold-out items had to be refused properly rather than creating an order.
Rounding was a real problem, too, with a payout shown as $81.90 (+ $0.003) once — the fix makes the last recipient absorb any rounding difference, so every payout always adds up to the exact total.
Accomplishments that we're proud of
We built a working, end-to-end PayPal sandbox agent with no dependencies: one PayPal order for a whole multi-item basket, captured only after the member approves, with seat counts decreasing only after capture; a full membership lifecycle (create product and plan on the fly, subscribe, revise, cancel); payout math that is exact and shown before any money moves; and a human-in-the-loop rule enforced in code, not just in the README — the agent only prepares a payout, and a host must press Approve before the Payouts API is called. The app also runs in a clearly labeled demo mode with no credentials, and the end-to-end test suite passes.
What we learned
We learned that the PayPal sandbox is a two-account flow — a Business seller and a Personal buyer — and that switching identities is often the fix when an approval looks broken. We learned that Subscriptions need a Product and a billing Plan created first, that seats should only change after capture, and that money work should be split into small steps: parse the intent, check seats, create the order, then capture — with the breakdown shown separately so the numbers always add up. Most of all, we learned to keep a human in charge: the agent proposes, a person approves anything that sends money out.
What's next for Room Pass
After the hackathon, we plan to connect a real PayPal business account, add webhooks so payment, subscription, and payout status update automatically instead of relying on the member returning to the app, and add persistent storage so the catalog, seats, memberships, and payout history survive a server restart.