Skip to content

Cloud API in the browser · Browser

@openseat/cloud

Browser client for the OpenSeat Cloud API: live seat maps, hold tokens and browser holds with your publishable key, OpenSeatBookingMap for React (hold or select mode, seats and standing zones), and the embeddable layout designer (mountDesigner, OpenSeatDesigner).

The OpenSeat Cloud API in the browser. Show a live seat map for your event with your publishable key, let the buyer choose seats and standing-zone tickets, and hold them; your server then books them with @openseat/node after payment.

  • 5 functions
  • 12 interfaces
  • 4 types
  • 3 constants
  • MIT
npm i @openseat/cloud
first npm release pending

Install commands show the public npm names. The first npm release is pending; the packages are free and MIT licensed.

depends on @openseat/adapter-rest, @openseat/booking, @openseat/core · peers @openseat/react, konva, react, react-dom

Import
import {
  createOpenSeatClient,
  rememberHold,
  recallHold,
} from "@openseat/cloud";
import type {
  OpenSeatClient,
  OpenSeatHold,
} from "@openseat/cloud";

Functions5

function

createOpenSeatClient

Creates the browser client. Throws an UNAUTHORIZED BookingError for a secret key (or anything that is not a publishable key) and VALIDATION for a bad baseUrl, before any request.

function createOpenSeatClient(
  o: OpenSeatClientOptions,
): OpenSeatClient;

Parameters

ParameterTypeDescription
oOpenSeatClientOptions

o takes OpenSeatClientOptions:

Returns

@openseat/cloud/src/client.ts

function

isOpenSeatErrorReason

True when reason is one of the Cloud API's documented refusal reasons.

function isOpenSeatErrorReason(
  reason: unknown,
): reason is OpenSeatErrorReason;

Parameters

ParameterTypeDescription
reasonunknown

Returns

@openseat/cloud/src/errors.ts

function

recallHold

The hold remembered for eventKey in this tab, or null. A malformed entry, or one more than an hour past its expiry, is removed. The hold may still have ended on the server; client.resumeHold finds out.

function recallHold(
  eventKey: string,
  now?: number,
): OpenSeatHold | null;

Parameters

ParameterTypeDescription
eventKeystring
nowoptionalnumber

Default Date.now()

Returns

@openseat/cloud/src/storage.ts

function

rememberHold

Remembers the buyer's hold for this tab (sessionStorage), one per event. null forgets every remembered hold. Does nothing where storage is unavailable.

function rememberHold(hold: OpenSeatHold | null): void;

Parameters

ParameterTypeDescription
holdOpenSeatHold | null

Returns

void

@openseat/cloud/src/storage.ts

function

resolveClientBase

The client API root (<origin>[/prefix]/api/v1/client) from baseUrl; accepts the dashboard's <origin>/api form.

function resolveClientBase(baseUrl: unknown): string;

Parameters

ParameterTypeDescription
baseUrlunknown

Returns

string

@openseat/cloud/src/client.ts

Interfaces12

interface

AreaRecord

interface AreaRecord

Members

MemberTypeDescription
inventoryIdstring
statusSeatStatus
remainingnumber
capacitynumber
versionnumber

@openseat/cloud/src/cloud-wire.ts

interface

OpenSeatAdapter

A BookingAdapter for one workspace's events, keyed by event key. Holds are made with a hold token the adapter mints and keeps in memory, one per event; it travels only in the OpenSeat-Hold-Token header of hold requests, never in a URL and never on reads.

interface OpenSeatAdapter extends BookingAdapter

Extends BookingAdapter

Members

MemberTypeDescription
extendHoldmethod(holdId: string, input?: { readonly seconds?: number; }, o?: RequestOptions) => Promise<Hold>

Optional: moves the hold's expiry to at least seconds from now (the server may clamp it, for example to a maximum hold length) and returns the hold with its new expiresAt. A locked hold comes back unchanged.

holdTokenmethod(eventKey: string) => string | null

The event's current hold token, or null when none has been minted (or it was reset).

preparemethod(eventKey: string) => Promise<void>

