API Reference
The forecast engine is a FastAPI service (forecast-api/, port 8020). Base path: /api/powerforecast/v1. OpenAPI: /docs and /openapi.json.
Endpoints
| Method | Path | Does |
|---|---|---|
| POST | /jobs | submit a forecast; answers at once with the job id (status: partial) |
| GET | /jobs/{jobId} | job status: partial while PENDING / RUNNING, success when DONE, failed with the error |
| GET | /jobs/{jobId}/result | the forecast result (below) once DONE |
| GET | /jobs/{jobId}/diagnostics | the residual diagnostics once DONE |
| POST | /forecast | same pipeline, synchronous: the result in one call (long for many series) |
| GET | /runs | the stored forecasts (below) |
| GET · PATCH · DELETE | /runs/{id} | one stored forecast: read (with spec, result, diagnostics), rename, delete |
| POST | /runs/{id}/restore, /runs/{id}/copy-spec | undo a delete; the stored request, to start a new forecast from it |
| GET | /runs/{id}/audit | its history |
| POST | /runs/import | store the files of an earlier run: {name?, spec?, result, diagnostics?} → 201 (history action import) |
| GET | /models | the methods the engine knows |
| GET | /enterprise-info | what the profiling and validation stages do |
| GET | /health, /info | (no prefix) liveness and service information |
The wizard uses the asynchronous flow: POST /jobs, poll GET /jobs/{id} every 0.5 s, then /result and /diagnostics.
Stored forecasts (/runs)
Every job the engine runs (/jobs or /forecast) is also stored as a run in the product's SQLite database (/data/powerforecast.db, volume powerforecast-data): the full request (input series included), the result, the diagnostics, the status (RUNNING, DONE, FAILED), who asked (header X-PPT-User, else caller, else api) and when. Runs never expire. Redis still holds the jobs while they run and for RUN_TTL_SECONDS after; once a job left Redis, GET /jobs/{id}, /result and /diagnostics answer from the stored run, so a finished job never vanishes. GET /jobs/{id} also gives run_id.
A request with call_context: "critic" (the AI Forecast Critic's trials) is stored with kind: "trial" and left out of GET /runs unless kind=trial or kind=all.
Query of GET /runs | Meaning |
|---|---|
query | text in the name or description (any case, accents included) |
kind | run (default), trial or all |
status | RUNNING, DONE or FAILED |
include_deleted | also the deleted runs |
limit, after | page size (≤ 500) and the id of the last row of the previous page (payload.next) |
Delete is two-step: DELETE /runs/{id} hides the run (restorable with POST /runs/{id}/restore); DELETE /runs/{id}?purge=true on a deleted run removes it for good (the history keeps its name and hash). Errors: NOT_FOUND 404, NOT_DELETED 409 (purge or restore of a run that is not deleted), TOO_LARGE 413 (a request over FORECAST_MAX_JSON_MB, 50 MB, refused by /jobs and /forecast before any work).
No sign-in check yet. Anyone who can reach the API can list, change and remove stored forecasts. Accepted until the product has its own authentication; keep backups (installation guide).
The envelope
Every response of /api/powerforecast/v1 is a PDP ProductResponseEnvelope:
{
"jobId": "jobId_1792874861471",
"producer": "PowerForecast",
"status": "success | partial | failed",
"timestamp": "2026-10-25T09:12:03.120Z",
"execution_time_ms": 48160,
"payload": { },
"errors": [ { "code": "VALIDATION_ERROR", "message": "…", "recoverable": true } ],
"trace": { "caller": "self", "call_context": "standalone" }
}
A refused or failed forecast still answers HTTP 200 with status: failed and errors[].
| Code | When |
|---|---|
VALIDATION_ERROR | the request does not fit (e.g. a series with no value) |
PIPELINE_PRODUCED_EMPTY_RESULTS | the pipeline ran but produced no usable forecast |
PIPELINE_ERROR | an unexpected engine error |
NOT_FOUND, JOB_FAILED, RESULT_MISSING, DIAGNOSTICS_MISSING | job lookups |
Request (POST /jobs, POST /forecast)
{
"caller": "self", "call_context": "standalone",
"name": "US retail sales 2026 budget",
"description": "…",
"business_target": "revenue",
"granularity": "per_category",
"scenario_type": "baseline",
"frequency": "M",
"horizon": 12,
"confidence_level": 0.95,
"models": null,
"handle_missing": true,
"handle_outliers": true,
"data": [
{ "unique_id": "Grocery stores", "ds": ["2015-01-01", "2015-02-01", "…"], "y": [48210.0, 45102.0, "…"] }
]
}
| Field | Values |
|---|---|
frequency | H, D, W, M, Q, Y |
horizon | 1 – 365 periods |
confidence_level | 0.5 – 0.99 (the wizard offers 0.8, 0.9, 0.95, 0.99) |
models | null or ["Auto"] = automatic; or a list among AutoARIMA, ETS, SeasonalNaive, Naive, Theta, MSTL |
enterprise_mode, validate_patterns | default true: consensus profiling and holdout validation of patterns |
name, description, business_target, granularity, scenario_type | labels kept with the run |
caller, call_context | trace (self / standalone for the wizard; PowerOrchestrator sets its own) |
Result (payload of /jobs/{id}/result)
| Field | Holds |
|---|---|
jobId, status (completed), business_target, frequency, horizon, series_count, execution_time_ms, models_used | the run |
forecasts[] | per series: unique_id, model_used, forecasts[] (ds, yhat, yhat_lower, yhat_upper), interval_method (model or none), accuracy |
forecasts[].accuracy | cross-validation: method, champion, mape, rmse, mae, baseline_model (Naive), baseline_rmse, candidates (each method's mape, rmse, mae) |
profiling[], enterprise_profiling[] | per series: count, mean, std, trend / seasonality / variance detection with consensus and validation, recommended transform and outlier method, data_quality, profile_reliability, warnings |
validation_summary | counts over all series |
diagnostics, enterprise_diagnostics | overall_quality, quality_score, recommendations, test_summary |
decisions[] | the engine's decision log: category (profiling, transform, outlier, model), series_id, decision, rationale, confidence, alternatives, metrics |
The wizard adds data (the input series) to the saved results file, so the Results page can draw the history.
Diagnostics (payload of /jobs/{id}/diagnostics)
residual_diagnostics[] per series: residual_mean, residual_std, skewness, kurtosis, has_bias (with its p-value), is_normal (normality tests), is_uncorrelated (Ljung-Box, Durbin-Watson), is_homoscedastic (Breusch-Pagan and others), analysis_scale, failed_tests. Plus overall_quality, quality_score, recommendations, test_summary.
Example
curl -s -X POST http://localhost:8020/api/powerforecast/v1/jobs \
-H "Content-Type: application/json" --data-binary @forecast-demos/04-us-retail-sales-budget/spec.budget.json
# -> { "status": "partial", "jobId": "jobId_…" }
curl -s http://localhost:8020/api/powerforecast/v1/jobs/jobId_… # until "status": "success"
curl -s http://localhost:8020/api/powerforecast/v1/jobs/jobId_…/result
Jobs, results and diagnostics are kept in Redis with a time-to-live; when a job has expired, the engine can ask PowerOrchestrator for it.