Predictions
GET /predictions returns model predictions for your links. One model family ships today: snr, which forecasts link signal-to-noise ratio. The endpoint is read-only; there is no POST /predictions.
GET /predictions
Auth: x-api-key. See Authentication.
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
model_family | string | snr | Model family. snr is the only family currently shipped. |
link_ids | repeated string | none | Links to predict for. Repeat the parameter per id. At most 100 per request. |
horizon_minutes | integer | model default | Forecast horizon. |
as_of_utc | ISO 8601 datetime | now | Evaluation instant; for live inference this anchors the feature window. |
live | boolean | false | false reads the latest cached prediction set. true runs live inference. |
Exceeding the link cap fails fast:
{ "error": "too_many_link_ids", "max": 100, "received": 250 }
with HTTP status 400. Chunk larger fleets into batches of 100.
Prediction values
SNR predictions are quantile forecasts in dB. Every prediction's value object carries:
| Field | Meaning |
|---|---|
p50 | Median forecast SNR. |
p10 | 10th percentile (pessimistic bound). |
p90 | 90th percentile (optimistic bound). |
A wide p10 to p90 spread is the model telling you it is uncertain; treat p10 as the planning floor for link-closure decisions.
Cached shape (live=false)
The default read returns the most recent precomputed PredictionSet:
{
"model_family": "snr",
"captured_at": "2026-07-09T14:30:00Z",
"items": [
{
"link_id": "SAT-0012:GS-SEA-01",
"horizon_minutes": 15,
"predicted_at": "2026-07-09T14:30:12Z",
"assignment_id": "asg-7f3c",
"model_version": "snr-v11",
"lease_id": "lease-01b2",
"value": { "p50": 12.4, "p10": 9.1, "p90": 15.8 },
"feature_view_id": "snr-features-v22"
}
]
}
items is empty ([]) when no cached predictions exist yet for the requested links, which is normal for a fresh tenant or brand-new link ids. That is not an error; either poll again after the next capture cycle or request live=true.
Live shape (live=true)
Live inference returns an InferencePayload with full provenance:
{
"schema_version": "v1",
"tenant_key": "acme-sat",
"served_at": "2026-07-09T14:32:05Z",
"predictions": [
{
"schema_version": "v1",
"link_id": "SAT-0012:GS-SEA-01",
"horizon_minutes": 15,
"value": { "p50": 12.1, "p10": 8.7, "p90": 15.2 }
}
],
"provenance": {
"served_from": "sagemaker",
"model_version": "snr-v11",
"feature_source": "influx",
"entity_id": "SAT-0012:GS-SEA-01",
"as_of_utc": "2026-07-09T14:32:00Z",
"feature_schema_version": "snr-features-v22",
"input_window_start": "2026-07-09T13:32:00Z",
"input_window_end": "2026-07-09T14:32:00Z",
"telemetry_points_used": 118,
"fill_policy": "forward_fill",
"horizons_minutes": [15]
}
}
The provenance block is the auditable answer to "where did this number come from":
| Field | Meaning |
|---|---|
served_from | sagemaker, local, or registry: which serving path produced the prediction. |
model_version | Exact model package version. |
feature_source | influx (your live telemetry) or npz (packaged features). |
feature_schema_version | Feature schema the inputs conform to (snr-features-v22 on prod; snr-features-v21 on stage and the whitney tenant). |
input_window_start / input_window_end | Telemetry window that fed the features. |
telemetry_points_used | How many samples were actually available in that window. |
fill_policy | How gaps in the window were filled. |
horizons_minutes | All horizons evaluated in this call. |
Low telemetry_points_used with an aggressive fill_policy means the model was starved for input; weigh the quantiles accordingly. The sandbox environment hosts the live SNR serving endpoint, which makes it the natural place to exercise live=true before pointing production automation at it.
Example
curl -sS \
-H "x-api-key: $CONSTELLATION_API_TOKEN" \
"https://api.constellation.space/predictions?model_family=snr&horizon_minutes=15&link_ids=SAT-0012:GS-SEA-01&link_ids=SAT-0013:GS-SVL-02"
Polling pattern
There are no webhooks or streaming. Cached predictions refresh on the platform's capture cadence, so the standard integration is a poll loop: request the cached set every 1 to 5 minutes, use captured_at to detect a new capture, and fall back to live=true only when you need an on-demand answer (live inference is slower and more expensive). A runnable client with empty-result and 429 handling is in Fetch predictions.
A note on tiers
The console UI groups prediction features into plan tiers. Those tiers are a console-side plan concept only; this API has no tier parameter and no tier gating. Every tenant key that can read /predictions gets the same snr model family.
Errors
| Status | Body | Cause |
|---|---|---|
400 | {"error": "too_many_link_ids", "max": 100, "received": N} | Over the link cap; chunk to 100. |
422 | detail list | Bad as_of_utc, horizon_minutes, or live value. |
401 / 403 / 404 | see Authentication | Key or tenant problems. |
429 | rate_limited or auth_lockout | Rate limits; honor Retry-After. |
503 | see Errors and limits | Data plane or serving backend unavailable; retry after the delay. |
Related
- Fetch predictions example: chunking, empty results, and backoff in four languages.
- Telemetry: live features are computed from what you ingest.
- Health:
GET /health/predictionschecks the serving path without consuming tenant rate budget.