Inspiration

Every campus fest starts the same way: a spreadsheet, a group chat, and a budget that only exists in someone's head. The lineup is the fun part. The deposits are where it breaks - a headliner's advance, a venue hold, a food truck's retainer, all due at different times and all competing for the same money.

FestOS began as a taste-aware planner: three signals in, a complete run of show out, with every pick traced to the Qloo taste graph. The PayPal AI Hackathon asked the next question - what does agentic commerce look like after the plan? So we built the missing half: a settlement agent that turns a finished lineup into vendor deposit obligations and settles them through PayPal, with policy, a cap, and a human in the loop.

What it does

FestOS has two agents and one shared state.

Planning agent. It takes a campus vibe, a budget and a date, resolves taste through Qloo Insights, scores audience affinity, and solves budget, genre mix and vendor spread into a lineup: headliner, support, opener, screening and food row. Every slot carries a reason and a Qloo trace.

Settlement agent. With one click it converts the lineup into vendor deposit obligations. A deterministic policy funds them in strict priority - headliner, screening/venue, support, opener, food - until the deposit cap is reached. The first slot that does not fit stops the run; everything below it is explicitly deferred, never silently skipped. The user reviews and approves. Then each funded obligation becomes a PayPal Orders v2 order (USD, 30% default deposit, fixed labelled FX), the vendor is paid through PayPal's approval page, and the server captures the order. The result is a ledger with order ids, capture ids, statuses and a funded/deferred split that can be audited line by line.

How we built it

  • Frontend: React 19, TypeScript, Vite. The settlement panel, obligation cards and ledger live beside the plan, not behind a settings page.
  • API: Node.js 20, Express. /settlement/draft runs the policy engine; /settlement/orders creates orders; /settlement/capture captures them.
  • PayPal: Orders v2 REST. OAuth 2 client-credentials token, POST /v2/checkout/orders with intent: CAPTURE, USD purchase units, return/cancel URLs and PayPal-Request-Id for idempotency; POST /v2/checkout/orders/{id}/capture for server-side capture. The base URL is sandbox-only - there is no live-money code path.
  • Taste: Qloo Insights API for entity resolution and audience affinity.
  • State: settlement runs persist in localStorage so a redirect to PayPal and back does not lose the run; the return URL auto-captures the approved order.
  • Tests: six automated tests, including a mocked-fetch contract test that asserts the exact OAuth, create-order and capture payloads, plus policy tests for cap behaviour and simulator end-to-end runs.

Challenges we faced

  • PayPal does not settle INR. Rather than hide it, we used a fixed, labelled FX rate (INR 83.50 = USD 1.00) and showed it in the UI and README. Judges should never have to guess what a number means.
  • Money is a different class of tool. Letting an LLM decide what to pay, and in what order, is not acceptable. The policy engine is deterministic; the agent can explain a decision but cannot override the cap or the priority order. The human approval step is a product requirement, not a formality.
  • Stateless redirects. A PayPal redirect leaves the app. Persisting the run and rehydrating it on return was the difference between a demo and a working flow.
  • Testing without credentials. We did not want "trust me" as a test strategy. Mocked-fetch contract tests pin the request shape, and a simulator runs the identical lifecycle with clearly labelled SIM- ids when keys are absent.

Accomplishments we're proud of

  • A full lifecycle that works: plan to obligations to prioritized funding to PayPal orders to approval to capture to an auditable ledger.
  • A policy that is strict, explainable and visibly stress-testable: move the cap and the deferral line moves with it.
  • Honest failure modes: the app says "simulator" when it is simulating, and labels the FX assumption.
  • A public, Apache-2.0 repo with the demo and setup instructions.

What we learned

Agentic commerce is not "the agent can call a payment API." It is everything around that call: a budget the agent cannot exceed, a priority order a human can inspect, idempotency so a retry never double-pays, and a ledger so every cent can be traced back to a decision. The payment call is the easy part.

What's next

  • Real sandbox credentials on the hosted demo, then a vendor onboarding flow.
  • Partial refunds and deposit terms per vendor through PayPal.
  • Multi-currency settlement.
  • A treasury agent that negotiates deposit terms, still bounded by the same policy engine.

Try it out

Demo note: the hosted app runs the PayPal lifecycle in a clearly labelled simulator because sandbox API keys are not set on that host. Set PAYPAL_CLIENT_ID and PAYPAL_CLIENT_SECRET and the same flow calls PayPal Orders v2 in sandbox. The demo video shows the simulator path and the labels that make it explicit.

Built With

Share this project:

Updates

Submission history