A promoter is about to wire $250,000 on a feeling. OfferSheet turns that feeling into one number, 2,084 tickets, and puts a SHA-256 receipt on every taste claim behind it.
OfferSheet is an agentic offer checker for independent promoters. You give it an artist, a city, a guarantee and a ticket price. It gives back the break-even ticket count, the live Qloo audience evidence behind it, and a receipt on every claim that you can replay.
▶ Live app · ▶ 3-minute film · Source · ✅ Verify every number · ⬇ Android APK

Inspiration
An independent promoter gets an offer: book this artist, in this city, for this guarantee. The guarantee gets paid whether the room fills or not. Every offer comes down to two questions:
- How many tickets do I have to sell before this guarantee pays for itself?
- Is there a real audience for this artist in this city, and who should open?
Today those answers come from a spreadsheet and a gut feeling. AI tools that answer with confidence but give no source make it worse. We wanted one page and one number, where every taste claim can be proven.
What it does
There's no sign-in and no mock data. Enter the offer, and OfferSheet runs a live agentic pipeline and returns:
| Output | What you get |
|---|---|
| Break-even | The exact ticket count, with every entered cost line shown |
| Taste evidence | Headliner and opener cards, city audience areas, demographics, shared tags, fan overlap and 90-day momentum, all live from Qloo |
| Opener race | Qloo's graph pick next to an LLM-only "gut" pick and an LLM + Wikidata "web" pick, with every miss named |
| Receipts | A SHA-256 receipt on every Qloo-backed claim, which you can replay in one click |
| Workspace | A hash-verified saved deal: replacement act, renegotiation, routing, budget envelope, comparison of up to 5 offers, and settlement |
The formula, in breakeven.js:
$$ n = \left\lceil \frac{G + F - S}{p - v} \right\rceil $$
Here \( G \) is the guarantee, \( F \) the fixed costs you entered, \( S \) the sponsor offset, \( p \) the ticket price and \( v \) the variable cost per ticket. A blank field means not entered, never a silent zero.
| Offer | Arithmetic | Break-even |
|---|---|---|
| Billie Eilish · New York · $250,000 / $120 | ceil(2,083.33) | 2,084 tickets |
| Same, plus a $10,000 venue cost | ceil(2,166.67) | 2,167 tickets (+83) |
When the break-even is above a known room capacity, the verdict says so in plain words: Cannot break even in this room at this guarantee.

Why it matters
- Money decisions get a number. The guarantee is the biggest risk on a show. OfferSheet turns it into a target you can sign or walk away from.
- Taste data gets accountability. Qloo's cultural graph becomes evidence a promoter can show a partner or an agent, with the exact call behind every claim.
- The graph is tested against the gut. In all 3 recorded trials, the LLM-only gut pick differed from Qloo's graph pick, and each miss is named in the ledger. That's the case for grounded taste data, measured on screen.
- Built for real use. It works on a 390 px phone, installs as a PWA, ships as an Android APK, and any AI agent can run it through MCP.
How it works

Promoter (web / PWA / Android)
│ artist · city · guarantee · price
▼
Frontend (Vercel, vanilla JS + GSAP) ──SSE──▶ Backend (Node 22, zero runtime deps, Render)
├─ qloo_capabilities gate ──▶ fail closed (visible 503) if Qloo is not live
├─ Qloo MCP: 10 official tools ─────┐
├─ Qloo REST: /search · /v2/insights · /v2/analysis/compare · /entities
├─ Ticketmaster Discovery (venue, capacity, price)
├─ OpenStreetMap (geocode) · Wikidata (facts for the Web arm)
├─ LLM provider chain (Gut and Web arms)
└─ break-even = ceil(total ÷ net) ─▶ every call hashed into a SHA-256 receipt
▼
Verdict · Evidence · Race with named misses · Replayable receipts
The browser never calls Qloo directly. Only artist, city and tag inputs are sent to Qloo, never names, emails or device IDs: aggregate audiences only, by design.
Deep Qloo integration: 10 of 10 official MCP tools
Every official Qloo MCP tool drives a named feature:
| Qloo MCP tool | Feature it powers |
|---|---|
qloo_capabilities |
Readiness gate and the "Qloo live" badge |
qloo_find_tags |
Tag-first headliner resolution |
qloo_describe |
Headliner and opener cards, plus an ambiguity picker |
qloo_recommend |
Opener candidates drawn from the headliner's fans |
qloo_rank |
Shortlist ranked for the city's audience |
qloo_where_popular |
City audience areas and routing |
qloo_audience_demographics |
Age and gender bands |
qloo_entity_tags |
Shared-tags evidence |
qloo_trends |
Momentum leg |
qloo_compare_audiences |
Headliner–opener fan overlap |
On top of that, a REST receipt layer cross-checks the MCP legs through /search, /v2/insights (with feature.explainability=true), /v2/analysis/compare and /entities. One live verdict produces 9 receipts: 7 MCP and 2 REST.


