Skip to content

Reports & analytics

Business analytics for your venues: a set of ready-made metric endpoints (covers, demand, operations, guests, reviews, vouchers, events…), a report builder you can query ad hoc or with a natural-language question, and saved reports and dashboards to come back to. Every endpoint is operator (client role) and scoped to venues you can access with venueId (omit it to combine every venue you can access) - send an Authorization: Bearer token from the Authentication flow. Some fields (guest names and contacts, exact revenue) only appear if your role has the matching permission grant - a role without it still gets the aggregate numbers, just without the sensitive detail.

Method Path Purpose Auth
GET /api/my-analytics/overview Home KPI overview operator
GET /api/my-analytics/heatmap Covers by day-of-week x hour operator
GET /api/my-analytics/calendar Covers/bookings per day for a month operator
GET /api/my-analytics/day Drill into one date’s bookings operator
GET /api/my-analytics/operations Table utilisation, turn time, no-shows operator
GET /api/my-analytics/guests Guest analytics (new vs returning, segments) operator
GET /api/my-analytics/demand Booking demand funnel operator
GET /api/my-analytics/reviews Guest review summary and list operator
GET /api/my-analytics/reviews/:id/booking The booking a review was for operator
POST /api/my-analytics/reviews/:id/flag Flag or unflag a review as fake operator
GET /api/my-analytics/vouchers Gift voucher performance operator
GET /api/my-analytics/events Per-event ticket performance operator
GET /api/my-analytics/revpash Revenue per available seat-hour operator
GET /api/my-analytics/revenue-reconciliation Key-paid bookings against ledger credit for a month operator
GET /api/my-analytics/brief Weekday trend summary operator
GET /api/my-analytics/export Bulk CSV/print export operator
GET /api/my-analytics/reports List standard one-click reports operator
GET /api/my-analytics/catalog Report builder’s field catalogue operator
POST /api/my-analytics/report Run an ad-hoc report operator
POST /api/my-analytics/nl-report Turn a question into a report operator, Aimy add-on
GET /api/my-analytics/saved List saved reports operator
POST /api/my-analytics/saved Save a report operator
PUT /api/my-analytics/saved/:id Update a saved report operator
DELETE /api/my-analytics/saved/:id Delete a saved report operator
GET /api/my-analytics/dashboards List dashboards operator
POST /api/my-analytics/dashboards Create a dashboard operator
PUT /api/my-analytics/dashboards/:id Update a dashboard operator
DELETE /api/my-analytics/dashboards/:id Delete a dashboard operator
POST /api/my-analytics/dashboards/:id/pin Pin/unpin a dashboard operator
GET /api/my-analytics/dashboards/:id/render Render a dashboard’s panels operator
GET /api/my-analytics/prebuilt-dashboards List Sidedoor’s curated dashboards operator
GET /api/my-analytics/prebuilt-dashboards/:id/render Render a curated dashboard operator

GET /api/my-analytics/overview is the analytics home screen: headline KPIs (bookings, covers, unique guests, no-show rate, average rating, review count), a trend series, covers by hour, and a per-venue breakdown. Takes days (0-730, default 90) and venueId.

Terminal window
curl "https://thesidedoor.co/api/my-analytics/overview?days=90" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
{
"period": "2026-04-19/2026-07-17",
"days": 90,
"kpis": { "bookings": 640, "covers": 1920, "uniqueGuests": 1040, "noShowRate": 4.2, "avgRating": 4.6, "reviewCount": 212 },
"trend": [{ "date": "2026-07-17", "covers": 86, "bookings": 28 }],
"hourly": [{ "hour": 19, "covers": 320 }],
"byVenue": [{ "id": "ven_123", "name": "The Attic", "covers": 1920 }]
}

GET /api/my-analytics/heatmap buckets covers by day-of-week and hour, in each venue’s own local time, with days and venueId. GET /api/my-analytics/calendar returns covers and bookings per day for one month (YYYY-MM).

Terminal window
curl "https://thesidedoor.co/api/my-analytics/heatmap?days=90" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
curl "https://thesidedoor.co/api/my-analytics/calendar?month=2026-07" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
{ "period": "...", "days": 90, "minHour": 11, "maxHour": 23, "peak": { "dow": 5, "hour": 20, "covers": 140 }, "grid": [[0, 0, 4]] }
{
"month": "2026-07",
"days": { "2026-07-17": { "covers": 86, "bookings": 28 } },
"totalCovers": 1920,
"totalBookings": 640,
"maxCovers": 140
}

grid is a 7 x 24 matrix of covers, one row per day of the week.