Mint ahead of time (called on first selection change). Idempotent while a usable token exists.

resetHoldTokenmethod(eventKey: string) => void

Forget the event's token; the next hold mints a new one.

holdSeatsmethod(input: HoldInput, options?: RequestOptions) => Promise<Hold>

Holds all seats and area quantities, or none. Rejects with SEATS_UNAVAILABLE (listing the seats in unavailableSeatIds) when any seat is taken, AREA_SOLD_OUT (listing unavailableAreaIds) when an area has too few places left, and LIMIT_EXCEEDED when the request is over the per-buyer ticket limit.

From BookingAdapter

confirmHoldmethod(input: { readonly holdId: string; readonly paymentReference: string; readonly idempotencyKey?: string; }, options?: RequestOptions) => Promise<Booking>

Converts a hold into a booking after the host's payment flow succeeds. paymentReference is whatever your payment provider returns; the server must verify it. The SDK never handles card data.

From BookingAdapter

releaseHoldmethod(holdId: string, options?: RequestOptions) => Promise<void>

From BookingAdapter

getHoldoptionalmethod(holdId: string, options?: RequestOptions) => Promise<Hold>

Optional: current hold state, for recovering after a reload.

From BookingAdapter

getStatusesmethod(input: { readonly eventId: string; readonly seatIds?: readonly string[]; }, options?: RequestOptions) => Promise<SeatStatusRecord[]>

From InventoryAdapter

subscribeoptionalmethod(eventId: string, listener: (changes: SeatStatusRecord[]) => void, onError?: (error: BookingError) => void, onSnapshot?: (records: SeatStatusRecord[]) => void) => () => void

Optional real-time updates. Return an unsubscribe function. Updates are hints that make the map fresher; they do not make it authoritative.

onSnapshot, when the adapter calls it, delivers the whole picture (for example after a reconnect): seats it does not list are available, so the caller replaces its cache instead of merging. Adapters that never re-read everything simply ignore it.

From InventoryAdapter

getAreaStatusesoptionalmethod(input: { readonly eventId: string; readonly inventoryIds?: readonly string[]; }, options?: RequestOptions) => Promise<AreaStatusRecord[]>

Optional: availability of GA areas, booths and whole tables (remaining capacity and status). Adapters without it simply do not report areas.

From InventoryAdapter

subscribeAreasoptionalmethod(eventId: string, listener: (changes: AreaStatusRecord[]) => void, onError?: (error: BookingError) => void) => () => void

Optional real-time area updates (remaining capacity), like subscribe for seats.

From InventoryAdapter

Every member is readonly.

@openseat/cloud/src/types.ts

interface

OpenSeatClient

interface OpenSeatClient

Members

MemberTypeDescription
adapterOpenSeatAdapter
loadEventmethod(eventKey: string, o?: RequestOptions & { ifNoneMatch?: string; }) => Promise<OpenSeatEvent | "not-modified">
watchEventmethod(eventKey: string, onChange: (e: OpenSeatEvent) => void) => () => void

Re-fetch the event on resync (SSE {"seats":[]} or reconnect); calls back only when layoutRevision changes.

resumeHoldmethod(h: OpenSeatHold) => Promise<Hold>

Re-seed the token after a reload and read the hold from the server.

completeHoldmethod(eventKey: string) => void

Mark the event's hold as finished (booked by your server); drops the token.

memethod() => Promise<{ mode: "live" | "test"; allowedOrigins: string[]; originAccepted: boolean; last4: string; }>

Every member is readonly.

@openseat/cloud/src/types.ts

interface

OpenSeatClientOptions

interface OpenSeatClientOptions

Members

MemberTypeDescription
publicKeystring

Your publishable key, os_pk_live_… or os_pk_test_…. It is not a secret: it identifies your workspace and only works from the origins you allowed. A secret key (os_sk_…) is refused with an UNAUTHORIZED BookingError and never sent anywhere.

baseUrlstring

Your OpenSeat address, for example https://openseat.example.com (a trailing /api is accepted). Required.

