Skip to content

Book inventory

Commit held inventory from your trusted server with an idempotent booking reference and safe conflict handling.

Updated View as Markdown
POST/v1/events/:eventKey/bookSecret key

Booking turns a temporary hold into a permanent inventory booking. It does not create your commercial order or fulfil the purchase. This endpoint is server-only and accepts sk_test_… or sk_live_… credentials whose mode matches the event. The event must explicitly use Platform checkout (buyerCheckout: "integrator"); Managed and unresolved events return 404 so a server key cannot bypass SeatLayer’s managed checkout.

Request

HTTP requesthttp
POST /v1/events/ev_9f3a/book HTTP/1.1
Host: api.seatlayer.io
Authorization: Bearer sk_test_••••••••
Content-Type: application/json

{
  "holdId": "hold_01J8F2A7MRQ4",
  "labels": ["STALLS-A-12", "STALLS-A-13"],
  "bookingRef": "order_1842"
}
Field Type Required Description
holdId string Yes for a buyer flow Opaque hold identifier returned by the buyer SDK.
labels string[] Recommended with holdId The seats you priced at checkout, copied from the trusted server-side hold inspection. A hold keeps its id when the buyer changes seats, so pinning the labels makes booking fail with 409 hold_changed instead of booking seats you never charged for. Required for a direct booking without a hold.
bookingRef string Yes Your stable order or reservation reference. It makes retries idempotent and links SeatLayer inventory to your own system.

Do not send buyer identity, payment details, ticket delivery data, or an amount to this endpoint. Those belong to your platform.

Responses

Every requested object is now booked in SeatLayer inventory.

200 responsejson
{
  "ok": true,
  "booked": ["STALLS-A-12", "STALLS-A-13"]
}

On an idempotent replay, booked may be empty because that same bookingRef already committed the inventory:

200 replay responsejson
{
  "ok": true,
  "booked": []
}

Keep the commercial receipt, buyer, tickets, and delivery state in your own order record. Only ok and booked belong to the Platform booking response.

Nothing is booked when any requested object is unavailable.

409 responsejson
{
  "error": "conflict",
  "conflicts": [
    {
      "label": "STALLS-A-13",
      "status": "booked"
    }
  ]
}

A test key cannot book live inventory, and a live key cannot book a sandbox event.

403 responsejson
{
  "error": "mode_mismatch"
}

Safe retry behavior

bookingRef is your idempotency key. Repeating the same request after a timeout succeeds without creating a second inventory booking or spending credits twice. Always reuse the same value for the same platform purchase.

server/book.jsjs
const trustedHold = await retrieveSeatLayerHold(eventKey, holdId);
const labels = trustedHold.items.map((item) => item.label);
const order = await priceAndAuthorizePayment(trustedHold); // Your commerce code.

const response = await fetch(
  `https://api.seatlayer.io/v1/events/${encodeURIComponent(eventKey)}/book`,
  {
    method: "POST",
    headers: {
      authorization: `Bearer ${process.env.SEATLAYER_SECRET_KEY}`,
      "content-type": "application/json",
    },
    body: JSON.stringify({ holdId, labels, bookingRef: order.id }),
  },
);

if (response.status === 409) {
  return recoverInventoryConflict();
}

if (!response.ok) {
  // Reconcile order.id through exact Booking History before another action.
  throw new Error(`SeatLayer booking failed: ${response.status}`);
}

If the connection fails before a response arrives, look up GET /v1/events/:eventKey/bookings/:bookingRef. Only then decide whether your workflow should repeat the same event, hold, labels, and bookingRef. Never change the reference merely because the first outcome is unknown.

Read inventory Booking History

Platform events expose the durable inventory ledger through the official server API:

List and searchhttp
GET /v1/events/ev_9f3a/bookings?q=order_1842&state=booked&limit=50
Authorization: Bearer sk_test_••••••••

Pass the opaque nextCursor back as cursor to read the next page. Search is limited to inventory identifiers such as booking reference, label, object, category, section, and sales-channel reference.

Exact booking and audithttp
GET /v1/events/ev_9f3a/bookings/order_1842
Authorization: Bearer sk_test_••••••••

The detail response includes immutable configured-price snapshots, current object cancellation state, and a chronological book / replay / partial_cancel / cancel audit. Configured value is operational inventory value—not the amount charged or settled. These routes never return buyer, payment, commercial Order, ticket, email, refund, or door data.

The synchronous booking response or this exact Booking History record is the command outcome. A later seat.booked webhook is a reconciliation signal; deduplicate it and never use it as permission to charge the buyer again.

For a resumable background sync, use the /booking-changes reconciliation feed. Its append-only activity checkpoint surfaces cancellations to older booking references without paging the full Booking History again.

Fulfilment and refunds stay in your platform

After a successful inventory booking, your platform confirms its commercial order and creates and delivers its own tickets, QR/barcodes, PDFs, and emails. It also owns ticket recovery, scanning/check-in, refunds, and customer support.

If your platform later cancels or refunds the purchase, call /unbook with the matching bookingRef to return inventory to sale. SeatLayer changes inventory on this route; it does not move or refund your money.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close