GET /api/my-analytics/day drills into a single date’s bookings and reservations, in order. Takes date (required, YYYY-MM-DD) and venueId. The guest field on each row only appears with the guest-PII permission grant.

Terminal window
curl "https://thesidedoor.co/api/my-analytics/day?date=2026-07-17" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
{
"date": "2026-07-17",
"items": [{ "time": "19:30", "covers": 4, "status": "seated", "venue": "The Attic" }],
"totalCovers": 86,
"bookings": 28,
"pii": false
}

GET /api/my-analytics/operations covers table-service KPIs: table utilisation, average turn time, overstay, and the economics of no-shows (lost covers, and where relevant lost minimum spend or deposits recovered). Takes days (0-365) and venueId.

Terminal window
curl "https://thesidedoor.co/api/my-analytics/operations?days=30" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
{
"period": "...",
"days": 30,
"utilisation": { "pct": 68 },
"turnTime": { "avgMinutes": 92 },
"overstay": { "avgMinutes": 11 },
"noShow": { "rate": 4.2, "count": 12, "settled": 9, "lostCovers": 40 }
}

GET /api/my-analytics/guests returns new-vs-returning and cross-venue guest analytics, visit-frequency and segment breakdowns, and a ranked guest list. Takes window, venueId, limit, offset, sort, dir, and format=csv to stream the guest list as a file instead of JSON.

Terminal window
curl "https://thesidedoor.co/api/my-analytics/guests?window=90&limit=25" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
{
"window": 90,
"pii": true,
"summary": { "newGuests": 420, "returningGuests": 620 },
"visitFrequency": [{ "visits": 1, "guests": 420 }],
"segments": [{ "name": "Big spenders", "guests": 84 }],
"guests": [{ "id": "gst_1", "name": "Sam Lee", "visits": 6, "lastVisit": "2026-07-10" }]
}

name/contact fields on guests are real guest data without the PII grant they’re omitted - use fake values in your own examples regardless.

GET /api/my-analytics/demand tracks the booking funnel (searched → availability shown → checkout started → booked) by day and by hour of week, with days and venueId.

Terminal window
curl "https://thesidedoor.co/api/my-analytics/demand?days=30" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
{
"days": 30,
"from": "2026-06-17",
"to": "2026-07-17",
"available": 2400,
"searched": 2400,
"checkoutStarted": 980,
"booked": 640,
"byDay": [{ "date": "2026-07-17", "searched": 90, "booked": 28 }],
"byHourOfWeek": [{ "dow": 5, "hour": 19, "searched": 40, "booked": 14 }]
}

GET /api/my-analytics/reviews returns a review summary (total, average rating, how many are 4-star-and-above, a rating distribution) and a paged list, with window, limit, offset, venueId, and q to search. GET /api/my-analytics/vouchers returns gift voucher performance: issued, redeemed, outstanding and expired counts, redemption and breakage rates, and revenue by currency, with days and venueId.

Terminal window
curl "https://thesidedoor.co/api/my-analytics/reviews?window=90&limit=25" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
curl "https://thesidedoor.co/api/my-analytics/vouchers?days=90" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
{
"window": 90,
"pii": false,
"summary": { "total": 212, "avgRating": 4.6, "fourPlus": 190, "fourPlusPct": 90, "lowCount": 6, "distribution": { "5": 140, "4": 50, "3": 16, "2": 4, "1": 2 } },
"reviews": [{ "id": "rev_1", "venueId": "ven_123", "venueName": "The Attic", "rating": 5, "comment": "Lovely evening", "categoryRatings": { "service": 5, "food": 5 }, "recommend": true, "createdAt": "2026-07-10T20:00:00Z" }]
}
{
"period": "...",
"days": 90,
"counts": { "issued": 140, "redeemed": 96, "outstanding": 38, "expired": 6 },
"redemptionRate": 68.6,
"breakageRate": 4.3,
"byCurrency": { "gbp": { "issuedPence": 700000, "redeemedPence": 480000 } }
}

A review row with a guest’s name or email attached (with the PII grant) is real guest data - use fake values when trying this yourself.

GET /api/my-analytics/reviews/:id/booking reads the booking a review was left for (a table reservation, guest-list spot or event booking), with its date, party size and a timeline of milestones (paid, checked in, closed, and so on). It returns { "booking": null } for a review that isn’t tied to a booking.

