Data contract — venue build
A build is an immutable directory published by the venue pipeline:
venues/{slug}/{build_id}/manifest.json
venues/{slug}/{build_id}/map.json
venues/{slug}/{build_id}/sections/{SECTION}/{product}_{view}[_r{row}].jpg
venues/{slug}/{build_id}/sections/{SECTION}/thumb.jpg
venues/{slug}/{build_id}/panos/{SECTION}/{candidate}/{Front|Back|Left|Right|Up|Down}.jpg
venues/{slug}/{build_id}/map/{product}/{layer}.jpg
venues/{slug}/latest # text: build_id
manifest.json
{
"venue": "united-center",
"build_id": "b20260904-1a2b3c",
"generated_at": "2026-09-04T18:00:00Z",
"source": "iomedia-virtual-venue",
"name": "United Center",
"products": [
{ "id": "bulls", "label": "Bulls", "surface": "basketball", "embed": "full" },
{ "id": "blackhawks", "label": "Blackhawks", "surface": "hockey", "embed": "full" },
{ "id": "events-180", "label": "180° Event", "surface": "stage", "embed": "full" }
],
"levels": [ { "id": "overview", "name": "Seating Bowl" } ],
"modes": [ { "id": "bulls_seat", "product": "bulls", "view": "seat", "label": "Bulls · Seat" } ],
"sections": [
{
"section": "B27",
"category": "Banner Level Suite",
"displayName": "Banner Suite 27",
"totalSeats": 12,
"defaultMode": "bulls_seat",
"humanReviewed": true,
"images": { "bulls_seat": "/venues/united-center/sections/B27/bulls_seat.jpg" },
"vantages": { "5": { "bulls_seat": "/venues/united-center/sections/112/bulls_seat_r5.jpg" } },
"thumb": "/venues/united-center/sections/B27/thumb.jpg",
"iomediaUrl": "https://bulls.io-media.com/#/vr/Suite/B27/GA/13/d",
"iomediaUrls": { "bulls_seat": "https://bulls.io-media.com/#/vr/Suite/B27/GA/13/d" },
"panos": { "bulls_seat": { "Front": "/venues/united-center/panos/B27/bulls_seat/Front.jpg", "Back": "…", "Left": "…", "Right": "…", "Up": "…", "Down": "…" } }
}
]
}
vantages, thumb, and iomediaUrl are optional. Image paths are
root-relative and prefixed by the SDK with its asset base.
panos (optional) holds six 1024px cube faces per candidate id; the SDK
renders them natively and only falls back to the IOMEDIA iframe when absent.
products[].embed says which IOMEDIA route the iframe may use: direct
(panorama-only router) or full (whole sales app).
products[].surface is one of baseball | basketball | hockey | football | soccer | stage | none and drives the painted surface in the flat theme.
products[].surfaceSpec (optional, baseball) carries the ballpark's real
geometry in feet by bearing from the home→centre axis: fence polyline,
cf_feet, warning_track_feet, batters_eye, pool, bullpens. With a spec
the SDK draws the actual outfield shape and landmarks (Chase Field: 330/374/413
alleys, flat 407 centre wall, pool behind right-centre) instead of a generic fan. The
first level listed is the SDK's default; the pipeline puts the whole-venue
level (overview) first.
map.json
{
"camera": "Aerial_Camera_Overview",
"products": {
"bulls": {
"levels": [
{
"id": "overview", "name": "Seating Bowl",
"image": "/venues/united-center/map/bulls/OV_FullStadium.jpg",
"width": 1024, "height": 768,
"sections": [
{ "section": "112", "vantage": "5", "label": "112",
"polygons": [[[x,y],[x,y],[x,y]]], "labelAt": [512, 400], "labelW": 38 }
]
}
]
}
}
}
Shapes with section: null are decorative context (stage, floor). A bowl
section may appear once per row band with distinct vantage values; only
the largest carries a non-zero labelW, so it gets the label.
Section keys are the join key between the map, the manifest, the host page's listing, and inventory adapters. They are stable across builds.