Api Reference
This guide shows you how to create a promotional event and apply it to a forecast scenario to adjust demand predictions.
forecast.write permissionCreate a promotional event that will drive demand adjustments.
Request:
1curl -X POST "https://app.betterdata.co/api/forecast/events" \2 -H "Authorization: Bearer YOUR_API_KEY" \3 -H "Content-Type: application/json" \4 -d '{5 "name": "Summer Sale 2024",6 "type": "PROMOTION",7 "startsAt": "2024-06-01T00:00:00Z",8 "endsAt": "2024-06-30T23:59:59Z",9 "value": {10 "liftPct": 0.25,11 "stackingMode": "MULTIPLICATIVE",12 "description": "25% lift during summer sale promotion"13 },14 "productMasterId": "prod_123"15 }'Response:
1{2 "id": "event_789",3 "name": "Summer Sale 2024",4 "type": "PROMOTION",5 "startsAt": "2024-06-01T00:00:00Z",6 "endsAt": "2024-06-30T23:59:59Z",7 "value": {8 "liftPct": 0.25,9 "stackingMode": "MULTIPLICATIVE"10 },11 "isGlobal": false,12 "isOrgWide": true,13 "productMaster": {14 "id": "prod_123",15 "name": "Product Name",16 "sku": "SKU-123"17 },18 "createdAt": "2024-03-15T00:00:00Z"19}Notes:
PROMOTION, PRICE_CHANGE, HOLIDAY, WEATHER, BOOKING, MACRO, OTHERMULTIPLICATIVE: Events multiply together (e.g., 1.25 × 1.15 = 1.4375)ADDITIVE: Events add together (e.g., 0.25 + 0.15 = 0.40)productMasterId to null for organization-wide eventslocationId to null for location-agnostic eventsCreate a new forecast scenario or use an existing one.
Request:
1curl -X POST "https://app.betterdata.co/api/forecast/scenarios" \2 -H "Authorization: Bearer YOUR_API_KEY" \3 -H "Content-Type: application/json" \4 -d '{5 "name": "Q2 2024 with Promotions",6 "description": "Forecast including summer sale promotion",7 "type": "PROMOTIONAL",8 "assumptions": {9 "narrative": "Q2 includes major promotional campaign",10 "includedEventIds": ["event_789"]11 }12 }'Response:
1{2 "scenario": {3 "id": "scenario_456",4 "name": "Q2 2024 with Promotions",5 "description": "Forecast including summer sale promotion",6 "type": "PROMOTIONAL",7 "status": "DRAFT",8 "createdAt": "2024-03-15T00:00:00Z"9 }10}Notes:
BASELINE, PROMOTIONAL, CONSERVATIVE, OPTIMISTIC, CHANNEL_LAUNCH, CUSTOMincludedEventIds arrayGenerate forecasts that incorporate the event.
Request:
1curl -X POST "https://app.betterdata.co/api/forecast/scenarios/scenario_456/generate" \2 -H "Authorization: Bearer YOUR_API_KEY" \3 -H "Content-Type: application/json" \4 -d '{5 "productMasterIds": ["prod_123"],6 "locationIds": ["loc_123"],7 "horizonDays": 90,8 "forceRegenerate": false9 }'Response:
1{2 "success": true,3 "generated": 1,4 "forecasts": [5 {6 "productMasterId": "prod_123",7 "locationId": "loc_123",8 "horizonDays": 90,9 "generatedAt": "2024-03-15T12:00:00Z"10 }11 ]12}Notes:
true to regenerate existing forecastsproductMasterIds and locationIds to limit scopeCheck the forecast change history to see how the event affected forecasts.
Request:
1curl -X GET "https://app.betterdata.co/api/forecast/change-history?productMasterId=prod_123&locationId=loc_123&changeTypes=EVENT_APPLIED" \2 -H "Authorization: Bearer YOUR_API_KEY" \3 -H "Content-Type: application/json"Response:
1{2 "entries": [3 {4 "id": "change_123",5 "changeType": "EVENT_APPLIED",6 "eventId": "event_789",7 "eventName": "Summer Sale 2024",8 "beforeValue": 100,9 "afterValue": 125,10 "changePercent": 25,11 "timestamp": "2024-03-15T12:00:00Z"12 }13 ],14 "total": 1,15 "hasMore": false16}Here's a complete workflow combining all steps:
1#!/bin/bash2 3API_KEY="YOUR_API_KEY"4BASE_URL="https://app.betterdata.co/api"5 6# Step 1: Create event7EVENT_RESPONSE=$(curl -s -X POST "${BASE_URL}/forecast/events" \8 -H "Authorization: Bearer ${API_KEY}" \9 -H "Content-Type: application/json" \10 -d '{11 "name": "Summer Sale 2024",12 "type": "PROMOTION",13 "startsAt": "2024-06-01T00:00:00Z",14 "endsAt": "2024-06-30T23:59:59Z",15 "value": {16 "liftPct": 0.25,17 "stackingMode": "MULTIPLICATIVE"18 }19 }')20 21EVENT_ID=$(echo $EVENT_RESPONSE | jq -r '.id')22echo "Created event: $EVENT_ID"23 24# Step 2: Create scenario25SCENARIO_RESPONSE=$(curl -s -X POST "${BASE_URL}/forecast/scenarios" \26 -H "Authorization: Bearer ${API_KEY}" \27 -H "Content-Type: application/json" \28 -d "{29 \"name\": \"Q2 2024 with Promotions\",30 \"type\": \"PROMOTIONAL\",31 \"assumptions\": {32 \"includedEventIds\": [\"${EVENT_ID}\"]33 }34 }")35 36SCENARIO_ID=$(echo $SCENARIO_RESPONSE | jq -r '.scenario.id')37echo "Created scenario: $SCENARIO_ID"38 39# Step 3: Generate forecasts40curl -X POST "${BASE_URL}/forecast/scenarios/${SCENARIO_ID}/generate" \41 -H "Authorization: Bearer ${API_KEY}" \42 -H "Content-Type: application/json" \43 -d '{44 "horizonDays": 9045 }'46 47echo "Forecasts generated successfully"forceRegenerate is set to false and forecasts already exist.page and limit parameters (default: 20, max: 100).limit and offset for pagination (default: 50, max: 100).Symptom: Event created but forecast doesn't reflect the lift.
Solutions:
includedEventIdsproductMasterId and locationId match forecast scopeSymptom: Error when creating event with lift percentage.
Solutions:
liftPct is between -0.99 and 5stackingMode is either MULTIPLICATIVE or ADDITIVESymptom: Error when generating forecasts.
Solutions:
DRAFT or PUBLISHED (not ARCHIVED)horizonDays is between 7 and 365forecast.write permissionCreating events and scenarios requires forecast.write permission. Generating forecasts requires ADMIN, MANAGER, or PLANNER role.
