Checkout
From a chosen Pass to a confirmed Order: the quote, the intent, the hold, and every way it can stop
Checkout is the short stretch between "I want this" and "I paid": the entry exists, the price is quoted, the seats are held, and the provider takes the money. Each step either finishes cleanly or leaves nothing behind.
Knowing the order of these steps is how you answer the two questions buyers actually ask: "was I charged?" and "do I still have my seat?"
Needs
A signed-in Account
The Account is the buyer on the Order
Starts from
A pending Registration
Created when the buyer picks a Pass
Quote
Advisory only
Creates no Order and no hold
Reserves
Seats, for 15 minutes
One hold per line, at intent
Pays on
The pay host
An opaque token stands in for the session
Confirms by
The provider, not the browser
A signed callback or a re-check
The steps, in order
The Registration is created as pending, with the attendance mode, the form answers, and one Participant for an individual entry or a roster for a team.
The buyer sees the full breakup before committing: list prices, discounts, tax components, fee, and total. A quote creates nothing and can be re-run after any edit.
The Order is created as payment pending, one InventoryHold per line reserves capacity, and a valid coupon is reserved against the code's caps — all in one transaction.
One provider order is created for the whole Ulsav Order. The provider owns retries on it, so there is exactly one place the money can move.
The pay page reads and acts through the Order's opaque token, because the buyer's session does not follow them to another host.
A signed provider callback — or an explicit status re-check — confirms the Order and turns held seats into sold ones.
The quote is not the charge
A quote is a calculation, not a promise. It reads the Pass, the buyer's basket, the coupon, and your tax and fee settings, and returns the same decomposition the Order will store.
Pass subtotal at list price
₹4,000.00
OrganizerDiscount
−₹500.00
CouponDiscount
−₹350.00
Tax, CGST and SGST at 9% each
+₹567.00
Platform fee and its GST
+₹177.12
Quoted total
₹3,894.12
This is exactly what Order ORD-000123 stores, provided nothing changes between the quote and the charge.
A quote can go stale. When checkout starts, the Order re-prices under a lock and stores that total, and that stored total is what the provider charges — never the quoted figure. If the basket is no longer sellable at all, because a Pass sold out or a coupon reached its cap, checkout refuses instead of charging something new.
What is reserved, and when
Starting checkout is the only moment anything is reserved. It happens inside one transaction, so a double-click cannot create two Orders:
- one Order in payment pending
- one InventoryHold per line, with an expiry
- one coupon reservation, counting against the code's caps
The provider order is created after that transaction commits, because a network call must never hold a database lock. If the provider refuses, the Order is cancelled, the seats are released, and the coupon slot is freed, so the buyer can retry cleanly.
Reloading and double-paying
Every checkout request carries an idempotency key. Repeating the same request with the same key replays the stored answer instead of creating a second Order or a second provider order.
The pay page uses a 256-bit opaque token instead of the buyer's session, because sessions are scoped to one host and the payment host is a different one. The token can read the summary, reopen the provider intent, check the canonical status, and ask for a re-check. It cannot confirm a payment.
The return page is a receipt. It shows canonical state and nothing else, so a browser redirect can never manufacture a sale.
Free checkouts are a different path
A Pass priced at zero does not need a payment, an intent, or a hold. The Order is created already confirmed, the entries confirm in the same transaction, and the buyer sees a receipt immediately.
That path deliberately refuses a priced Pass. It cannot be used to turn a paid order into free admission.
Where checkout stops
| What went wrong | What happens |
|---|---|
| The buyer is not signed in | No checkout; the Account is the buyer |
| A required answer is missing | Refused before payment starts; the requirements view lists what is outstanding |
| The Pass needs approval and there is none | Refused; an approved application is required first |
| The basket is below the Pass minimum, or above its maximum | Refused with a quantity error |
| A typed coupon code is invalid | Refused with the code's reason; no silent fallback |
| The coupon brings the total to zero | Refused; a paid Order needs a real amount |
| Capacity ran out | Refused; nothing is charged |
| Sales are paused, the Event is cancelled, or fulfilment is disabled | Refused |
| The provider refuses the order | The Order is cancelled and the seats are released |
| The 15 minutes run out | The Order expires, the entries unlink, and the buyer starts again |
Retrying after expiry
An expired attempt is not a dead end. The Registration goes back to pending and can be checked out again, which creates a fresh Order with a fresh hold and a fresh 15 minutes.
The old Order stays as expired, with its prices and lines intact. Nothing is reused, so the new attempt always reflects today's Pass, today's coupon, and today's capacity.
Does the quote lock the price?
No. A quote is a calculation. The Order stores what was actually charged at confirmation, and a later attempt re-prices from the current Pass and coupon state.
Why did the price change between the quote and the payment?
Because something changed in between: another buyer took the last seat, a coupon reached its cap, or the basket changed. The payment step refuses rather than charging a total the buyer never saw.
Can I pay twice by clicking twice?
No. The same request replays the same Order, and one Ulsav Order maps to exactly one provider order.
Related
- Orders — what the finished record contains
- Payments — what happens after the provider is opened
- Availability — the hold and its expiry
- Registrations — the entry being checked out