SeatSquirrel
Deployment

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.

PropertyTypeRequiredDescription
idstringYesMachine-generated unique identifier. Format: price_{16chars} (e.g., price_x7k2m9p4q1B2c3D4). Globally unique across all layouts.
labelstringYesCustomisable display label visible to end users in the Picker (e.g., "Adult", "VIP", "Early Bird")
slugstringYesURL-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)
pricenumberYesPrice in your currency's smallest unit (cents)
colorstringYesHex color for visual representation
customerNotesstringNoNotes 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,
}, { 
// ...
}]
//...
PropertyTypeRequiredDescription
idstringYesMachine-generated unique identifier. Format: section_{16chars} (e.g., section_a1B2c3D4e5F6g7H8). Globally unique across all layouts.
labelstringYesCustomisable display label visible to end users in the Picker (e.g., "Orchestra", "Balcony", "Mezzanine")
slugstringYesURL-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)
parentSectionIdstringNoParent section ID for nested hierarchy
bounds{ x, y, width, height }NoVisual bounds of the section on canvas
pricingCategoryIdsstring[]YesPricing categories for this section
entrancesstring[]NoEntrance identifiers for this section
isCollapsedbooleanNoWhether the section is collapsed in the UI
ordernumberNoDisplay order among sibling sections
colorstringNoSection color (hex)
metadataRecord<string, any>NoArbitrary key-value metadata

Row

A row of seats with positioning and labeling configuration. Seats are nested inside the row in the seats array.

PropertyTypeRequiredDescription
idstringYesMachine-generated unique identifier. Format: row_{16chars} (e.g., row_a1B2c3D4e5F6g7H8). Globally unique across all layouts.
labelstringYesCustomisable display label visible to end users in the Picker (e.g., "A", "1", "AA")
slugstringYesURL-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)
seatCountnumberYesNumber of seats in row
seatLabelType'numeric' | 'alphabetic-upper' | 'alphabetic-lower'YesHow seats are labeled
seatLabelStartnumber | stringNoStarting label (default: 1 or 'A')
seatLabelOrder'forward' | 'reverse'NoLabel direction
sectionIdstringNoParent section ID
miscMiscProperty[]NoCustom metadata properties (e.g., entrance info). Inherited by seats when not overridden
pricingCategoryIdsstring[]YesPricing categories (inherited by seats)
rowSeatsRowSeat[]YesArray of seats in this row
drawingRowDrawingYesPosition and curve data

RowDrawing

PropertyTypeRequiredDescription
startXnumberYesRow start X coordinate
startYnumberYesRow start Y coordinate
endXnumberYesRow end X coordinate
endYnumberYesRow end Y coordinate
curvenumberYesCurve factor (-1 to 1, 0 = straight)
anglenumberYesRow angle in radians
seatSpacingnumberNoCustom spacing between seats
rowLabelPlacement'start' | 'end' | 'both' | 'none'NoWhere to show row labels
seatDrawingSeatDrawingNoDefault seat color overrides

SeatDrawing

PropertyTypeRequiredDescription
fillstringNoRow seat fill color
strokestringNoRow seat stroke color

MiscProperty

Custom key-value metadata attached to bookable entities. Used for entrance info and organizer-defined fields.

PropertyTypeRequiredDescription
keystringYesMachine key (camelCase, e.g., entranceToUse)
labelstringYesHuman-readable label (e.g., Entrance to Use)
valuestringYesThe value (e.g., Door 3)
{
  key: "entranceToUse",
  label: "Entrance to Use",
  value: "Door 3"
}

RowSeat

An individual seat within a row.

PropertyTypeRequiredDescription
idstringYesMachine-generated unique identifier. Format: rowseat_{16chars} (e.g., rowseat_a1B2c3D4e5F6g7H8). Globally unique across all layouts.
rowIdstringYesParent row ID
indexInRownumberYesPosition index within the row (0-based)
labelstringYesCustomisable display label visible to end users in the Picker (e.g., "1", "A", "12")
slugstringYesURL-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)
pricingCategoryIdsstring[]YesAvailable pricing categories for this seat
isAvailablebooleanNoWhether seat can be booked (picker mode)
isUnbookablebooleanNoPermanently unbookable (e.g., removed seat)
isAccessiblebooleanNoWheelchair accessible
hasRestrictedViewbooleanNoHas obstructed or limited view
miscMiscProperty[]NoCustom metadata — inherits from parent row when not set
drawingSeatDrawingNoOptional 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.

