Forecasting
Forecasting API
The canonical request and response contract for `/v1/forecast`, including covariates, timestamps, quantiles, batch jobs, and ensemble routing.
Canonical request
Standardize on the canonical shape { model, inputs, parameters } for all new integrations. Compatibility aliases remain accepted for migration, but the canonical form is what the playground, SDK examples, MCP tools, and the reference docs all optimize around.
{
"model": "google/timesfm-2.0-500m-pytorch",
"inputs": [{
"start": "2026-03-01T00:00:00Z",
"target": [[110], [113], [108], [116], [119], [121]],
"past_covariates": {
"promo": [0, 1, 0, 1, 1, 0]
},
"future_covariates": {
"promo": [1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0]
},
"static_covariates": {
"store_cluster": 2,
"shelf_capacity": 1
},
"metadata": {"item_id": "sku_42"}
}],
"parameters": {
"prediction_length": 12,
"frequency": "D",
"quantile_levels": [0.1, 0.5, 0.9],
"context_length": 256
},
"metadata": {
"surface": "docs.forecast"
}
}{
"id": "6a6e8f62-7f6e-43e5-a33a-64279440cb90",
"object": "forecast",
"created": 1773369600,
"model": "google/timesfm-2.0-500m-pytorch",
"provider": "harpoon",
"horizon": 12,
"prediction_length": 12,
"quantile_levels": [0.1, 0.5, 0.9],
"input_points": 6,
"outputs": [{
"mean": [[122.0], [123.3], [124.1], [124.8], [125.4], [126.0], [126.8], [127.4], [128.0], [128.9], [129.4], [129.9]],
"quantile_predictions": [
{"level": 0.1, "values": [[119.4], [119.8], [120.6], [121.0], [121.7], [122.1], [122.6], [123.0], [123.6], [124.0], [124.5], [124.8]]},
{"level": 0.5, "values": [[122.0], [123.3], [124.1], [124.8], [125.4], [126.0], [126.8], [127.4], [128.0], [128.9], [129.4], [129.9]]},
{"level": 0.9, "values": [[125.2], [126.9], [127.7], [128.8], [129.6], [130.2], [131.3], [132.0], [132.9], [133.6], [134.2], [134.8]]}
],
"timestamps": [
"2026-03-07T00:00:00Z",
"2026-03-08T00:00:00Z",
"2026-03-09T00:00:00Z",
"2026-03-10T00:00:00Z",
"2026-03-11T00:00:00Z",
"2026-03-12T00:00:00Z",
"2026-03-13T00:00:00Z",
"2026-03-14T00:00:00Z",
"2026-03-15T00:00:00Z",
"2026-03-16T00:00:00Z",
"2026-03-17T00:00:00Z",
"2026-03-18T00:00:00Z"
],
"metadata": {"item_id": "sku_42"}
}],
"usage": {
"input_tokens": 188,
"output_tokens": 36,
"total_tokens": 224
},
"latency_ms": 51,
"metadata": {
"surface": "docs.forecast"
}
}Request semantics
Be explicit about timeline and feature alignment
Most integration bugs are not caused by the top-level JSON shape. They happen when clients disagree with the service about cadence, timestamp generation, or how covariates line up against the target history and future horizon.
Timeline rules
| Field | Type | Required | Description |
|---|---|---|---|
| `inputs[].start` + `parameters.frequency` | regular cadence | Conditional | The wire shape assumes a regular grid. A start timestamp plus a pandas offset alias defines the time index for both the input and the returned forecast timestamps. |
| `inputs[].target` | (number | null)[][] | Yes | Always 2D — outer axis is time, inner axis is channels. Univariate uses a length-1 channel axis. Use null to encode missing observations; models that support imputation will handle them, others will reject or impute internally. |
| `parameters.prediction_length` | integer >= 1 | Yes | Defines the horizon length. It also becomes the minimum number of forward-looking values you should plan for when you send future covariates. |
| `parameters.frequency` | string | Conditional | Pandas offset alias (D, 1h, 15min, Q, etc.). Strongly recommended whenever you expect returned forecast timestamps — without it, clients should not assume a calendar interval from the response alone. |
Covariate rules
| Field | Type | Required | Description |
|---|---|---|---|
| `past_covariates` | dict<string, (number | null)[]> | No | Historical covariate arrays should align to the observed target history. Treat them like parallel feature columns for the same past window. null is allowed for missing observations. |
| `future_covariates` | dict<string, number[]> | No | Forward-looking covariates should cover the forecast horizon. Keep the feature names stable across series so downstream evaluation stays interpretable. |
| `static_covariates` | dict<string, number> | No | Series-level scalar attributes such as store cluster or asset class. Use them when the model family supports static context. |
| `metadata` | object | No | Opaque per-series metadata, echoed verbatim on the corresponding output. The convention for join keys is metadata.item_id, but the server doesn't interpret the contents — store whatever your downstream needs. |
{
"model": "amazon/chronos-bolt-small",
"inputs": [{
"start": "2026-02-01T00:00:00Z",
"target": [[428], [435], [441], [438], [446], [452], [460], [458], [466], [472]],
"metadata": {"item_id": "store_017"}
}],
"parameters": {
"prediction_length": 7,
"frequency": "D",
"quantile_levels": [0.1, 0.5, 0.9]
}
}Request fields
Build the payload from three layers
Top-level request fields
| Field | Type | Required | Description |
|---|---|---|---|
| model | string | Yes | Catalog model id, e.g. amazon/chronos-bolt-small. See /api/models for the full list. |
| inputs | array<object> | Yes | One or more series payloads. Preferred canonical shape for TSFM requests. |
| parameters | object | No | Forecast controls (prediction_length, frequency, quantile_levels) and model knobs. |
| metadata | object | No | Opaque passthrough metadata for client traceability. |
Series objects in `inputs[]`
| Field | Type | Required | Description |
|---|---|---|---|
| target | (number | null)[][] | Yes | Historical observations as a 2D array [num_timesteps][num_channels]. Univariate series use a length-1 inner axis; missing observations are encoded as null. |
| start | string (ISO date/time) | No | Anchor timestamp of the first observation. Combined with parameters.frequency it defines the time index for the input and the returned forecast. |
| metadata | object | No | Opaque per-series metadata, echoed verbatim on the corresponding output. Use it for item_id or any join key your downstream needs. |
| past_covariates | record<string, (number | null)[]> | No | Observed exogenous signals aligned with target history. null is allowed for missing observations. |
| future_covariates | record<string, number[]> | No | Known future exogenous signals aligned with the forecast horizon. |
| static_covariates | record<string, number> | No | Per-series scalar features such as store cluster, region, or product family. |
Forecast parameters
| Field | Type | Required | Description |
|---|---|---|---|
| prediction_length | integer | No | Number of future points to generate. Defaults to 24 in the backend request model. |
| frequency | string | No | Pandas offset alias (D, 1h, 15min, Q, etc.). Combined with inputs[].start it defines the time index and is what unlocks the populated outputs[].timestamps field on the response. |
| quantile_levels | number[] | No | Requested quantiles in ascending order, typically [0.1, 0.5, 0.9]. |
| num_samples | integer | No | When set on a sample-based probabilistic model, returns outputs[].samples with shape [num_samples][prediction_length][num_channels]. Ignored by deterministic models. |
| context_length | integer | No | Optional cap on the number of historical observations passed to the model. |
| sensitivity | number | Conditional | Anomaly threshold for /v1/detect-anomalies (higher means fewer anomalies). |
| temperature | number | No | Optional sampling temperature for models whose metadata explicitly advertises temperature support. Requests to unsupported models return INVALID_ARGUMENT. |
| top_p | number | No | Optional nucleus sampling control for models whose metadata explicitly advertises top-p support. Requests to unsupported models return INVALID_ARGUMENT. |
Implementation notes
- Use `inputs[]` even for a single series. It keeps your payload shape stable when you later add batching or multiple series.
- Always 2D `target`. The inner axis is channels: a univariate series is `[[v1], [v2], …]`, multivariate is `[[v1_a, v1_b], …]`.
- Send `inputs[].start` plus `parameters.frequency` whenever timestamps matter — that's what populates `outputs[].timestamps` on the response.
- Put any user-side identifier (item id, channel names, tags) in `inputs[].metadata`. The server echoes it verbatim on the corresponding output.
- Request `parameters.quantile_levels` explicitly if your downstream consumers need uncertainty bands or interval-based business logic.
- Treat `usage` and `latency_ms` as first-class telemetry and persist them next to request ids in production.
Response fields
Read the result like a production client
The response includes forecast outputs and the operational telemetry you should log. Most downstream bugs happen when teams read the forecast line but ignore timing, usage, or item ids.
Response shape
| Field | Type | Required | Description |
|---|---|---|---|
| id / object / created | string / string / integer | Yes | Stable envelope fields for logging, tracing, and replay. |
| horizon / prediction_length | integer | Yes | Requested forecast length echoed in normalized response form. |
| quantile_levels | number[] | Yes | The quantile levels returned in outputs[].quantile_predictions. |
| outputs | array<object> | Yes | Forecast outputs per input series. Each entry has mean (2D, [time][channels]), optional quantile_predictions (array of {level, values: 2D}), optional samples, optional timestamps, and the verbatim echo of the input's metadata. |
| usage | object | Yes | Token accounting used by usage/billing dashboards. |
| latency_ms | number | Yes | Observed server latency for the request. |
| metadata | object | No | Opaque client metadata echoed back for request correlation. |
| truncated_from | integer | No | Original number of input points before truncation. Present only when the input exceeded the model's maximum context length and was automatically truncated (most recent values kept). |
| max_context_length | integer | No | Maximum served context length for this model on TSFM.ai. Present only when truncation occurred. |
Validation failures
The mistakes that usually produce 4xx responses
When a request fails, verify the contract before you retry. The most common issues are missing horizon parameters, timeline ambiguity, misaligned covariates, and ensemble requests that are too short to score.
Missing or malformed `prediction_length`
A forecast call is not actionable without a horizon. Keep `parameters.prediction_length` present and greater than zero on every request, even in local smoke tests.
1D `target` arrays
`target` is always 2D, even for univariate series. If you have a `number[]`, wrap each value: `[v1, v2, v3]` becomes `[[v1], [v2], [v3]]`. Sending a 1D array returns `INVALID_ARGUMENT`.
Timeline assumptions without `frequency`
If downstream code expects returned `outputs[].timestamps`, send `inputs[].start` and `parameters.frequency`. Otherwise the forecast is numerically correct but the response will not include a timestamp index for charting or joins.
Covariate arrays that do not align to history or horizon
Treat covariates as synchronized feature columns. Past covariates should align to observed history; future covariates should cover the forecast horizon you asked for.
Ensemble requests with series shorter than the held-out horizon
Ensemble selection performs an internal backtest. At least one input series must be longer than `prediction_length`, otherwise the route returns a validation error.
{
"detail": [
{
"loc": ["body", "parameters", "prediction_length"],
"msg": "Field required",
"type": "missing"
}
]
}Common patterns
Expand from a single forecast without changing mental models
Once the base contract is stable, you can add richer patterns such as batch execution or ensemble selection. Those patterns still build on the same canonical series objects and parameter names.
{
"requests": [
{
"model": "amazon/chronos-bolt-small",
"inputs": [{
"target": [[10], [11], [12], [13], [14]],
"metadata": {"item_id": "north"}
}],
"parameters": { "prediction_length": 6, "frequency": "D" }
},
{
"model": "google/timesfm-2.5-200m-pytorch",
"inputs": [{
"target": [[6], [7], [8], [9], [10]],
"metadata": {"item_id": "south"}
}],
"parameters": { "prediction_length": 6, "frequency": "D" }
}
]
}{
"object": "list",
"data": [
{
"ok": true,
"result": {
"object": "forecast",
"model": "amazon/chronos-bolt-small",
"prediction_length": 6,
"outputs": [{ "mean": [[10.5], [11.1], [11.7], [12.2], [12.7], [13.1]], "metadata": {"item_id": "north"} }]
}
},
{
"ok": false,
"error": {
"error": "Model access denied",
"code": "PERMISSION_DENIED",
"endpoint": "/v1/forecast"
}
}
]
}