Build my booking setup

Capacity & Inventory

Zero seats means zero seats.

No reading a number and then writing a number. Every capacity or stock code claim is a single conditional operation in the database, so two purchases for the same seat, at the exact same instant, can never both win.

  • 1 write Every claim is a single conditional SQL operation, never "read then write"
  • Shared or independent Several ticket types can draw from the same seat count, or keep their own
  • Up to 5 tries If a stock code loses the race to another claim, it tries the next one before giving up

Four pieces of inventory.

Each one models a different kind of real-world constraint.

01

Shared or independent capacity

Several ticket types can draw from the same real seat count, like adults and children sharing one pool, or keep their own separate pool for a reserved category.

02

Capacity exceptions

Reduce or expand capacity for a date, a date range or one specific time, without creating a new pool or touching the default that governs the rest of the calendar.

03

Shared resources

Guides, vehicles or equipment can back a capacity pool and be shared across products, modeling staffing constraints, not just physical space.

04

Third-party stock

Codes bought in advance from an external supplier, imported by CSV in the background, with their own expiry and duplicate detection.

How it resolves

How a seat gets claimed, without overselling

Five steps, every single time something reserves a piece of inventory.

  1. 1

    The row gets found or created

    Every date-and-time combination has its own counting row, created the first time anyone claims it, inheriting capacity from whatever exception is in force, or the pool default.

  2. 2

    One conditional write

    The claim adds held, booked and the requested quantity together, and only goes through if that total doesn't exceed capacity. No reading first, no gap between reading and writing.

  3. 3

    If it doesn't fit, it's rejected

    If the condition fails, the write touches no row at all and the attempt is rejected immediately. There's no way for two claims to pass the same condition at the same time.

  4. 4

    Holding and confirming

    A pending payment holds the seat in its own counter. If payment confirms, it moves to booked; if it expires or gets cancelled, it releases, never touching what's already booked for real.

  5. 5

    Stock codes, same principle

    Claiming a stock code follows the same logic: the oldest still-available candidate gets picked, and the update only goes through if it is still available at that exact instant; if it loses the race, it tries the next one.

The API, as it is

What "remaining" actually means

The same calendar query returns remaining capacity per ticket type, not one shared number. Two types sharing a pool show the same figure; a reserved, independent one shows its own.

GET /api/v1/products/observation-deck/calendar
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
{
  "date": "2026-08-14",
  "slots": [
    {
      "start_time": "18:00",
      "remaining_capacity": {
        "adult": 12,
        "child": 12,
        "accessible": 4
      }
    }
  ]
}
200 Capacity resolved

The detail almost nobody thinks to test

An unlimited pool never carries phantom numbers

If a pool has no limit, claiming it never adds anything to "held": there's nothing to count. Confirming or releasing that same hold follows the exact same rule, even though it looks redundant, because if that pool is ever switched from unlimited to limited later, those counters need to genuinely start at zero, not carry subtractions from numbers that were never added in the first place.

Frequently asked questions

Only one wins. The claim is a single conditional database operation: it adds the requested quantity and only applies if the total stays within capacity. The second purchase simply fails that condition and gets rejected, with no window where both could pass.

Yes, if configured that way. Several ticket types, even across different options or products, can point at the same capacity pool: selling one reduces what the others have left. A separate, fully independent pool can also be kept for a reserved category.

With a capacity exception: one date, a date range, or one specific time with its own capacity, without creating a new pool or touching the default that governs the rest of the calendar.

It gets held in its own counter, separate from what's already booked for real. If payment confirms, it moves to booked; if it expires or gets cancelled, it releases automatically, never touching sales that already closed.

Yes. Each code is claimed with the same atomic logic: the oldest available one gets picked, and the update only goes through if it is still available at that exact instant. If it loses the race against another claim, the system tries the next candidate, up to five times, before giving up.

More bookings. More channels. The same calm.

Tiqory keeps availability, pricing, payments and access working together as your operation grows. Tell us where you are headed; we’ll show you how to get there without starting over.