Set these once at the top of your shell session:
export BASE=https://client-api.stg.future-demand.com/api/v3
export FD_USER=you@partner.com
export FD_PASS='...'

Auth — sign in and stash tokens

RESP=$(curl -s -X POST "$BASE/auth" \
  -H "Content-Type: application/json" \
  -d "{\"username\":\"$FD_USER\",\"password\":\"$FD_PASS\"}")

export FD_ACCESS_TOKEN=$(echo "$RESP"  | jq -r .AccessToken)
export FD_ID_TOKEN=$(echo "$RESP"      | jq -r .IdToken)
export FD_REFRESH_TOKEN=$(echo "$RESP" | jq -r .RefreshToken)

# Extract the first partner-id from cognito:groups
export FD_PARTNER_ID=$(echo "$FD_ID_TOKEN" | cut -d. -f2 | base64 -d 2>/dev/null \
  | jq -r '."cognito:groups"[]' | grep -E '^(partner-id-|fd[0-9]+)' | head -1)

echo "Signed in as $FD_USER, partner $FD_PARTNER_ID"
A reusable header alias:
alias fd='curl -s -H "Authorization: Bearer $FD_ACCESS_TOKEN" -H "X-Preferred-Partner-Id: $FD_PARTNER_ID"'

Refresh

curl -s -X POST "$BASE/auth/refresh_token" \
  -H "Content-Type: application/json" \
  -d "{\"token\":\"$FD_REFRESH_TOKEN\"}" \
  | jq

Partner / profile

fd "$BASE/partners/"   | jq
fd "$BASE/profile/"    | jq
fd "$BASE/features/"   | jq
fd "$BASE/permissions" | jq

Events — list and detail

fd "$BASE/events/?page=1&limit=5&descending=false" | jq

EID=$(fd "$BASE/events/?limit=1" | jq -r '.items[0].id')
echo "Picked $EID"

fd "$BASE/events/$EID"                    | jq
fd "$BASE/events/$EID/statistics"         | jq
fd "$BASE/events/$EID/benchmark"          | jq
fd "$BASE/events/$EID/sales-graph"        | jq
fd "$BASE/events/$EID/tickets"            | jq
fd "$BASE/events/$EID/clusters"           | jq
fd "$BASE/events/$EID/campaigns?limit=10" | jq

Affinity recommendations

fd "$BASE/events/$EID/suggested_tcs?budget=5000&goal=tickets"          | jq
fd "$BASE/events/$EID/campaigns_expected_value?budget=5000&goal=tickets" | jq
fd "$BASE/events/$EID/budget_min_max?runtime_in_days=14"               | jq
fd "$BASE/events/$EID/default_campaigns_parameters"                    | jq
fd "$BASE/setup_processes/call_to_action/?goal=tickets&has_pixel=true&lead_form_id=" | jq

Wave — campaigns lifecycle

# Read existing draft (404 = no draft)
fd "$BASE/setup_processes/$EID" | jq

# Create draft
fd -X POST "$BASE/setup_processes/$EID" \
  -H "Content-Type: application/json" \
  -d '{
    "goal": "tickets",
    "total_budget": 5000,
    "start_date": "2026-05-25",
    "end_date":   "2026-06-12",
    "tc_run_id":  42,
    "creatives": {},
    "targeting": {}
  }' | jq

# Update (debounced autosave in a real UI)
fd -X PUT "$BASE/setup_processes/$EID" \
  -H "Content-Type: application/json" \
  -d '{ "goal": "tickets", "total_budget": 6000, "start_date": "2026-05-25", "end_date": "2026-06-12", "tc_run_id": 42, "creatives": {}, "targeting": {} }' | jq

# Publish
fd -X POST "$BASE/setup_processes/$EID/boost" | jq

# Edit one published cluster
fd -X POST "$BASE/campaigns_setup" \
  -H "Content-Type: application/json" \
  -d "{
    \"eid\":      \"$EID\",
    \"tc\":       \"family_outings_munich\",
    \"tc_run_id\": 42,
    \"audience_id\": \"aud_777\",
    \"creatives\": {},
    \"targeting\": {}
  }" | jq

# Cancel / reset
fd -X DELETE "$BASE/setup_processes/$EID?cancel=true" | jq
fd -X PUT    "$BASE/events/$EID/reset_campaigns_setup" | jq

Wave — Package Builder

# Create package
PKG=$(fd -X POST "$BASE/package_builder/packages" \
  -H "Content-Type: application/json" \
  -d '{
    "num_packages":   3,
    "n_top_events":   3,
    "event_ids":      [12345],
    "package_title":  "Test",
    "targeting_mode": "lookalike",
    "filters":        {}
  }' | jq -r .id)

echo "Created $PKG"

# Poll status
while true; do
  STATUS=$(fd "$BASE/package_builder/packages/$PKG" | jq -r .status)
  echo "$(date +%T) — $STATUS"
  case "$STATUS" in DONE|FAILED|EXPIRED) break;; esac
  sleep 5
done

# Download cluster CSV
fd "$BASE/package_builder/packages/$PKG/family_outings_munich/customer_list" \
  -o family_outings_munich.csv

# Backhaul evaluation
fd "$BASE/package_builder/packages/$PKG/backhaul_evaluation_details" | jq
fd -X PUT "$BASE/package_builder/packages/$PKG/backhaul_evaluation_details" \
  -H "Content-Type: application/json" \
  -d '{
    "backhaul_evaluation_attribution_window": 14,
    "backhaul_evaluation_model":              "EVENTS_FROM_PACKAGE",
    "email_sent_date":                        "2026-06-01"
  }' | jq

fd "$BASE/package_builder/packages/$PKG/backhaul_evaluation" | jq

Attribution

fd "$BASE/campaign_results/?eid=$EID&partner_id=$FD_PARTNER_ID" | jq
fd "$BASE/events/$EID/attribution_model"                       | jq

Messages / Notifications

fd "$BASE/messages/partner/?limit=10&page=1"   | jq
fd "$BASE/messages/totalunread"                | jq
fd "$BASE/notifications/?limit=10"             | jq
fd "$BASE/notifications/stats"                 | jq

Sales — manual ingest

fd -X POST "$BASE/ingest/transaction_summary" \
  -H "Content-Type: application/json" \
  -d "{
    \"eid\":  \"$EID\",
    \"from\": \"2026-06-01\",
    \"to\":   \"2026-06-12\",
    \"tickets\": [
      { \"type\": \"standard\", \"sold\": 412, \"revenue\": 18540 }
    ]
  }" | jq

File upload — XLSX ingest

curl -s -X POST "$BASE/ingest/transaction_summary/from_excel?eid=$EID" \
  -H "Authorization: Bearer $FD_ACCESS_TOKEN" \
  -H "X-Preferred-Partner-Id: $FD_PARTNER_ID" \
  -F "file=@./sales.xlsx" \
  | jq

Media upload (note: no /v3 prefix)

# /media is on the API host but WITHOUT /v3
MEDIA_BASE="${BASE%/v3}"

curl -s -X POST "$MEDIA_BASE/media" \
  -H "Authorization: Bearer $FD_ACCESS_TOKEN" \
  -H "X-Preferred-Partner-Id: $FD_PARTNER_ID" \
  -F "file=@./creative.jpg" \
  | jq

Health

curl -s "$BASE/status/" | jq      # no auth