fetchoptionaltypeof fetch

Defaults to the global fetch.

EventSourceoptionaltypeof EventSource

Defaults to the global EventSource (inject a polyfill in Node or tests).

timeoutMsoptionalnumber

Per-request timeout in milliseconds. Default 15,000.

Every member is readonly.

@openseat/cloud/src/types.ts

interface

OpenSeatEvent

An event as the browser sees it (C1), with its layout parsed and the response's ETag.

interface OpenSeatEvent

Members

MemberTypeDescription
eventKeystring
namestring
startsAtstring
venuestring
currency"INR"
maxTicketsPerBookingnumber
holdSecondsnumber
saleOpenboolean
modeMode
priceLabelsReadonly<Record<string, string>>

Category ID → rupees as text ("450", "12.50"). Display only; may be empty.

layoutRevisionnumber
layoutLayoutDocument
etagstring

Pass back as ifNoneMatch to loadEvent for a cheap "has it changed?" check.

Every member is readonly.

@openseat/cloud/src/types.ts

interface

OpenSeatHold

The buyer's browser hold, as your page hands it to your server: send holdToken (in a request body, never a URL) so your server can attach the order and book it with @openseat/node after payment.

interface OpenSeatHold

Members

MemberTypeDescription
holdTokenstring
holdIdstring
eventKeystring
seatIdsreadonly string[]
areasreadonly AreaQuantity[]
expiresAtstring
lockedboolean

Every member is readonly.

@openseat/cloud/src/types.ts

interface

StatusRecord

expiresAt is the PUBLIC expiry for token holds.

interface StatusRecord

Members

MemberTypeDescription
seatIdstring
statusSeatStatus
versionoptionalnumber
expiresAtoptionalstring

@openseat/cloud/src/cloud-wire.ts

interface

WireAvailability

eventId holds the eventKey (kept for adapter-rest parsing).

interface WireAvailability

Members

MemberTypeDescription
eventIdstring
seatsStatusRecord[]
areasAreaRecord[]
serverTimestring

@openseat/cloud/src/cloud-wire.ts

interface

WireError

interface WireError

Members

MemberTypeDescription
error{ code: string; message: string; reason?: OpenSeatErrorReason; unavailableSeatIds?: string[]; unavailableAreaIds?: string[]; maxExpiresAt?: string; minimumSdk?: string; details?: { path: string; message: string; }[]; }

@openseat/cloud/src/cloud-wire.ts

interface

WireEvent

C1.

interface WireEvent

Members

MemberTypeDescription
eventKeystring
namestring
startsAtstring
venuestring
currency"INR"
maxTicketsPerBookingnumber
holdSecondsnumber
saleOpenboolean
modeMode
priceLabelsRecord<string, string>

categoryId → rupees string ("450" | "12.50"); display only; may be {}.

layoutRevisionnumber
layoutunknown

A LayoutDocument; parse it with parseLayout on the client.

@openseat/cloud/src/cloud-wire.ts

interface

WireHold

C5–C8. expiresAt is the public expiry.

interface WireHold

Members

MemberTypeDescription
holdIdstring
eventIdstring
seatIdsstring[]
areasoptionalAreaQuantity[]
expiresAtstring
maxExpiresAtstring
serverTimestring
statusHoldStatus
lockedboolean

@openseat/cloud/src/cloud-wire.ts

interface

WireHoldToken

expiresAt is the unused-token expiry.

interface WireHoldToken

Members

MemberTypeDescription
holdTokenstring
expiresAtstring
serverTimestring

@openseat/cloud/src/cloud-wire.ts

Types4

type

HoldStatus

type HoldStatus = "active" | "expired" | "released" | "booked";

@openseat/cloud/src/cloud-wire.ts

type

Mode

Same union as Mode in wire.ts; repeated here so this file stands alone.

type Mode = "live" | "test";

@openseat/cloud/src/cloud-wire.ts

type

OpenSeatErrorReason

Every reason the Cloud API gives when it refuses a request (the reason of an error response).

