The Event editor lets a partner correct an event’s metadata after it’s been ingested — title, description, category, lineups, setlists, venue, hall, city, capacity, price, and special-ad category — and re-submit it to the Customer Representation model.
This page is the only Lookout surface that lives on the CR API for both read and write. Different host, different base URL. Get this wrong and you get a 404 or a 401 with a confusing message.

What you’ll build

  • A form pre-filled with the event’s current values.
  • Submit handler that POSTs to the CR API.
  • A “changes detected” heuristic that signals to the backend whether recommendations should be refreshed for this event.

Prerequisites

  • An eid.
  • partnerDetails.product from your client store (sourced from localStorage in the reference webapp). Drives the partner_product query param.
  • User has Lookout or Wave access.

The call chain

On mount:
#MethodPathHostPurpose
1GET/events/{eid}CR APIRaw event payload (includes lineups_raw, description — not on the slim main-API view).
On submit:
#MethodPathHostPurpose
2PUT/events/{eid}?event_type={prisma|fdlive}&partner_product={product}&itc_retry={bool}CR APIPersist the edited event. Body = full event payload.
Then redirect:
/events?drawer-open=true&event-id={eid}&tab=0   // if user has Lookout
/campaigns?drawer-open=true&event-id={eid}      // if user only has Wave

URL params on the PUT

ParamValuesWhen
event_typeprisma if the event’s category is product, else fdliveAlways.
partner_productOne of the partner’s registered products (from localStorage.partnerDetails.product)Always. Mismatch ⇒ 422.
itc_retrytrue if any field that affects recommendations changed (see below), else falseAlways.

Detecting recommendation-relevant changes

When certain fields change, the backend should refresh the event’s taste-cluster recommendations. The reference webapp computes this client-side:
const RECO_RELEVANT_FIELDS = [
  "title",
  "description",
  "category",
  "lineups",
  "setlists",
  "venue",
  "hall",
  "city",
  "capacity",
  "special_ad_category",
];

const itc_retry = RECO_RELEVANT_FIELDS.some(f =>
  !deepEqual(original[f], current[f])
);
Send the result as the itc_retry query param on the PUT. The backend honours it.

Body shape

The form posts back the full event with whatever the user edited:
{
  "title":               "Concert at Olympiahalle (rescheduled)",
  "description":         "...",
  "category":            "concert",
  "venue":               "Olympiahalle",
  "hall":                "Main Hall",
  "city":                "München",
  "capacity":            12000,
  "date":                "2026-06-12",
  "time":                "18:30",
  "tz":                  "Europe/Berlin",
  "price":               { "min": 25, "max": 145 },
  "lineups":             [{ "name": "Headliner", "starts_at": "20:00" }],
  "setlists":            [],
  "special_ad_category": null
}

Reference implementation

import { fdCr } from "./fd-cr";

export async function loadEvent(eid: string) {
  return fdCr.get<RawEvent>(`/events/${eid}`);
}

export async function saveEvent(
  eid: string,
  category: string,
  partnerProduct: string,
  itcRetry: boolean,
  body: RawEvent,
) {
  const eventType = category === "product" ? "prisma" : "fdlive";
  const query = new URLSearchParams({
    event_type:      eventType,
    partner_product: partnerProduct,
    itc_retry:       String(itcRetry),
  });
  return fdCr.put(`/events/${eid}?${query}`, body);
}
Where fdCr is the CR API axios instance — different baseURL than your main fd client. See CORS & two-host architecture.

Forcing a recommendation refresh without changes

If a user wants to force a recommendation refresh without changing any event fields, send the save with itc_retry=true and an unchanged payload. The backend treats the flag as the trigger.

Gotchas

Both the GET (load) and the PUT (save) live on the CR API. Mixing it up with the main /v3/events/{eid} (which returns a different, slimmer shape) is the #1 mistake here.
The CR API 422s if event_type=prisma is sent for a non-product partner, or if partner_product doesn’t match the partner’s registration. Don’t derive event_type from a UI toggle — derive it from category.
The reference webapp redirects to /events if the user has Lookout access, otherwise /campaigns. Mirror that — sending Wave-only users to /events produces an empty-state page.
Don’t send true on every save — it costs the backend a refresh. Use the field-comparison heuristic above so only edits that actually affect recommendations trigger it.