Receipts & replay: check a number in 60 seconds
Each receipt stores an operation, a requestHash, a requestId, a resultCount and a replay object. MCP receipts hash tool + " " + JSON(args). REST receipts hash METHOD + " " + URL. When Qloo returns no requestId, it shows as null and is never made up.
B=https://offersheet-backend-k2zp.onrender.com
curl -s $B/api/health
# {"status":"ok",...,"qlooConfigured":true,"ticketmasterConfigured":true,"llmConfigured":true}
curl -s -X POST $B/api/verdict -H 'Content-Type: application/json' \
-d '{"artist":"Billie Eilish","city":"New York","guarantee":250000,"ticketPrice":120}' > verdict.json
# breakEven.tickets = 2084, receipts.length = 9
printf '%s' 'qloo_find_tags {"query":"Billie Eilish","limit":10}' | sha256sum
# affa6e35703be8f54ddeec84c42966a06093e94f21082f4cd446ada31f7f93f7 = receipts[1].requestHash
node -e 'process.stdout.write(JSON.stringify(require("./verdict.json").receipts[1].replay))' > replay.json
curl -s -X POST $B/api/replay -H 'Content-Type: application/json' -d @replay.json
# {"kind":"mcp","tool":"qloo_find_tags",...,"status":"ok",...,"resultCount":10}
In the app, every receipt row has a Replay button. It re-runs the exact recorded call and matches the fresh results to the recorded ones by ID order. There's also an offline trial pack: offersheet_trial_pack_verify checks all 3 recorded trials with no network and no keys (allPassed: true).

Engineering quality
| Metric | Result |
|---|---|
Test suite (fresh clone, node --test) |
610 tests · 607 pass · 0 fail · 3 skipped |
| CI | GitHub Actions: test job + Playwright browser job, green |
| Accessibility | 0 serious or critical axe issues on every tab; all text at least 4.5:1, checked at 1280 px and 390 px |
| Runtime dependencies | Zero (Node ≥ 22.19) |
| Our own MCP server | 33 tools (23 offersheet_ + 10 qloo_), stdio JSON-RPC 2.0 |
| Qloo 429 resilience | De-duplication, at most 2 concurrent calls, Retry-After honoured, backoff with jitter, one retry |
| Ships as | Web app, installable PWA, Android APK (295,972 bytes, signed release) |
With the 33-tool MCP server, any agent can run the whole product: verdicts, the race, receipt replay and hash checks, trial packs, venue search, opener reranking and health.
Design
A dark, calm, gold-accented term sheet. Albert Sans for the interface, Hedvig Letters Serif for accents, and monospace for numbers and hashes. The page leads with the number, then shows the evidence underneath. There are five real tabs: Offer → Verdict → Evidence → Workspace → Ledger. Motion comes from GSAP with one easing curve, and it switches off under prefers-reduced-motion. Every layout is checked at 1280 px and at 390 px.

Challenges we turned into features
- Trust became a design principle. A taste signal with no source is just an opinion. So every Qloo call is hashed, receipted and replayable, and the receipt layer is now the core of the product.
- Fail closed, never fake. If Qloo is not live, the page shows a 503 instead of a mock. The verdict shows how strong its evidence is, with status pills for each source (ok, no data, retried), so a promoter knows exactly how much weight each claim carries.
- Rate limits became resilience. Qloo 429s led to request de-duplication, a concurrency cap of 2,
Retry-Aftersupport and backoff. Recovered calls are marked retried. That's covered by three dedicated test files. - Blank never means zero. Each cost line is either entered or left out, so the formula on screen is always the one you actually entered.
Accomplishments we're proud of
- 10 of 10 official Qloo MCP tools wired, each powering a named feature, plus a 4-endpoint REST cross-check.
- 9 replayable SHA-256 receipts on every live verdict.
- Zero mocks. Every number comes from a live call or from the user's own input.
- 610 tests, green CI with Playwright and axe, and a 33-tool MCP server.
- A full product on web, PWA and Android, with a 3-minute film.
What we learned
A promoter doesn't need a ranking. He needs a number he can sign or walk away from, and he needs to trust where it came from. Receipts and replay turn "the AI says" into "here's the exact call, run it yourself." Qloo's graph is most convincing when it sits right next to the gut it is tested against.
What's next
- Settlement loop. Feed settled shows back into the ledger, so the break-even and the actual sales sit side by side.
- Room-scoped verdicts for more venues, with capacity data.
- Tour routing. Use
qloo_where_popularacross a full multi-city run, with a break-even for each stop. - REST receipt hash audit and persistent quota counters.
- Agent-to-agent deal desks. Agencies and promoters' agents could negotiate over the 33-tool MCP server, with receipts on both sides.
Built With
- android
- css3
- github-actions
- gsap
- html5
- javascript
- llm
- model-context-protocol
- node.js
- openstreetmap
- playwright
- qloo
- qloo-mcp
- render
- sha-256
- ticketmaster-discovery-api
- vercel
- wikidata
Log in or sign up for Devpost to join the conversation.