A countdown is a display. A reservation is a recorded allocation. For a small course or event, ask who holds the seats, when that hold ends and what happens if payment evidence arrives late. This is a website acceptance brief, not a ready-made ticketing service.
Platform fact and implementation choice
Stripe’s hosted Checkout inventory guide supports session expiration and an expired event for your own stock-release handling. Timed expires_at is documented as 30 minutes to 24 hours after creation; manual expiry is separate. Checked 16 October 2026. A five-minute visual timer is not evidence that a session’s timed expiry can be set to five minutes.
Filled five-seat ledger
Synthetic, serial example: capacity is five. A requests two places, B requests three, and C requests one. All events refer to a unique reservation ID. No real attendee or payment is involved.
On narrow screens, scroll sideways to read the full table.
| Event | Held | Sold | Available | Decision |
|---|---|---|---|---|
| A holds 2 | 2 | 0 | 3 | Accept A |
| B holds 3 | 5 | 0 | 0 | Accept B |
| C requests 1 | 5 | 0 | 0 | Reject or waitlist C |
| A paid, then duplicate paid | 3 | 2 | 0 | Sell A once |
| A expiry arrives after paid | 3 | 2 | 0 | Do not release sold seats |
| B expires twice | 0 | 2 | 3 | Release B once |
Choose a complete workflow
A native booking product may already own capacity and payment handling; demonstrate that behaviour before adding another ledger. A custom checkout integration needs durable reservation state and an atomic allocation mechanism. A brochure site may instead accept an availability enquiry without promising a confirmed seat. None is universally the best choice; the customer promise determines the required behaviour.
Acceptance tests that matter
- Replay the six rows and confirm held + sold + available always equals five.
- Submit two simultaneous requests for the last place in an isolated integration test. At most one can become confirmed.
- Replay duplicate and out-of-order events. A duplicate must not sell or release capacity twice.
- If payment evidence follows a released hold, stop automatic confirmation and use an explicitly designed reconciliation path. Do not silently oversell or automatically assume a refund has occurred.
Evidence to retain
Keep reservation ID, quantity, session ID, server-side expiry, payment state, allocation state and reconciliation outcome. A success-page visit or a browser timer is insufficient. Record late/unknown evidence separately from confirmed sales.
Boundaries
The download demonstrates serial transitions only. It is not a database concurrency test, webhook receiver or payment integration. It excludes asynchronous payment methods, refunds, cancellations and attendance rules; those need a supplier-confirmed design. The existing durable webhook inbox resource covers message receipt, a different task from allocating seats.
Replay the teaching example
These files run locally without network access. They model only the stated cases, not a live vendor integration. Filled inputs and expected results · Inspectable teaching functions
Save both files in one folder. With Node 22.13 or newer, run:
node decision-check.mjs checkout-seat-hold-contract.json