Prediction model configuration

Prediction models can be managed using the REST API or the Exabel Python SDK.
The Python SDK accepts a dictionary with the same JSON field names and converts
it to the typed PredictionModelConfiguration message. Algorithm-specific
modelOptions.parameters remains a flexible JSON object.

Create a custom KPI model

A saved model supplies the target, predictors, entities, and training setup.
Its modelOptions uses the same message as a KPI mapping group's algorithm
settings. Referencing a mapping group's proxy does not inherit its model options.

POST /v1/predictionModels?folder=folders/456
Content-Type: application/json

{
  "displayName": "Revenue forecast",
  "configuration": {
    "modelOptions": {
      "modelType": "sarimax",
      "parameters": {"positive": true},
      "yearOverYear": false
    },
    "goal": "PREDICT",
    "entities": [{"name": "entityTypes/company/entities/F_000C7F-E"}],
    "targetSignals": [{"signal": {"kpi": {
      "type": "VISIBLE_ALPHA_STANDARD_KPI", "value": "190", "freq": "FQ"
    }}}],
    "predictorSignals": [{"signal": {"kpiMappingGroup": {
      "resourceName": "kpiMappings/123/groups/456"
    }}}],
    "trainingDuration": {"base": "YEAR", "multiplier": 10}
  }
}

Omit folder to use the customer's shared Analytics API folder. Creating or
updating a model does not run it. Creation has no idempotency key: investigate
an ambiguous timeout before retrying. The Python SDK disables automatic retries
for model creation.

For an existing stored signal, use signal.id. To select predictors from the
KPI's accessible proxies automatically, use kpiAutoPredictors: true with one
entity and a structured KPI target. The declared predictor list does not identify
the resolved inputs in this mode.

Proxy forecasting is configured separately through a KPI mapping group's
forecastingOptions, including Prophet holiday settings. Those options forecast
the input proxy; they do not select the prediction model's algorithm.

Algorithm parameters for saved models

The field reference documents the typed training, optimization, backtest, and
signal settings. The following keys are accepted within modelOptions.parameters;
keys retain their snake_case spelling.

Model typeParameter keys
ratio_prediction, spread_modelmodel, target_model, theta
ensembletarget_model, theta
ratio_prediction_mlml_version, ratio_model, target_model
sarimax, SARIMAXlevel, alpha, l1_ratio, positive, enforce_stationarity
unobserved_componentslevel, trend, autoregressive, seasonal, use_seasonality
linear_regressionnone
elastic_netalpha, l1_ratio, positive
elastic_net_cvpositive
huber_regressionepsilon
ard_regressionalpha_1, alpha_2, lambda_1, lambda_2

model and ratio_model accept basic, uc, uc_trend, theta, or ml;
target_model additionally accepts none. The ml method uses the framework's
default pretrained forecast model. Custom model-file paths are unsupported.
ml_version is a string. SARIMAX level accepts n, c, t, or ct;
unobserved-components level is a trainer-specific string.

positive, enforce_stationarity, trend, and use_seasonality are booleans.
Numeric values must be finite and nonnegative, with theta and epsilon at least
one. Exact trainer constraints are checked when running the model. A null
parameter value clears the key. Saving successfully does not guarantee enough
data, data entitlement, or a successful numerical fit.

Read-only configurations

All saved model types remain inspectable. configurationWritable describes
configuration compatibility; it does not grant write permission. If false,
configurationError explains the limitation and metadata updates remain possible.
Do not remove settings merely to make a configuration writable.

Writes support the standard prediction pipeline with goal PREDICT. Alternative
pipelines, panel training, k-fold backtests, and executable parameter expressions
remain read-only. This includes SARIMAX configurations that store order or
seasonal_order in parametersToEvaluate.

If saved settings cannot be represented in the typed fields, legacyConfiguration
contains the complete legacy configuration for inspection, excluding model
metadata and the signal-library snapshot. It cannot be submitted as a configuration
write. Typed fields still expose the representable portion. Historical inline
signal definitions and unsupported settings remain available through this field.

