Fair Share — product requirements
Fair Share splits restaurant and shopping bills. A user uploads a receipt photo (or picks a sample) and the parser extracts items, tax, tip and discounts. The user edits items, adds people, assigns items whole, shared or by unit, and gets per-person totals with proportional tax and tip and exact-cent rounding, then copies or shares a read-only link. Optional accounts add bill history, groups with running balances, debt simplification, recurring drafts, multi-currency expenses and sandbox settlement payments with fees, refunds and requests.
Problem. Splitting a bill by hand is error-prone: tax and tip must follow what each person ordered, cents must not vanish, and groups that share expenses over time need to know who owes whom and settle it with the fewest payments.
Users
- Casual splitter — Photograph a receipt, say who had what, and get fair totals without signing up.
- Group member — Track shared expenses in a group, see a balance and settle it with the fewest payments.
- Group admin — Manage members and invites for a household or trip group.
Goals
- Per-person totals always add up to the bill to the cent.
- Tax and tip follow each person's share of the items.
- Group balances net to zero and can be settled with the fewest transfers; payments and refunds keep the ledger correct.
Out of scope
- Reading arbitrary real photos accurately (samples are deterministic)
- Real card or bank networks
- The native share sheet on mobile
Contents
Receipt reading
Photo upload, sample receipts and failure handling.
- Choosing the "Harbor Grill — dinner for three" sample and "Use sample" shows "Reading your receipt…", then the Items step
- Margherita pizza 1 × 16.50, Caesar salad 1 × 11.25, Craft beer 3 × 7.00, Truffle fries 1 × 8.75, Sparkling water 2 × 3.50
- Tax 5.72, tip 0, "✓ Matches the receipt total $70.22"
- "Café Lumière — euro receipt with service": symbol €
- Croque-monsieur 12.50, Café crème 2 × 3.80, Tarte Tatin 7.90 (subtotal €28.00); tax 2.80, tip 2.80; matches the receipt total €33.60
- "Corner Market — groceries with a member discount": badge "⚠ … off by $0.45"
- Price of Sourdough 6.49 + Enter: "✓ Matches the receipt total"
- "A blurry photo (not readable)": "We couldn't find a receipt in this photo. Try a sharper photo, or enter the items yourself."
- Buttons "Try another photo" and "Enter items manually", no Retry; manual entry opens an empty Items step with "New item name"
- The first attempt fails with an error and a "Retry" button; Retry reads the receipt and opens Items
Items, tax and tip
Editing the bill lines, tax and tip.
- Quantity 0, 100 or 2.5: "Quantity must be a whole number from 1 to 99"
- Quantity 99 on Craft beer gives a line total of 693.00
- Price -2: "Price can't be negative — tick “Discount” for a discount line"
- Soup 2 × 6.00 and Bread 1 × 3.00: bill total $15.00
- Coupon 5.00 with Discount ticked: bill total $10.00
- 101: "Tip must be between 0 and 100%"
- Switching to $ and typing 10 gives bill total $80.22 on Harbor Grill
- Harbor Grill with the "18" chip: tip $11.61 and bill total $81.83
- Tax 200.00 shows a warning about unusually high tax; the total still updates
People and assignment
Adding people and assigning items whole, shared or by unit.
- Ana then ana: "Ana is already on this bill"; only one Ana
- A 31-character name is refused
- Removing Cleo opens a dialog (not a browser popup); Cancel keeps her and her items
- Assign starts with "5 unassigned"
- Craft beer "By unit" with Ana 2 and Ben 1 shows "3 of 3 assigned"
- All items assigned shows "All items assigned"
- "Nothing is assigned yet…" followed by the five item names
Results and rounding
Per-person totals with proportional tax and tip.
- Harbor Grill, 18% tip; Margherita pizza to Ana + Ben, Caesar salad to Cleo, Craft beer by unit Ana 2 and Ben 1, Truffle fries to everyone, Sparkling water to Cleo
- Ana $31.93, Ben $23.05, Cleo $26.85; grand total $81.83 and sum of people $81.83
- Ana's card: items 25.17, tax 2.23, tip 4.53
- A $10.00 item shared by three: one person $3.34, two $3.33, sum $10.00 equals the grand total
Sharing
Read-only share links.
- "Create share link" shows a /splitter/s/<id> link
- In a fresh browser: Harbor Grill with Ana $31.93, Ben $23.05, Cleo $26.85 and no edit controls
- After deleting the shared bill from History the link shows "This bill no longer exists — its owner deleted it."
Bill history
Saved bills of a signed-in user.
- Lands on /splitter/history with 23 bills for Maya
- First rows: Harbor Grill 2026-10-16 $81.83, Corner Market $34.46, Noodle Bar 88 $44.02
- "Older ›" shows three rows: Green Bowl, Night Market, Bill 20 Jun 2026, with "‹ Newer" enabled
- "rafael" finds exactly Noodle Bar 88 (2026-10-11) and Golden Wok (2026-09-02)
- 81 characters: "Title must be 1–80 characters"
- Rename to "Team lunch"; Duplicate adds a second "Team lunch" at $44.02, 24 bills in total
Accounts
Sign-up, verification, reset, lockout and deletion.
- Wrong attempts one to five: "Incorrect email or password"
- Sixth attempt: "Too many failed attempts. Try again in 15 minutes."
- The correct password is still refused with the same message
- Existing email: "That email is already in use."
- Password under 8 characters or lacking a letter or number: "Password must be at least 8 characters and include a letter and a number"
- Valid sign-up signs in with an "unverified" banner; the Mailbox link removes it; opening it again: "This link was already used."
- The new password works and the old one fails
- The same link again: "This reset link was already used. Request a new one."
- "delete": "Type DELETE to confirm"
- Wrong current password: "Current password is incorrect"
Groups
Group list, membership and invites.
- Flat 4B 🏠 (4 members) "gets back $40.00"; Lisbon trip ✈️ (3 members) "owes €85.08"
- Leaving Flat 4B with −$80.00: "You can't leave while your balance is −$80.00. Settle up first."; the member stays
- LISBON-JOIN opens Lisbon trip with 4 members
- FLAT4B-NOPE: "This invite link is no longer valid."
- A non-admin sees no "Remove", "Make admin" or invite link controls in Flat 4B; "Leave group" is present
Group expenses
Expenses with several split modes and currencies.
- Flat 4B: Concert tickets $150 (10 Oct), Pizza night $80, Cleaning supplies $45, Groceries $120, Internet $60 (repeats monthly)
- Banner: a draft "Internet" due 2026-10-15 awaiting confirmation
- Taxi $40.00 exact 10 / 10 / 10: remainder $10.00 left, Save disabled; Sam 10: remainder 0, Save enabled
- Percent 25 / 25 / 25 / 20: 5% left, Save disabled
- Lisbon trip: Museum tickets €49.68, Dinner in Alfama €84.60, Hostel (3 nights) €270.00
- Museum tickets: originally $54.00 at 0.92, rate of 2026-09-12
- Balances: Theo +€135.24, Maya −€85.08, Jonas −€50.16
Balances and settle-up
Who owes whom and the suggested payments.
- Flat 4B: Maya +$40.00, Theo +$70.00, Priya −$80.00, Sam (guest) −$30.00
- Flat 4B suggests exactly three: Priya → Theo $70.00, Sam → Maya $30.00, Priya → Maya $10.00
Payments
Sandbox in-app payments, fees, refunds and requests.
- Priya paying Maya $10.01 when she owes $10.00: "You owe Maya Lin $10.00 — you can't pay more than that"
- $10.00 by card: fee "2.9% + 0.30" = $0.59, total $10.59
- Status turns to succeeded within about 5 s; Flat 4B balances Maya +$30.00, Priya −$70.00
- A $700 payment by bank shows fee "0.8%, max 5.00" = $5.00 and total $705.00
- The recipient refunds the $10.00 payment: status refund_pending then refunded within about 2 s
- Balances return to Maya +$40.00, Priya −$80.00
- "Theo Park can't receive payments yet — their payout account isn't verified"
- "Payments are not available in your country yet. Everything else keeps working."
- "Record a payment" saves and updates balances
- Theo asks $70.00 "Concert tickets 🎟️" (Flat 4B), open; declining with "Paid in cash" shows declined with the reason
Non-functional requirements
- After reload: still on People with Ana, Ben, Cleo and five items
- Start new bill, confirm: back to Upload with no items
Glossary and rules
| Settle-up | The set of payments that brings every group balance to zero. |
|---|---|
| Sandbox processor | A simulated payment network; no real money moves. |