Reports are private organizer data. They describe the event’s durable inventory record, including immutable configured-price snapshots captured when inventory was booked. They are not a payment-provider or commercial-order ledger.
JSON report
/v1/events/:key/reportSecret key, dashboard session, or event:reports manage tokencurl -s "https://api.seatlayer.io/v1/events/ev_9f3a/report" \
-H "authorization: Bearer $SEATLAYER_SECRET_KEY"The response is {report, event, categories}.
{
"report": {
"byStatus": {
"free": 40,
"held": 3,
"booked": 55,
"not_for_sale": 2
},
"byCategory": [
{
"category": "vip",
"total": 80,
"free": 35,
"held": 2,
"booked": 41,
"not_for_sale": 2,
"bookedValue": 3075,
"bookedRevenue": 3075
}
],
"bySection": [
{
"sectionId": "sec-stalls",
"sectionLabel": "Stalls",
"zoneId": "floor-main",
"total": 400,
"free": 180,
"held": 4,
"booked": 206,
"not_for_sale": 10,
"bookedValue": 15450,
"bookedRevenue": 15450
}
],
"byAccessibility": [],
"byWheelchairProvision": []
},
"event": {
"key": "ev_9f3a",
"name": "Opening Night",
"status": "active",
"seatTotal": 1200
},
"categories": [
{
"key": "vip",
"label": "VIP",
"color": "#d97706",
"price": 75
}
]
}Interpret each breakdown
| Field | Meaning |
|---|---|
byStatus |
Guest-weighted totals for the entire event |
byCategory |
Status and configured booked value by category key |
bySection |
Status and configured booked value by event section, with zone id |
byAccessibility |
One row per accommodation type |
byWheelchairProvision |
Physical accessible seat versus empty wheelchair space |
A grouped table or variable-occupancy object is guest-weighted, so its
quantity contributes to capacity rather than counting the object once.
Accessibility rows are not mutually exclusive: one seat with multiple accommodations contributes to each matching row. Do not sum those rows to derive whole-event inventory.
bookedValue is the sum of stored configured-price snapshots in major currency
units for inventory that is currently booked. It changes when bookings are
cancelled and does not prove that a payment was charged, settled, or refunded.
bookedRevenue returns the same number as a deprecated compatibility alias.
CSV export
CSV downloads are dashboard/Control Room exports in this launch: they require a
dashboard session and reject secret keys. They are not published OpenAPI
operations or server-SDK methods. Server integrations should call the typed JSON
reports above and serialize the fields they need; do not depend on an internal
.csv route.
The response is a downloadable text/csv file with:
category,label,price,total,free,held,booked,not_for_sale,booked_valueA TOTALS row follows the category rows. Accessibility, wheelchair-provision,
and section breakdowns remain available in JSON because they are not one
mutually exclusive category table.
Sales channel report
/v1/events/:key/channels/reportSecret key, dashboard session, or event:channels:view manage tokenOne row per sales channel, plus Public sale. Each row carries two things that are easy to confuse and that move independently.
allocation |
Where inventory is assigned right now, and its physical status. Changes when you move seats. |
attribution |
Which channel each unit was sold from, recorded at the moment of booking and never rewritten. |
{
"report": {
"assignmentVersion": 7,
"includesBookedValue": true,
"includesRevenue": true,
"methodology": {
"allocation": "Current allocation: where inventory is assigned right now…",
"attribution": "Sale attribution: the channel each unit was sold from…",
"sellThrough": "Sell-through = attributed sold / current allocated…"
},
"rows": [
{
"channelId": "public",
"name": "Public sale",
"externalRef": null,
"state": "active",
"allocation": { "allocated": 800, "free": 612, "held": 4, "booked": 180, "blocked": 4, "units": 800 },
"attribution": { "sold": 180, "units": 180, "bookedValue": 8100, "revenue": 8100 },
"sellThrough": 0.225
},
{
"channelId": "chn_7f2a",
"name": "Travel Agency A",
"externalRef": "travel-agency-a",
"state": "active",
"allocation": { "allocated": 120, "free": 78, "held": 2, "booked": 40, "blocked": 0, "units": 120 },
"attribution": { "sold": 40, "units": 40, "bookedValue": 3000, "revenue": 3000 },
"sellThrough": 0.3333333333333333
}
],
"totals": {
"allocated": 1000, "free": 690, "held": 6, "booked": 220, "blocked": 4,
"sold": 220, "bookedValue": 11100, "revenue": 11100
}
},
"event": { "key": "ev_9f3a", "name": "Opening Night", "status": "active", "seatTotal": 1000 }
}bookedValue is the canonical configured-value field. revenue and
includesRevenue return the same values as deprecated compatibility aliases.
These are inventory attribution snapshots, not proof of a charge or settlement.
When creating a channel report link, send includesBookedValue: true to include
these configured values. The older includesRevenue request field remains an
additive compatibility alias; if both fields are sent, they must agree.
Sell-through, and why it can exceed 100%
sellThrough is attributed sold divided by current allocated. The numerator
is frozen at sale time; the denominator is live. So a channel whose remaining
inventory is moved out after it sold can report more than 1.0, and a channel
with no allocation left reports null rather than 0 — there is genuinely
nothing to divide by, which is not the same as “sold nothing”.
The same three sentences ship inside every response as methodology, so a
report you export or forward explains itself.
Who sees what
| Capability | Result |
|---|---|
event:channels:view |
Every allocation and attribution figure, with configured booked value hidden as bookedValue: null and includesBookedValue: false |
event:channels:view + event:reports |
The same report, with configured booked value in bookedValue |
event:reports alone |
403 missing_manage_capability |
Configured booked value is null, never 0, when you may not see it — a zero
would read as a channel that sold nothing.
Channel CSV export
Channel CSV is likewise a dashboard export rather than a stable server-SDK operation. Integrations should retrieve the typed channel report and generate their own file.
channel_id,channel,external_ref,state,allocated,free,held,booked,blocked,sold_by_attribution,sell_through,booked_value_by_attributionA TOTALS row follows. sell_through is a ratio, not a percentage string, so a
spreadsheet can format it; an empty cell means there is no current allocation to
divide by. The booked_value_by_attribution column is absent entirely when the caller
lacks event:reports.
Partner-facing channel reports
An organizer can share one channel without granting dashboard or API access. In Performance → Channel, choose Share partner report for a private channel. The generated URL opens a live, read-only projection containing one channel row and the exact inventory currently assigned to it.
The projection deliberately excludes event totals, sibling channel names, buyer identities, holds, and booking references. Configured booked value is excluded unless the organizer explicitly enables it for that link. The partner can search and filter the allocation or export the scoped inventory as CSV.
The URL capability appears after #, is removed from browser history before
the application starts, and is stored by SeatLayer only as a SHA-256 hash. The
organizer must copy it when it is created; later listings contain status, expiry,
view count, and last-viewed time, never the URL. Revoke the link to stop access
immediately.
Audit log
/v1/events/:key/logSecret key, dashboard session, or event:reports manage tokenEntries are newest first. limit defaults to 50 and is capped at 200. Pass the
returned nextBefore as before to retrieve older entries.
curl -s \
"https://api.seatlayer.io/v1/events/ev_9f3a/log?limit=50&before=405" \
-H "authorization: Bearer $SEATLAYER_SECRET_KEY"{
"entries": [
{
"id": 404,
"at": 1736897900000,
"action": "book",
"labels": ["A-1", "A-2"],
"ref": "order_5567"
}
],
"nextBefore": 354
}Actions include hold, replace, extend, book, release, expiry, block, unblock, unbook, reveal, and availability changes as those operations occur.
Incremental booking reconciliation
/v1/events/:key/booking-changesSecret key, dashboard session, or event:view/event:reports manage tokenPlatform events expose an oldest-first, append-only change feed for inventory bookings. Use it for a background reconciliation job that must discover later cancellations to older booking references without rescanning every booking.
curl -s \
"https://api.seatlayer.io/v1/events/ev_9f3a/booking-changes?after=418&limit=100" \
-H "authorization: Bearer $SEATLAYER_SECRET_KEY"{
"changes": [
{
"id": 419,
"action": "partial_cancel",
"at": 1786897900000,
"labels": ["A-2"],
"actor": "refund-worker",
"source": "server_api",
"booking": {
"eventKey": "ev_9f3a",
"bookingRef": "order_5567",
"state": "partially_cancelled",
"activeQuantity": 1,
"activeConfiguredValue": 75,
"currency": "USD"
}
}
],
"nextAfter": null,
"checkpoint": 419
}The numeric activity id—not bookedAt or updatedAt—is the cursor. That
matters because cancelling a week-old booking changes its current record while
its original booking time stays the same, and multiple changes may share one
millisecond.
Drain pages while nextAfter is non-null. After the final page, persist
checkpoint and send it as the next after. An empty poll echoes the same
checkpoint. Actions are book, replay, partial_cancel, cancel, and
reconcile; each change includes the current inventory-only booking record.
The feed contains no buyer, payment, refund, ticket, email, or door data.
Reporting checklist
- Keep configured booked value grouped by event currency.
- Do not label SeatLayer snapshots as payment-provider settlement.
- Do not sum overlapping accessibility rows.
- Export until
nextBeforeis null when a complete audit is required. - Persist the final booking-change
checkpointonly after your reconciliation write commits. - Restrict browser manage tokens to the event and
event:reports. - Store your own order, refund, tax, fee, and payment identifiers.
- Retain the event key and booking reference in every reconciliation record.
- Reconcile channel booked value by attribution, never by current allocation.
- State the sell-through denominator anywhere you republish the figure.
Archived events continue to serve reports. See event lifecycle and webhook delivery.