Skip to main content

Create and Apply Forecast Events

This guide shows you how to create a promotional event and apply it to a forecast scenario to adjust demand predictions.

Prerequisites

  • API Key: Valid API key with forecast.write permission
  • Organization Access: Access to your organization’s forecasting features
  • Product ID: Product master ID for product-specific events (optional)
  • Location ID: Location ID for location-specific events (optional)

Step-by-Step Guide

Step 1: Create an External Event

Create a promotional event that will drive demand adjustments. Request:
curl -X POST "https://app.betterdata.co/api/forecast/events" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Summer Sale 2024",
    "type": "PROMOTION",
    "startsAt": "2024-06-01T00:00:00Z",
    "endsAt": "2024-06-30T23:59:59Z",
    "value": {
      "liftPct": 0.25,
      "stackingMode": "MULTIPLICATIVE",
      "description": "25% lift during summer sale promotion"
    },
    "productMasterId": "prod_123"
  }'
Response:
{
  "id": "event_789",
  "name": "Summer Sale 2024",
  "type": "PROMOTION",
  "startsAt": "2024-06-01T00:00:00Z",
  "endsAt": "2024-06-30T23:59:59Z",
  "value": {
    "liftPct": 0.25,
    "stackingMode": "MULTIPLICATIVE"
  },
  "isGlobal": false,
  "isOrgWide": true,
  "productMaster": {
    "id": "prod_123",
    "name": "Product Name",
    "sku": "SKU-123"
  },
  "createdAt": "2024-03-15T00:00:00Z"
}
Notes:
  • Event Types: PROMOTION, PRICE_CHANGE, HOLIDAY, WEATHER, BOOKING, MACRO, OTHER
  • Lift Percentage: Range from -0.99 (99% reduction) to 5 (500% increase)
  • Stacking Mode:
    • MULTIPLICATIVE: Events multiply together (e.g., 1.25 × 1.15 = 1.4375)
    • ADDITIVE: Events add together (e.g., 0.25 + 0.15 = 0.40)
  • Global Events: Set productMasterId to null for organization-wide events
  • Org-Wide Events: Set locationId to null for location-agnostic events

Step 2: Create or Select a Forecast Scenario

Create a new forecast scenario or use an existing one. Request:
curl -X POST "https://app.betterdata.co/api/forecast/scenarios" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Q2 2024 with Promotions",
    "description": "Forecast including summer sale promotion",
    "type": "PROMOTIONAL",
    "assumptions": {
      "narrative": "Q2 includes major promotional campaign",
      "includedEventIds": ["event_789"]
    }
  }'
Response:
{
  "scenario": {
    "id": "scenario_456",
    "name": "Q2 2024 with Promotions",
    "description": "Forecast including summer sale promotion",
    "type": "PROMOTIONAL",
    "status": "DRAFT",
    "createdAt": "2024-03-15T00:00:00Z"
  }
}
Notes:
  • Scenario Types: BASELINE, PROMOTIONAL, CONSERVATIVE, OPTIMISTIC, CHANNEL_LAUNCH, CUSTOM
  • Event Inclusion: Add event IDs to includedEventIds array
  • Multiple Events: Include multiple events to model complex scenarios

Step 3: Generate Forecasts for the Scenario

Generate forecasts that incorporate the event. Request:
curl -X POST "https://app.betterdata.co/api/forecast/scenarios/scenario_456/generate" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "productMasterIds": ["prod_123"],
    "locationIds": ["loc_123"],
    "horizonDays": 90,
    "forceRegenerate": false
  }'
Response:
{
  "success": true,
  "generated": 1,
  "forecasts": [
    {
      "productMasterId": "prod_123",
      "locationId": "loc_123",
      "horizonDays": 90,
      "generatedAt": "2024-03-15T12:00:00Z"
    }
  ]
}
Notes:
  • Horizon Days: Forecast period (7-365 days)
  • Force Regenerate: Set to true to regenerate existing forecasts
  • Selective Generation: Specify productMasterIds and locationIds to limit scope

