Types Reference
All shared data structures and TypeScript types for SeatSquirrel
This page documents every data structure used by the Designer and Picker SDKs. Types are referenced from the Designer API Reference and Picker API Reference.
LayoutOutput
The root schema returned by the Designer's onSave callback and accepted by the Picker's loadLayout() method.
{
type: 'seatSquirrelLayout',
version: '1.0.0',
layout: {
sections: Section[],
rows: Row[],
areas?: Area[],
tables?: Table[],
pricingCategories: PricingCategory[],
drawing?: Drawing,
metadata: {
name?: string,
exportedAt: string, // ISO 8601 timestamp
dimensions: { width: number, height: number },
currency?: string, // ISO 4217 currency code (e.g., 'USD', 'EUR')
locale?: string, // BCP 47 locale code (e.g., 'en-US', 'de-DE')
permissions?: DesignerPermissions // Feature restrictions stored with layout
}
}
}PricingCategory
Defines a pricing tier that can be assigned to seats, rows, sections, or areas.
| Property | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Machine-generated unique identifier. Format: price_{16chars} (e.g., price_x7k2m9p4q1B2c3D4). Globally unique across all layouts. |
label | string | Yes | Customisable display label visible to end users in the Picker (e.g., "Adult", "VIP", "Early Bird") |
slug | string | Yes | URL-safe identifier for API integrations. Auto-generated from the label but fully customisable. Must be unique within each layout. (e.g., pricing-vip, pricing-early_bird) |
price | number | Yes | Price in your currency's smallest unit (cents) |
color | string | Yes | Hex color for visual representation |
customerNotes | string | No | Notes visible to customers during booking |
{
id: "price_x7k2m9p4q1B2c3D4",
label: "VIP",
slug: "vip",
price: 15000, // e.g., $150.00
color: "#8b5cf6",
customerNotes: "Includes complimentary drinks"
}Section
Organizes rows and areas into named venue sections with optional hierarchy.
Full functionality coming coon
Sections are not fully implemented in SeatSquirrel yet and will be in a future version. Sections will eventually be able to recursively contain layouts eg:
//...
sections: [{
sections: Section[],
rows: Row[],
areas?: Area[],
tables?: Table[],
pricingCategories: PricingCategory[],
drawing?: Drawing,
}, {
// ...
}]
//...| Property | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Machine-generated unique identifier. Format: section_{16chars} (e.g., section_a1B2c3D4e5F6g7H8). Globally unique across all layouts. |
label | string | Yes | Customisable display label visible to end users in the Picker (e.g., "Orchestra", "Balcony", "Mezzanine") |
slug | string | Yes | URL-safe identifier for API integrations. Auto-generated from the label but fully customisable. Must be unique within each layout. (e.g., section-orchestra, section-balcony_left) |
parentSectionId | string | No | Parent section ID for nested hierarchy |
bounds | { x, y, width, height } | No | Visual bounds of the section on canvas |
pricingCategoryIds | string[] | Yes | Pricing categories for this section |
entrances | string[] | No | Entrance identifiers for this section |
isCollapsed | boolean | No | Whether the section is collapsed in the UI |
order | number | No | Display order among sibling sections |
color | string | No | Section color (hex) |
metadata | Record<string, any> | No | Arbitrary key-value metadata |
Row
A row of seats with positioning and labeling configuration. Seats are nested inside the row in the seats array.
| Property | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Machine-generated unique identifier. Format: row_{16chars} (e.g., row_a1B2c3D4e5F6g7H8). Globally unique across all layouts. |
label | string | Yes | Customisable display label visible to end users in the Picker (e.g., "A", "1", "AA") |
slug | string | Yes | URL-safe identifier for API integrations. Auto-generated from the label but fully customisable. Must be unique within each layout. (e.g., row-a, row-aa) |
seatCount | number | Yes | Number of seats in row |
seatLabelType | 'numeric' | 'alphabetic-upper' | 'alphabetic-lower' | Yes | How seats are labeled |
seatLabelStart | number | string | No | Starting label (default: 1 or 'A') |
seatLabelOrder | 'forward' | 'reverse' | No | Label direction |
sectionId | string | No | Parent section ID |
misc | MiscProperty[] | No | Custom metadata properties (e.g., entrance info). Inherited by seats when not overridden |
pricingCategoryIds | string[] | Yes | Pricing categories (inherited by seats) |
rowSeats | RowSeat[] | Yes | Array of seats in this row |
drawing | RowDrawing | Yes | Position and curve data |
RowDrawing
| Property | Type | Required | Description |
|---|---|---|---|
startX | number | Yes | Row start X coordinate |
startY | number | Yes | Row start Y coordinate |
endX | number | Yes | Row end X coordinate |
endY | number | Yes | Row end Y coordinate |
curve | number | Yes | Curve factor (-1 to 1, 0 = straight) |
angle | number | Yes | Row angle in radians |
seatSpacing | number | No | Custom spacing between seats |
rowLabelPlacement | 'start' | 'end' | 'both' | 'none' | No | Where to show row labels |
seatDrawing | SeatDrawing | No | Default seat color overrides |
SeatDrawing
| Property | Type | Required | Description |
|---|---|---|---|
fill | string | No | Row seat fill color |
stroke | string | No | Row seat stroke color |
MiscProperty
Custom key-value metadata attached to bookable entities. Used for entrance info and organizer-defined fields.
| Property | Type | Required | Description |
|---|---|---|---|
key | string | Yes | Machine key (camelCase, e.g., entranceToUse) |
label | string | Yes | Human-readable label (e.g., Entrance to Use) |
value | string | Yes | The value (e.g., Door 3) |
{
key: "entranceToUse",
label: "Entrance to Use",
value: "Door 3"
}RowSeat
An individual seat within a row.
| Property | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Machine-generated unique identifier. Format: rowseat_{16chars} (e.g., rowseat_a1B2c3D4e5F6g7H8). Globally unique across all layouts. |
rowId | string | Yes | Parent row ID |
indexInRow | number | Yes | Position index within the row (0-based) |
label | string | Yes | Customisable display label visible to end users in the Picker (e.g., "1", "A", "12") |
slug | string | Yes | URL-safe identifier for API integrations. Auto-generated from the label but fully customisable. Must be unique within each layout. (e.g., rowseat-row_a-1, rowseat-row_b-12) |
pricingCategoryIds | string[] | Yes | Available pricing categories for this seat |
isAvailable | boolean | No | Whether seat can be booked (picker mode) |
isUnbookable | boolean | No | Permanently unbookable (e.g., removed seat) |
isAccessible | boolean | No | Wheelchair accessible |
hasRestrictedView | boolean | No | Has obstructed or limited view |
misc | MiscProperty[] | No | Custom metadata — inherits from parent row when not set |
drawing | SeatDrawing | No | Optional color overrides |
{
id: "rowseat_x7k2m9p4q1B2c3D4",
rowId: "row_d5E6f7G8h9I0j1K2",
indexInRow: 0,
label: "1",
slug: "rowseat-row_a-1",
pricingCategoryIds: ["price_x7k2m9p4q1B2c3D4"],
isAccessible: true
}Area
A bookable area (general admission, tables, VIP sections) with flexible pricing models.
| Property | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Machine-generated unique identifier. Format: area_{16chars} (e.g., area_a1B2c3D4e5F6g7H8). Globally unique across all layouts. |
label | string | Yes | Customisable display label visible to end users in the Picker (e.g., "General Admission", "VIP Lounge", "Standing Room") |
slug | string | Yes | URL-safe identifier for API integrations. Auto-generated from the label but fully customisable. Must be unique within each layout. (e.g., area-general_admission, area-vip_lounge) |
purchaseType | 'multiple-customer' | 'single-customer' | Yes | Multiple tickets vs. exclusive booking |
pricingMethod | 'per-person' | 'as-whole' | Yes | Price per person or flat rate for entire area |
sectionId | string | No | Parent section ID |
pricingCategoryIds | string[] | Yes | Available pricing categories |
minOccupancy | number | No | Minimum people required |
maxOccupancy | number | Yes | Maximum capacity |
displayUnit | 'seat' | 'standing' | 'sofa' | null | No | How capacity is labeled |
misc | MiscProperty[] | No | Custom metadata properties (e.g., entrance info) |
showMaxOccupancy | boolean | No | Show capacity to customers |
showMinOccupancy | boolean | No | Show minimum to customers |
showOccupancyInfo | boolean | No | Show current availability |
isUnbookable | boolean | No | Permanently unavailable |
isAccessible | boolean | No | Wheelchair accessible |
hasRestrictedView | boolean | No | Has obstructed view |
currentOccupancy | number | No | Current bookings (for availability display) |
availableCount | number | No | Remaining capacity |
isAvailable | boolean | No | Single-customer area: is it available? |
bookedByCustomerId | string | No | Single-customer: who booked it |
locked | boolean | No | Prevent editing in designer |
drawing | AreaDrawing | Yes | Shape and visual properties |
AreaDrawing
| Property | Type | Required | Description |
|---|---|---|---|
shape | 'rectangle' | 'circle' | 'polygon' | 'custom' | Yes | Shape type |
shapeData | AreaShapeData | Yes | Shape-specific dimensions |
fill | string | Yes | Fill color (hex) |
stroke | string | No | Stroke color |
strokeWidth | number | No | Stroke width in pixels |
opacity | number | No | Opacity (0-1) |
rotation | number | No | Rotation in degrees |
scaleX | number | No | Horizontal scale |
scaleY | number | No | Vertical scale |
label | string | No | Label overlay shown on area |
labelFontSize | number | No | Font size for label |
labelX | number | No | Label X position (% 0-100) |
labelY | number | No | Label Y position (% 0-100) |
labelColor | string | No | Label color |
labelAlign | 'left' | 'center' | 'right' | No | Label alignment |
AreaShapeData
Properties vary by shape type:
| Property | Type | Used By | Description |
|---|---|---|---|
x | number | All | X position |
y | number | All | Y position |
width | number | rectangle | Width |
height | number | rectangle | Height |
radius | number | circle (if equal radii) | Circle radius |
radiusX | number | circle (ellipse) | Horizontal radius |
radiusY | number | circle (ellipse) | Vertical radius |
sides | number | polygon | Number of sides (3-20) |
points | number[] | custom | Array of [x,y,x,y,...] points |
cornerRadius | number | rectangle | Rounded corner radius |
Table
A table with seats arranged around its perimeter. Tables are a hybrid between rows (individual bookable seats) and areas (a visible shape on the canvas).
| Property | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Machine-generated unique identifier. Format: table_{16chars} (e.g., table_a1B2c3D4e5F6g7H8). Globally unique across all layouts. |
label | string | Yes | Customisable display label visible to end users in the Picker (e.g., "Table 1", "VIP Table", "Corner Booth") |
slug | string | Yes | URL-safe identifier for API integrations. Auto-generated from the label but fully customisable. Must be unique within each layout. (e.g., table-table_1, table-vip_table) |
seatCount | number | Yes | Number of seats around the table |
seatLabelType | 'numeric' | 'alphabetic-upper' | 'alphabetic-lower' | Yes | How seats are labeled |
seatLabelStart | number | string | No | Starting label (default: 1 or 'A') |
seatLabelOrder | 'clockwise' | 'counter-clockwise' | No | Seat label direction around table |
purchaseType | 'multiple-customer' | 'single-customer' | Yes | Multiple individual seat bookings vs. exclusive whole-table booking |
pricingMethod | 'per-person' | 'as-whole' | Yes | Price per person or flat rate for the whole table |
pricingCategoryIds | string[] | Yes | Pricing categories for this table |
minOccupancy | number | No | Minimum number of people required |
showMinOccupancy | boolean | No | Show min occupancy in picker (single-customer) |
showMaxOccupancy | boolean | No | Show max occupancy (seat count) in picker (single-customer) |
sectionId | string | No | Parent section ID |
misc | MiscProperty[] | No | Custom metadata properties (e.g., entrance info). Inherited by seats when not overridden |
isUnbookable | boolean | No | Permanently unavailable |
isAccessible | boolean | No | Wheelchair accessible |
hasRestrictedView | boolean | No | Has obstructed view |
isAvailable | boolean | No | Single-customer table: is it available? |
bookedByCustomerId | string | No | Single-customer table: who booked it |
locked | boolean | No | Prevent editing in designer |
tableSeats | TableSeat[] | Yes | Array of seats around this table |
drawing | TableDrawing | Yes | Shape and visual properties |
TableDrawing
| Property | Type | Required | Description |
|---|---|---|---|
shape | 'circular' | 'rectangular' | Yes | Table shape |
x | number | Yes | X position |
y | number | Yes | Y position |
radius | number | No | Radius (circular tables) |
width | number | No | Width (rectangular tables) |
height | number | No | Height (rectangular tables) |
cornerRadius | number | No | Corner radius (rectangular tables) |
fill | string | Yes | Fill color (hex) |
stroke | string | No | Stroke color |
strokeWidth | number | No | Stroke width |
opacity | number | No | Opacity (0-1) |
rotation | number | No | Rotation in degrees |
scaleX | number | No | Horizontal scale |
scaleY | number | No | Vertical scale |
label | string | No | Label shown on table surface |
labelFontSize | number | No | Font size for label |
labelColor | string | No | Label color |
seatDrawing | SeatDrawing | No | Default seat color overrides |
TableSeat
An individual seat belonging to a table.
| Property | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Machine-generated unique identifier. Format: tableseat_{16chars} (e.g., tableseat_a1B2c3D4e5F6g7H8). Globally unique across all layouts. |
tableId | string | Yes | Parent table ID |
indexInTable | number | Yes | Position index around the table (0-based) |
label | string | Yes | Customisable display label visible to end users in the Picker (e.g., "1", "A", "Seat 3") |
slug | string | Yes | URL-safe identifier for API integrations. Auto-generated from the label but fully customisable. Must be unique within each layout. (e.g., tableseat-table_1-1, tableseat-vip_table-a) |
pricingCategoryIds | string[] | Yes | Available pricing categories for this seat |
isAvailable | boolean | No | Whether seat can be booked (picker mode) |
isUnbookable | boolean | No | Permanently unbookable |
isAccessible | boolean | No | Wheelchair accessible |
hasRestrictedView | boolean | No | Has obstructed or limited view |
misc | MiscProperty[] | No | Custom metadata — inherits from parent table when not set |
drawing | SeatDrawing | No | Optional color overrides |
Drawing
Visual annotations that are not bookable (decorative shapes, labels, stage outlines).
| Property | Type | Required | Description |
|---|---|---|---|
backgroundColor | string | No | Canvas background color |
lines | Line[] | No | Line elements |
textElements | TextElement[] | No | Text labels |
rectangles | Rectangle[] | No | Rectangle shapes |
circles | Circle[] | No | Circle/ellipse shapes |
polygons | Polygon[] | No | Regular polygon shapes |
Line
Lines and custom shapes are both represented as Line entities. The Custom Shape tool creates closed, filled lines with bezier curve support.
| Property | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Machine-generated ID |
vertices | LineVertex[] | Yes | Array of vertex objects with bezier handles |
strokeWidth | number | Yes | Line width |
strokeColor | string | Yes | Line color |
strokeStyle | 'solid' | 'dashed' | 'dotted' | Yes | Line style |
dashArray | number[] | No | Custom dash pattern |
opacity | number | Yes | Opacity (0-1) |
fill | string | No | Fill color (only rendered when closed) |
label | string | No | Optional label |
labelColor | string | No | Label color |
labelFontSize | number | No | Label font size |
labelX | number | No | Label X position (0-100%) |
labelY | number | No | Label Y position (0-100%) |
labelAlign | 'left' | 'center' | 'right' | No | Label alignment |
locked | boolean | No | Prevent editing |
closed | boolean | No | Connect last to first vertex |
LineVertex
| Property | Type | Required | Description |
|---|---|---|---|
x | number | Yes | Vertex X position |
y | number | Yes | Vertex Y position |
handleIn | { dx: number; dy: number } | No | Incoming bezier handle (offset) |
handleOut | { dx: number; dy: number } | No | Outgoing bezier handle (offset) |
mirror | boolean | No | Whether handles are mirrored |
TextElement
| Property | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Machine-generated ID |
x | number | Yes | X position |
y | number | Yes | Y position |
text | string | Yes | Text content |
fontSize | number | Yes | Font size |
color | string | Yes | Text color |
bold | boolean | No | Bold text |
italic | boolean | No | Italic text |
rotation | number | No | Rotation in degrees |
scaleX | number | No | Horizontal scale |
scaleY | number | No | Vertical scale |
width | number | No | Text box width |
align | 'left' | 'center' | 'right' | No | Text alignment |
locked | boolean | No | Prevent editing |
label | string | No | Optional identifier |
Rectangle
| Property | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Machine-generated ID |
x | number | Yes | X position |
y | number | Yes | Y position |
width | number | Yes | Width |
height | number | Yes | Height |
fill | string | Yes | Fill color |
cornerRadius | number | Yes | Corner radius |
stroke | string | No | Stroke color |
strokeWidth | number | No | Stroke width |
rotation | number | No | Rotation in degrees |
scaleX | number | No | Horizontal scale |
scaleY | number | No | Vertical scale |
opacity | number | No | Opacity (0-1) |
locked | boolean | No | Prevent editing |
label | string | No | Display label |
labelFontSize | number | No | Label font size |
labelX | number | No | Label X offset |
labelY | number | No | Label Y offset |
labelColor | string | No | Label color |
labelAlign | 'left' | 'center' | 'right' | No | Label alignment |
Circle
Supports both circles (equal radii) and ellipses (different radiusX/radiusY).
| Property | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Machine-generated ID |
x | number | Yes | Center X position |
y | number | Yes | Center Y position |
radiusX | number | Yes | Horizontal radius |
radiusY | number | Yes | Vertical radius |
fill | string | Yes | Fill color |
stroke | string | No | Stroke color |
strokeWidth | number | No | Stroke width |
rotation | number | No | Rotation in degrees |
scaleX | number | No | Horizontal scale |
scaleY | number | No | Vertical scale |
opacity | number | No | Opacity (0-1) |
locked | boolean | No | Prevent editing |
label | string | No | Display label |
labelFontSize | number | No | Label font size |
labelX | number | No | Label X offset |
labelY | number | No | Label Y offset |
labelColor | string | No | Label color |
labelAlign | 'left' | 'center' | 'right' | No | Label alignment |
Polygon
Regular polygons (triangles, hexagons, etc.).
| Property | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Machine-generated ID |
x | number | Yes | Center X position |
y | number | Yes | Center Y position |
radius | number | Yes | Distance to vertices |
sides | number | Yes | Number of sides (3-20) |
fill | string | Yes | Fill color |
stroke | string | No | Stroke color |
strokeWidth | number | No | Stroke width |
rotation | number | No | Rotation in degrees |
scaleX | number | No | Horizontal scale |
scaleY | number | No | Vertical scale |
opacity | number | No | Opacity (0-1) |
locked | boolean | No | Prevent editing |
label | string | No | Display label |
labelFontSize | number | No | Label font size |
labelX | number | No | Label X offset |
labelY | number | No | Label Y offset |
labelColor | string | No | Label color |
labelAlign | 'left' | 'center' | 'right' | No | Label alignment |
DesignerPermissions
Configuration object to control which features are enabled in the Designer. All fields are optional — omitted fields
default to enabled (true).
Used with the permissions option in the Designer constructor to restrict functionality (e.g., pre-supply pricing
categories and prevent users from creating/editing them).
Key Principle: Default to full access. Permissions are opt-in restrictions, not opt-in grants.
| Property | Type | Default | Description |
|---|---|---|---|
readOnly | boolean | false | Global read-only mode — disables all editing |
assignmentOnly | boolean | false | Pricing assignment-only mode — blocks structural/visual edits while allowing pricing assignment |
tools | object | — | Tool-level permissions (see below) |
properties | object | — | Properties panel permissions (see below) |
tools
| Property | Type | Default | Description |
|---|---|---|---|
row | boolean | true | Allow seat row creation tool |
table | boolean | true | Allow table creation tools |
area | boolean | true | Allow area creation tools |
shape | boolean | true | Allow shape tools (rectangle, circle, polygon, custom, line) |
text | boolean | true | Allow text creation tool |
traceImage | boolean | true | Allow trace image upload tool |
properties
| Property | Type | Default | Description |
|---|---|---|---|
showProperties | boolean | true (false in assignmentOnly mode) | Show greyed-out (non-editable) properties when an element is selected in readOnly or assignmentOnly mode. Defaults to false when assignmentOnly is true, so only the interactive pricing panel is shown. Set true to also show greyed-out structural properties for context. |
settingsTab | boolean | true | Allow access to the Settings tab in Properties Panel |
pricingCategoriesCrud | boolean | true | Allow creating/editing/deleting pricing categories |
currencySettings | boolean | true | Allow changing currency and locale settings |
warnings
| Property | Type | Default | Description |
|---|---|---|---|
pricingCategoriesAssignmentSaveWarning | boolean | true | Show warning when rows, areas, or tables don't have pricing categories assigned |
pricingCategoriesAssignmentPanelWarning | boolean | true | Show "Missing Pricing Categories" warning in the properties panel when nothing is selected |
// Example: All permissions with defaults shown
{
readOnly: false,
assignmentOnly: false,
tools: {
row: true,
table: true,
area: true,
shape: true,
text: true,
traceImage: true
},
properties: {
showProperties: true,
settingsTab: true,
pricingCategoriesCrud: true,
currencySettings: true
},
warnings: {
pricingCategoriesAssignmentSaveWarning: true,
pricingCategoriesAssignmentPanelWarning: true
}
}readOnly takes precedence over assignmentOnly when both are set to true.
SelectionData
The data structure returned by onSelectionChanged and onComplete callbacks, and accepted as input by
setSelections(). Each item in the selections
array is one of four subtypes: RowSeatSelection, AreaSelection,
TableSeatSelection, or WholeTableSelection.
| Property | Type | Description |
|---|---|---|
selections | SelectionItem[] | Array of selection items — see subtypes below |
lastSelection | SelectionItem | null | The enriched SelectionItem for the most recently selected or modified item. null when an item is deselected or selections are cleared. |
totals | object | { count: number, amount: number } |
{
selections: [
{ type: 'row-seat', ... },
{ type: 'area', ... },
{ type: 'table-seat', ... },
{ type: 'whole-table', ... }
],
lastSelection: { type: 'row-seat', id: '...', ... }, // or null on deselect/clear
totals: {
count: 5, // Total items selected
amount: 25000 // Sum of selections that have pricing in cents (e.g., $250.00)
}
}Selections without a pricing category return categoryId: null, omit pricing labels/slugs, and contribute 0 to
totals.amount.
RowSeatSelection
Returned when a user selects a seat.
| Property | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique seat identifier |
type | 'row-seat' | Yes | Discriminator for selection type |
rowId | string | Yes | Parent row identifier |
rowLabel | string | Yes | Row label (e.g., "A", "1") |
seatLabel | string | Yes | Seat label (e.g., "1", "12") |
slug | string | Yes | Seat slug |
rowSlug | string | Yes | Row slug |
sectionId | string | No | Section identifier |
sectionName | string | No | Section display name |
sectionSlug | string | No | Section slug |
categoryId | string | null | Yes | Selected pricing category ID, or null when the seat is uncategorized |
categoryLabel | string | null | No | Pricing category display label |
categorySlug | string | null | No | Pricing category slug |
price | number | Yes | Price in cents |
AreaSelection
Returned when a user selects spots in an area.
| Property | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique area identifier |
type | 'area' | Yes | Discriminator for selection type |
areaLabel | string | Yes | Area display label |
slug | string | Yes | Area slug |
sectionId | string | No | Section identifier |
sectionName | string | No | Section display name |
sectionSlug | string | No | Section slug |
categoryId | string | null | Yes | Selected pricing category ID, or null when the area is uncategorized |
categoryLabel | string | null | No | Pricing category display label |
categorySlug | string | null | No | Pricing category slug |
quantity | number | Yes | Number of spots selected |
pricePerUnit | number | Yes | Price per spot in cents |
totalPrice | number | Yes | Total price in cents (quantity x pricePerUnit) |
TableSeatSelection
Returned when a user selects an individual seat at a table (multiple-customer purchase type).
| Property | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique table seat identifier |
type | 'table-seat' | Yes | Discriminator for selection type |
tableId | string | Yes | Parent table identifier |
tableLabel | string | Yes | Table display label |
seatLabel | string | Yes | Seat label within the table |
slug | string | Yes | Table seat slug |
tableSlug | string | Yes | Table slug |
sectionId | string | No | Section identifier |
sectionName | string | No | Section display name |
sectionSlug | string | No | Section slug |
categoryId | string | null | Yes | Selected pricing category ID, or null when the seat is uncategorized |
categoryLabel | string | null | No | Pricing category display label |
categorySlug | string | null | No | Pricing category slug |
price | number | Yes | Price in cents |
WholeTableSelection
Returned when a user books an entire table (single-customer purchase type).
| Property | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique table selection identifier |
type | 'whole-table' | Yes | Discriminator for selection type |
tableId | string | Yes | Table identifier |
tableLabel | string | Yes | Table display label |
tableSlug | string | Yes | Table slug |
sectionId | string | No | Section identifier |
sectionName | string | No | Section display name |
sectionSlug | string | No | Section slug |
categoryId | string | null | Yes | Selected pricing category ID, or null when the table is uncategorized |
categoryLabel | string | null | No | Pricing category display label |
categorySlug | string | null | No | Pricing category slug |
quantity | number | Yes | Number of people / units selected |
pricePerUnit | number | Yes | Price per unit in cents |
totalPrice | number | Yes | Total price in cents (quantity x pricePerUnit) |
SetSelectionsInput
Discriminated union input for setSelections().
Allows passing selections either by machine ID or by human-readable slug.
| Mode | Shape | Description |
|---|---|---|
'by-id' | { mode: 'by-id', selections: SelectionItem[] } | Full SelectionItem objects with machine IDs |
'by-slug' | { mode: 'by-slug', selections: SlugSelectionItem[] } | Simplified objects with human-readable slugs (recommended) |
For backward compatibility, passing a SelectionData object without a mode field is treated as by-id.
SlugSelectionItem
Simplified selection items for the by-slug mode. The engine resolves slugs to IDs and enriches the full
SelectionItem internally.
Row Seat:
| Property | Type | Description |
|---|---|---|
type | 'row-seat' | Selection type |
slug | string | Row seat slug (e.g., 'row-a-seat-1') |
categorySlug | string | null | Pricing category slug (e.g., 'standard'). Omit or set null for uncategorized seats. |
Area:
| Property | Type | Description |
|---|---|---|
type | 'area' | Selection type |
slug | string | Area slug (e.g., 'vip-lounge') |
categorySlug | string | null | Pricing category slug. Omit or set null for uncategorized areas. |
quantity | number | Number of units to select |
Table Seat:
| Property | Type | Description |
|---|---|---|
type | 'table-seat' | Selection type |
slug | string | Table seat slug (e.g., 'table-1-seat-3') |
categorySlug | string | null | Pricing category slug. Omit or set null for uncategorized table seats. |
Whole Table:
| Property | Type | Description |
|---|---|---|
type | 'whole-table' | Selection type |
tableSlug | string | Table slug (e.g., 'table-5') |
categorySlug | string | null | Pricing category slug. Omit or set null for uncategorized whole-table bookings. |
quantity | number | Number of people/units |
SetSelectionsResult
The result returned by setSelections(). Reports
which selections were applied and which failed, with per-item failure reasons.
| Property | Type | Description |
|---|---|---|
success | boolean | true only if all items were applied (no failures) |
applied | SelectionItem[] | Items that were successfully selected |
failed | SetSelectionsFailedItem[] | Items that failed validation, each with a reason |
SetSelectionsFailedItem
A selection item that failed validation during setSelections().
| Property | Type | Description |
|---|---|---|
selection | SelectionItem | The original input item that failed |
reason | SetSelectionsFailureReason | Why the item failed |
SetSelectionsFailureReason
A string enum indicating why a selection item was rejected.
| Value | Description |
|---|---|
'entity-not-found' | The entity ID or slug doesn't exist in the loaded layout |
'entity-unavailable' | Entity exists but is unavailable (isAvailable is false or isUnbookable is true), or the requested quantity exceeds the area's available count |
'invalid-category' | The categoryId/categorySlug is invalid for the entity, or a required category was omitted |
'unknown-type' | The selection type is not one of 'row-seat', 'area', 'table-seat', 'whole-table' |
Availability by ID
Set availability using machine-generated IDs. Used with setAvailability({ mode: 'by-id', ... }).
| Property | Type | Description |
|---|---|---|
rowSeats | Record<string, boolean> | Map of seat ID to availability (true = available) |
areas | Record<string, number | boolean> | Map of area ID to available count (number), or boolean (true = 1, false = 0) |
tableSeats | Record<string, boolean> | Map of table seat ID to availability |
tables | Record<string, boolean> | Map of table ID to availability (true = available) |
picker.setAvailability({
mode: 'by-id',
rowSeats: {
rowseat_a1B2c3D4e5F6g7H8: true,
rowseat_h8G7f6E5d4C3b2A1: false,
},
areas: {
area_j9K0l1M2n3O4p5Q6: 50,
area_x1Y2z3A4b5C6d7E8: false, // boolean: false = 0 (unavailable)
},
tables: {
table_x1Y2z3: false,
},
});Availability by Slug
Set availability using user-defined slugs. Used with setAvailability({ mode: 'by-slug', ... }). Recommended.
| Property | Type | Description |
|---|---|---|
rowSeats | Record<string, boolean> | Map of seat slug to availability |
areas | Record<string, number | boolean> | Map of area slug to available count (number), or boolean (true = 1, false = 0) |
tableSeats | Record<string, boolean> | Map of table seat slug to availability |
tables | Record<string, boolean> | Map of table slug to availability (true = available) |
picker.setAvailability({
mode: 'by-slug',
rowSeats: {
'row-a-seat-1': false,
'row-a-seat-2': true,
},
areas: {
'standing-room': 50,
'vip-lounge': 0,
'private-booth': false, // boolean: false = 0 (unavailable)
},
tables: {
'vip-table-1': false,
},
});Availability by Labels
Set availability using display labels. Used with setAvailability({ mode: 'dangerously-by-labels', ... }).
⚠️ Warning: Labels can clash if duplicated across sections. Prefer slugs.
SeatAvailabilityByLabel
| Property | Type | Required | Description |
|---|---|---|---|
sectionId | string | No | Section ID (required if row/seat is ambiguous) |
rowLabel | string | Yes | Row label (e.g., "A", "1") |
seatLabel | string | Yes | Seat label (e.g., "1", "12") |
isAvailable | boolean | Yes | Whether the seat is available |
AreaAvailabilityByLabel
| Property | Type | Required | Description |
|---|---|---|---|
sectionId | string | No | Section ID (required if area name is ambiguous) |
areaLabel | string | Yes | Area label as defined in the layout |
availableCount | number | boolean | Yes | Number of available spots (0 = sold out), or boolean (true = 1, false = 0) |
TableAvailabilityByLabel
| Property | Type | Required | Description |
|---|---|---|---|
sectionId | string | No | Section ID (required if table name is ambiguous) |
tableLabel | string | Yes | Table label as defined in the layout |
isAvailable | boolean | Yes | Whether the table is available |
picker.setAvailability({
mode: 'dangerously-by-labels',
rowSeats: [
{ rowLabel: 'A', seatLabel: '1', isAvailable: false },
{ rowLabel: 'A', seatLabel: '2', isAvailable: true },
],
areas: [{ areaLabel: 'Standing Room', availableCount: 50 }],
tables: [{ tableLabel: 'VIP Table', isAvailable: false }],
});Availability by Pricing Category
Bulk-set availability based on pricing categories. Used with setAvailability({ mode: 'by-pricing-category', ... }) (by ID) or setAvailability({ mode: 'by-pricing-category-slug', ... }) (by slug).
Instead of targeting individual entities, you specify which pricing categories are available or unavailable and the picker resolves each entity's availability from its assigned categories. Row-level categories are inherited by seats, and table-level categories are inherited by table seats.
| Property | Type | Required | Description |
|---|---|---|---|
available | string[] | No | Category IDs (or slugs) whose entities should be available. Unlisted categories → entities unavailable. This is a full reset — every entity is re-evaluated. |
unavailable | string[] | No | Category IDs (or slugs) whose entities should be unavailable. Only flips an entity when all of its effective category IDs are in this list. Unlisted → unchanged. This is a delta update. |
requirePricingCategory | boolean | No | When true, uncategorized entities (empty pricingCategoryIds) are treated as unavailable. When provided, updates the picker-wide setting. |
Semantics:
availableonly — Full reset. Entities assigned to listed categories become available; all others become unavailable.unavailableonly — Delta. Entities are flipped to unavailable only when every effective category ID is in the list. Others are unchanged.- Both —
availableis applied first (full reset), thenunavailableoverrides: entities whose entire set of effective category IDs appear inunavailableare flipped to unavailable.
Uncategorized entities (empty pricingCategoryIds) are left unchanged by these modes. To also make uncategorized entities unavailable, set requirePricingCategory: true.
// By pricing category ID — only "Standard" entities are available (full reset)
picker.setAvailability({
mode: 'by-pricing-category',
available: ['price_abc123'],
});
// By pricing category slug — same semantics, using slugs
picker.setAvailability({
mode: 'by-pricing-category-slug',
available: ['standard', 'vip'],
});
// Delta: make VIP-only entities unavailable (others unchanged)
picker.setAvailability({
mode: 'by-pricing-category',
unavailable: ['price_def456'],
});
// Combined + requirePricingCategory
picker.setAvailability({
mode: 'by-pricing-category',
available: ['price_abc123', 'price_def456'],
unavailable: ['price_abc123'],
requirePricingCategory: true,
});Pricing Category Partial Update by ID
Partially update pricing categories using machine-generated IDs. Used with updatePricingCategoriesById(). Merges
provided fields into matching categories — unmentioned categories are untouched. All-or-nothing: if any ID doesn't
match, the call fails with no changes.
| Property | Type | Required | Description |
|---|---|---|---|
pricingCategories | Array<{ id, ...fields }> | Yes | Array of category partial updates |
Partial Update Object (by ID)
| Property | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Category ID (must match existing category) |
label | string | No | New display label |
slug | string | No | New slug |
price | number | No | New price in cents |
color | string | No | New hex color |
customerNotes | string | No | New customer notes |
picker.updatePricingCategoriesById({
pricingCategories: [
{ id: 'price_a1B2c3D4e5F6g7H8', price: 7500, label: 'Standard (updated)' },
{ id: 'price_h8G7f6E5d4C3b2A1', color: '#10B981' },
],
});Pricing Category Partial Update by Slug
Partially update pricing categories using user-defined slugs. Used with updatePricingCategoriesBySlug().
Recommended. Merges provided fields into matching categories — unmentioned categories are untouched. All-or-nothing:
if any slug doesn't match, the call fails with no changes.
Note: The
slugfield is used only for matching — it is not merged into the category. To change a slug, useupdatePricingCategoriesByIdand passslugas an update field.
| Property | Type | Required | Description |
|---|---|---|---|
pricingCategories | Array<{ slug, ...fields }> | Yes | Array of category partial updates |
Partial Update Object (by Slug)
| Property | Type | Required | Description |
|---|---|---|---|
slug | string | Yes | Category slug (used for matching only, not merged) |
label | string | No | New display label |
price | number | No | New price in cents |
color | string | No | New hex color |
customerNotes | string | No | New customer notes |
picker.updatePricingCategoriesBySlug({
pricingCategories: [
{ slug: 'standard', price: 7500, label: 'Standard (updated)' },
{ slug: 'vip', color: '#10B981' },
],
});AssignPricingCategoriesInput
Input for assignPricingCategories() on both the Designer and Picker APIs. Allows programmatic assignment of pricing
categories to layout objects. Uses a mode discriminator to control how objects and categories are identified.
Atomic semantics: If any assignment fails validation, none are applied.
| Property | Type | Required | Description |
|---|---|---|---|
mode | 'by-id' | 'by-slug' | 'dangerously-by-labels' | Yes | How to identify objects and categories |
Mode: 'by-id'
Each property is a Record<objectId, categoryId[]> map:
| Property | Type | Required | Description |
|---|---|---|---|
rows | Record<string, string[]> | No | Map of row ID to category IDs |
rowSeats | Record<string, string[]> | No | Map of seat ID to category IDs |
areas | Record<string, string[]> | No | Map of area ID to category IDs |
tables | Record<string, string[]> | No | Map of table ID to category IDs |
tableSeats | Record<string, string[]> | No | Map of table seat ID to category IDs |
Mode: 'by-slug'
Same shape as 'by-id', but keys are user-defined slugs for both objects and categories.
Mode: 'dangerously-by-labels'
Each property is an array of label-based entries. Categories are always referenced by slug.
| Property | Type | Required | Description |
|---|---|---|---|
rows | Array<{ sectionId?, rowLabel, pricingCategorySlugs }> | No | Row assignments by label |
rowSeats | Array<{ sectionId?, rowLabel, seatLabel, pricingCategorySlugs }> | No | Seat assignments by label |
areas | Array<{ sectionId?, areaLabel, pricingCategorySlugs }> | No | Area assignments by label |
tables | Array<{ sectionId?, tableLabel, pricingCategorySlugs }> | No | Table assignments by label |
tableSeats | Array<{ sectionId?, tableLabel, seatLabel, pricingCategorySlugs }> | No | Table seat assignments by label |
// By slug (recommended)
{
mode: 'by-slug',
rows: {
'row-a': ['vip', 'standard'],
'row-b': ['standard'],
},
areas: {
'vip-lounge': ['vip'],
}
}
// By ID
{
mode: 'by-id',
rows: {
'row-uuid-1': ['cat-uuid-1', 'cat-uuid-2'],
},
areas: {
'area-uuid-1': ['cat-uuid-2'],
}
}
// Dangerously by labels
{
mode: 'dangerously-by-labels',
rows: [
{ rowLabel: 'A', pricingCategorySlugs: ['vip', 'standard'] },
{ sectionId: 'section-uuid', rowLabel: 'A', pricingCategorySlugs: ['economy'] },
]
}AssignPricingCategoriesResult
Result returned by assignPricingCategories(). Uses atomic semantics — if any assignment fails validation, none are
applied and all errors are returned.
| Property | Type | Description |
|---|---|---|
success | boolean | true if all assignments applied, false if any validation failed |
errors | string[] | Present when success is false. Lists all validation errors (e.g., unknown object slug, unknown category ID) |
// Success
{ success: true }
// Failure — no assignments applied
{
success: false,
errors: [
'No object found with slug "nonexistent-row"',
'No pricing category found with slug "unknown-category"'
]
}Complete Example
A full LayoutOutput JSON showing all structures together:
{
type: 'seatSquirrelLayout',
version: '1.0.0',
layout: {
sections: [{
id: 'section_a1B2c3D4e5F6g7H8',
label: 'Orchestra',
slug: 'section-orchestra',
pricingCategoryIds: ['price_v1I2p7R8s9T0u1W2', 'price_s3T4d5A6n7D8r9E0']
}],
rows: [{
id: 'row_d5E6f7G8h9I0j1K2',
label: 'A',
slug: 'row-a',
seatCount: 10,
seatLabelType: 'numeric',
seatLabelStart: 1,
sectionId: 'section_a1B2c3D4e5F6g7H8',
pricingCategoryIds: ['price_v1I2p7R8s9T0u1W2'],
drawing: {
startX: 100,
startY: 200,
endX: 400,
endY: 200,
curve: 0.1,
angle: 0
},
seats: [
{
id: 'rowseat_x7k2m9p4q1B2c3D4',
rowId: 'row_d5E6f7G8h9I0j1K2',
indexInRow: 0,
label: '1',
slug: 'rowseat-row_a-1',
pricingCategoryIds: ['price_v1I2p7R8s9T0u1W2']
}
// ... more seats
]
}],
areas: [{
id: 'area_g1H2i3J4k5L6m7N8',
label: 'General Admission',
slug: 'area-general_admission',
purchaseType: 'multiple-customer',
pricingMethod: 'per-person',
pricingCategoryIds: ['price_s3T4d5A6n7D8r9E0'],
maxOccupancy: 200,
displayUnit: 'standing',
drawing: {
shape: 'rectangle',
shapeData: { x: 500, y: 100, width: 300, height: 200 },
fill: '#e5e7eb'
}
}],
tables: [{
id: 'table_t1A2b3L4e5S6e7A8',
label: 'Table 1',
slug: 'table-table_1',
seatCount: 6,
seatLabelType: 'numeric',
seatLabelStart: 1,
purchaseType: 'multiple-customer',
pricingMethod: 'per-person',
pricingCategoryIds: ['price_s3T4d5A6n7D8r9E0'],
sectionId: 'section_a1B2c3D4e5F6g7H8',
drawing: {
shape: 'circular',
x: 600,
y: 400,
radius: 40,
fill: '#d1d5db'
},
seats: [
{
id: 'tableseat_p1Q2r3S4t5U6v7W8',
tableId: 'table_t1A2b3L4e5S6e7A8',
indexInTable: 0,
label: '1',
slug: 'tableseat-table_1-1',
pricingCategoryIds: ['price_s3T4d5A6n7D8r9E0']
}
// ... more seats
]
}],
pricingCategories: [
{ id: 'price_v1I2p7R8s9T0u1W2', label: 'VIP', slug: 'vip', price: 15000, color: '#8b5cf6' },
{ id: 'price_s3T4d5A6n7D8r9E0', label: 'Standard', slug: 'standard', price: 5000, color: '#3b82f6' }
],
drawing: {
backgroundColor: '#ffffff',
rectangles: [{
id: 'rect_j1K2l3M4n5O6p7Q8',
x: 200,
y: 50,
width: 200,
height: 60,
fill: '#1f2937',
cornerRadius: 4,
label: 'STAGE',
labelColor: '#ffffff',
labelFontSize: 24,
labelAlign: 'center'
}],
textElements: [{
id: 'text_m1N2o3P4q5R6s7T8',
x: 50,
y: 400,
text: 'EXIT',
fontSize: 16,
color: '#ef4444'
}]
},
metadata: {
name: 'Main Theater',
exportedAt: '2024-01-15T10:30:00.000Z',
dimensions: { width: 800, height: 600 },
currency: 'USD',
locale: 'en-US',
permissions: {
properties: { pricingCategoriesCrud: false }
}
}
}
}