The Event detail page composes a full picture of one event: hero, demand prediction (benchmark + curve), daily revenue, and ticket-category breakdowns. The same component tree is reused by the Wave campaign detail.

What you’ll build

  • Hero (title, date, venue, status pills, action menu).
  • Demand prediction (benchmark + prediction curve, with a Capacity / Tickets toggle).
  • Daily revenue chart (with a Revenue / Tickets toggle, client-side).
  • Ticket categories + ticket type charts.
  • Side actions: edit, flag, archive, add sales, clear sales, edit series.

Prerequisites

  • An eid (from the Events list or a deep link).
  • Tenant-level partnerId set in your client.

The call chain

The reference FE fires these on mount (several in parallel). This is not an exhaustive list — it reflects the primary loads:
#MethodPathPurpose
1GET/events/{eid}Hero: title, date, venue_name, hall_name, city, frontend_status, category. 404 → not-found.
2GET/events/{eid}/lookout_prediction_benchmark?type=capacityBenchmark vs prediction.
3GET/events/{eid}/lookout_prediction?type=capacityDemand prediction curve.
4GET/daily_revenue_summary/?event_id=&currency=&start_date=1900-01-01&end_date=2100-01-01Daily revenue + manual adjustments.
5GET/events/{eid}/ticketsTicket category + type charts.
6GET/events/{eid}/series?limit=1000Sibling events in the series.
7GET/events/{eid}/campaignsCampaigns for the event (and any series members).
8GET/events/{eid}/attribution_modelCurrent attribution model.
9GET/integrations/facebook/events/{eid}/campaign_resultsCampaign stats (Statistics tab / Wave).
10GET/integrations/facebook/events/{eid}/fb_insightsImpressions / clicks / ad spend.
The reference FE on Event Detail does not call /events/{eid}/statistics (an fetchEventStatistics helper exists but is unused), and does not render a taste-clusters panel here (fetchTopClusters isn’t called). The KPI values on the Wave Statistics tab come from campaign_results + fb_insights, not /statistics. If you want a KPI bar driven by /events/{eid}/statistics, treat it as a separate integrator choice — it’s a valid API, just not what the reference FE wires here.

Demand prediction — endpoints and contract

GET /events/{eid}/lookout_prediction_benchmark?type=capacity     # or type=ticket_count
GET /events/{eid}/lookout_prediction?type=capacity               # or type=ticket_count
The type query param is required:
  • capacity — percentage mode (values are shares; multiply by 100 for display).
  • ticket_count — absolute values mode.

Benchmark response

{
  "now":        { "value": 0.42, "benchmark": 0.50 },
  "prediction": { "value": 0.78, "benchmark": 0.65 }
}
Each of now and prediction carries value and benchmark. There is no today field and no state field.
Do not implement a “scale auto-detection” heuristic. Scale is controlled entirely by the Capacity / Tickets toggle: when type=capacity, multiply by a fixed ×100 for display; when type=ticket_count, render the absolute values as-is.

Prediction curve response

{
  "sales": [
    { "mapped_date": "2026-05-01", "tickets_sold_actual": 120, "tickets_sold_predicted": 100 },
    { "mapped_date": "2026-05-02", "tickets_sold_actual": 180, "tickets_sold_predicted": 130 }
  ]
}
Use tickets_sold_actual, tickets_sold_predicted, and mapped_date. (The older norm_tickets_sold_* fields no longer apply.)

Ticket categories

GET /events/{eid}/tickets
Document/consume these response fields:
{
  "price_categories":     { "...": "..." },
  "tickets_per_category": { "...": "..." }
}
The reference FE multiplies values by 100 for chart display. It also calls this endpoint twice (once for the category chart, once for the type chart) — dedupe with a single fetch shared via context or your request cache.

Daily revenue

GET /daily_revenue_summary/?event_id={eid}&currency={cur}&start_date=1900-01-01&end_date=2100-01-01
currency comes from the user/tenant setting (the reference FE reads userCurrency from browser storage), not from a currency field on the event (there isn’t one). The canonical “all time” window uses start_date=1900-01-01 and end_date=2100-01-01.
The Revenue / Tickets toggle on this chart is client-side only — it flips which series renders; no extra GET.

Status updates (flag / archive) — the two-step sequence

export async function setFrontendStatus(
  eid: string,
  status: "FLAGGED" | "DEFAULT" | "HIDDEN" | "CANCELLED",
) {
  // Step 1 — main API
  await fd.put(`/events/${eid}/setup_frontend_status`, { frontend_status: status });

  // Step 2 — CR API on a different host.
  // CANCELLED only when frontend_status is CANCELLED; otherwise RUNNING
  // (including for HIDDEN).
  const crStatus = status === "CANCELLED" ? "CANCELLED" : "RUNNING";
  await fdCr.put(`/events/last_updated_on_fe/${eid}`, { status: crStatus });
}
The reviewer flagged this in two places (15.2, 16.2): HIDDEN does not map to CANCELLED. Only frontend_status === "CANCELLED" sends CANCELLED to the CR API. Everything else — including HIDDEN — sends RUNNING.

Other interactions

InteractionAPI calls
Open in Wavenavigate to /campaigns/{eid} (no API)
Edit (event)navigate to /events/edit/{eid} — see Event editor
Edit event series (modal)GET /events/{eid}/series?limit=1000; GET /events/{eid}/available_events_for_series?limit=1000; save POST /events/{eid}/series?event_series=...; remove DELETE /events/{eid}/series?event_series=...
Add salesnavigate to the update-sales flow — see Sales uploads
Clear salesDELETE /daily_revenue_summary?eid={eid} (FE treats 200 as success)
Toggle flaggedsetFrontendStatus(eid, "FLAGGED" | "DEFAULT")
ArchivesetFrontendStatus(eid, "HIDDEN"). The reference FE typically stays on the current URL after archive (history.push of the current pathname), not a hard redirect to /events.
Change attribution modelPUT /events/{eid}/attribution_model → refetch campaign_results + fb_insights
Capacity / Tickets togglere-request lookout_prediction* with type=capacity | ticket_count
Revenue / Tickets toggle (daily chart)none (client-side only)

Gotchas

The endpoints are /events/{eid}/lookout_prediction_benchmark and /events/{eid}/lookout_prediction, each requiring type=capacity or type=ticket_count.
Scale is the Capacity/Tickets toggle + fixed ×100 for capacity mode. Don’t infer fraction-vs-percent from the data.
Once per chart in the reference FE. Dedupe with a shared fetch.
Read it from the user/tenant setting, not event.currency (which doesn’t exist).
Even for non-Meta partners. Handle empty / 404 responses gracefully.
Only frontend_status === "CANCELLED" sends CANCELLED.