---
title: "Submit an async forecast job"
method: POST
path: "/api/v1/forecasts"
---

# Submit an async forecast job

`POST /api/v1/forecasts`

Submits a monthly forecast job. The job runs asynchronously — poll
`GET /api/v1/forecasts/{id}` until `status` is `completed` or `failed`.
Output files are then available via `GET /api/v1/forecasts/{id}/artifacts/{name}`.

The timeseries must contain at least the horizon-dependent minimum number of
monthly observations (40 for max horizon 1–3, 60 for 4–6, 120 for 7–12) aligned
to the first of each month. At least one of `soft_horizon` or `hard_horizon`
must be specified.

## Request body

- ForecastRequestV1 — Body of `POST /api/v1/forecasts`. Submit a monthly timeseries and the pipeline produces a forward forecast (and optionally a backtest). At least one of `soft_horizon` or `hard_horizon` must be present. The minimum number of monthly observations depends on the largest requested horizon (`max(soft_horizon, hard_horizon)`): **40** points for horizons 1–3, **60** for 4–6, and **120** for 7–12. Observations must be aligned to the first of each month (YYYY-MM-01). `recency_factor` controls how strongly the driver-selection step weights recent data.
  - `aux_timeseries` object[] — Optional. One to ten auxiliary driver series. Each item is a map of the same YYYY-MM-DD date keys as `timeseries` — exactly the same dates, no more and no fewer — to numeric values. Each series becomes a forecast driver that is kept through feature selection, and series are identified by their array position (the first is `aux_0`, the second `aux_1`, and so on). When omitted, the forecast runs without auxiliary drivers.
  - `backtest` boolean — When true, run a backtest evaluation alongside the forecast and include `backtest_metrics.json` and `backtest_trajectories.json` in the artifacts.
  - `filters` Filters — Optional narrowing for forecast, drivers, and alerts requests. Category and region ids must fall in **1–9999**. Discover valid ids via `GET /api/v1/regions` and `GET /api/v1/categories` — submitted ids are not cross-checked on submit.
    - `categories` integer[] — Thematic category ids to filter by; each must be an integer **1–9999** inclusive.
    - `general_drivers` boolean — When true, general (non category/region-specific) drivers are included in the driver candidate pool. Defaults to false.
    - `limit` integer — Maximum number of items to return. When omitted, a per-environment default is applied (100 by default). The maximum accepted value is operator-configurable (default 1000).
    - `regions` integer[] — Geographic region ids to filter by; each must be an integer **1–9999** inclusive.
  - `frequency` 'monthly', required — Series cadence. Only `monthly` is currently supported.
  - `hard_horizon` integer — Minimum acceptable horizon (months) for the quality step-down ladder. When omitted, the pipeline falls back to a driverless forecast at `soft_horizon` if no quality run succeeds. When still failing at `hard_horizon`, the pipeline emits a driverless forecast at that horizon. At least one of `soft_horizon` or `hard_horizon` must be present. When both are set, `hard_horizon` must be less than or equal to `soft_horizon`. Maximum 12.
  - `max_num_features` integer — Optional. Caps the number of drivers kept by the final feature-selection step (top-k). When omitted, the pipeline uses the regime default. Bounded above by the regime's selector ceiling, so a value larger than that cap is a no-op. Must be a positive integer when present.
  - `optimization_budget` 'none' | 'low' | 'mid' | 'high' — Optional. Tunes the number of hyper-parameter-optimization trials. `low` runs fewer trials, `high` runs the most; `none` and `mid` fall back to the pipeline default. Defaults to `none`.
  - `pipeline_version` 'v1', required — Pipeline version. Closed set — only `v1` is supported today.
  - `recency_factor` number, double, required — Weight given to more recent observations when selecting drivers. 0.0 = equal weight across the full history; 1.0 = strongest recency bias.
  - `run_baseline` boolean — When true, re-run the same primary model with drivers stripped and surface its metrics as a self-comparison baseline alongside the reference baselines, isolating the lift the drivers add. Defaults to false.
  - `soft_horizon` integer — Ideal forecast horizon (months). The pipeline tries this first, then steps down by one month until it reaches `hard_horizon` (when set) while seeking a quality forecast. At least one of `soft_horizon` or `hard_horizon` must be present. When both are set, `hard_horizon` must be less than or equal to `soft_horizon`. Maximum 12.
  - `strictly_positive` boolean — When true, every value in `timeseries` must be `>= 0`; a single negative observation rejects the request with 422. The pipeline also clamps output values at zero. Defaults to false.
  - `timeseries` object, required — Map of YYYY-MM-DD date keys to numeric observation values. Must contain at least the horizon-dependent minimum number of monthly observations (40 for max horizon 1–3, 60 for 4–6, 120 for 7–12) aligned to the first of each month.
  - `timeseries_metadata` TimeseriesMetadata, required — Descriptive metadata the ranking model uses to interpret and contextualize the timeseries.
    - `description` string — Extended context for the model, up to 2048 characters. More detail improves driver relevance.
    - `keywords` string[] — Up to 20 semantic tags that help anchor the search to relevant datasets.
    - `title` string, required — Short identifier for the series, 20–511 characters.
  - `trend_num_classes` 2 | 3 — Optional. Trend-classification label granularity: `2` (binary up/down) or `3` (down/flat/up). Consumed only on the trend analysis path and ignored otherwise. When omitted, the pipeline applies its default of `3`.

## Response `202`

Job accepted. Use `job_id` to poll status.

- object
  - `job_id` string, uuid — Unique job id — use this to poll status and download artifacts.
  - `poll_url` string — Convenience URL for polling this job's status.
  - `run_id` string — Internal run identifier (opaque; useful for support).
  - `workflow` string — Internal workflow identifier (opaque; useful for support).

## Other responses

- `400` — Malformed JSON body.
- `401` — Missing or invalid bearer token.
- `402` — Insufficient credits.
- `413` — Request body too large.
- `422` — Payload failed validation.
- `429` — Too many concurrent jobs for your tier.
- `503` — Service Unavailable

---

[API](https://skmtc.net/sybilion/apis/sybilion-api.md) · [All operations](https://skmtc.net/sybilion/apis/sybilion-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/sybilion/sybilion-api/versions/2ba1f4c6f25d/schema)
