Tools used

  • PayPal (sandbox): Orders v2 (create, capture, get; PayPal-Request-Id on every write) for gifts in. Payouts v1 (create batch, read status) for money out, one batch per approved spend.
  • AI: Claude claude-sonnet-5-5 through the Anthropic TypeScript SDK. It reads receipt photos into fixed JSON (vendor, date, amount, currency, category, line items, confidence) and turns plain-English questions into AG Grid filters.
  • Sponsor tools: AG Grid Community (the public ledger and the trustee view), Render (hosting, free plan).
  • App: Next.js 16, React 19, TypeScript, Node built-in SQLite, Zod, Vitest.

Inspiration

Small charities, food banks and clubs run on small gifts. A donor gives $25 and never hears what it bought. Trust in the charity is the main reason people give again, and "we spent it well" is hard to prove when the books live in one volunteer's spreadsheet.

On the other side, the people who spend the money are volunteers. They buy rice or diesel with their own card, hand in a crumpled receipt, and wait weeks to be paid back. The trustee who signs off has to type every receipt by hand.

We wanted one place where both problems meet: the gift comes in, the receipt goes out, and anyone can follow the money between them.

What it does

Glasshouse is a public, glass-walled ledger for a small charity. The demo charity is Northside Food Bank, with three appeals: Winter Food Parcels, Kitchen Equipment and Delivery Van Fuel.

  1. Give. A donor picks an appeal and $10, $25 or $50 and pays with PayPal (Orders v2, sandbox). The capture is checked against the amount asked for, and the gift shows up in the public ledger within seconds.
  2. Receipt. A volunteer uploads a photo of a receipt. Claude reads the vendor, date, amount, category and line items, and gives a confidence score.
  3. Check. Before anyone can pay, Glasshouse checks Claude's reading and holds the spend, with a plain reason, when it looks like a duplicate, goes over the appeal's per-item cap, is more than 3x the appeal's recent average, has no readable amount, or Claude's confidence is below 0.5. Held spends sit in amber on top of the trustee's list with "No payout while held".
  4. Approve. A trustee looks at the receipt and clicks Approve and pay. This click is the only path to money: no code path pays without it, and the app refuses to pay more than the appeal has raised.
  5. Pay out. Glasshouse sends exactly one PayPal Payouts batch to the volunteer and shows its batch id and status until it reads SUCCESS.
  6. Trace. Every gift is matched first-in-first-out to the spends it paid for, in whole cents. Any donor can open "Where did your $25.00 go?" and see the exact receipts, and the total always equals the gift. The trace page has a shareable link.
  7. Ask. On the public ledger anyone can type a question in plain words ("unpaid kitchen spends since 1 Oct") and Claude turns it into a grid filter.

Who it is for: donors who want proof, volunteers who want to be paid back fast, and trustees who want to sign off without typing.

How we built it

  • Next.js 16 app with three roles (donor, volunteer, trustee) and a public ledger that needs no login.
  • Money in: lib/paypal.ts creates the order on the server, PayPal returns the donor to us, and we capture it. The capture is idempotent on the order id, so a replayed return never counts a gift twice. If the captured amount does not match, the gift is marked MISMATCH for a trustee and is not spent.
  • Money out: lib/gate.ts is the only function that can call Payouts, and it runs only after a trustee approval on a spend that is not held. A retry reuses the original sender_batch_id, so PayPal drops the duplicate.
  • Claude: lib/extract.ts sends the receipt image with a JSON schema and checks the answer with Zod. A reply that breaks the schema is kept as an "Unreadable receipt" at $0 with confidence 0, so it is held for a human instead of being lost. lib/nlfilter.ts turns questions into a filter with fields for category, vendor, appeal, amount range, date range and statuses.
  • Ledger: lib/allocation.ts is a pure FIFO match in integer cents; every money move is a row in one SQLite file.
  • Grid: AG Grid Community shows appeals as expandable groups with their spends, colours held rows, filters by column or by Claude's filter, and exports CSV.
  • Hosting: Render free plan. Demo data reseeds on each restart, so judges always start from the same state.
  • Landing page: a 3D "glass ledger" hero made in Blender, where gifts land and one gift travels through the five stops: give, receipt, Claude check, trustee approves, PayPal payout.

Challenges we ran into

  • Our mocked tests passed but the real API did not. The first live Claude run failed every plain-English question with HTTP 400, because our filter schema used a shape the API rejects. It also showed that a blurred receipt made the upload fail, so a trustee never saw it. Both are fixed, and a unit test stops the old schema from coming back.
  • Claude followed our prompt, not our test data. It answered supplies where our fixtures said Equipment. We fixed the cause: one shared category list now feeds the prompt, the schema, the seed data and the test fixtures.
  • "Unpaid" is not one status. Donors mean pending, held or approved. The filter now takes a list of statuses and a date range, and knows the appeal names.
  • Sandbox details: the sandbox buyer only held GBP, which hid USD payouts, so the payout receiver is a separate USD sandbox account. Signing in to the sandbox in a headless browser also needed care for our end-to-end tests.

Accomplishments that we're proud of

  • Money moves both ways on PayPal in one demo: a gift in through Orders v2 and a reimbursement out through Payouts, with a named person approving every payout.
  • Live Claude results, with request ids in the repo (docs/claude-runs): 24 of 24 receipt fields right on 4 readable receipts, the blurred receipt held at $0, and 5 of 5 plain-English questions turned into the exact filter.
  • The trace always adds up: any gift's receipts sum to the gift, to the cent.
  • A judge can test the whole loop on the hosted site in about five minutes, on a phone or a laptop.

What we learned

  • Run the real model early. Two bugs only showed up on live calls.
  • When the AI's answer and your data disagree, fix the shared list, not the prompt wording.
  • For money, the AI should read and warn, and a person should decide. Holding a spend with a reason is more useful to a trustee than a score.
  • Idempotency keys on every PayPal write make retries safe, which matters when a volunteer's network drops.

What's next for Glasshouse

  • Monthly giving with PayPal Subscriptions.
  • More than one charity on one install, each with its own trustees.
  • A donor email with the trace link once their gift has been spent.
  • A small MCP tool so an assistant can answer "where did my gift go?" from the same ledger.
  • A pilot with one real food bank, starting in the sandbox.

Built during the submission period

Glasshouse is a new project, written from scratch for this hackathon. The repo's first commit is dated 2026-10-25 and every commit falls inside the submission period (1 Oct to 12 Nov 2026). No earlier project or code was reused.

Built With

Share this project:

Updates

Submission history