Replace configuration sections

For example, this changes only the algorithm's parameter object:

PATCH /v1/predictionModels/123?updateMask=configuration.modelOptions.parameters
Content-Type: application/json

{"configuration": {"modelOptions": {"parameters": {"positive": false}}}}

An explicit update mask is required. A selected section replaces the entire
section, including lists and dictionaries. Omit a selected section to clear it;
unselected sections remain unchanged. False and zero are applied when selected.
Use configuration to replace the entire configuration. Parent and child paths
cannot appear together in a mask, and * is unsupported.

Masks accept typed top-level configuration fields and the individual
modelOptions fields. Arbitrary dictionary-key paths, such as
configuration.modelOptions.parameters.positive, are unsupported. To switch
between trainingRange and trainingDuration, select both sections and omit
the old one. A fixed range uses from and an optional later to timestamp.

REST uses JSON names in masks, such as configuration.modelOptions.yearOverYear.
gRPC and the Python SDK use protobuf names, such as
configuration.model_options.year_over_year. Dictionary keys use JSON names
in both clients. Serialize updates to the same model: there is no revision token
or optimistic concurrency check.

Delete a model

DELETE /v1/predictionModels/123

With the Python SDK:

client.prediction_model_api.delete_model("predictionModels/123")

Deletion requires model-write permission and write access to the model's folder.
It removes the model from the Library and marks it deleted, using the same operation
as the Exabel app. Historical storage is retained until the model-cleanup job purges it;
submitted runs are not cancelled.
Deleting a model does not delete its input signals or other models.

The response is empty; the SDK returns None. Invalid resource names return
INVALID_ARGUMENT. Models without write access, including already removed Library
entries, return PERMISSION_DENIED.

Inspect an exact run

Create a run with {"description":"Forecast refresh","configuration":"LATEST"}.
The run's configuration selects LATEST, ACTIVE, or SPECIFIC_RUN; it is
separate from the saved model's typed configuration. SPECIFIC_RUN also requires
configurationSource. Save the returned run name and poll that exact resource.
Run zero is not an alias for the active run.

modelConfiguration contains the saved typed configuration snapshot.
modelConfigurationWritable concerns configuration compatibility, while
configurationError concerns configuration limitations, not run failure.
active reports current activation independently of the original run request.
Get/list do not reconstruct the original configuration-selection or auto-activation
request options. Creation returns the requested options and resource name.

Missing timestamps are unknown, not the Unix epoch. MIXED is not full success;
missing entity errors after a job failure do not prove success. Entity outcomes
can be incomplete or absent when evaluation did not finish. Treat unspecified
states as unknown.

A configuration snapshot is not an archive of underlying data or model artifacts.
Requesting an old configuration still uses the current signal library and data.
Saved schedules lack the owner's timezone, so they cannot predict a UTC next-run
time. A queued run's state does not identify its trigger or recurring schedule.

Finding saved models

GET /v1/predictionModels returns metadata with the highest numeric model IDs first.
Use orderBy to select name (numeric ID), display_name (case-insensitive),
create_time, or update_time, optionally followed by asc or desc.
The default is name desc. Ties use numeric ID descending; missing timestamps sort last.
createTime and updateTime are output-only metadata. For a model never updated,
updateTime falls back to its creation time.

Use filter to match a display name or an exact folder, or combine them with AND:

filter=display_name="*Revenue*" AND folder="folders/123"
orderBy=update_time desc

Display names match case-insensitively; * matches any sequence of characters.
Folder filters do not include subfolders or grant access to private models.
Filtering and ordering happen before pagination. totalSize counts matching accessible models.
Pass the same filter and order with each pageToken. Pagination uses the same offset mechanism
as other lists; concurrent additions, edits, or removals can shift results between pages.