---
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 60 monthly observations (5 years) 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 timeseries must contain at least 60 monthly observations (5 years) aligned to the first of each month (YYYY-MM-01). `recency_factor` controls how strongly the driver-selection step weights recent data.
  - `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.
    - `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 strictly less than `soft_horizon`. Maximum 12.
  - `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.
  - `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 strictly less than `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 60 monthly observations (5 years of history) 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.

## 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.
- `422` — Payload failed validation.
- `503` — Service Unavailable

---

[API](https://skmtc.dev/sybilion/apis/sybilion-api.md) · [All operations](https://skmtc.dev/sybilion/apis/sybilion-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/sybilion/sybilion-api/revisions/7dd56c65ce7f/schema)