PropertyTypeRequiredDescription
idstringYesMachine-generated unique identifier. Format: area_{16chars} (e.g., area_a1B2c3D4e5F6g7H8). Globally unique across all layouts.
labelstringYesCustomisable display label visible to end users in the Picker (e.g., "General Admission", "VIP Lounge", "Standing Room")
slugstringYesURL-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'YesMultiple tickets vs. exclusive booking
pricingMethod'per-person' | 'as-whole'YesPrice per person or flat rate for entire area
sectionIdstringNoParent section ID
pricingCategoryIdsstring[]YesAvailable pricing categories
minOccupancynumberNoMinimum people required
maxOccupancynumberYesMaximum capacity
displayUnit'seat' | 'standing' | 'sofa' | nullNoHow capacity is labeled
miscMiscProperty[]NoCustom metadata properties (e.g., entrance info)
showMaxOccupancybooleanNoShow capacity to customers
showMinOccupancybooleanNoShow minimum to customers
showOccupancyInfobooleanNoShow current availability
isUnbookablebooleanNoPermanently unavailable
isAccessiblebooleanNoWheelchair accessible
hasRestrictedViewbooleanNoHas obstructed view
currentOccupancynumberNoCurrent bookings (for availability display)
availableCountnumberNoRemaining capacity
isAvailablebooleanNoSingle-customer area: is it available?
bookedByCustomerIdstringNoSingle-customer: who booked it
lockedbooleanNoPrevent editing in designer
drawingAreaDrawingYesShape and visual properties

AreaDrawing

PropertyTypeRequiredDescription
shape'rectangle' | 'circle' | 'polygon' | 'custom'YesShape type
shapeDataAreaShapeDataYesShape-specific dimensions
fillstringYesFill color (hex)
strokestringNoStroke color
strokeWidthnumberNoStroke width in pixels
opacitynumberNoOpacity (0-1)
rotationnumberNoRotation in degrees
scaleXnumberNoHorizontal scale
scaleYnumberNoVertical scale
labelstringNoLabel overlay shown on area
labelFontSizenumberNoFont size for label
labelXnumberNoLabel X position (% 0-100)
labelYnumberNoLabel Y position (% 0-100)
labelColorstringNoLabel color
labelAlign'left' | 'center' | 'right'NoLabel alignment

AreaShapeData

Properties vary by shape type:

PropertyTypeUsed ByDescription
xnumberAllX position
ynumberAllY position
widthnumberrectangleWidth
heightnumberrectangleHeight
radiusnumbercircle (if equal radii)Circle radius
radiusXnumbercircle (ellipse)Horizontal radius
radiusYnumbercircle (ellipse)Vertical radius
sidesnumberpolygonNumber of sides (3-20)
pointsnumber[]customArray of [x,y,x,y,...] points
cornerRadiusnumberrectangleRounded 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).

PropertyTypeRequiredDescription
idstringYesMachine-generated unique identifier. Format: table_{16chars} (e.g., table_a1B2c3D4e5F6g7H8). Globally unique across all layouts.
labelstringYesCustomisable display label visible to end users in the Picker (e.g., "Table 1", "VIP Table", "Corner Booth")
slugstringYesURL-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)
seatCountnumberYesNumber of seats around the table
seatLabelType'numeric' | 'alphabetic-upper' | 'alphabetic-lower'YesHow seats are labeled
seatLabelStartnumber | stringNoStarting label (default: 1 or 'A')
seatLabelOrder'clockwise' | 'counter-clockwise'NoSeat label direction around table
purchaseType'multiple-customer' | 'single-customer'YesMultiple individual seat bookings vs. exclusive whole-table booking
pricingMethod'per-person' | 'as-whole'YesPrice per person or flat rate for the whole table
pricingCategoryIdsstring[]YesPricing categories for this table
minOccupancynumberNoMinimum number of people required
showMinOccupancybooleanNoShow min occupancy in picker (single-customer)
showMaxOccupancybooleanNoShow max occupancy (seat count) in picker (single-customer)
sectionIdstringNoParent section ID
miscMiscProperty[]NoCustom metadata properties (e.g., entrance info). Inherited by seats when not overridden
isUnbookablebooleanNoPermanently unavailable
isAccessiblebooleanNoWheelchair accessible
hasRestrictedViewbooleanNoHas obstructed view
isAvailablebooleanNoSingle-customer table: is it available?
bookedByCustomerIdstringNoSingle-customer table: who booked it
lockedbooleanNoPrevent editing in designer
tableSeatsTableSeat[]YesArray of seats around this table
drawingTableDrawingYesShape and visual properties

