SeatBuilderSeatBuilder Docs

Hold seats

Places a hold on the requested seat(s) for the calling workspace. Pass `objectLabels[]` — the single canonical request shape — to hold N individual seats atomically under one `holdToken` (all-or-nothing: if any seat cannot be held the whole request fails `409` and nothing is held). A single seat is a one-element array. GA areas ride on a single-element array: pass `objectLabels: ["GA-LAWN"]` together with `objectType: "generalAdmission"`, `quantity`, and (optionally) `categoryKey`; those GA fields are only valid on a one-element array. The hold lasts `ttlSeconds` (default 900). Pass the returned `holdToken` to `/book` to confirm purchase or `/release` to cancel. Holds expire automatically; subscribers to `seat.hold_expired` receive a webhook on expiry. Atomic via Redis SET NX EX — concurrent hold attempts on the same seat never double-book. The response is always the array shape ({ chartKey, eventKey, holdToken, holdExpiresAt, objects: [...] }), whether one seat or many.

POST/api/v1/events/{eventKey}/seats/hold

Path Parameters

eventKeystring
objectLabelsarray<string>

Seat labels to hold in one atomic request. Single seat = array of one. All-or-nothing: if any seat cannot be held the whole request fails 409 (D-11). GA holds ride on a single-element array — pass objectLabels: ["GA-LAWN"] together with objectType: "generalAdmission", quantity, and (optionally) categoryKey. Those GA fields are only valid on a single-element array; a multi-element array holds individual seats only.

Items1 <= items <= 200
holdTokenstring

Client-generated token (≥ 8 chars; recommended: random UUID). Pass the same token to /book to confirm or /release to cancel the hold. The SDK generates one automatically per chart session.

Length8 <= length
ttlSeconds?integer

Hold expiry in seconds. Defaults to 900 (15 minutes) when omitted. Holds auto-expire and emit a seat.hold_expired webhook if a subscription exists.

Range0 < value
extraData?object

Arbitrary JSON metadata attached to this status change (e.g. { orderId: "ord_98a2", buyerName: "Alex Doe" }). Surfaces in subsequent webhook payloads and the event status response.

Empty Object

objectType?string

Seat-vs-GA discriminator. To hold a general-admission area you MUST pass "generalAdmission" here AND an explicit non-zero quantity — the server does not infer GA from the label. A single-element objectLabels array that names a GA area but omits objectType:"generalAdmission" is rejected 400 (it is never silently held as an individual seat). Omit for individual seat holds.

categoryKey?string

Optional category key — narrows the hold to that category if present. Useful for GA areas spanning multiple categories.

quantity?integer

Number of GA tickets to hold from this area's capacity pool. REQUIRED for a GA hold and only valid when objectType is "generalAdmission" — there is NO silent default-to-1 for GA: a GA-area label held without an explicit non-zero quantity is rejected 400. The GA area is a real pool: multiple hold tokens can each reserve tickets concurrently. The hold succeeds only if capacity − sum(held + booked quantity across all tokens) ≥ quantity, checked atomically; otherwise the request is rejected 409 (pool full). A single request whose quantity alone exceeds total area capacity is rejected 400 (per D-1/D-2/D-3).

Range1 <= value

Response Body

curl -X POST "https://seatbuilder.org/api/v1/events/string/seats/hold" \  -H "Content-Type: application/json" \  -d '{    "objectLabels": [      "A-12",      "A-13"    ],    "holdToken": "7f6c3a91-b1ef-4d0a-9c84-3f12a8e0b5d2",    "extraData": {      "orderId": "ord_98a2"    }  }'

{
  "chartKey": "chart_8a2b1c",
  "eventKey": "evt_q3-2026-jazz-night",
  "holdToken": "7f6c3a91-b1ef-4d0a-9c84-3f12a8e0b5d2",
  "holdExpiresAt": "2026-10-02T18:55:00.000Z",
  "objects": [
    {
      "objectLabel": "A-12",
      "status": "held",
      "extraData": {
        "orderId": "ord_98a2"
      }
    },
    {
      "objectLabel": "A-13",
      "status": "held",
      "extraData": {
        "orderId": "ord_98a2"
      }
    }
  ]
}
{
  "statusCode": 0,
  "message": "string",
  "errors": {
    "property1": [
      "string"
    ],
    "property2": [
      "string"
    ]
  }
}
{
  "statusCode": 0,
  "message": "string",
  "errors": {
    "property1": [
      "string"
    ],
    "property2": [
      "string"
    ]
  }
}
{
  "statusCode": 0,
  "message": "string",
  "errors": {
    "property1": [
      "string"
    ],
    "property2": [
      "string"
    ]
  }
}
{
  "statusCode": 0,
  "message": "string",
  "errors": {
    "property1": [
      "string"
    ],
    "property2": [
      "string"
    ]
  }
}

{
  "error": "One or more seats could not be held",
  "failed": [
    {
      "objectLabel": "A-13",
      "reason": "not_held_by_token"
    }
  ]
}
Hold seats — SeatBuilder Docs