{
"booking": {
"kind": "reservation",
"ruleType": "tables",
"typeLabel": "Reservation",
"id": "res_123",
"date": "2026-07-10",
"time": "20:00",
"partySize": 4,
"status": "closed",
"statusLabel": "Closed",
"eventName": null,
"tableLabel": "12",
"milestones": [
{ "key": "paid", "label": "Paid", "at": "2026-07-10T19:40:00Z" },
{ "key": "checked_in", "label": "Checked in", "at": "2026-07-10T20:05:00Z" },
{ "key": "closed", "label": "Closed", "at": "2026-07-10T22:00:00Z" }
]
}
}

POST /api/my-analytics/reviews/:id/flag flags a review as fake, or clears the flag. A flagged review stays in the list but is left out of every rating (the summary above, the venue’s Sidedoor rating, and the daily rollup). Send { "flagged": true } to flag, or { "flagged": false } to clear it.

Terminal window
curl -X POST "https://thesidedoor.co/api/my-analytics/reviews/rev_1/flag" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"flagged": true}'

GET /api/my-analytics/events returns per-event ticket performance: sell-through, attendance and revenue, with days and venueId.

Terminal window
curl "https://thesidedoor.co/api/my-analytics/events?days=90" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
{
"period": "...",
"days": 90,
"totals": { "sold": 640, "capacity": 800, "attended": 590 },
"revenueByCurrency": { "gbp": 1280000 },
"events": [{ "id": "evt_1", "name": "Live jazz night", "date": "2026-07-20", "venue": "The Attic", "sold": 80, "capacity": 100, "attended": 74, "sellThroughPct": 80, "attendancePct": 92.5 }]
}

GET /api/my-analytics/revpash returns revenue per available seat-hour, per venue, each in its own currency, for one period (YYYY-MM) - it needs the revenue permission grant. GET /api/my-analytics/brief is a shorter weekday-trend summary (recent vs. prior period, broken down by weekday) - the same facts Aimy reasons over when you ask it a question in the portal. Takes venueId, days and period.

Terminal window
curl "https://thesidedoor.co/api/my-analytics/revpash?period=2026-07" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
curl "https://thesidedoor.co/api/my-analytics/brief?days=30" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
{ "period": "2026-07", "venues": [{ "id": "ven_123", "name": "The Attic", "currency": "gbp", "revpashPence": 420 }] }
{
"brief": {
"totals": { "recent": { "covers": 1920, "bookings": 640 }, "prior": { "covers": 1780, "bookings": 590 } },
"byWeekday": [{ "weekday": "Friday", "covers": 420, "bookings": 140, "noShows": 6, "revenuePence": 820000 }]
},
"has_data": true
}

GET /api/my-analytics/revenue-reconciliation checks that every booking paid with keys in a month has a matching credit on your account. It needs the revenue permission grant and access to every venue (it can’t be scoped to one). Takes period (YYYY-MM, defaults to the current month).

Terminal window
curl "https://thesidedoor.co/api/my-analytics/revenue-reconciliation?period=2026-07" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
{
"period": "2026-07",
"bookingsKeyPaid": 42,
"grossKeyValuePence": 168000,
"ledgerAccruals": 42,
"ledgerCreditPence": 168000,
"drift": 0,
"ok": true
}

drift is bookingsKeyPaid minus ledgerAccruals; above zero means a booking is missing its credit, and ok is false.

GET /api/my-analytics/export downloads a bulk export of type (reservations, guests, events, payments or vouchers) as format (csv, default, or print for an HTML page suited to printing/PDF), over a window of days and optionally one venueId. Each type needs its own elevated permission grant (guest-PII for reservations/guests, revenue for payments/vouchers), and the endpoint is rate-limited to 20 requests per 5 minutes per account.

Terminal window
curl "https://thesidedoor.co/api/my-analytics/export?type=reservations&window=30" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-o reservations.csv

The response is the file itself (text/csv or text/html), not JSON - this can contain real guest and payment data, so handle downloaded files the way you would any other export of customer data.

Beyond the ready-made metrics above, you can query your own data directly. GET /api/my-analytics/catalog returns the field catalogue filtered to your grants: available metrics, dimensions, filter fields, chart types, comparison periods, and live filter-option lists (venues, events, statuses, campaigns) - use it to construct a report spec. GET /api/my-analytics/reports lists Sidedoor’s standard one-click report cards you’re allowed to run. POST /api/my-analytics/report runs any report spec (a metric, a dimension, filters and a chart type - built from the catalogue above) and returns its series and summary.