TableDrawing

PropertyTypeRequiredDescription
shape'circular' | 'rectangular'YesTable shape
xnumberYesX position
ynumberYesY position
radiusnumberNoRadius (circular tables)
widthnumberNoWidth (rectangular tables)
heightnumberNoHeight (rectangular tables)
cornerRadiusnumberNoCorner radius (rectangular tables)
fillstringYesFill color (hex)
strokestringNoStroke color
strokeWidthnumberNoStroke width
opacitynumberNoOpacity (0-1)
rotationnumberNoRotation in degrees
scaleXnumberNoHorizontal scale
scaleYnumberNoVertical scale
labelstringNoLabel shown on table surface
labelFontSizenumberNoFont size for label
labelColorstringNoLabel color
seatDrawingSeatDrawingNoDefault seat color overrides

TableSeat

An individual seat belonging to a table.

PropertyTypeRequiredDescription
idstringYesMachine-generated unique identifier. Format: tableseat_{16chars} (e.g., tableseat_a1B2c3D4e5F6g7H8). Globally unique across all layouts.
tableIdstringYesParent table ID
indexInTablenumberYesPosition index around the table (0-based)
labelstringYesCustomisable display label visible to end users in the Picker (e.g., "1", "A", "Seat 3")
slugstringYesURL-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)
pricingCategoryIdsstring[]YesAvailable pricing categories for this seat
isAvailablebooleanNoWhether seat can be booked (picker mode)
isUnbookablebooleanNoPermanently unbookable
isAccessiblebooleanNoWheelchair accessible
hasRestrictedViewbooleanNoHas obstructed or limited view
miscMiscProperty[]NoCustom metadata — inherits from parent table when not set
drawingSeatDrawingNoOptional color overrides

Drawing

Visual annotations that are not bookable (decorative shapes, labels, stage outlines).

PropertyTypeRequiredDescription
backgroundColorstringNoCanvas background color
linesLine[]NoLine elements
textElementsTextElement[]NoText labels
rectanglesRectangle[]NoRectangle shapes
circlesCircle[]NoCircle/ellipse shapes
polygonsPolygon[]NoRegular 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.

PropertyTypeRequiredDescription
idstringYesMachine-generated ID
verticesLineVertex[]YesArray of vertex objects with bezier handles
strokeWidthnumberYesLine width
strokeColorstringYesLine color
strokeStyle'solid' | 'dashed' | 'dotted'YesLine style
dashArraynumber[]NoCustom dash pattern
opacitynumberYesOpacity (0-1)
fillstringNoFill color (only rendered when closed)
labelstringNoOptional label
labelColorstringNoLabel color
labelFontSizenumberNoLabel font size
labelXnumberNoLabel X position (0-100%)
labelYnumberNoLabel Y position (0-100%)
labelAlign'left' | 'center' | 'right'NoLabel alignment
lockedbooleanNoPrevent editing
closedbooleanNoConnect last to first vertex

LineVertex

PropertyTypeRequiredDescription
xnumberYesVertex X position
ynumberYesVertex Y position
handleIn{ dx: number; dy: number }NoIncoming bezier handle (offset)
handleOut{ dx: number; dy: number }NoOutgoing bezier handle (offset)
mirrorbooleanNoWhether handles are mirrored

TextElement

PropertyTypeRequiredDescription
idstringYesMachine-generated ID
xnumberYesX position
ynumberYesY position
textstringYesText content
fontSizenumberYesFont size
colorstringYesText color
boldbooleanNoBold text
italicbooleanNoItalic text
rotationnumberNoRotation in degrees
scaleXnumberNoHorizontal scale
scaleYnumberNoVertical scale
widthnumberNoText box width
align'left' | 'center' | 'right'NoText alignment
lockedbooleanNoPrevent editing
labelstringNoOptional identifier

Rectangle

