Inventory Planning
The inventory-planning endpoint turns a demand forecast into concrete purchasing recommendations. It forecasts future demand for a single item, then computes reorder points, safety stock, per-supplier order quantities, delivery estimates, and an overall stock-health assessment — everything you need to decide whether to order, how much, and from whom.
Base URL
https://forecastapi.com/v2
Authentication
Bearer YOUR_API_KEY
Generate Inventory Plan
/inventory-planning
Supply your historical demand series in data, describe your
current inventory position and suppliers in inventory_settings,
and receive a full plan back. The endpoint forecasts demand automatically — you do not call
/forecast separately.
Request Body
{
"identifier": "SKU-12345",
"frequency": "M",
"periods": 6,
"data": [
{"date": "2024-01-31", "value": 190},
{"date": "2024-02-29", "value": 205},
{"date": "2024-03-31", "value": 210},
{"date": "2024-04-30", "value": 198},
{"date": "2024-05-31", "value": 215},
{"date": "2024-06-30", "value": 208}
],
"inventory_settings": {
"current_stock": 300,
"minimum_stock": 100,
"service_level": 0.95,
"suppliers": [
{
"identifier": "Acme Supply",
"lead_time_days": 14,
"minimum_order_quantity": 100,
"cost_per_unit": 12.50,
"reliability_score": 0.98
}
]
}
}
Top-level Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| identifier | string | Yes | Unique identifier for the item (e.g., SKU or product ID). Echoed back in the response. |
| data | array | Yes | Historical demand series. Each item needs a date (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS, consistent across the series) and a numeric value. |
| periods | integer | Yes | Number of future periods to forecast (min 1). Must cover at least the longest supplier lead time. |
| frequency | string | Yes | Series granularity: H, D, W, M, MS, ME, Q, or Y. Used to convert supplier lead times (in days) into forecast periods. |
| inventory_settings | object | Yes | Inventory position and supplier configuration. See the two tables below. |
| start_date | date | No | Anchor date for the forecast and for all returned dates (delivery, next order). Defaults to the last date in data. |
| data_type | string | No | Semantic type used for model selection. Defaults to "inventory" for this endpoint, which enables intermittent-demand methods. |
| model | string | No | Forecasting model behind the plan: standard (default), advanced-quantized, or advanced-patched. See Model Options. Advanced variants cost 25% more usage. |
| selection_metric | string | No | Back-testing metric used to pick the winning model: auto (default), combined, mase, or smape. Same semantics as on /forecast. |
| confidence_level | float | No | Confidence level for the forecast intervals that drive safety-stock variability (0.10–0.99). Default: 0.95. |
| tenant_context | string | No | Optional multi-tenant scoping tag. Echoed back in the response. |
inventory_settings Object
| Field | Type | Required | Description |
|---|---|---|---|
| current_stock | number ≥ 0 | Yes | Units currently on hand. Drives stock status, days of coverage, and order quantities. |
| minimum_stock | number ≥ 0 | Yes | Floor you never want to drop below. Reserved from available stock and added into the reorder point. |
| service_level | number 0.5–0.999 | Yes | Target probability of not stocking out during lead time. Mapped to a Z-score that scales safety stock (e.g. 0.95 → 1.65, 0.99 → 2.33). Higher means more buffer. |
| suppliers | array (min 1) | Yes | One or more suppliers to evaluate. A recommendation is produced for each; the cheapest total cost is treated as the "best" supplier and drives the top-level plan. See the table below. |
suppliers[] Object
| Field | Type | Required | Description |
|---|---|---|---|
| identifier | string | Yes | Supplier name or ID. Returned as supplier in each recommendation. |
| lead_time_days | number ≥ 0.1 | Yes | Delivery lead time in days. Converted to whole forecast periods (rounded up, min 1) to compute lead-time demand and the expected delivery date. |
| minimum_order_quantity | number ≥ 0 | Yes | MOQ. Any suggested order is rounded up to a whole multiple of this value. |
| cost_per_unit | number ≥ 0 | Yes | Unit cost. Drives total order cost and the "best supplier" selection (lowest total cost wins). |
| reliability_score | number 0.1–1.0 | No | How dependable the supplier is. Safety stock is scaled by 1 / reliability_score, so a less reliable supplier gets a larger buffer. Defaults to 1.0 when omitted. |
Response
{
"result": {
"tenant_context": null,
"identifier": "SKU-12345",
"current_stock": 300,
"minimum_stock": 100,
"reorder_point": 377.35,
"safety_stock": 67.35,
"suppliers": [
{
"supplier": "Acme Supply",
"order_quantity": 200,
"total_cost": 2500.00,
"cost_per_unit": 12.5,
"expected_delivery": "2024-07-14",
"lead_time_days": 14,
"minimum_order_quantity": 100,
"reliability_score": 0.98,
"lead_time_demand": 210.00,
"safety_stock": 67.35,
"reorder_point": 377.35,
"reason": "$12.50 per unit, reasonable lead time, high reliability"
}
],
"stock_analysis": {
"days_of_coverage": 29,
"stockout_risk": 0.75,
"next_order_date": "2024-06-30",
"daily_demand_rate": 7.06,
"stock_status": "reorder_needed"
},
"forecasts": [
{"period": 1, "date": "2024-07-31", "forecast": 210.00, "lower": 180.00, "upper": 250.00},
{"period": 2, "date": "2024-08-31", "forecast": 205.00, "lower": 175.00, "upper": 245.00}
]
},
"meta": {
"timing": { "validation": 3.2, "planning": 284.1, "total": 288.5 }
}
}
The response always has this single shape on success (HTTP 200): a
result object with the plan and a meta
object with timing. There are no alternate success response types.
result Fields
| Field | Type | Description |
|---|---|---|
| identifier | string | The item identifier, echoed from the request. |
| tenant_context | string | null | The tenant tag, echoed from the request (null if not sent). |
| current_stock | number | Current on-hand units, echoed from the request. |
| minimum_stock | number | Minimum stock floor, echoed from the request. |
| reorder_point | number | The stock level at which to reorder, taken from the best (cheapest) supplier. Equals lead_time_demand + safety_stock + minimum_stock. 0 if no supplier could be evaluated. |
| safety_stock | number | Buffer stock from the best supplier, sized from forecast uncertainty, service level, and supplier reliability. |
| suppliers | array | One recommendation object per input supplier (see below). |
| stock_analysis | object | Overall stock-health summary, including stock_status (see below). |
| forecasts | array | The underlying demand forecast used to build the plan (see below). |
suppliers[] Fields
| Field | Type | Description |
|---|---|---|
| supplier | string | Supplier identifier from the request. |
| order_quantity | number | Recommended units to order, rounded up to a multiple of the MOQ. 0 means no order is needed right now. |
| total_cost | number | order_quantity × cost_per_unit, rounded to 2 decimals. |
| cost_per_unit | number | Unit cost, echoed from the request. |
| expected_delivery | date | start_date + lead_time_days, formatted YYYY-MM-DD. |
| lead_time_days | number | Lead time, echoed from the request. |
| minimum_order_quantity | number | MOQ, echoed from the request. |
| reliability_score | number | Reliability, echoed from the request (or 1.0 if it was omitted). |
| lead_time_demand | number | Forecast demand summed over the lead-time periods. |
| safety_stock | number | Buffer for this supplier: demand_variability × Z(service_level) × (1 / reliability_score). |
| reorder_point | number | lead_time_demand + safety_stock + minimum_stock for this supplier. |
| reason | string | Human-readable rationale for the recommendation (see values below). |
stock_analysis Fields
| Field | Type | Description |
|---|---|---|
| days_of_coverage | integer | How many days the available stock (above the minimum) lasts at the average daily demand rate. 999 when there is no forecast demand. |
| stockout_risk | number | Estimated probability of running out (0–1). Returns one of a fixed set of values — see below. |
| next_order_date | date | Estimated date the stock will fall to the reorder point. Equal to start_date when you are already at or below it (order now). |
| daily_demand_rate | number | Average forecast demand per day across all forecast periods. |
| stock_status | string | A single label summarizing stock health. One of four values — see below. |
stock_status — possible values
The status compares your current_stock against the best supplier's
reorder_point and your minimum_stock.
They are checked in order, so the first matching row wins.
| Value | Condition | Meaning |
|---|---|---|
| critical | current_stock ≤ minimum_stock |
At or below the minimum floor. Highest urgency — you are effectively out of usable buffer. |
| reorder_needed | minimum_stock < current_stock ≤ reorder_point |
Below the reorder point. Place an order now to avoid a future stockout during lead time. |
| low | reorder_point < current_stock ≤ reorder_point × 1.2 |
Within 20% above the reorder point. Not urgent, but worth watching — a reorder is coming soon. |
| adequate | current_stock > reorder_point × 1.2 |
Healthy. Comfortably above the reorder point; no action needed. |
Edge case: if no supplier could be evaluated, the best-supplier
reorder_point is 0,
so any positive stock above the minimum reports as adequate. In normal
requests (at least one supplier) this does not happen.
stockout_risk — possible values
A coarse risk estimate rather than a continuous probability. Let
stock_ratio = (current_stock − minimum_stock) / demand over the next 3 periods.
The endpoint returns exactly one of these values:
| Value | Returned when |
|---|---|
| 0.99 | current_stock ≤ minimum_stock (at or below the floor). |
| 0.01 | Near-term demand is zero, or stock_ratio ≥ 2.0. |
| 0.05 | 1.5 ≤ stock_ratio < 2.0. |
| 0.15 | 1.0 ≤ stock_ratio < 1.5. |
| 0.35 | 0.5 ≤ stock_ratio < 1.0. |
| 0.75 | stock_ratio < 0.5. |
reason — how it is built
When no order is needed, reason is exactly
"No order needed - current stock is sufficient". Otherwise it is a
comma-separated string assembled from the fragments below (empty fragments are skipped; if none apply it falls back to
"standard recommendation").
| Fragment | Included when |
|---|---|
"$X.XX per unit" |
cost_per_unit > 0. |
"fast delivery" / "reasonable lead time" / "longer lead time" |
Lead time ≤ 7 days / ≤ 14 days / otherwise. |
"high reliability" / "good reliability" |
Reliability ≥ 0.95 / ≥ 0.85 (below 0.85 adds nothing). |
"minimum order quantity" |
The recommended order equals the MOQ exactly. |
forecasts[] Fields
The demand forecast the plan is built on. Fields depend slightly on the selected model, but every entry always includes
a point forecast and an upper
bound — the two values that drive lead-time demand and safety stock.
| Field | Type | Description |
|---|---|---|
| period | integer | 1-based index of the forecast period. |
| date | string | Period date (YYYY-MM-DD, or YYYY-MM-DD HH:00:00 for hourly data). |
| forecast | number | Point demand forecast for the period (never negative). |
| lower | number | Lower bound of the confidence interval. |
| upper | number | Upper bound of the confidence interval. Its gap above forecast is the demand variability used for safety stock. |
meta.timing
Server-side timing in milliseconds: validation (request checks),
planning (forecast + inventory math), and
total (whole request).
Acting on the Recommendations
There is no single action field. The recommended action is expressed
through three fields together: stock_analysis.stock_status (how urgent),
each supplier's order_quantity (how much, and from whom), and
reason (why). The table below maps the status to what you should do.
stock_status |
Recommended action |
|---|---|
| critical | Order immediately, and consider expediting. Pick the supplier with a non-zero order_quantity and the earliest expected_delivery — cost is secondary when you are below the floor. |
| reorder_needed | Place an order this cycle. The top-level reorder_point/safety_stock come from the cheapest supplier; use its order_quantity unless lead time or reliability pushes you to another entry. |
| low | No immediate order required, but a reorder is near. Watch next_order_date and days_of_coverage; batch this into your next purchase run. |
| adequate | Do nothing. Stock is comfortably above the reorder point; order_quantity will typically be 0 for every supplier. |
Usage & Cost
Each call counts as one standard API call. Using an advanced model
consumes 25% more usage, exactly as on the forecast endpoint.
The same rate limits apply.
Error Responses
HTTP Status Codes
inventory_settings fields, an empty suppliers array, a bad date format, or too many data points for your plan. The body lists per-field errors.422 Validation Error
{
"message": "The inventory_settings.suppliers field is required.",
"errors": {
"inventory_settings.suppliers": [
"The inventory_settings.suppliers field is required."
]
}
}
500 Planning Error
{
"error": "Inventory planning failed",
"time_taken_ms": 42.7
}