If you internalise one page in this documentation, make it this one. Almost every endpoint in the API lives somewhere on this tree, and a request that “doesn’t work” is usually a missing piece of context up the tree.

The hierarchy

Future Demand
├── Cognito User (sub)               You, as a person.
│   └── belongs to ──> Partner       The tenant you're acting under.

└── Partner (partner_id)             One per Future Demand customer
    ├── Users (Cognito group)        Members of this tenant.
    ├── Integrations                 Connected ad platforms (Meta, etc.) + grants.
    ├── Settings                     Pricing tier, attribution model defaults, ...
    ├── Clients                      Backend-side delivery surfaces (mostly 1:1 with partner).

    └── Events (eid)                 The thing you're selling or running.
        ├── Tickets                  Categories + price points.
        ├── Sales                    Ingested transactions over time.
        ├── Series                   Sibling events (multi-date tour, repeat dates).
        ├── Taste Clusters (tc)      Affinity-derived audience segments for this event.
        │   └── TC Run (tc_run_id)   One generation of the cluster set.

        └── Setup Process            One per event — the Wave campaign state machine.
            └── Campaigns (cid)      One per (event × taste cluster × tc_run).
                ├── Creative         Headline, body, media, CTA.
                ├── Targeting        Geography, demographics, custom audiences.
                └── Attribution      Backhaul model + window.

Why each level exists

The tenancy boundary. A partner has its own users, its own data, its own integrations. Every authenticated call must carry X-Preferred-Partner-Id to scope reads/writes — see Partner & Client.
A backend-side delivery target. In most partner integrations it is 1:1 with the partner; you usually don’t need to think about it. It surfaces in localStorage.partnerDetails.clientId in the reference webapp and in a handful of admin endpoints, but the canonical handle is partner_id.
The atom of demand. An event has a date, a venue, a capacity, a price structure, and a sales curve. Lookout is “the view of all your events”; Wave activates campaigns against an event. See Events.
A segment of likely buyers, computed by Affinity for one specific event. Clusters are versioned by tc_run_id — when an event’s data changes, a new run produces a new set, but old campaigns keep their tc_run_id for stability. See Recommendations.
A per-event row that holds the Wave campaign configuration while you’re editing it and after it’s published. The Wave wizard creates / updates / publishes the setup process; campaigns are derived from it. See Wave Campaigns Lifecycle.
The actual delivery unit. Each (event × taste cluster × tc_run) maps to one campaign, identified by the composite cid = {tc_run_id}__$ .

What gets sent on each request

IdentifierWhere it livesHow it’s passed
User identityCognito AccessTokenAuthorization: Bearer <token>
Partnercognito:groups matching partner-id-* or fd\d+X-Preferred-Partner-Id: <partner-id> header
EventURL path param/events/{eid}/...
Taste clusterURL path or body/events/{eid}/{tc}/... or { "tc": "..." }
CampaignComposite via tc_run_id/campaigns/{eid}/{tc}/{tc_run_id}/...
Read IDs and Hierarchy for the exact naming and rules.

A worked example

A user belongs to two partners. They want to activate a Wave campaign for a concert at Olympiahalle.
  1. Sign in → JWT carries cognito:groups: ["partner-id-acme", "partner-id-beta"].
  2. UI shows a partner picker; user selects partner-id-acme. Set X-Preferred-Partner-Id: partner-id-acme on all subsequent requests.
  3. GET /events/ returns Acme’s events. User clicks the concert (evt_abc).
  4. GET /events/evt_abc + GET /events/evt_abc/clusters populate Lookout. The clusters carry a tc_run_id of 42.
  5. POST /setup_processes/evt_abc starts a Wave draft. PUT /setup_processes/evt_abc autosaves each edit (creative, targeting).
  6. POST /setup_processes/evt_abc/boost publishes the campaigns. The platform creates one campaign per (evt_abc, <tc>, 42).
Same shape, different products — Lookout reads from the tree, Wave writes into the setup_processes branch.

Where this breaks down

  • Multi-partner users: if a user belongs to >1 partner, forgetting X-Preferred-Partner-Id is the #1 source of “why is my data wrong” bugs.
  • Stale tc_run_id: if you build a campaign against an old run, then refresh the event’s clusters, the new run gets a different id. Your campaign still references the old one — that’s intentional, but show the user that a newer recommendation is available.
  • Two API hosts: the main API and the Customer Representation API are two different hosts. Most calls hit the main API; EventEditor, Simulation, and bulk upload go to CR. See Two-host architecture.