PropertyTypeRequiredDescription
idstringYesMachine-generated ID
xnumberYesX position
ynumberYesY position
widthnumberYesWidth
heightnumberYesHeight
fillstringYesFill color
cornerRadiusnumberYesCorner radius
strokestringNoStroke color
strokeWidthnumberNoStroke width
rotationnumberNoRotation in degrees
scaleXnumberNoHorizontal scale
scaleYnumberNoVertical scale
opacitynumberNoOpacity (0-1)
lockedbooleanNoPrevent editing
labelstringNoDisplay label
labelFontSizenumberNoLabel font size
labelXnumberNoLabel X offset
labelYnumberNoLabel Y offset
labelColorstringNoLabel color
labelAlign'left' | 'center' | 'right'NoLabel alignment

Circle

Supports both circles (equal radii) and ellipses (different radiusX/radiusY).

PropertyTypeRequiredDescription
idstringYesMachine-generated ID
xnumberYesCenter X position
ynumberYesCenter Y position
radiusXnumberYesHorizontal radius
radiusYnumberYesVertical radius
fillstringYesFill color
strokestringNoStroke color
strokeWidthnumberNoStroke width
rotationnumberNoRotation in degrees
scaleXnumberNoHorizontal scale
scaleYnumberNoVertical scale
opacitynumberNoOpacity (0-1)
lockedbooleanNoPrevent editing
labelstringNoDisplay label
labelFontSizenumberNoLabel font size
labelXnumberNoLabel X offset
labelYnumberNoLabel Y offset
labelColorstringNoLabel color
labelAlign'left' | 'center' | 'right'NoLabel alignment

Polygon

Regular polygons (triangles, hexagons, etc.).

PropertyTypeRequiredDescription
idstringYesMachine-generated ID
xnumberYesCenter X position
ynumberYesCenter Y position
radiusnumberYesDistance to vertices
sidesnumberYesNumber of sides (3-20)
fillstringYesFill color
strokestringNoStroke color
strokeWidthnumberNoStroke width
rotationnumberNoRotation in degrees
scaleXnumberNoHorizontal scale
scaleYnumberNoVertical scale
opacitynumberNoOpacity (0-1)
lockedbooleanNoPrevent editing
labelstringNoDisplay label
labelFontSizenumberNoLabel font size
labelXnumberNoLabel X offset
labelYnumberNoLabel Y offset
labelColorstringNoLabel color
labelAlign'left' | 'center' | 'right'NoLabel 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.

PropertyTypeDefaultDescription
readOnlybooleanfalseGlobal read-only mode — disables all editing
assignmentOnlybooleanfalsePricing assignment-only mode — blocks structural/visual edits while allowing pricing assignment
toolsobjectTool-level permissions (see below)
propertiesobjectProperties panel permissions (see below)

tools

PropertyTypeDefaultDescription
rowbooleantrueAllow seat row creation tool
tablebooleantrueAllow table creation tools
areabooleantrueAllow area creation tools
shapebooleantrueAllow shape tools (rectangle, circle, polygon, custom, line)
textbooleantrueAllow text creation tool
traceImagebooleantrueAllow trace image upload tool

properties

