The FastAPI backend runs on https://localhost:8443 in the default Docker setup. Interactive Swagger docs are available at /docs and ReDoc at /redoc — those are always up to date with the code.
Health check. Returns {"status": "ok"}. No auth required.
Returns whether API auth is enabled and whether any users exist. No auth required.
{"auth_enabled": true, "has_users": true}All of these require X-API-Username and X-API-Key headers.
Upload a CSV or XLSX file for forecasting.
Request: multipart/form-data with a file field.
Response:
{"file_id": "abc123", "filename": "data.csv", "rows": 144, "columns": ["date", "value"]}Run data quality checks on an uploaded file before forecasting.
Request:
{
"file_id": "abc123",
"forecast_horizon": 12,
"date_col": "date",
"value_col": "value"
}Response: Quality metrics, missing value counts, outlier detection results, and recommended transformations.
Start a forecasting job. Returns a job_id that you poll with /jobs/{job_id}.
Request:
{
"file_id": "abc123",
"forecast_horizon": 12,
"date_col": "date",
"value_col": "value"
}Response:
{"job_id": "xyz789", "status": "queued"}Poll job status. Returns the current state and, when complete, the full results.
Response (in progress):
{"job_id": "xyz789", "status": "running", "progress": "Forecasting..."}Response (complete):
{
"job_id": "xyz789",
"status": "completed",
"results": {
"forecast": [...],
"lower_ci": [...],
"upper_ci": [...],
"rmse": 2.34,
"mae": 1.87,
"mape": 5.2,
"model": "ARIMA(1,1,1)",
"report": "..."
}
}| Method | Path | Description |
|---|---|---|
POST |
/jobs/{job_id}/actuals |
Record or correct observed values as a JSON timestamp-to-number mapping; return updated accuracy |
GET |
/jobs/{job_id}/monitoring |
Read accuracy, bias, baseline skill, coverage, and horizon scores for an issued forecast |
Both endpoints require authentication and job ownership (or admin access). Predictions are immutable. Unknown jobs and jobs without snapshots return 404; invalid actuals return 422. See statistical forecasting for examples, model options, and interpretation.
Ask a follow-up question about the analysis results.
Request:
{"job_id": "xyz789", "query": "Why was ARIMA chosen over Holt-Winters?"}Response:
{"answer": "ARIMA was selected because..."}These endpoints also require auth. They let you manage API users from the admin panel.
| Method | Path | Description |
|---|---|---|
GET |
/api-users |
List all API users (never includes key hashes) |
POST |
/api-users |
Create a new API user (returns plaintext key once) |
POST |
/api-users/{id}/rotate |
Rotate a user's key (returns new plaintext key once) |
POST |
/api-users/{id}/toggle |
Enable or disable a user |
DELETE |
/api-users/{id} |
Delete a user |
First-run provisioning. Unauthenticated; the bootstrap endpoint is guarded by an atomic "no users exist yet" check (no preset admin token).
| Method | Path | Description |
|---|---|---|
GET |
/setup/status |
Setup state flags (setup_complete, admin_exists, llm_configured, models_enabled) — never secrets |
POST |
/setup/bootstrap |
One-time atomic bootstrap: creates the first admin API user, generates the backend encryption key, enables auth. 409 once any user exists |
| Method | Path | Description |
|---|---|---|
GET |
/config/llm |
Masked LLM config (provider, model, base_url, temperature, api_key_set) — the key is never returned |
GET |
/config/llm/allowed-origins |
Saved connection-test allowlist (origins array); always requires verified admin credentials |
PUT |
/config/llm/allowed-origins |
Replace allowlist with {"origins": ["https://ollama.com"]} (up to 100 exact HTTP(S) base URLs); always requires verified admin credentials |
PUT |
/config/llm |
Update LLM config; api_key is write-only (omit to keep the stored key) |
| Method | Path | Description |
|---|---|---|
GET |
/models |
List the seven forecasting models with enabled state |
PUT |
/models/{name} |
Enable/disable a model; 400 when disabling the last enabled model |
All errors return JSON with a detail field:
{"detail": "Unauthorized"}| Status | When |
|---|---|
400 |
Bad file, unsupported extension, file too large, empty file, bad preflight options |
401 |
Missing or invalid API key headers, or disabled account |
409 |
/setup/bootstrap called after setup completed |
404 |
Unknown file_id or job_id |
409 |
Duplicate username, or bootstrap attempted when users already exist |
422 |
Pydantic validation failure (e.g. chat query too long) |
500 |
Unexpected server error (details logged server-side) |
503 |
Worker not ready, or backend unreachable from frontend |
preflight_options.known_covariates supports dated values and revision histories:
{
"known_covariates": {
"price": {
"2025-01-01": [
{"value": 9.99, "available_at": "2024-11-01"},
{"value": 10.99, "available_at": "2025-02-01"}
]
}
},
"monitoring_series_id": "store-12-product-8-units"
}Supply every historical and forecast timestamp required by the model. Each fit
uses the latest version available at its training cutoff. A missing eligible
version fails that candidate’s fold. Scalar predictor values require an explicit
covariates_known_in_advance: true assertion; the fit records that assumption.
Custom events accept available_at too, defaulting to their event date.
POST /monitoring/compare accepts a JSON array of 1–100 distinct job IDs:
["earlier-job-id", "later-job-id"]The endpoint checks ownership of every job and returns 404 for inaccessible jobs,
or 422 for invalid or incompatible groups. Jobs must refer to the same owner,
application user, target columns, units, frequency, aggregation, bounds, and forecast quantile.
Use the same monitoring_series_id across uploads of one continuing series;
otherwise the comparison requires the same file ID.
The response includes summary, earlier, recent, alerts, and alert_status.
It groups complete runs with equal horizon lengths into recent and earlier
windows, each with at least five runs, 20 observations, and 20 distinct actual
dates. Alerts remain unavailable until both groups meet those requirements.
Duplicate forecast origins count once. These are descriptive review rules;
they neither establish statistical drift nor trigger automatic retraining.
Forecast responses also include validation_design.interval_calibration, with
per-horizon sample counts, empirical interval expansions, and a separate final-test
coverage/width audit. Five non-overlapping observed backtest errors are required
per horizon. Unsupported horizons retain their model intervals. The adjustment
uses selection folds and does not guarantee nominal coverage.