Terminal window
curl "https://thesidedoor.co/api/my-analytics/catalog" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
curl -X POST "https://thesidedoor.co/api/my-analytics/report" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"metric": "covers", "dimension": "weekday", "chart": "bar"}'
{
"metrics": [{ "key": "covers", "label": "Covers" }],
"dimensions": [{ "key": "weekday", "label": "Day of week" }],
"filterFields": [{ "key": "venue", "label": "Venue" }],
"filterOptions": { "venue": [{ "id": "ven_123", "name": "The Attic" }] },
"chartTypes": ["bar", "line", "table"],
"comparePeriods": ["previous_period", "previous_year"]
}
{ "data": [{ "id": "rep_bookings_trend", "title": "Bookings trend", "chart": "line" }] }
{
"series": [{ "label": "Friday", "value": 420 }],
"summary": { "total": 1920 }
}

POST /api/my-analytics/nl-report uses the Aimy add-on to turn a plain question into a validated report spec, run it, and return both - send { "question" }. It needs the add-on enabled with allowance remaining (403 otherwise).

Terminal window
curl -X POST "https://thesidedoor.co/api/my-analytics/nl-report" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"question": "Which day of the week do we get the most covers?"}'
{
"question": "Which day of the week do we get the most covers?",
"spec": { "metric": "covers", "dimension": "weekday", "chart": "bar" },
"report": { "series": [{ "label": "Friday", "value": 420 }], "summary": { "total": 1920 } },
"tokens": 140,
"cached": false,
"usage": { "allowance": 5000, "used": 1520, "remaining": 3480, "unit": "tokens" }
}

Save a report spec from the builder to come back to it later. GET /api/my-analytics/saved lists your saved reports (your own and ones shared with you), filterable with owner (mine, shared or all) and searchable with q. POST /api/my-analytics/saved saves one - send { "title", "spec", "isShared"? } where spec is a report spec of the shape used by POST /report. PUT /api/my-analytics/saved/:id updates a saved report’s title, spec or sharing (owner only); DELETE /api/my-analytics/saved/:id deletes it (owner only).

Terminal window
curl -X POST "https://thesidedoor.co/api/my-analytics/saved" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title": "Covers by weekday", "spec": {"metric": "covers", "dimension": "weekday", "chart": "bar"}}'
{ "reports": [{ "id": "rep_1", "title": "Covers by weekday", "spec": { "metric": "covers" }, "isShared": false, "mine": true, "updatedAt": "2026-07-17T20:00:00Z" }] }
{ "ok": true, "id": "rep_1" }

A dashboard is an ordered set of saved reports shown as tiles. GET /api/my-analytics/dashboards lists your dashboards (your own and shared ones, pinned first). POST /api/my-analytics/dashboards creates one - send { "title", "items": [{ "reportId", "size" }], "isShared"? }, where size is stat, wide, wide3 or full. PUT /api/my-analytics/dashboards/:id updates a dashboard’s title, items or sharing (owner only); DELETE /api/my-analytics/dashboards/:id deletes it (owner only). POST /api/my-analytics/dashboards/:id/pin pins or unpins it for you with { "pinned": boolean }. GET /api/my-analytics/dashboards/:id/render runs every panel through the report engine and returns the results together - any panel you no longer have permission for, or whose report was deleted, is silently skipped.

Terminal window
curl -X POST "https://thesidedoor.co/api/my-analytics/dashboards" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title": "Weekly review", "items": [{"reportId": "rep_1", "size": "wide"}]}'
curl "https://thesidedoor.co/api/my-analytics/dashboards/dsh_1/render" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
{ "dashboards": [{ "id": "dsh_1", "title": "Weekly review", "items": [{ "reportId": "rep_1", "size": "wide" }], "isShared": false, "mine": true, "pinned": true, "updatedAt": "2026-07-17T20:00:00Z" }] }
{ "title": "Weekly review", "panels": [{ "reportId": "rep_1", "title": "Covers by weekday", "size": "wide", "series": [{ "label": "Friday", "value": 420 }] }] }

GET /api/my-analytics/prebuilt-dashboards lists Sidedoor’s own curated dashboard templates that you have the permissions to run. GET /api/my-analytics/prebuilt-dashboards/:id/render renders one, with date (an optional anchor trading day) and days.

Terminal window
curl "https://thesidedoor.co/api/my-analytics/prebuilt-dashboards" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
curl "https://thesidedoor.co/api/my-analytics/prebuilt-dashboards/weekly-overview/render?days=7" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
{ "dashboards": [{ "id": "weekly-overview", "title": "Weekly overview", "description": "Covers, revenue and no-shows for the week", "period": "7 days", "panelCount": 6 }] }
{ "title": "Weekly overview", "description": "Covers, revenue and no-shows for the week", "panels": [{ "title": "Covers", "series": [{ "label": "Mon", "value": 260 }] }] }