PayPal hackathon 2026 | documentation, sandbox only
The hammer falls.
Only the winner pays.
Every online auction has one ugly moment: the gavel comes down and the winner has gone quiet. GAVEL asks for the money first. A bid is a PayPal hold, so when the hammer falls we charge the winning price and let everything else go.
These pages are the receipts. Each claim points at a file or a run, and what has only been tried on a fake or a simulation says so.
- G0 PASS
- G1 PASS
- G2 PASS
- G3 IN PROGRESS
- G4 PASS
- G5 PARTIAL
Hammer price, example
Lot 14, 1962 poster
Example only
- A Priya Raman | hold $500charged $350
$150 of this hold is released, not charged
- B Tomas Eriksen | hold $300released
- C Lena Okafor | hold $200released
cents: held 0 | charged 35000 | released 65000 = 100000
- Hatched means held
- Solid means charged
- Hollow means released
Try it: drag the price, or replay the hammer. Three bidders, one winner; the same rule the ledger follows, in whole cents.
Orientation
Eleven minutes, three steps.
- Read the claimAbout 2 minThe two-minute path: five clicks that show what GAVEL claims and what its status is.Go
- Check the proofAbout 4 minSix gates against the PayPal sandbox, each with its run and its stamp: PASS, PARTIAL or simulated.Go
- Break it on paperAbout 5 minCrash recovery and the tough questions: what happens when the server dies at the hammer.Go
Status, stated plainly
What we can prove, and how.
Numbers come from the committed gate record and the simulation output, read at build time.
4 of 6
PayPal sandbox gates passed: G0, G1, G2, G4. G3 is in progress, G5 is partial (synthetic audio only).
40 of 40
simulated lots settled in the 30 day run, none in review.
51
simulated process crashes survived, with no double capture.
294
simulated holds, every one captured or released, none left open.
Pick a path
Judge path first, then the rest.
The pages are short: one screen of prose, one diagram, and a list of the files that hold the claim.
The idea
Commit before the first bid.
Online auctions break at the hammer: the winner may never pay. GAVEL moves the money question to the start. The bidder's ceiling is held by PayPal, and only the winning price is ever charged.
Bidder
approves a ceiling
GAVEL
bids, ledger, saga
PayPal sandbox
holds the money
Five diagrams
The mechanism, drawn from the code.
Each figure uses the product's own language: hatched means held, solid means charged, hollow means released. State and event names are the ones in the source, and each figure says what it was verified against.
1. Where the money is
Money flow: holds, capture and void
Scroll the figure sideways, or open it full size.
final_capture) passed on the real PayPal sandbox for two PayPal-account buyers. That the remainder is released is inferred (the authorization reads CAPTURED and a later void answers 422 PREVIOUSLY_CAPTURED), not read from a buyer balance. Settlement of a whole auction was run on the fake PayPal. The three bidders and their ceilings are round illustration numbers.Text version of this diagram
- T0 Approve: three bidders approve holds. A holds $500, B $300, C $200. A hold is an authorization, nothing is charged.
- T1 Bid: A bids $350. The engine accepts it and the ledger appends a hash-chained event.
- T2 Hammer: A wins at $350.
- T3 Capture: GAVEL reads the truth of A's hold, then captures $350 with final_capture. PayPal closes the remaining $150 (inferred in gate G1).
- T4 Void: the holds of B ($300) and C ($200) are voided. The journal closes.
Invariant: charged $350 + released $150 + $300 + $200 = $1000 held. In the 30 day simulation the same equality holds on larger totals: held $159,385.00 = captured $34,170.00 + released $125,215.00 + open $0.00.
2. The settlement saga
Settlement saga: every state and legal move
Scroll the figure sideways, or open it full size.
docs/GATES.md cover single calls and the nightly specs. States and moves are copied from the transition table in packages/payments/src/saga/machine.ts.Text version of this diagram
The main path is HELD, BIDDING (start_auction), WINNER_SELECTED (hammer), CAPTURING (begin), CAPTURED (capture_ok or adopted), VOIDING (begin_void), SETTLED (all_released).
- cancel moves HELD or BIDDING to VOIDING. no_candidate moves WINNER_SELECTED to VOIDING.
- definite_fail moves CAPTURING to FALLBACK_RUNNER_UP. next_candidate returns to CAPTURING. no_candidates_left moves it to VOIDING.
- FAILED_NEEDS_REVIEW is terminal. It is reached by invariant (from WINNER_SELECTED, CAPTURING, FALLBACK_RUNNER_UP), unknown_deadline (from CAPTURING, after ten minutes), mismatch (from CAPTURING or CAPTURED) and void_budget_exhausted (from VOIDING).
- Each transition is one compare-and-set save of the journal. The capture intent is saved before the PayPal call and cleared when the outcome is saved.
3. Crash recovery
Crash recovery: charged exactly once
Scroll the figure sideways, or open it full size.
Text version of this diagram
The capture sequence is: read the truth of the hold, save the intent (capture, amount, request id), call PayPal, save capture_ok.
- Crash A, after the intent is saved and before the call: on restart the truth shows no capture, and the saved intent is sent again with the same request id.
- Crash B, after PayPal took the capture and before the answer was saved: on restart the truth shows the capture, which is adopted. If the truth cannot be read, or PayPal does not know the hold, the settlement waits with the same request id for ten minutes and then goes to FAILED_NEEDS_REVIEW. It never tries the next bidder.
- Crash C, after capture_ok was saved: the state is already CAPTURED, so the restart goes on to void the other holds without a capture call.
Result: the winner is charged once.
4. Voice, and the confirm gate
Voice pipeline and the confirm gate
Scroll the figure sideways, or open it full size.
packages/voice/src/decide/policy.ts, decide.ts, score.ts, packages/server/src/voice/bridge.ts and room/confirm.ts. The dashed red path is what the code allows, not what the default build does: with one parser the score tops out at 0.82, so a spoken bid confirms. Accuracy numbers are in the table below the figure, not drawn here.Text version of this diagram
- Microphone audio is cut into segments.
- Speech to text turns a segment into a transcript. The default build plays cached transcripts; a live provider (Groq or Deepgram) runs only when VOICE_STT is set with its key.
- The parser reads amount, paddle and intent from the transcript.
- The decision step merges parser opinions, scores confidence and validates the bid against the room. The result is accept, confirm or drop.
- Confirm: the bidder is asked, for example "Did you mean $150 for paddle 12?". Yes places the bid after it is checked against the current price. No or expiry places nothing and is logged.
- Drop: nothing is placed, the decision is logged.
- Accept (dashed): a clean parse with confidence of 0.85 or more that both parsers agree on skips the gate and goes to the engine.
- Manual entry by the auctioneer and tap to bid skip speech and enter at the engine.
- The engine accepts or rejects the bid and an accepted bid is appended to the hash-chained ledger.
Gate G5 is PARTIAL: wrong-accept 0.000 to 0.000 on 24 synthetic, noise-free clips per set (limit 0.05), after fixes chosen on those same clips. No real-room or noisy-room test exists, and spoken bids always confirm.
5. Thirty simulated days
30 day simulated timeline
Scroll the figure sideways, or open it full size.
docs/evidence/SIM/SIM-MULTIDAY.md (seed 20261107).Text version of this diagram
Everything here is simulated: a fake PayPal and a fake clock.
- S1: hold day 0, capture day 1. 6/6 checks, PASS.
- S2: close day 2.5, inside honor period. 6/6 checks, PASS.
- S3: capture day 3.5, reauthorized. 8/8 checks, PASS.
- S4: reauth day 3, capture day 5. 5/5 checks, PASS.
- S5: never reauthorized, day 30. 6/6 checks, PASS.
- S6: crash and restart at day 2. 10/10 checks, PASS.
- S7: late expiry webhook, day 31. 5/5 checks, PASS.
- S8: 40 lots, 100 bidders, crashes. 7/7 checks, PASS.
S8 ran 40 lots: 40 settled, 0 in review. 294 holds, 94 reauthorize calls, 51 process crashes survived, 31 PayPal faults armed, 3 lots used the runner-up fallback, 8 of 8 injected rate-limit storms settled after a restart.
Ledger: held $159,385.00 = captured $34,170.00 + released $125,215.00 + open $0.00.
Proof
Six gates against the real sandbox.
Source of truth: docs/GATES.md. A gate closes only with a recorded result.
| Gate | Question | Result | Run |
|---|---|---|---|
| G0 | sandbox app and buyer accounts | PASS | 2026-11-04 by harshbhx (workflow gate-g0, run 41815593520, branch gate/g0) |
| G1 | partial capture and remainder release | PASS | 2026-11-04 by harshbhx (wallet); 2026-11-05 by harshbhx (card, run G1-20261105T123116Z) |
| G2 | card and guest AUTHORIZE | PASS | 2026-11-05 by harshbhx (owner laptop, run G2-20261105T115228Z) |
| G3 | honor period versus validity and reauthorize | IN PROGRESS | Real probe. Day 0 was 7 Nov 2026 03:06 UTC. Final reading about 12 Nov 06:17 UTC. |
| G4 | real webhook signature verification | PASS | 2026-11-05 by harshbhx (workflow gate-g4, run 41947655945) |
| G5 | STT accuracy on noisy bids | PARTIAL | 2026-11-07, cached eval over recorded provider outputs (PR #1940, issue #1864; second clip set PR VOI-01; error analysis, parser fixes and option trials PR VOI-02) |
Behaviour that no passed gate covers is established only against the project's own fake PayPal. Read each gate.
FAQ
Questions, answered straight.
Does any real money move?
No. GAVEL talks to the PayPal sandbox only, and production mode refuses the fake PayPal. The whole site carries the sandbox notice on every page.
What does a hold actually do?
A bidder approves a PayPal authorization for their ceiling. It is a promise, not a charge. At the hammer the saga captures the winning price only; the rest of the money is released.
What if the server crashes during settlement?
The saga journals its intent before each PayPal call and, on restart, reads the truth at PayPal first. That recovery is verified with injected crashes against the fake PayPal; no real server kill has run on a hosted host.
Does voice bidding work?
It exists, but the speech accuracy gate (G5) is only PARTIAL: wrong accepts are 0.000 on 24 synthetic, noise-free clips after fixes chosen on those same clips, and there is no real-room test. Spoken bids always wait for a confirmation. No live speech run is recorded.
Is there a hosted demo?
Yes, in sandbox mode: the web app is at gavel-web.creharsh.workers.dev and the API at gavel-auction-aufz.onrender.com. Storage is temporary until a disk is added, and nobody has walked the whole flow on it yet. The demo guide lists what is verified.
Read it the way a judge would.
Five minutes: the judge path, the proof page, then the crash recovery page.