Inspiration
Small service jobs grow one message at a time: "could you also do two posters?", "one more sign", "the menu in three more languages". By invoice time, those extras are buried in a thread with the original quote, included revisions and ordinary correspondence. Freelancers either forget to bill them or bill without being able to show where each line came from.
What it does
Scope Receipt turns a client's own messages into a checked PayPal invoice draft.
- A local AI reader. A language model running on the user's own computer (Gemma 4,
gemma4:12b-it-qat, through Ollama) reads the thread. For every request it returns a category (extra, within the quote, correspondence, or check meaning), the exact words it came from, a line name, a quantity, any written unit price and a one-sentence reason tied to the agreed scope. One message can become several rows, and "Spanish, French and Korean" becomes a quantity of three. - Rules that check the model. The model only proposes. Before a row reaches the table, rules check it against its message: the quoted words must really be there; a price must be written in that message, so a budget, a limit, a discount, two different amounts or an invented price leaves the price for the person; an amount for several items needs per-item wording; repeated items are dropped or combined and marked for checking. The inspector highlights the quoted words and shows which checks passed.
- A review table in AG Grid. The person selects work, with a pinned total, edits line names, corrects a category (the correction is marked and carried into the draft), edits quantity and price, undoes and redoes edits, searches, filters and exports CSV. Nothing is selected or sent automatically.
- PayPal as the output and the check. After the person confirms the review, the app creates an invoice draft through the PayPal sandbox Invoicing API, then reads the draft back from PayPal and compares PayPal's stored copy with the review, line by line: ID, DRAFT status, currency, total, and each line's name, quantity and unit price. Every PayPal line keeps a
Source N-04areference to the client message it came from.
Without Ollama, a built-in Naive Bayes classifier runs the same review.
How we built it
Node.js with native HTTP and Fetch, Vite, plain JavaScript and AG Grid Community 36.2.0. The server calls Ollama at 127.0.0.1:11434 with a JSON schema, temperature 0 and thinking turned off. Only loopback Ollama addresses are accepted, so client messages stay on the computer. PayPal calls (POST /v2/invoicing/invoices to create, GET /v2/invoicing/invoices/{id} to read back) run on the server, with credentials from the environment. A retried uncertain request reuses its PayPal-Request-Id. Money is handled in integer cents.
The code, design, tests and synthetic examples were generated with Codex and Claude under the entrant's direction during the hackathon. No real client messages or transaction records were used, and no cloud model service is called.
Challenges we ran into
Gemma 4's thinking mode used up the whole token budget before answering, so the request turns thinking off. The model sometimes listed one request twice, or split an item from its count and price. Overlap removal, combining items with the same name, and one prompt sentence fixed that on the threads we tried, and combined lines are marked for a person to check. A message can mention a budget or several amounts without agreeing on a price, so the rules never take a price that is not clearly written per item. An uncertain network outcome is the other hard case: a lost answer does not mean no invoice exists, so retries reuse the original request ID and the readback shows what PayPal actually stored.
Accomplishments that we're proud of
Real PayPal sandbox drafts were created and read back on 2026-11-07, with every line, the DRAFT status and USD 260.00 matching the review. The demo video shows one of these runs, recorded live with nothing mocked. The project has 60 unit tests and 15 browser tests, covering the rules that check the AI, the PayPal adapter's success and failure cases, and the readback comparison.
What we learned
A model's answer becomes useful for billing only when each claim can be checked: the quoted words, the written price, the count. Keeping the model as the proposer, with the rules and the person as checkers, made the output both more helpful and easier to trust. Reading the result back from PayPal closes the loop in a way an export alone cannot.
Limitations
The AI reader was observed with gemma4:12b-it-qat on two authored English threads. On the sample thread, nine runs gave the same nine rows; a second thread gave the expected result in three of three runs. That is not an accuracy measurement, and accuracy on real client messages has not been measured. The fallback classifier was trained on 81 authored synthetic examples and checked on small authored lists. Every selection and price needs human review. Draft creation is the deliberate end of this prototype: client details, tax and sending remain human decisions, and the app has no sending or payment function.
What's next for Scope Receipt
Trying more local models and real-world thread styles, Japanese-language messages, and a dashboard view of unbilled extras across projects.
Built With
- ag-grid
- gemma
- javascript
- node.js
- ollama
- paypal
- playwright
- vite