Getting started

Yes. The two products share concepts (partner, event, taste cluster) but the API surfaces are independent. You can ship a Lookout-only integration first and add Wave later.
Yes — see Environments. The sandbox resets weekly.
With this kit and one experienced engineer: ~3–5 days for a Lookout integration, ~2 weeks for full Wave. The hardest piece is the campaigns lifecycle wizard.
No. Future Demand hosts the canonical site at docs.future-demand.com. The source is in this repository if you want to fork it.

Auth

There is no separate static API key. The apikey scheme in the OpenAPI spec is actually Authorization: Bearer <Cognito JWT> — you obtain the JWT by signing in with username/password at POST /auth. See Authentication.
The most likely cause is a missing or wrong X-Preferred-Partner-Id header. Multi-partner users need to send the right partner; single- partner users still should. See Partner & Client.
Two common causes: (1) the refresh token is corrupted (e.g. only the access token was stored, then “refresh” sends a malformed value); (2) the user was logged out server-side via password reset. Re-sign-in.
Don’t. Turn MFA off for service accounts at provisioning time and rely on strong password + network controls. MFA is for interactive logins.

Endpoints and conventions

The backend expects the repeat style — repeated keys without brackets, no CSV. Use qs.stringify(..., { arrayFormat: "repeat" }) or the equivalent in your serialiser.
Historical reason. It’s unusual but documented. Most other writes accept a JSON body. The webapp uses query string for: POST /campaigns/, PUT /events/{eid}/client_campaign_status?..., POST /events/{eid}/series?..., POST /package_builder/packages/merge?packages_ids=.... Watch out for each.
The benchmark payload (/events/{eid}/benchmark) does this. Use the peak < 1.5 ? ×100 : ×1 heuristic — see Event Detail.
A handful of endpoints used by the reference webapp aren’t documented in the canonical spec:
  • /events/{eid}/client_campaign_status[/task]
  • /events/{eid}/campaign_optimisation_status
  • /events/{eid}/ad_campaign_optimisation_status
  • /events/{eid}/attribution_model
  • /events/{eid}/available_events_for_series
They are real, but spec drift means they may change. Confirm with Future Demand before relying on them.
The Customer Representation API is a separate service for event ingest, editing, simulation, and bulk upload. See Two-host architecture.

Wave wizard

Network reordering. The reference webapp uses a module-level AbortController to cancel any in-flight PUT before issuing a new one. Without it, you can have edit N+1 land before edit N. See Campaigns Lifecycle.
No — 404 means “no draft for this event yet”. Show the “Start setup” CTA and let the user POST /setup_processes/{eid} to begin.
Published campaigns are immutable as a whole — you edit one cluster at a time via POST /campaigns_setup (body carries eid, tc, tc_run_id). The draft endpoint PUT /setup_processes/{eid} only works while the setup is unpublished.
Two possibilities: (1) client-side validation passed but Meta rejected one of the assets — check /integrations/facebook/events/{eid}/...; (2) Meta auth expired — re-check /meta/authorization/status and prompt the user to reconnect.

Package Builder

Terminal statuses are DONE, FAILED, EXPIRED. Stop on any of those. Also gate the loop on an AbortController tied to component lifetime — the reference webapp doesn’t, and it leaks polls on unmount.
No. Call POST /package_builder/packages/{id}/regenerate to refresh it. The TTL is server-side; ask Future Demand for your tenant’s value.
tc is used raw (URL-encoded) in the per-package path. The campaign- side cid composite slugifies it. Two different conventions; URL- encode either way.

Operations

Not today. Poll, or talk to Future Demand if you have a hard real-time requirement.
Yes — see Rate limits. No headers expose them today; treat any 429 as “back off”.
Open a ticket at support.future-demand.com with the x-request-id from the failing response. We can trace across services in seconds with that.
Changelog — also emailed to your integrations contact ≥ 90 days in advance of any breaking change.