Seat States & Hold Types

Seatmap.pro tracks every seat in every event through a two-layer state model. The first layer is a small closed set of lifecycle states that the booking engine uses for concurrency and availability. The second layer is an open holdType, defined per organization, that carries the business context – why is this seat held, who can release it, and how should it look on the seatmap.

The two layers

Layer Field Values Controls
Lifecycle state closed enum concurrency, availability
Hold type holdType open string release policy, payment, display

The booking engine only ever asks whether a seat is ACTIVE to determine whether it can be locked. The holdType is metadata that governs the business flow around that seat.

Lifecycle states

Three states, fixed by the platform.

State Meaning Bookable
ACTIVE Available for selection Yes
LOCKED Unavailable; holdType says why No
SOLD Committed and fulfilled No

A typical cart flow moves a seat ACTIVELOCKEDSOLD. An abandoned cart moves it back LOCKEDACTIVE. A seat taken out of service – damaged, obstructed, or otherwise withdrawn from sale – is simply LOCKED with a hold type that records why: RESERVED covers this today, and a dedicated OUT_OF_SERVICE default is planned.

NOTE The state enum in the API also carries a BLOCKED value. The platform never sets it – no seat is returned in that state – and it is being retired. If you switch over state, treat it as unavailable.

The state of every seat in an event is available from GET /api/private/v2.0/event/{id}/seats/, alongside the seat’s row, section and price. That endpoint also supports incremental reads: pass the largest updatedAt you have seen back as lastUpdated to receive only what has changed since.

Hold types

The holdType is a string you attach to a seat when it transitions out of ACTIVE. It lives alongside the lifecycle state and describes the reason the seat is held.

Platform defaults

Two hold types are shipped out of the box:

Hold type Valid state Released by Payment Display
CART LOCKED customer, admin, system required In Cart
RESERVED LOCKED admin not required Reserved

CART is the default for the v2 booking /lock endpoint – omitting holdType in the request body resolves to CART.

RESERVED is the hold type for anything an operator holds outside a sale – a seat kept back for a named customer, or one taken out of service. It is released only by an explicit /unlock.

WARNING The ttlSeconds field below is accepted and stored as part of a hold type definition, but automatic release on expiry is not currently enforced. Holds persist until an explicit /unlock, /sale, or /revertsale call. Do not rely on a hold releasing itself.

Defining your own hold types

Beyond the two defaults, hold types are provisioned for your organization by Seatmap.pro. Send us the definitions you need and we apply them to your organization, or to your tenant so that every organization under it inherits them.

NOTE There is no self-service endpoint for defining hold types today – contact support with the definitions you need.

A definition has this shape:

{
  "holdTypes": {
    "PARTNER_HOLD": {
      "validStates": ["LOCKED"],
      "ttlSeconds": 3600,
      "releaseApi": "ADMIN,API",
      "paymentRequired": true,
      "displayName": "Partner Hold",
      "displayColor": "#8B008B"
    },
    "COMP": {
      "validStates": ["LOCKED", "SOLD"],
      "ttlSeconds": null,
      "releaseApi": "ADMIN",
      "paymentRequired": false,
      "displayName": "Complimentary",
      "displayColor": "#FFD700"
    }
  }
}

Field reference:

Field Type Description
validStates string array Which lifecycle states this hold type is valid for. Requests that combine an invalid pairing are rejected.
ttlSeconds integer or null Intended auto-release window in seconds. Stored as configuration metadata; auto-release is not currently enforced (see note above). null means the hold persists until explicitly released.
releaseApi string Comma-separated list of actors allowed to release: CUSTOMER, ADMIN, SYSTEM, API.
paymentRequired boolean Whether this hold must be followed by payment to convert to SOLD.
skipLockedState boolean When true, transitions directly ACTIVESOLD (used for box office flows).
displayName string Human-readable label shown in admin UIs.
displayColor string Hex color for renderer styling.
displayIcon string Optional image or icon reference for the renderer.

Tenant-level inheritance

If your organization belongs to a tenant, hold types can be defined once at the tenant level and apply to every organization in it. Per-organization overrides take precedence field-by-field, so an organization can, for example, override the CART displayColor without restating the full definition.

Resolution order for any hold type lookup:

  1. Organization-level definition
  2. Tenant-level definition
  3. Platform defaults

These three layers are merged. If you override only displayColor at the organization level, the rest of the definition is inherited from the tenant or the platform default.

Using hold types in the booking API

The v2 booking lock payload accepts an optional holdType field:

POST /api/private/v2.0/booking/lock?eventId=123e4567-e89b-12d3-a456-426614174000
Content-Type: application/json

{
  "sessionId": "abc123",
  "seats": [{ "id": 42 }],
  "holdType": "PARTNER_HOLD"
}

When a seat moves out of ACTIVE, the hold type is validated:

  • It must be defined for the calling organization, as a platform default, a tenant-level entry, or an organization-level entry.
  • Its validStates must include the target lifecycle state.

Unknown or mismatched hold types return 400 Bad Request. The /unlock and /revertsale endpoints do not take a holdType – returning a seat to ACTIVE clears whatever hold was attached.

Concurrency

Every state transition asserts the seat’s expected current state as part of the change. Two concurrent requests locking the same seat cannot both succeed: the second one finds the seat is no longer in the state it expected, and that seat comes back in the unsuccessful attempts list. Double-booking is therefore prevented no matter how cart flows overlap in time, without any coordination on the caller’s side.

Audit trail

Every successful state transition is recorded immutably, capturing:

  • Previous and new lifecycle state
  • Hold type at the moment of the transition
  • Session id (when available)
  • Seat or group of seats affected
  • Timestamp

This record backs conversion reporting – questions such as what share of CART holds became SOLD over a given week. It is not currently exposed as an API. If a per-seat transition history would be useful in your own admin tooling, contact support and we will scope it.

Renderer integration

The booking renderer styles seats by their lifecycle state (ACTIVE, LOCKED, SOLD) out of the box.

To visualize holdType values – or any other distinction your staff need – with your own colors, animations, or icons, the renderer SDK provides setSeatsState(seats, stateKey) and clearSeatsState(seats), driven by a declarative theme.seatStyles config.

IMPORTANT The seats endpoint returns the lifecycle state but does not currently return holdType per seat. Track the hold types you have applied on your own side, and map them to renderer state keys when you draw the map. Returning holdType on the seat payload is planned.

See Custom Seat States (Renderer SDK) for the full API, type reference, and worked examples.

  • Booking Renderer Custom Seat States (Renderer SDK) – applying and styling arbitrary seat states in the browser.
  • Booking Renderer Section States & Styling – the equivalent concept applied to section outlines (highlighted, selected, unavailable, filtered).
  • Admin Renderer Admin Renderer – selection modes and staff tooling built on the same seat model.