Premium inventory and forecasting APIs
Use the inventory optimization and reinforcement-learning forecasting endpoints with a 30-day Bearer token. This page documents the current contracts, entitlement behavior, and usage signals.
At a glance
These endpoints support inventory planning and demand forecasting. Inventory optimization and prediction can be called without authentication; the learning loop is available only to accounts with an active paid entitlement.
| Method | Path | Access mode |
|---|---|---|
POST | /api/tools/inventory-optimization | Optional auth; free limit or active-paid limit |
POST | /api/forecasting/predict | Optional auth; free or Premium response |
POST | /api/forecasting/feedback | Bearer auth + active entitlement required |
GET | /api/forecasting/accuracy?account_key=... | Public read endpoint |
GET | /api/forecasting/platform-stats | Public aggregate endpoint |
Authentication
Obtain a 30-day JWT by posting JSON credentials to POST /api/auth/login. Use the returned token on authenticated API calls as Authorization: Bearer <token>.
{
"email": "ops@example.com",
"password": "your-password"
}
Successful login response
{
"success": true,
"token": "eyJ...30-day-jwt...",
"user": {
"id": 42,
"name": "Operations Lead",
"email": "ops@example.com",
"company_name": "Example Distribution"
}
}
The API reads the current users.plan_tier and users.subscription_status from the database. Do not rely on stale plan claims stored in a client-side token. An unverified login attempt returns 403 with code: "EMAIL_NOT_VERIFIED" and message: "Please verify your email before logging in.".
const login = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: 'ops@example.com', password: 'your-password' })
});
const { token } = await login.json();
const forecast = await fetch('/api/forecasting/predict', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
account_key: 'example-distribution',
historical_demand: [820, 860, 910, 940],
product_name: 'Widget A',
industry: 'industrial'
})
});
console.log(await forecast.json());
Node.js 18+ fetch
const response = await fetch('https://supplychainstack.ai/api/forecasting/platform-stats', {
headers: { 'User-Agent': 'Mozilla/5.0 SupplyChainStack-api-client' }
});
console.log(await response.json());
Inventory optimization
POST /api/tools/inventory-optimization
Send company_name, an array of skus, and optionally service_level (the route defaults to 95). SKU records may include the planning inputs shown below.
{
"company_name": "Example Distribution",
"service_level": 95,
"skus": [
{
"name": "Widget A",
"sku": "WID-A",
"category": "industrial",
"current_stock": 420,
"avg_monthly_demand": 300,
"unit_cost": 12.5,
"selling_price": 24,
"lead_time": 21,
"supplier_reliability": "mostly_reliable",
"monthly_sales": [280, 310, 295, 315]
}
]
}
Unauthenticated and free requests support up to 50 SKUs. An active paid request supports up to 500 SKUs. An over-limit free request returns 402 with gate: true; a paid request above 500 returns 400 with message: "Maximum 500 SKUs per analysis.".
{
"success": false,
"gate": true,
"message": "Free Explorer plan supports up to 50 SKUs. You submitted 51 SKUs.",
"upgrade_url": "/api/checkout/professional",
"upgrade_message": "Upgrade to Professional ($149/mo) for unlimited access."
}
Paid over-limit response (501 SKUs)
{
"success": false,
"message": "Maximum 500 SKUs per analysis."
}
Successful response groups
{
"success": true,
"company_name": "Example Distribution",
"service_level": 95,
"analysis_date": "2026-09-02T12:00:00.000Z",
"portfolio": {
"health_score": 86,
"total_skus": 1,
"total_inventory_value": 5250,
"total_monthly_carrying_cost": 122.5,
"total_annual_carrying_cost": 1470,
"dead_stock_value": 0,
"dead_stock_pct": 0,
"excess_capital": 0,
"inventory_turns": 6.9,
"status_summary": { "optimal": 1, "overstocked": 0, "reorder_now": 0, "dead_stock": 0 }
},
"skus": [{
"name": "Widget A", "sku": "WID-A", "category": "industrial",
"current_stock": 420, "avg_monthly_demand": 300, "unit_cost": 12.5,
"selling_price": 24, "lead_time": 21, "supplier_reliability": "mostly_reliable",
"safety_stock": 46, "reorder_point": 256, "eoq": 155,
"days_of_supply": 42, "monthly_carrying_cost": 122.5,
"inventory_value": 5250, "excess_value": 0, "status": "optimal",
"status_emoji": "✅", "days_until_reorder": 16, "optimal_stock": 334,
"ai_insight": { "name": "Widget A", "key_insight": "Inventory levels are within optimal range", "recommendation": "Maintain current reorder cadence" }
}],
"dead_stock_analysis": { "skus": [], "total_value": 0, "strategy": "No significant dead stock." },
"cash_flow": { "current_monthly_carry": 122.5, "optimized_monthly_carry": 85.75, "monthly_savings": 36.75, "capital_freed": 0, "insight": "Optimize inventory to free working capital." },
"reorder_calendar": [{ "sku": "Widget A", "order_date": "2026-09-18", "days_from_now": 16, "order_quantity": 155, "urgency": "upcoming" }],
"benchmark_comparison": { "category": "Industrial & MRO", "your_turns": 6.9, "industry_turns": 6.2, "turns_gap_pct": 11, "your_dos": 42, "industry_dos": 59, "your_dead_pct": 0, "industry_dead_pct": 5.8, "interpretation": "Inventory is turning efficiently." },
"ai_analysis": {
"executive_summary": "Portfolio health score: 86/100.",
"top_priority_action": "Maintain calculated reorder points.",
"dead_stock_strategy": "No significant dead stock.",
"cash_flow_insight": "Current carrying costs can be reduced by right-sizing.",
"reorder_narrative": "No immediate reorder actions required.",
"sku_insights": [{ "name": "Widget A", "key_insight": "Inventory levels are within optimal range", "recommendation": "Maintain current reorder cadence" }],
"supplier_dependency_risk": "Review backup suppliers for frequently-late vendors.",
"benchmark_interpretation": "Inventory turns compare favorably with the industry average.",
"optimization_roadmap": [{ "week": "Week 1-2", "action": "Review reorder points", "expected_impact": "Prevent stockouts" }],
"automated_monitoring_checklist": ["Weekly: Check SKUs at or below reorder point"]
},
"disclaimer": "AI-generated recommendations for informational purposes only. Not financial advice. Verify with your operations team. <a href=\"/ai-disclaimer\">Learn more</a>"
}
Demand prediction
POST /api/forecasting/predict
Authentication is optional. Send a string account_key, at least three oldest-first historical_demand values, and optionally horizon (default 3, capped at 12), product_name, and industry. The submitted tier is not trusted; the route derives the effective tier from the current account entitlement.
{
"account_key": "example-distribution-widget-a",
"historical_demand": [820, 860, 910, 940],
"horizon": 3,
"product_name": "Widget A",
"industry": "industrial"
}
Without authentication, or for a non-Premium caller, the response is the free shape:
{
"success": true,
"tier": "free",
"account_key": "example-distribution-widget-a",
"forecasts": [
{ "h": 1, "point": 952, "low80": 923, "high80": 981, "low95": 907, "high95": 997 },
{ "h": 2, "point": 964, "low80": 922, "high80": 1006, "low95": 899, "high95": 1029 },
{ "h": 3, "point": 976, "low80": 922, "high80": 1030, "low95": 894, "high95": 1058 }
],
"model_info": { "alpha": 0.3, "beta": 0.1, "gamma": 0.1, "total_cycles": 0, "avg_accuracy_pct": null, "accuracy_trend": [] },
"upsell": {
"message": "Upgrade to Pro to unlock the learning loop — your forecasts improve each cycle.",
"accuracy_potential": "60% → 90%+ over 12 months"
}
}
An active paid entitlement receives the Premium learning-loop shape. It has the same forecast entry fields, but model_info reflects learned parameters and there is no free-tier upsell object.
{
"success": true,
"tier": "premium",
"account_key": "example-distribution-widget-a",
"forecasts": [{ "h": 1, "point": 952, "low80": 923, "high80": 981, "low95": 907, "high95": 997 }],
"model_info": { "alpha": 0.312, "beta": 0.104, "gamma": 0.098, "total_cycles": 7, "avg_accuracy_pct": 88.4, "accuracy_trend": [87.1, 88.4] }
}
Forecast feedback
POST /api/forecasting/feedback
This endpoint requires a Bearer token and an active entitlement. Send account_key, numeric predicted, numeric positive actual, and optionally forecast_period and product_name.
{
"account_key": "example-distribution-widget-a",
"predicted": 952,
"actual": 970,
"forecast_period": "30d",
"product_name": "Widget A"
}
Successful response
{
"success": true,
"mape": 1.9,
"accuracy_pct": 98.1,
"reward": 0.981,
"model_updated": {
"before": { "alpha": 0.3, "beta": 0.1, "gamma": 0.1 },
"after": { "alpha": 0.301, "beta": 0.101, "gamma": 0.1 }
},
"total_cycles": 8,
"avg_accuracy_pct": 89.6,
"accuracy_history": [{ "cycle": 8, "mape": 1.9, "accuracy_pct": 98.1, "reward": 0.981, "timestamp": "2026-09-02T12:00:00.000Z" }]
}
Accuracy and platform stats
GET /api/forecasting/accuracy?account_key=...
This is a public read endpoint. It returns a no-model response when the account has not created a Premium model:
{
"success": true,
"account_key": "new-account",
"has_model": false,
"total_cycles": 0,
"avg_accuracy_pct": null,
"accuracy_history": [],
"model_params": null
}
When a model exists, the response adds the Premium tier, improvement, model parameters, and platform context:
{
"success": true,
"account_key": "example-distribution-widget-a",
"has_model": true,
"tier": "premium",
"total_cycles": 8,
"avg_accuracy_pct": 89.6,
"improvement_pct": 4.2,
"accuracy_history": [],
"model_params": { "alpha": 0.301, "beta": 0.101, "gamma": 0.1 },
"platform_avg_accuracy": 84.7,
"platform_total_models": 42,
"platform_total_cycles": 318
}
GET /api/forecasting/platform-stats
This public endpoint returns aggregate platform context:
{
"success": true,
"total_models": 42,
"avg_accuracy_pct": 84.7,
"avg_mape": 15.3,
"models_above_80_pct": 29,
"total_feedback_cycles": 318,
"stat_date": "2026-09-02"
}
Entitlement and status matrix
| Situation | Result |
|---|---|
feedback with missing or invalid Bearer auth | 401 JSON: {"success":false,"message":"Authentication required"} for missing auth; an invalid token returns {"success":false,"message":"Invalid or expired token"}. |
feedback with an authenticated Explorer or inactive user | 403 JSON: {"success":false,"message":"Active Premium subscription required"}. |
predict without auth or with a non-Premium entitlement | 200 free forecast shape with tier: "free" and upsell. |
predict with an active paid entitlement | 200 Premium learning-loop shape with tier: "premium". |
| Inventory optimization without auth or over 50 SKUs on free access | Optional auth falls back to free access; over the free limit returns 402 with gate: true, upgrade_url, and the route’s upgrade message. |
| Inventory optimization with active paid access over 500 SKUs | 400 JSON with message: "Maximum 500 SKUs per analysis.". |
These JSON responses are different from the server-level scanner response. Requests whose User-Agent matches the security scanner blocker are stopped before routing with plain-text 403 Forbidden. Use a normal browser-like User-Agent for manual requests; the examples above use fetch instead of assuming raw curl will pass that middleware.
Usage expectations
There is no endpoint-specific rate limiter on these documented routes. A successful authenticated predict records one forecast_generated credit asynchronously. Feedback and inventory optimization do not consume credits.
For server-returned account state, authenticated callers can use GET /api/billing/status and GET /api/billing/usage. Do not promise a fixed Premium monthly allowance: the current TIER_CREDITS map has no premium entry.
Next steps
See the Premium page for entitlement details, pricing for current plan options, or try the demand forecaster in the browser.
AI-generated planning output: Forecasts and inventory recommendations are estimates for informational purposes. Validate results against your operational data and decisions with your team; they are not financial advice or a guarantee of future performance.