PropertyTypeDefaultDescription
showPropertiesbooleantrue (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.
settingsTabbooleantrueAllow access to the Settings tab in Properties Panel
pricingCategoriesCrudbooleantrueAllow creating/editing/deleting pricing categories
currencySettingsbooleantrueAllow changing currency and locale settings

warnings

PropertyTypeDefaultDescription
pricingCategoriesAssignmentSaveWarningbooleantrueShow warning when rows, areas, or tables don't have pricing categories assigned
pricingCategoriesAssignmentPanelWarningbooleantrueShow "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.

PropertyTypeDescription
selectionsSelectionItem[]Array of selection items — see subtypes below
lastSelectionSelectionItem | nullThe enriched SelectionItem for the most recently selected or modified item. null when an item is deselected or selections are cleared.
totalsobject{ 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.

PropertyTypeRequiredDescription
idstringYesUnique seat identifier
type'row-seat'YesDiscriminator for selection type
rowIdstringYesParent row identifier
rowLabelstringYesRow label (e.g., "A", "1")
seatLabelstringYesSeat label (e.g., "1", "12")
slugstringYesSeat slug
rowSlugstringYesRow slug
sectionIdstringNoSection identifier
sectionNamestringNoSection display name
sectionSlugstringNoSection slug
categoryIdstring | nullYesSelected pricing category ID, or null when the seat is uncategorized
categoryLabelstring | nullNoPricing category display label
categorySlugstring | nullNoPricing category slug
pricenumberYesPrice in cents

AreaSelection

Returned when a user selects spots in an area.

PropertyTypeRequiredDescription
idstringYesUnique area identifier
type'area'YesDiscriminator for selection type
areaLabelstringYesArea display label
slugstringYesArea slug
sectionIdstringNoSection identifier
sectionNamestringNoSection display name
sectionSlugstringNoSection slug
categoryIdstring | nullYesSelected pricing category ID, or null when the area is uncategorized
categoryLabelstring | nullNoPricing category display label
categorySlugstring | nullNoPricing category slug
quantitynumberYesNumber of spots selected
pricePerUnitnumberYesPrice per spot in cents
totalPricenumberYesTotal price in cents (quantity x pricePerUnit)

TableSeatSelection

Returned when a user selects an individual seat at a table (multiple-customer purchase type).

PropertyTypeRequiredDescription
idstringYesUnique table seat identifier
type'table-seat'YesDiscriminator for selection type
tableIdstringYesParent table identifier
tableLabelstringYesTable display label
seatLabelstringYesSeat label within the table
slugstringYesTable seat slug
tableSlugstringYesTable slug
sectionIdstringNoSection identifier
sectionNamestringNoSection display name
sectionSlugstringNoSection slug
categoryIdstring | nullYesSelected pricing category ID, or null when the seat is uncategorized
categoryLabelstring | nullNoPricing category display label
categorySlugstring | nullNoPricing category slug
pricenumberYesPrice in cents

WholeTableSelection

Returned when a user books an entire table (single-customer purchase type).

PropertyTypeRequiredDescription
idstringYesUnique table selection identifier
type'whole-table'YesDiscriminator for selection type
tableIdstringYesTable identifier
tableLabelstringYesTable display label
tableSlugstringYesTable slug
sectionIdstringNoSection identifier
sectionNamestringNoSection display name
sectionSlugstringNoSection slug
categoryIdstring | nullYesSelected pricing category ID, or null when the table is uncategorized
categoryLabelstring | nullNoPricing category display label
categorySlugstring | nullNoPricing category slug
quantitynumberYesNumber of people / units selected
pricePerUnitnumberYesPrice per unit in cents
totalPricenumberYesTotal price in cents (quantity x pricePerUnit)

SetSelectionsInput

Discriminated union input for setSelections(). Allows passing selections either by machine ID or by human-readable slug.

ModeShapeDescription
'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:

PropertyTypeDescription
type'row-seat'Selection type
slugstringRow seat slug (e.g., 'row-a-seat-1')
categorySlugstring | nullPricing category slug (e.g., 'standard'). Omit or set null for uncategorized seats.

Area:

PropertyTypeDescription
type'area'Selection type
slugstringArea slug (e.g., 'vip-lounge')
categorySlugstring | nullPricing category slug. Omit or set null for uncategorized areas.
quantitynumberNumber of units to select

Table Seat:

PropertyTypeDescription
type'table-seat'Selection type
slugstringTable seat slug (e.g., 'table-1-seat-3')
categorySlugstring | nullPricing category slug. Omit or set null for uncategorized table seats.

Whole Table:

PropertyTypeDescription
type'whole-table'Selection type
tableSlugstringTable slug (e.g., 'table-5')
categorySlugstring | nullPricing category slug. Omit or set null for uncategorized whole-table bookings.
quantitynumberNumber of people/units

SetSelectionsResult

The result returned by setSelections(). Reports which selections were applied and which failed, with per-item failure reasons.

PropertyTypeDescription
successbooleantrue only if all items were applied (no failures)
appliedSelectionItem[]Items that were successfully selected
failedSetSelectionsFailedItem[]Items that failed validation, each with a reason

SetSelectionsFailedItem

A selection item that failed validation during setSelections().

PropertyTypeDescription
selectionSelectionItemThe original input item that failed
reasonSetSelectionsFailureReasonWhy the item failed

SetSelectionsFailureReason

A string enum indicating why a selection item was rejected.

ValueDescription
'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', ... }).

