This playbook covers the end-to-end integration pattern for connecting ERP systems with dedicated demand planning tools. The ERP serves as the system of record for historical transactions (sales orders, shipments, invoices) and as the execution system that consumes the approved forecast (MRP, procurement). The demand planning tool is the analytical engine that generates, adjusts, and publishes the demand signal.
| System | Role | API Surface | Direction |
|---|---|---|---|
| SAP S/4HANA / ECC | ERP — source of historical sales, target for forecast | OData v4, BAPI/RFC, IDoc | Bidirectional |
| Oracle ERP Cloud | ERP — source of historical sales, target for forecast | REST API, FBDI, BI Publisher | Bidirectional |
| Microsoft Dynamics 365 F&O | ERP — source of historical sales, target for forecast | OData v4, Data Management Framework | Bidirectional |
| SAP IBP for Demand | Demand planning — statistical forecasting, consensus | CPI-DS, OData, SAP Integration Suite | Inbound + Outbound |
| Anaplan | Demand planning — connected planning, scenario modeling | Integration API v2.0, CloudWorks | Inbound + Outbound |
| Oracle Planning Cloud | Demand planning — replaces Demantra for cloud | REST API, EPM Automate | Inbound + Outbound |
| Blue Yonder Luminate | Demand planning — ML-driven demand sensing | REST API, file-based | Inbound + Outbound |
| Kinaxis Maestro | Demand planning — concurrent planning | REST API, Integration Workbench | Inbound + Outbound |
| iPaaS (MuleSoft / Boomi / Workato) | Middleware — orchestration, transformation | N/A | Orchestrator |
The demand planning integration follows a six-phase closed-loop pattern. Every phase has distinct data objects, frequencies, and failure modes.
Phase 1: EXTRACT — Historical Data from ERP
(Sales orders, shipments, invoices, returns, promotions)
Frequency: Nightly batch or weekly full refresh
|
Phase 2: TRANSFORM — Cleansing & Harmonization
(UoM conversion, calendar mapping, hierarchy alignment,
outlier detection, promo flag tagging)
|
Phase 3: LOAD — Into Demand Planning Tool
(Master data sync first, then time-series actuals)
|
Phase 4: FORECAST — Generate & Review
(Statistical baseline → ML enrichment → consensus adjustment)
Human-in-the-loop: S&OP review meeting
|
Phase 5: PUBLISH — Approved Forecast to ERP
(Planned Independent Requirements / Demand Forecasts)
Write to ERP MRP input tables
|
Phase 6: FEEDBACK — Accuracy Measurement
(Actual vs. Forecast: MAPE, WMAPE, Bias, FVA)
Flows back to Phase 3 for model retraining
| Planning Tool | Import API | Export API | Bulk Support | Max Payload | Auth Method | Scheduling |
|---|---|---|---|---|---|---|
| SAP IBP | CPI-DS, SAP Integration Suite | CPI-DS, OData | Yes — batch jobs | 10M records/job | OAuth 2.0 + X.509 | CPI-DS / BTP Job Scheduling |
| Anaplan | Integration API v2.0 (bulk) | Integration API v2.0 (bulk) | Yes — file-based | 1M cells/action | OAuth 2.0 (client credentials) | CloudWorks / Data Orchestrator |
| Oracle Planning Cloud | EPM Automate, REST API | EPM Automate, REST API | Yes — batch | 500MB/file | OAuth 2.0 | EPM Automate / OIC |
| Blue Yonder | REST API, file-based (SFTP/S3) | REST API, file-based | Yes — file drops | Vendor-specific | OAuth 2.0 / API key | Vendor-managed |
| Kinaxis | Integration Workbench, REST API | Integration Workbench, REST API | Yes — batch | Vendor-specific | OAuth 2.0 / SAML | Workbench scheduling |
| Planning Tool | Limit Type | Value | Notes |
|---|---|---|---|
| Anaplan Integration API v2.0 | Max cells per import action | 1,000,000 | Split larger datasets into multiple actions |
| Anaplan Integration API v2.0 | Max file upload size | 50 MB per chunk | Use chunked upload for larger files |
| Anaplan Integration API v2.0 | Max concurrent API requests | 10 per workspace | Queue excess requests |
| SAP IBP (CPI-DS) | Max records per extraction template | 10,000,000 | Use time-based filtering to reduce scope |
| Oracle Planning Cloud | Max file size (EPM Automate) | 500 MB | Split data by planning dimension |
| Oracle Planning Cloud REST | Max records per REST call | 500,000 | Paginate larger result sets |
| Planning Tool | Limit Type | Value | Window | Notes |
|---|---|---|---|---|
| Anaplan | API calls | Tenant-level fair use | Rolling | Monitor via Admin console |
| SAP IBP | CPI-DS job executions | Based on BTP entitlement | 24h | Track via SAP BTP cockpit |
| Oracle Planning Cloud | EPM Automate operations | Varies by subscription tier | 24h | Enterprise tier has higher limits |
| All tools | Concurrent integration jobs | Typically 3-5 parallel | Per tenant | Exceeding causes queueing |
| Planning Tool | Flow | Use When | Token Lifetime | Notes |
|---|---|---|---|---|
| Anaplan | OAuth 2.0 Client Credentials | Server-to-server batch | 35 min | Rotate client secret quarterly |
| Anaplan | Certificate-based auth | High-security environments | Session-based | X.509 certificate |
| SAP IBP | OAuth 2.0 + X.509 | CPI-DS and Integration Suite | Configurable (BTP) | Managed via BTP destination service |
| Oracle Planning Cloud | OAuth 2.0 | REST API and EPM Automate | 60 min | Via Oracle Identity Cloud Service |
| Oracle Planning Cloud | Basic Auth | EPM Automate CLI (legacy) | Session-based | Moving to OAuth |
START — Integrate ERP with Demand Planning Tool
├── What type of data is flowing?
│ ├── Historical actuals (ERP → Planning tool)
│ │ ├── Volume < 100K records → REST API
│ │ ├── Volume 100K-10M → Bulk API (Anaplan v2.0, CPI-DS, EPM Automate)
│ │ └── Volume > 10M → File-based (CSV/SFTP) + staged loading
│ ├── Master data (bidirectional sync)
│ │ ├── Product/location hierarchy → push from ERP (source of truth)
│ │ └── Planning attributes → push from planning tool
│ ├── Approved forecast (Planning tool → ERP)
│ │ ├── SAP: Planned Independent Requirements (PIRs) via BAPI
│ │ ├── Oracle: Demand Forecast via FBDI
│ │ ├── D365: Demand Forecast Entity (OData)
│ │ └── Always: respect frozen horizon, apply disaggregation
│ └── Accuracy feedback (actuals vs. forecast)
│ └── Scheduled weekly/monthly comparison
├── What middleware to use?
│ ├── SAP ecosystem → SAP Integration Suite / CPI-DS
│ ├── Oracle ecosystem → Oracle Integration Cloud
│ ├── Multi-vendor → MuleSoft, Boomi, Workato
│ └── Budget-constrained → Custom scripts + SFTP + cron
└── Error handling?
├── Master data failures → queue and retry; block dependent jobs
├── Historical load failures → partial OK; log gaps
├── Forecast write failures → CRITICAL alert; MRP on stale data
└── Accuracy feedback failures → non-blocking; degrade gracefully
| Step | Source | Action | Target | Data Objects | Frequency | Failure Handling |
|---|---|---|---|---|---|---|
| 1 | ERP | Extract sales history | Staging | Sales transactions | Nightly / weekly | Retry 3x; alert if >2h late |
| 2 | ERP | Extract master data | Staging | Material, plant, customer master | Daily (delta) | Block downstream on failure |
| 3 | Staging | Transform: UoM, calendar, outliers | Staging | Cleansed actuals | After extraction | Log exceptions; proceed |
| 4 | Staging | Load actuals into planning tool | Planning Tool | Time-series actuals | After transform | Validate record counts |
| 5 | Planning Tool | Generate statistical forecast | Planning Tool | Baseline forecast | Weekly (automated) | Alert on convergence failure |
| 6 | Planning Tool | Consensus review (S&OP) | Planning Tool | Adjusted forecast | Weekly/monthly | N/A — human process |
| 7 | Planning Tool | Export approved forecast | Staging | Forecast at ERP granularity | After S&OP sign-off | Validate disaggregation |
| 8 | Staging | Disaggregate (week → day) | Staging | Daily material-plant demand | After export | Validate sum matches |
| 9 | Staging | Write forecast to ERP | ERP | PIRs / demand forecasts | After disaggregation | Skip frozen horizon; log |
| 10 | ERP | MRP consumes forecast | ERP | Planned orders, PRs | Per ERP schedule | Standard MRP exceptions |
| 11 | ERP + Planning | Accuracy feedback | Planning Tool | MAPE, Bias, FVA | Monthly | Non-blocking; log trends |
Extract 2-3 years of daily sales transactions including orders, shipments, returns, and credit memos. Include promotional flags, pricing, and customer segment. [src2, src8]
-- SAP CDS View for sales history extraction
SELECT
material, plant, billing_date,
SUM(quantity) AS shipped_qty,
SUM(net_amount) AS revenue,
currency_code, sales_org, distribution_channel
FROM i_billingdocumentitem
WHERE billing_date >= ADD_DAYS(CURRENT_DATE, -1095)
AND billing_type IN ('F1', 'F2')
AND cancelled_billing_doc = ''
GROUP BY material, plant, billing_date, currency_code,
sales_org, distribution_channel
Verify: Record count in extract matches ERP transaction count (tolerance: <0.1% variance).
Transform raw ERP data to match the planning tool's data model: UoM conversion, calendar period mapping, outlier detection, hierarchy alignment. [src4, src7]
# Transform daily ERP sales to weekly planning granularity
def transform_sales(raw_df, uom_factors):
# UoM: ERP eaches → planning cases
raw_df['planning_qty'] = raw_df['shipped_qty'] / raw_df['case_qty'].fillna(1)
# Calendar: fiscal → ISO weeks
raw_df['iso_week'] = pd.to_datetime(raw_df['date']).dt.isocalendar().week
# Outlier: flag values > 3 std dev from rolling 8-week mean
# Aggregate to product x location x week
return weekly_aggregated_df
Verify: SUM(planning_qty * case_qty) in output equals SUM(shipped_qty) in source (must be exact).
Master data must load before time-series data. Always sync product and location hierarchies first. [src1, src5]
# Anaplan Integration API v2.0 bulk import
# 1. Upload file (chunked if > 50MB)
# 2. Mark upload complete
# 3. Run import action
# 4. Poll for completion (refresh token at 30-min mark)
Verify: Record count in planning tool matches extract. Spot-check 5 random product-location-week combinations.
Statistical baseline + ML enrichment + promotional uplift + consensus adjustment. The S&OP review is human-in-the-loop. [src8]
Verify: Forecast Value Added (FVA) at each step — if ML or consensus worsens accuracy vs. baseline, the step adds cost without value.
Disaggregate from planning granularity (product-location-week) to ERP granularity (material-plant-day) and write to ERP forecast consumption mechanism. [src2, src3]
# SAP: Write PIRs via BAPI_REQUIREMENTS_CREATE
# Oracle: Import via FBDI CSV
# D365: Write via Demand Forecast Entity (OData)
# Always: skip frozen horizon dates, validate disaggregation totals
Verify: MRP run picks up new forecast quantities. Check planned orders vs. expected.
Compare actual sales to published forecast at same granularity. Feed back for model recalibration. [src4, src7]
# Key metrics:
# MAPE = mean(|actual - forecast| / actual) * 100
# WMAPE = sum(|actual - forecast|) / sum(actual) * 100
# Bias = sum(forecast - actual) / sum(actual) * 100
# FVA = naive_mape - forecast_mape (positive = value added)
Verify: Bias within +/-5%. Persistent bias >10% requires model recalibration.
| Source Field (ERP) | Target Field (Planning) | Type | Transform | Gotcha |
|---|---|---|---|---|
| SAP: MATNR / Oracle: ITEM_NUMBER | Product ID | String | Direct (pad SAP to 18 chars) | SAP leading zeros |
| SAP: WERKS / Oracle: ORG_CODE | Location ID | String | Direct | Multi-plant hierarchy mapping |
| SAP: FKDAT (billing date) | Period (ISO week) | Date → Period | ISO calendar conversion | Fiscal calendar misalignment |
| SAP: FKIMG (billed qty) | Actuals Quantity | Decimal | Apply UoM conversion | Base UoM may differ |
| SAP: MEINS (base UoM) | UoM | String | Map ERP to planning UoM | "EA" vs "Each" naming |
| SAP: NETWR (net value) | Revenue | Currency | Convert at period-end rate | Multi-currency rate alignment |
| Customer segment | Demand stream | String | Map to planning hierarchy | Classification mismatch |
| Sales order type | Demand type flag | String | Standard = base; promo = promo | Critical for accuracy |
| Error | System | Meaning | Resolution |
|---|---|---|---|
| 429 Too Many Requests | Anaplan API | Rate limit exceeded | Exponential backoff: 2^n seconds, max 5 retries |
| AUTH_TOKEN_EXPIRED | Anaplan API | OAuth token expired mid-import | Refresh at 30-min mark |
| CPI-DS TIMEOUT | SAP IBP | Extraction timed out | Add time-based filtering; split by year |
| PIR_FROZEN_HORIZON | SAP ERP | Write rejected inside frozen zone | Filter dates inside planning fence |
| FBDI_VALIDATION_ERROR | Oracle ERP | Import rejected | Validate master data alignment first |
| HIERARCHY_MISMATCH | Any | Product/location not found | Run master data sync before load |
| DUPLICATE_KEY | Any | Duplicate forecast record | Use upsert; version with timestamp |
Run master data sync before actuals load. [src2]Validate post-load count; alert on >0.1% variance. [src1]Use version-controlled forecasts; export to "system" version, not "consensus". [src5]Add forecast age check; alert if >7 days old. [src8]Use explicit date ranges instead of week numbers at year boundaries.# BAD — wastes API calls, risks rate limits, takes 4+ hours
all_data = extract_all_sales_last_3_years() # 50M rows
delete_all_actuals()
load_all_actuals(all_data)
# GOOD — nightly delta (10K-100K rows), weekly full reconciliation
delta = extract_sales_since(last_load_timestamp)
upsert_actuals(delta) # upsert, not insert
# BAD — all demand lands on Monday; MRP over-orders
create_pir(date=week_start, quantity=weekly_qty)
# GOOD — spread weekly forecast across days using demand pattern
for day, weight in daily_profile:
upsert_pir(date=day, quantity=weekly_qty * weight)
# BAD — forecast degrades 5-15% per year without feedback
generate_forecast(); publish_to_erp() # Done! Never look back.
# GOOD — monthly accuracy review with threshold alerts
metrics = calculate_accuracy(actuals, forecast)
if metrics['wmape'] > 40: alert("Review forecast model")
if abs(metrics['bias']) > 10: alert("Systematic bias detected")
Tag promo orders in ERP; model promo lift as overlay on base demand. [src8]Use order data (gross demand); impute unconstrained demand for stockout periods. [src4]Extract at finest granularity; aggregate in planning tool. [src7]Maintain MDM mapping layer; freeze hierarchy during forecast cycle. [src2]Segment by ABC class, product family, demand pattern, and horizon. [src4]Use batch (nightly max); reserve real-time for demand sensing only. [src8]# Verify Anaplan API connectivity
curl -X POST "https://us1a.app.anaplan.com/token/authenticate" \
-H "Content-Type: application/json" \
-d '{"grant_type":"client_credentials","client_id":"ID","client_secret":"SECRET"}'
# Check Anaplan import actions
curl -X GET "https://api.anaplan.com/2/0/workspaces/{id}/models/{id}/imports" \
-H "Authorization: AnaplanAuthToken {token}"
# SAP IBP — monitor CPI-DS jobs via BTP cockpit
# Oracle — check EPM Automate job status
epmautomate.sh liststatus
# Validate record counts post-load
echo "ERP: $(wc -l < exports/sales.csv) | Planning: $(curl -s $API/count)"
| Use When | Don't Use When | Use Instead |
|---|---|---|
| 500+ SKUs with seasonal/promotional demand | <100 SKUs with stable demand | ERP's built-in forecast module |
| Multi-location distribution | Single warehouse | Spreadsheet or ERP native tools |
| S&OP requires collaborative consensus | No formal S&OP process | Min-max reorder points in ERP |
| Need ML/AI beyond exponential smoothing | Make-to-order business | Order-driven planning (MTO/CTO) |
| Multi-channel demand (retail + ecomm + wholesale) | Single-channel B2B with contracts | EDI-based customer forecasts |
| Capability | SAP IBP | Anaplan | Oracle Planning Cloud | Blue Yonder | Kinaxis |
|---|---|---|---|---|---|
| ERP integration depth | Deep (native S/4HANA) | Broad (any ERP via API) | Deep (Oracle ERP) | Broad (any ERP) | Broad (any ERP) |
| Primary integration | CPI-DS / Integration Suite | API v2.0 / CloudWorks | EPM Automate / OIC | REST / file-based | Workbench |
| Bulk loading | 10M+ records (CPI-DS) | 1M cells/action | 500MB/file (EPM) | File-based (SFTP) | Workbench batch |
| Statistical forecasting | Holt-Winters, Croston's, causal | Basic (formula-driven) | Multiple algorithms | ML-native | ML-native |
| ML / demand sensing | SAP Analytics Cloud | External ML required | Oracle AI built-in | Core strength | Core strength |
| Consensus workflow | Built-in S&OP | Flexible (model-driven) | Built-in EPM | Built-in | Built-in |
| NPI handling | Analog-based | Custom model logic | Lifecycle module | ML-based | Analog + ML |
| Pricing | Premium (BTP required) | Premium (per-workspace) | Mid-range (EPM sub) | Premium (enterprise) | Premium (per-user) |
| Best fit | SAP-centric enterprises | Multi-vendor, finance-led | Oracle-centric | Retail, CPG | Complex manufacturing |