SDK reference
Hand-authored reference for the SeatBuilder browser SDK — install options, the full SdkConfig field table, callbacks, the ChartInstance surface, the React component, and a worked render() example.
SDK reference
The SeatBuilder browser SDK renders an interactive seat map inside your page and
manages seat selection and holds against the SeatBuilder API. You embed it by
calling SeatBuilder.render(config), which returns a ChartInstance
you can drive imperatively. The SDK authenticates with your public key
(pk_live_… / pk_test_…) — the browser render credential — so it is safe to
ship in client code.
This page is the canonical, hand-authored reference. The full auto-generated type reference is linked at the bottom.
Install
The SDK is published to npm as @seatbuilder/sdk
(ESM, TypeScript types included; konva and zod install automatically):
npm install @seatbuilder/sdkimport SeatBuilder from '@seatbuilder/sdk';
import type { SdkConfig, ChartInstance } from '@seatbuilder/sdk';Or load the script-tag bundle, which exposes a window.SeatBuilder global:
<script src="https://seatbuilder.org/sdk/latest/seatbuilder.iife.min.js"></script>React apps can use the <SeatBuilderChart> component
from @seatbuilder/sdk/react instead of calling render() directly.
SDK 5.7.x requires SeatBuilder server v1.16.0+. 5.7 moved own-hold
detection to the server (/status ?holdToken= → mine /
mineQuantity) and scopes release to a holdToken. An older SDK
against a v1.16.0+ server keeps rendering, but its own holds show as
held-by-other after a refresh and deselect-release fails (the seat still
frees itself at hold expiry) — upgrade to 5.7.1 for hold-mode embeds. See
the changelog for the full release notes.
Configuration (SdkConfig)
Pass a single config object to SeatBuilder.render(). Every field below is
transcribed from packages/sdk/src/types.ts.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| publicKey | string | Yes | — | Public API key (pk_live_… / pk_test_…). This is the browser render credential. |
| eventKey | string | Yes | — | Event key (UUID or slug). |
| container | HTMLElement | string | Yes | — | DOM element or element ID string to mount into. |
| apiUrl | string | Yes | — | Base URL of the SeatBuilder API (e.g. https://seatbuilder.org). Required since 1.0.0 — the SDK throws at construction if it is absent. |
| maxSelectedObjects | number | { total?: number; perCategory?: Record<string, number> } | No | unlimited | Seat selection cap. A bare number is the total cap; the object form adds per-category caps (both enforced when set together). |
| showSeatLabels | boolean | No | false | Show seat-number labels on the map (hidden below ~0.43× zoom regardless). |
| holdDurationSeconds | number | No | server default 900 (no client default) | Passed as ttlSeconds on the initial /hold. Omit to use the server default of 900s — there is no silent client default; the field is simply absent from the /hold body when unset. 300 is only an example value, not a default. |
| showHoldCountdown | boolean | No | false | Re-enable the built-in 2-minute warning banner + auto-deselect timer. |
| selectionMode | 'hold' | 'select' | No | 'hold' | 'hold' = buyer purchase flow; 'select' = operator selection-only (no /hold round-trip). Advanced/operator use. |
| language | string | No | 'en' | BCP-47 language code selecting a built-in string catalog for every user-facing SDK string (legend, tooltips, GA "N left"/"Sold out", hold/expiry/connection banners, quantity picker). Shipped catalogs: en (default) and vi (Vietnamese). An unset or unrecognized code falls back to en. Region subtags are ignored (vi-VN → vi). |
| messages | Partial<SdkMessages> | No | {} | Per-string overrides merged over the selected catalog. Each provided key wins over both the language catalog and the en fallback. Plural keys (e.g. gaRemaining) take a { one, other } object; the override replaces the whole value. |
Localization (language and messages)
Every built-in string the SDK renders — status-legend labels, seat/GA
tooltips, the GA "N left" / "Sold out" text, the hold-warning, hold-expired,
and connection-lost banners, and the GA quantity picker — is drawn from a typed
string catalog. Set language to pick a shipped catalog, and/or pass
messages to override individual keys:
SeatBuilder.render({
container: '#chart',
apiUrl: 'https://seatbuilder.org',
publicKey: 'pk_live_…',
eventKey: 'my-event',
language: 'vi',
messages: { sold: 'Đã bán' },
});Resolution is per-key: an override wins over the language catalog, which wins
over the en fallback. A missing or blank value can never reach the DOM — an
unresolved key always falls back to en. The SdkMessages type is re-exported
from @seatbuilder/sdk if you want to author a complete standalone catalog.
A note on holdDurationSeconds and the hold TTL
holdDurationSeconds is the single client-side control over the browse-hold
lifetime. When set, it is sent as ttlSeconds on the initial POST /hold.
When you omit it, the field is absent from the request body and the server
default of 900 seconds applies. There is no separate silent client default,
and 300 (seen in some examples) is only an illustrative shorter value, not a
built-in default.
Select mode (selectionMode: 'select')
selectionMode defaults to 'hold' — the buyer purchase flow, where
clicking a free seat calls POST /seats/hold immediately. Set
selectionMode: 'select' for an operator/admin selection tool
instead: clicking any seat (free, held, or booked) just toggles its
local selection state for your own UI to read back — the SDK never
calls /hold or /release in this mode. There is no round-trip, no
holdToken reservation, and nothing is written to the server from
selection alone; your own backend decides what to do with the selected
labels (e.g. force-release via the server-side /release API with a
secret key).
Seats held or booked by other sessions are still shown as unavailable
(the held-by-other / booked visual states) — in select mode this
comes entirely from the live snapshot and realtime feed described below,
never from a hold the SDK itself took. Live cross-user updates reach the
chart the same way in both modes: a WebSocket subscription pushes
seat.held / seat.booked / seat.released / seat.hold_expired
deltas as they happen, and on connect or reconnect the SDK does a full
GET /status refetch to reconcile before applying any further deltas —
so a select-mode operator view stays live without ever holding a seat
itself.
Callbacks
All callbacks are optional and passed alongside the config fields above
(SdkConfig extends SdkCallbacks).
| Callback | Payload fields |
|---|---|
onObjectSelected(event) | objectLabel, holdToken, categoryKey |
onObjectDeselected(event) | objectLabel |
onSelectionValid(event) | selectedObjectLabels[] |
onSelectionInvalid(event) | selectedObjectLabels[], reason ('max_selected' | 'hold_expired' | 'hold_failed'), categoryKey? |
onChartRendered(event) | chartData |
Chart instance (ChartInstance)
SeatBuilder.render() returns a ChartInstance for imperative control:
| Member | Signature | Purpose |
|---|---|---|
holdToken | string (readonly) | Current session hold token — share with your backend to extend, book, or release the held seats. |
clearSelection | (): void | Deselect all seats and release holds. |
selectObjects | (labels: string[]): Promise<void> | Programmatically select seats by objectLabel. |
refreshStatus | (): Promise<void> | Re-fetch the server status snapshot and repaint every seat in place (operator dashboard use). |
destroy | (): void | Destroy the chart and clean up all resources. |
The holdToken is the link between the browser session and your server: pass it
to the backend extend / book / release endpoints to confirm or free the buyer's
seats.
Worked example
Render a chart with the public key and read back the session hold token:
import SeatBuilder from '@seatbuilder/sdk';
const chart = SeatBuilder.render({
publicKey: 'pk_live_xxx',
eventKey: 'evt_summer_gala',
container: '#seatmap',
apiUrl: 'https://seatbuilder.org',
onObjectSelected: ({ objectLabel, categoryKey }) => {
console.log(`selected ${objectLabel} (${categoryKey})`);
},
});
// Hand this token to your backend to book or release the held seats.
async function checkout() {
await fetch('/api/checkout', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ holdToken: chart.holdToken }),
});
}A minimal render with a selection cap and shorter browse hold:
import SeatBuilder from '@seatbuilder/sdk';
const chart = SeatBuilder.render({
publicKey: 'pk_live_xxx',
eventKey: 'evt_summer_gala',
container: '#seatmap',
apiUrl: 'https://seatbuilder.org',
maxSelectedObjects: { total: 6, perCategory: { vip: 2 } },
holdDurationSeconds: 300,
});React component (SeatBuilderChart)
@seatbuilder/sdk/react exports SeatBuilderChart, a client component that
calls SeatBuilder.render() for you (React 18+). It is safe to render from a
Next.js App Router server component tree — the chart mounts on the client.
'use client';
import { useRef } from 'react';
import { SeatBuilderChart } from '@seatbuilder/sdk/react';
import type { ChartInstance } from '@seatbuilder/sdk';
export function SeatMap({ eventKey }: { eventKey: string }) {
const chart = useRef<ChartInstance | null>(null);
return (
<SeatBuilderChart
ref={chart}
publicKey="pk_live_xxx"
eventKey={eventKey}
apiUrl="https://seatbuilder.org"
onObjectSelected={({ objectLabel }) => console.log('held', objectLabel)}
style={{ height: 600 }}
/>
);
}| Prop | Type | Description |
|---|---|---|
every SdkConfig field except container | see Configuration | Passed through to render(); the component creates its own container <div>. |
onReady | (chart: ChartInstance | null) => void | Called with the live instance after render, and with null on teardown. |
className / style | string / CSSProperties | Applied to the container <div> — give it a height. |
ref | Ref<ChartInstance | null> | The live ChartInstance; null until the chart mounts. |
Re-mount rules: changing an on* callback, onReady, className or style
never re-mounts the chart; changing any config field (e.g. eventKey,
maxSelectedObjects) destroys it and renders a new one. Unmounting destroys
the chart — don't call destroy() yourself. See the
React & Next.js recipe for a full walkthrough.
Full generated reference
Every exported symbol is also documented in the auto-generated TypeDoc tree:
- All modules — the generated entry page.
sdk/src— the main SDK module (SdkConfig,ChartInstance, event payloads).sdk/src/react—SeatBuilderChartandSeatBuilderChartProps(@seatbuilder/sdk/react).sdk/src/types— flattened type aliases.shared/src/chart-schema— theChartDatafamily consumed bySeatBuilder.render.