PropertyTypeDescription
rowSeatsRecord<string, boolean>Map of seat ID to availability (true = available)
areasRecord<string, number | boolean>Map of area ID to available count (number), or boolean (true = 1, false = 0)
tableSeatsRecord<string, boolean>Map of table seat ID to availability
tablesRecord<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.

PropertyTypeDescription
rowSeatsRecord<string, boolean>Map of seat slug to availability
areasRecord<string, number | boolean>Map of area slug to available count (number), or boolean (true = 1, false = 0)
tableSeatsRecord<string, boolean>Map of table seat slug to availability
tablesRecord<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

PropertyTypeRequiredDescription
sectionIdstringNoSection ID (required if row/seat is ambiguous)
rowLabelstringYesRow label (e.g., "A", "1")
seatLabelstringYesSeat label (e.g., "1", "12")
isAvailablebooleanYesWhether the seat is available

AreaAvailabilityByLabel

PropertyTypeRequiredDescription
sectionIdstringNoSection ID (required if area name is ambiguous)
areaLabelstringYesArea label as defined in the layout
availableCountnumber | booleanYesNumber of available spots (0 = sold out), or boolean (true = 1, false = 0)

TableAvailabilityByLabel

PropertyTypeRequiredDescription
sectionIdstringNoSection ID (required if table name is ambiguous)
tableLabelstringYesTable label as defined in the layout
isAvailablebooleanYesWhether 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.

PropertyTypeRequiredDescription
availablestring[]NoCategory IDs (or slugs) whose entities should be available. Unlisted categories → entities unavailable. This is a full reset — every entity is re-evaluated.
unavailablestring[]NoCategory 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.
requirePricingCategorybooleanNoWhen true, uncategorized entities (empty pricingCategoryIds) are treated as unavailable. When provided, updates the picker-wide setting.

Semantics:

  • available only — Full reset. Entities assigned to listed categories become available; all others become unavailable.
  • unavailable only — Delta. Entities are flipped to unavailable only when every effective category ID is in the list. Others are unchanged.
  • Bothavailable is applied first (full reset), then unavailable overrides: entities whose entire set of effective category IDs appear in unavailable are 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.

PropertyTypeRequiredDescription
pricingCategoriesArray<{ id, ...fields }>YesArray of category partial updates

Partial Update Object (by ID)

PropertyTypeRequiredDescription
idstringYesCategory ID (must match existing category)
labelstringNoNew display label
slugstringNoNew slug
pricenumberNoNew price in cents
colorstringNoNew hex color
customerNotesstringNoNew 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 slug field is used only for matching — it is not merged into the category. To change a slug, use updatePricingCategoriesById and pass slug as an update field.

PropertyTypeRequiredDescription
pricingCategoriesArray<{ slug, ...fields }>YesArray of category partial updates

Partial Update Object (by Slug)

PropertyTypeRequiredDescription
slugstringYesCategory slug (used for matching only, not merged)
labelstringNoNew display label
pricenumberNoNew price in cents
colorstringNoNew hex color
customerNotesstringNoNew 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.

PropertyTypeRequiredDescription
mode'by-id' | 'by-slug' | 'dangerously-by-labels'YesHow to identify objects and categories

Mode: 'by-id'

Each property is a Record<objectId, categoryId[]> map:

PropertyTypeRequiredDescription
rowsRecord<string, string[]>NoMap of row ID to category IDs
rowSeatsRecord<string, string[]>NoMap of seat ID to category IDs
areasRecord<string, string[]>NoMap of area ID to category IDs
tablesRecord<string, string[]>NoMap of table ID to category IDs
tableSeatsRecord<string, string[]>NoMap 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.

PropertyTypeRequiredDescription
rowsArray<{ sectionId?, rowLabel, pricingCategorySlugs }>NoRow assignments by label
rowSeatsArray<{ sectionId?, rowLabel, seatLabel, pricingCategorySlugs }>NoSeat assignments by label
areasArray<{ sectionId?, areaLabel, pricingCategorySlugs }>NoArea assignments by label
tablesArray<{ sectionId?, tableLabel, pricingCategorySlugs }>NoTable assignments by label
tableSeatsArray<{ sectionId?, tableLabel, seatLabel, pricingCategorySlugs }>NoTable 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.

PropertyTypeDescription
successbooleantrue if all assignments applied, false if any validation failed
errorsstring[]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 }
      }
    }
  }
}