Schemas
ForecastRequest
A forecast request: your data and what its columns mean (input), which columns to forecast (targets), which series and at what level of aggregation (selector), and when and how far ahead to forecast (cutoff, prediction_length and the other time settings).
A timeseries family written out in full: where its rows come from, plus what its columns mean.
targetsThe columns to forecast. Omit to forecast every column the schema
declares with the "target" kind.
Which series to forecast, and at what level of aggregation. Omit it
to forecast every series at the finest level the data has; {}
forecasts a single series, the total over everything. Cannot be
combined with selectors.
Several selectors, to forecast more than one level of aggregation in
one request, such as per store and per city. The response holds the
series of every selector. No two selectors may name the same levels.
Cannot be combined with selector.
{}Quantile levels to forecast for every target, as numbers in
[0, 1]; include "mean" to also request the mean. Defaults to
[0.1, 0.5, 0.9, "mean"].
Score the forecast against the actuals the request carries, and
report the scores under metrics in the response. A cutoff is
scored when its forecast window lies inside the data and observes
some target; missing actuals are skipped. The point scores use the
0.5 quantile when quantiles includes it, and the mean otherwise;
when this is set the mean is forecasted whether or not quantiles
asks for it.
true scores with the default settings and false does not score.
An object scores with the settings it gives: crps picks how the
CRPS weighs the quantile levels, "trapezoid" (the default) or
"mean_quantile_loss". The response does not say which was used.
return_actualsReturn each target's actuals over every forecast window under
actuals in the response, aligned with the forecast values. These
are the values the model reads, after aggregation and gap filling;
a step without a value is null.
model_configOptions for the model named by the model query parameter, passed to
it as given. Each model defines which options it takes and rejects
the ones it does not know.
A non-empty array of information cutoffs. For example ["latest"], an
explicit date ["2025-01-31"], or a recurring schedule [{ "every": "3d" }].
["latest"]Time to skip between the cutoff and the first forecast value. Defaults to
0: the forecast starts at the step right after the cutoff. With daily data
and a cutoff on Monday, a lead_time of "2d" starts the forecast on
Thursday.
How much history before each cutoff the model sees, such as "90d". Leave
it out to send all the history before the cutoff.
How far ahead to forecast, such as "28d" or 28 steps. Defaults to 1:
one step of the time grid.
Time each forecast value covers. Only one step of the time grid is
supported, the default 1. To forecast weekly or monthly totals, select a
coarser time level instead: "selector": { "weekly": "any" }.
Temporary clockwork covariates over the resolved cutoff/context window. UTC and positional calendar values, including pandas W/M/Q anchors. Omit or use [] to bypass. Unsupported on /v0; no publication-vintage guarantees.
[]Input
A timeseries family written out in full: where its rows come from, plus what its columns mean.
Where the timeseries family's rows come from.
The timeseries family's columns, keyed by name. Exactly one declares
kind: "time".
has_gapsWhether rows may be missing from the grid. false, the default,
asserts the rows are complete and reports the first gap as an error.
true completes the grid and lets series start late, then fills the
rows it added the way each column says to: a column with an impute
rule gets that rule's value, and a column without one is left null.
Roll-up paths, keyed by the name you give each one.
Other timeseries families to attach, each contributing extra variables.
nameA name for the timeseries family, for your own reference.
descriptionWhat the timeseries family holds, for your own reference.
metadataAnything you want to keep alongside the timeseries family. It is stored as written and plays no part in the forecast.
Column
Decision Table
| Variant | Matching Criteria |
|---|---|
| No specific criteria | |
| No specific criteria |
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = string | |
| type = string | |
| type = string | |
| type = string |
ColumnRole
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = string | |
| type = string | |
| type = string | |
| type = string |
ColumnDeclaration
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = object · requires: kind | |
| type = object · requires: kind | |
| type = object · requires: kind | |
| type = object · requires: kind | |
| type = object · requires: kind | |
| type = object · requires: kind |
Names which series a row belongs to.
kindtypeType of the column's values. Omit it and the type is read from the data; a type given here wins.
columnColumn to read in the source data, when it differs from the name this
declaration sits under. Cannot be combined with virtual.
virtualExpression computing the column instead of reading it from the source.
Cannot be combined with column. Not supported yet: a request
declaring it is rejected.
descriptionWhat the column means, for your own reference.
Type
A value type: bool, int32, int64, float32, float64, string,
date32, or timestamp_us. Wrap one in nullable<...> to allow
missing values, or in list<...> for a column of lists.
Expression
An expression: an aggregation (sum, mean, avg, min, max, or
first, any one value of a bucket whose values are all equal), a
literal (0, 1.5, true), null (a NULL of the input's type), or a
comma-separated tuple of those in parentheses.
Known
Decision Table
| Variant | Matching Criteria |
|---|---|
| No specific criteria | |
| type = object · requires: at |
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = string | |
| type = string |
KnownTime
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = string | |
| type = string |
KnownAt
An observation time given as an expression. Not supported yet: a request declaring it is rejected.
atWhen the value becomes observable, as an expression over the time column.
Impute
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = object · requires: const | |
| type = object · requires: locf | |
| type = object · requires: locb | |
| type = object · requires: rolling |
Fill every gap with the same value.
constThe value to fill with. A string keeps its own quotation marks inside the JSON string, as the examples show, and there is no null: to leave gaps empty, omit the rule instead.
GapFill
How far a carried value reaches.
max_gapLongest run of consecutive missing values to fill, counted in grid steps. Omit it to fill runs of any length.
Rolling
A statistic over the values around each gap.
Which statistic to compute.
sizeHow many rows around the missing cell contribute. A centred window needs an even number, so it has as many rows on each side.
Where the window sits relative to the value being filled. Defaults to
trailing. centered needs an even size.
RollingStat
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = string | |
| type = string | |
| type = string | |
| type = string |
RollingAlignment
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = string | |
| type = string | |
| type = string |
Interpolate
Decision Table
| Variant | Matching Criteria |
|---|---|
| No specific criteria | |
| type = object · requires: proportional_by |
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = string | |
| type = string |
InterpolateName
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = string | |
| type = string |
ProportionalBy
A split weighted by another column.
proportional_byColumn whose values weight the split.
Rule
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = object · requires: at, impute | |
| type = object · requires: from, to |
How to fill missing values at the levels it names.
atLevels this rule applies at.
How the missing values are filled there.
ImputeRule
How to fill missing values at named levels.
atLevels this rule applies at.
How the missing values are filled there.
RankPattern
Which levels a rule applies to: * for every level of every roll-up path,
or a comma-separated list of clauses, one per path. A clause compares a
path's level with =, >=, <=, >, or <, where the coarser level is
the greater one, and its right-hand side is a level name, * for any
level, or absent for rows not broken down by that path at all.
TransitionRule
How values move from one level to another: aggregate when the target is
coarser, interpolate when it is finer. Giving neither leaves that change
with no rule of its own.
fromLevels the values are read at.
toLevels the values are produced at.
aggregateHow the values combine, when to is the coarser side.
Whether this aggregation includes partial leading and trailing time buckets.
Defaults to drop. An allowed bucket is an ordinary input to later aggregations.
Requires aggregate on this rule; rejected cells are not imputed.
How the values are spread out, when to is the finer side.
PartialBuckets
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = string | |
| type = string |
Encoding
Decision Table
| Variant | Matching Criteria |
|---|---|
| No specific criteria | |
| No specific criteria |
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = string |
EncodingName
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = string |
ConfiguredEncoding
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = object · requires: ordinal |
Numbers the distinct values 0, 1, 2, … in the order they first appear in time across the whole data, ties broken by value.
Options of the ordinal encoding.
OrdinalNulls
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = string | |
| type = string |
Interval
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = string | |
| type = object |
The spacing written as one string.
IntervalString
An interval written as one string: a name (daily, weekly, 5min),
numbers with units separated by spaces (1d 3h), or an ISO 8601 duration
in capitals (P1Y2M10D). Names accept the singular, the plural, and the
adjective (day, days, daily), in any case. The units are y, q,
mo, w, d, h, m, s and us; write them lowercase, since m is
minutes and mo months.
IntervalParts
An interval written field by field. Fields left out count as zero, and the total has to be strictly forward.
yearsWhole years.
monthsWhole months.
daysWhole days.
hoursWhole hours.
minutesWhole minutes.
secondsWhole seconds.
msWhole milliseconds.
usWhole microseconds.
Anchor
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = string | |
| type = object |
A weekday, which anchors weekly grids; a month, which anchors yearly ones; or the date or timestamp the grid starts at.
Partition
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = string | |
| type = object |
The grid's spacing on its own.
Chain
One roll-up path: identifier columns from finest to coarsest. At least one column.
{"0": "store", "1": "city", "2": "country"}Source
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = object · requires: inline | |
| type = object · requires: uri | |
| type = object · requires: parquet |
The rows themselves, one array of values per column name. Every array has the same length, and each position across them is one row.
The rows themselves, one array of values per column name. Every array has the same length, and each position across them is one row.
{
"time": ["2020-01-01", "2020-01-02", "2020-01-03"],
"sales": [12, 9, 15]
}{
"time": ["2020-01-01", "2020-01-01", "2020-01-02", "2020-01-02"],
"store": ["north", "south", "north", "south"],
"sales": [12, 7, 9, 11],
"on_promotion": [false, false, true, false]
}Scalar
A single value: a number, a boolean, a string, or null for a missing observation.
ParquetPaths
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = string | |
| type = array |
One file, or a glob matching several.
Covariate
Another table attached to this one, contributing extra variables such as
weather or prices. The attached table only adds columns: its rows are matched
onto this table's rows by on, and this table's series and time steps stay
as they are. One exception: when a kept variable is of kind future and on
matches the time column, each series also takes the attached rows it matches
past its last time step, with its own variables empty there. A series read at
a finer time step than the one on matches is not extended.
A kept variable keeps its column name unless rename gives it another.
When it clashes with a column already present, the request is rejected if
only or rename is given; otherwise the attached column is renamed with
an _rhs suffix (temperature becomes temperature_rhs).
The attached timeseries family, written out here or pointed at elsewhere.
Which columns to match rows on. Required. An empty list matches every attached row to every row of this table, for a covariate shared by all series, such as a national price index.
{"0": "time"}{"0": {"base": "store", "attached": "shop_id"}, "1": "time"}{"0": {"base": "region", "attached": "region"}, "1": "time"}onlyWhich of the attached table's variables to keep, by their name there. Omit it to keep all of them.
Names to give the kept variables, keyed by the name they carry on the attached timeseries family.
VersionedSchema
A schema document: one timeseries family, plus the version saying which schema format it is written in.
versionWhich schema format this document is written in.
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = object · requires: columns, source, version | |
| type = object · requires: ref, version | |
| type = object · requires: version | |
| type = object · requires: version |
A timeseries family written out in full: where its rows come from, plus what its columns mean.
Where the timeseries family's rows come from.
The timeseries family's columns, keyed by name. Exactly one declares
kind: "time".
versionWhich schema format this document is written in.
has_gapsWhether rows may be missing from the grid. false, the default,
asserts the rows are complete and reports the first gap as an error.
true completes the grid and lets series start late, then fills the
rows it added the way each column says to: a column with an impute
rule gets that rule's value, and a column without one is left null.
Roll-up paths, keyed by the name you give each one.
Other timeseries families to attach, each contributing extra variables.
nameA name for the timeseries family, for your own reference.
descriptionWhat the timeseries family holds, for your own reference.
metadataAnything you want to keep alongside the timeseries family. It is stored as written and plays no part in the forecast.
SchemaUri
Where another schema document lives: a path to a schema file, relative to the document naming it.
On
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = string | |
| type = object · requires: base, attached |
OnPair
One pair of columns to match rows on. Two time columns must step on the
same grid; "time" matches time columns on different grids.
baseColumn in your main table.
attachedColumn in the attached table.
Selector
Which series to forecast, and at what level of aggregation.
Each key names a level to forecast at: an identifier column, or a time
level. Naming "city" in a table with a store → city hierarchy forecasts
one series per city, combining its stores as each column's aggregate says
("sum" adds them up). Naming a time level such as "weekly" rolls the
data up to weeks the same way before forecasting; the time levels are the time
column's own name and the names under its partitions, which by default
include weekly, monthly, quarterly and yearly for daily data.
Each value narrows which of that level's values to take:
-
"any"takes every value. -
["Paris", "Lyon"]takes the values listed. -
{ "from": "2024-04-01" }takes a range; givefrom,toor both.
An identifier column you leave out is aggregated away entirely: no entry
for store or city forecasts one series for all stores together. Rolling
up needs an aggregate on every variable column. Time you leave out stays
at the time column's own frequency.
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = string | |
| type = array | |
| type = object |
SelectorPattern
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = string | |
| type = array | |
| type = object |
SelectorRange
A range of values: { "from": …, "to": … }. Both bounds are optional; give
only one for a half-bounded range. The values match the column's type
(number, string, or date).
fromLower bound of the range; omit for an open lower end.
toUpper bound of the range; omit for an open upper end.
Quantile
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = number | |
| type = string |
MetricsRequest
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = boolean | |
| type = object |
true scores with the default settings; false does not score.
MetricsSettings
How to score the forecast.
How crps weighs the quantile levels. Defaults to "trapezoid".
CrpsWeighting
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = string | |
| type = string |
Cutoffs
A non-empty array of information cutoffs. For example ["latest"], an
explicit date ["2025-01-31"], or a recurring schedule [{ "every": "3d" }].
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = string | |
| type = string | |
| type = object · requires: every |
The targets' last value, or the earliest of their last values when they end at different times.
Cutoff
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = string | |
| type = string | |
| type = object · requires: every |
The targets' last value, or the earliest of their last values when they end at different times.
Latest
The string "latest": cut off at the targets' last value, or at the
earliest of their last values when they end at different times.
Datetime
^\d{4}-\d{2}-\d{2}([…A date (2025-01-04) or a date and time (2025-01-04T00:00:00Z), in ISO 8601. A time without a UTC offset is read as UTC.
RecurringCutoff
A recurring information cutoff: one cutoff every every, repeated across
the series. Use this for backtesting or rolling-origin evaluation instead
of listing every cutoff date by hand.
every is a whole number of the timeseries' calendar frequency steps, or
any calendar interval at least as coarse as the grid: "monthly" on a
daily grid cuts monthly on the day selected by the anchor. Bounds are
inclusive and resolved separately for each series against its stored time
grid, so missing target values never move them; rows appended with NULL
targets (e.g. future rows carrying covariates) extend the grid and count
toward its last timestamp. Each cutoff observes its containing grid span;
the lower bound includes its entire containing span, even when a cutoff
precedes the start instant within that span. Only cutoffs on the series'
stored time grid are admitted, even when a bound lies outside it: a start
before the first stored timestamp admits every cutoff from there on, without
changing the alignment.
For example, the last 6 evaluation origins of a 48-step horizon, each
leaving a full horizon of stored rows after it:
{ "every": 48, "start": -288, "end": 48, "anchor": "end" }.
A length of time: a number of steps of the data's time grid, or a duration
string. With daily data, 7 and "1w" are the same. A duration must be a
whole number of steps: "1mo" does not fit daily data, and "1d" does not
fit monthly data.
Absolute start, or an offset from a series boundary: nonnegative counts
forward from the first stored timestamp, negative counts backward from
the last. Defaults to 0, the first stored timestamp.
Absolute end, or an offset from a series boundary: nonnegative counts
backward from the last stored timestamp, negative counts forward from
the first. Defaults to 0, the last stored timestamp.
anchorAlign to the resolved start or end, defaulting to the end.
StepsOrDuration
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = integer | |
| type = string |
A whole number of steps of the data's time grid, such as 7.
Duration
A length of time, written in one of three ways:
-
Numbers with units, separated by spaces:
28d,2w,1d 12h. The units arey(years),q(quarters),mo(months),w(weeks),d(days),h(hours),m(minutes),s(seconds) andus(microseconds). They are lowercase, andmis minutes, not months. -
A name:
yearly,quarterly,monthly,weekly,daily,hourly,minute,second,5min,10min,15minor30min. -
An ISO 8601 duration, in capitals:
P1M,P2W,PT1H30M.
The length must be more than zero. Responses always write durations in ISO 8601, without weeks: two weeks read P14D.
CutoffBound
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = string | |
| type = integer | |
| type = string |
^\d{4}-\d{2}-\d{2}([…An absolute instant (e.g. "2025-01-31").
SignedDuration
A duration (1mo, 1d 3h, P1M), or one pointing backward, with a - before every term (-1mo, -1d -3h, -P1M).
CutoffAnchor
Boundary that aligns the recurrence: forward from start or backward from
end. Clipping to the stored time grid does not change this alignment.
LeadTime
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = integer | |
| type = string |
A whole number of steps of the data's time grid, such as 7.
Context
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = integer | |
| type = string |
A whole number of steps of the data's time grid, such as 7.
PredictionLength
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = integer | |
| type = string |
A whole number of steps of the data's time grid, such as 7.
Span
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = integer | |
| type = string |
A whole number of steps of the data's time grid, such as 7.
ForecastResponse
The forecast as a long-format table in columnar form: every field is a
column, and row i of the table is entry i of each column. There is one
row per series, cutoff and forecast step.
Accuracy metrics, one entry per series and cutoff whose forecast window
lies inside the actuals and observes some target. Present only when the
request set compute_metrics.
ForecastTable
The forecast as a long-format table in columnar form: every field is a
column, and row i of the table is entry i of each column. There is one
row per series, cutoff and forecast step.
timeTarget time of the prediction: one step past cutoff, plus lead_time.
cutoffInformation cutoff the prediction was made from, the last instant it saw.
lead_timeHow far ahead the row is: the request's lead_time plus the row's
step within its forecast, as an ISO 8601 duration. A daily forecast
with no lead_time reads PT0S, P1D, P2D, …
spanTime interval each value covers, as an ISO 8601 duration: P1D for a
daily total.
Which series each row belongs to, keyed by identifier column: the
columns the selector names, plus the coarser columns above them in
their hierarchies. A column is null on rows aggregated above it — a
per-city total has a null store.
Forecast values, keyed by target column. Each target's quantiles maps a
level's label ("0.1", "0.5", "mean") to one value per row.
Each target's actual value at time, null where it has none. Present
only when the request set return_actuals.
ColumnValues
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = array | |
| type = array | |
| type = array | |
| type = array | |
| type = array | |
| type = array | |
| type = array |
SeriesMetrics
Accuracy for one timeseries of the timeseries family at one information cutoff, keyed by target column.
The series' identifier values, as the response dataframe's identifiers
columns carry them.
cutoff^\d{4}-\d{2}-\d{2}([… · requiredInformation cutoff the scored forecast was made from.
Value
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = null | |
| type = string | |
| type = integer | |
| type = boolean |
Metrics
Accuracy for one target: the distribution scored over the requested quantile
levels, and a point forecast scored by mae, mape, wape and
scaled_bias. The point forecast is the 0.5 quantile when requested, and the
mean otherwise. A field is null where the metric does not apply — the CRPS
under three levels with the "trapezoid" weighting, mape when every actual
is zero or missing, a scaled metric whose actuals are all zero, every metric
when the target has no observed actual over the forecast window. Missing
actuals are skipped: each metric averages over the window's observed steps,
and mape also skips zero actuals.
crpsContinuous ranked probability score, from the pinball loss of each
requested quantile level weighed as compute_metrics.crps says:
"trapezoid", the default, approximates the CRPS integral;
"mean_quantile_loss" is twice the mean pinball loss over the levels.
The response does not say which weighting was used.
scaled_crpscrps divided by the mean absolute observed actual over the forecast
window. It is scaled per window, so its average across windows is not
the scaled CRPS of the whole dataset.
maeMean absolute error of the point forecast.
mapeMean absolute percentage error of the point forecast, as a fraction, not a percentage.
wapemae divided by the mean absolute observed actual over the forecast
window.
scaled_biasMean signed error of the point forecast, prediction - actual, divided by
the mean absolute observed actual over the forecast window: negative when
the forecast runs low.
SeriesForecast
One timeseries forecast for one information cutoff datetime.
A streamed response (application/x-ndjson or application/vnd.msgpack)
is a sequence of these records, one for each timeseries and cutoff, sent as
each forecast is ready.
Example
A daily sales forecast for store 42, made with data up to 2024-03-31:
Code
Forecast times
Each quantile holds one value per forecast step, in time order. The times
are not listed; compute them from origin, first_step and frequency:
the value at index i (counting from 0) is the forecast for
Code
In the example, origin is January 1 and first_step is 91, so the three
values are the forecasts for April 1, 2 and 3.
Why origin and first_step?
A single start time would not be enough: each time must be computed from
origin directly, not by adding frequency to the previous time. On a
monthly series the two can disagree, because months have different
lengths. With origin = 2024-01-31 and frequency = P1M:
Code
The series' identifier values, keyed by source column name: its selected levels and their hierarchy ancestors.
cutoff^\d{4}-\d{2}-\d{2}([… · requiredInformation cutoff the series was forecast from, the last instant it saw.
origin^\d{4}-\d{2}-\d{2}([… · requiredStart of the series' first step: the span holding its first observation.
first_stepSteps from origin to the first value.
lead_timeGap held between the step after cutoff and the first value.
frequencyTime between consecutive values.
spanTarget-time interval covered by each value.
The forecast values, keyed by target column, then by quantile label.
The actuals, keyed by target column: one per forecast value, null where
the target has none. Present only when the request set return_actuals.
Accuracy of this forecast, keyed by target column. Present only when the
request set compute_metrics and some target is observed across its
values.
StreamError
The last record of a stream a failure cut short.
What went wrong, as a problem response reports it.
{
"type": "about:blank",
"title": "Unprocessable Entity",
"status": 422,
"code": "unprocessable",
"detail": "unknown target column `revenue`"
}Problem
An error, as an RFC 9457 problem document.
typeA URI naming the kind of problem. Always about:blank: code tells
the kinds apart.
titleThe HTTP status phrase, such as Unprocessable Entity.
statusThe HTTP status code, repeated from the response.
What kind of error this is, stable across releases: match on this, not
on title or detail.
detailWhat went wrong with this request, for a person to read. The wording may change.
ProblemCode
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = string | |
| type = string | |
| type = string | |
| type = string | |
| type = string | |
| type = string | |
| type = string | |
| type = string | |
| type = string | |
| type = string | |
| type = string | |
| type = string |