type OpenSeatErrorReason =
  | "KEY_INVALID"
  | "WRONG_KEY_KIND"
  | "KEY_MISUSE"
  | "KEY_IN_URL"
  | "ORIGIN_NOT_ALLOWED"
  | "INSUFFICIENT_SCOPE"
  | "REAUTH_REQUIRED"
  | "KEY_LIMIT"
  | "EVENT_NOT_API_ENABLED"
  | "EVENT_MODE_MISMATCH"
  | "EVENT_NOT_PUBLISHED"
  | "EVENT_KEY_TAKEN"
  | "EVENT_KEY_LOCKED"
  | "HOSTED_PAGE_OFF"
  | "PRICES_REQUIRED"
  | "SALE_CLOSED"
  | "SDK_TOO_OLD"
  | "HOLD_TOKEN_IN_URL"
  | "HOLD_LOCKED"
  | "HOLD_MISMATCH"
  | "HOLD_ALREADY_BOOKED"
  | "EXTENSION_LIMIT"
  | "EXPIRED"
  | "RELEASED"
  | "SEATS_TAKEN"
  | "ORDER_ID_IN_USE"
  | "HOSTED_BOOKING"
// … 17 more lines (type truncated)

This type is long; its declaration is shortened here.

@openseat/cloud/src/cloud-wire.ts

type

SeatStatus

type SeatStatus = "available" | "held" | "booked" | "blocked";

@openseat/cloud/src/cloud-wire.ts

Constants3

const

LAYOUT_SCHEMA_VERSION

The newest layout schema this SDK reads, sent as schema=<n> so the server can refuse an event whose seat map is newer (409 SDK_TOO_OLD) instead of sending one this SDK cannot draw. A test keeps it equal to SCHEMA_VERSION in

const LAYOUT_SCHEMA_VERSION = 1

@openseat/cloud/src/version.ts

const

OPEN_SEAT_ERROR_REASONS

Every Cloud API refusal reason as a runtime list, so an unknown reason from a newer server is kept as free text rather than mistaken for a known one. The check below fails to compile if this list and the OpenSeatErrorReason union (a verbatim copy of the server's) differ.

const OPEN_SEAT_ERROR_REASONS: readonly [
  "KEY_INVALID",
  "WRONG_KEY_KIND",
  "KEY_MISUSE",
  "KEY_IN_URL",
  "ORIGIN_NOT_ALLOWED",
  "INSUFFICIENT_SCOPE",
  "REAUTH_REQUIRED",
  "KEY_LIMIT",
  "EVENT_NOT_API_ENABLED",
  "EVENT_MODE_MISMATCH",
  "EVENT_NOT_PUBLISHED",
  "EVENT_KEY_TAKEN",
  "EVENT_KEY_LOCKED",
  "HOSTED_PAGE_OFF",
  "PRICES_REQUIRED",
  "SALE_CLOSED",
  "SDK_TOO_OLD",
  "HOLD_TOKEN_IN_URL",
  "HOLD_LOCKED",
  "HOLD_MISMATCH",
  "HOLD_ALREADY_BOOKED",
  "EXTENSION_LIMIT",
  "EXPIRED",
  "RELEASED",
  "SEATS_TAKEN",
  "ORDER_ID_IN_USE",
  "HOSTED_BOOKING",
// … 18 more lines (type truncated)

This type is long; its declaration is shortened here.

@openseat/cloud/src/errors.ts

const

VERSION

This package's version, sent as OpenSeat-Client: cloud/<version>; schema=<n>. A test keeps it equal to package.json.

const VERSION = "0.1.0"

@openseat/cloud/src/version.ts

Re-exports5

interface

AreaQuantity

Re-exported from @openseat/booking: A quantity of something sold as a unit rather than seat by seat: places in a general-admission (standing) area, a booth, or a bookAsWhole table. inventoryId is the area's or booth's inventoryId, or the table's object ID, as listed by getBookableAreas. Booths and whole tables have quantity 1.

class

BookingError

Re-exported from @openseat/booking: Normalised error from any adapter. Adapters should throw this, not raw HTTP errors.