Step 4: Verify Event Impact

Check the forecast change history to see how the event affected forecasts. Request:
curl -X GET "https://app.betterdata.co/api/forecast/change-history?productMasterId=prod_123&locationId=loc_123&changeTypes=EVENT_APPLIED" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json"
Response:
{
  "entries": [
    {
      "id": "change_123",
      "changeType": "EVENT_APPLIED",
      "eventId": "event_789",
      "eventName": "Summer Sale 2024",
      "beforeValue": 100,
      "afterValue": 125,
      "changePercent": 25,
      "timestamp": "2024-03-15T12:00:00Z"
    }
  ],
  "total": 1,
  "hasMore": false
}

Complete Example

Here’s a complete workflow combining all steps:
#!/bin/bash

API_KEY="YOUR_API_KEY"
BASE_URL="https://app.betterdata.co/api"

# Step 1: Create event
EVENT_RESPONSE=$(curl -s -X POST "${BASE_URL}/forecast/events" \
  -H "Authorization: Bearer ${API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Summer Sale 2024",
    "type": "PROMOTION",
    "startsAt": "2024-06-01T00:00:00Z",
    "endsAt": "2024-06-30T23:59:59Z",
    "value": {
      "liftPct": 0.25,
      "stackingMode": "MULTIPLICATIVE"
    }
  }')

EVENT_ID=$(echo $EVENT_RESPONSE | jq -r '.id')
echo "Created event: $EVENT_ID"

# Step 2: Create scenario
SCENARIO_RESPONSE=$(curl -s -X POST "${BASE_URL}/forecast/scenarios" \
  -H "Authorization: Bearer ${API_KEY}" \
  -H "Content-Type: application/json" \
  -d "{
    \"name\": \"Q2 2024 with Promotions\",
    \"type\": \"PROMOTIONAL\",
    \"assumptions\": {
      \"includedEventIds\": [\"${EVENT_ID}\"]
    }
  }")

SCENARIO_ID=$(echo $SCENARIO_RESPONSE | jq -r '.scenario.id')
echo "Created scenario: $SCENARIO_ID"

# Step 3: Generate forecasts
curl -X POST "${BASE_URL}/forecast/scenarios/${SCENARIO_ID}/generate" \
  -H "Authorization: Bearer ${API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "horizonDays": 90
  }'

echo "Forecasts generated successfully"

Idempotency Notes

  • Event Creation: Creating an event with the same name and date range will create a new event (not idempotent). Use event IDs to track which events you’ve already created.
  • Scenario Generation: Generating forecasts for the same scenario multiple times will update existing forecasts unless forceRegenerate is set to false and forecasts already exist.
  • Event Application: Events are applied during forecast generation. Regenerating forecasts will reapply events.

Pagination Notes

  • List Events: The events list endpoint supports pagination with page and limit parameters (default: 20, max: 100).
  • Change History: The change history endpoint uses limit and offset for pagination (default: 50, max: 100).

Common Issues

Event Not Applied

Symptom: Event created but forecast doesn’t reflect the lift. Solutions:
  1. Verify event is included in scenario’s includedEventIds
  2. Check event date range overlaps with forecast period
  3. Ensure forecasts were generated after event was created
  4. Verify event productMasterId and locationId match forecast scope

Invalid Lift Percentage

Symptom: Error when creating event with lift percentage. Solutions:
  1. Ensure liftPct is between -0.99 and 5
  2. Use decimal format (0.25 for 25%, not 25)
  3. Check stackingMode is either MULTIPLICATIVE or ADDITIVE

Forecast Generation Fails

Symptom: Error when generating forecasts. Solutions:
  1. Verify scenario status is DRAFT or PUBLISHED (not ARCHIVED)
  2. Check product and location IDs are valid
  3. Ensure horizonDays is between 7 and 365
  4. Verify you have forecast.write permission


Permissions & Roles

Creating events and scenarios requires forecast.write permission. Generating forecasts requires ADMIN, MANAGER, or PLANNER role.