Errors & status codes

How Temporis reports success and failure, what each status means, and how to handle them.

Response shape

The shape of a response depends on what happened:

  • A successful ingest returns 204 No Content with no body.
  • A successful prediction returns 200 with a JSON body.
  • Any error returns the relevant HTTP status with a JSON body of the form { "detail": "..." }.
{ "detail": "Data profile not found." }

Status codes

StatusMeaningWhere
200 OKPrediction succeeded; body holds the samples.predict
204 No ContentIngest succeeded; no body.ingest
400 Bad RequestInvalid prediction parameters.predict
401 UnauthorizedMissing or invalid access token.all requests
402 Payment RequiredNo card on file, or a payment issue.predict
404 Not FoundData source not found (ingest); data profile not found or not ready to serve (predict).ingest, predict
409 ConflictData source archived (ingest); not enough data (predict).ingest, predict
502 Bad GatewayPrediction failed — a transient server-side error.predict

Handling errors

Most failures map to a clear next action:

  • 401 — check that the Authorization header is present and the token is valid. See Authentication.
  • 402 — add or fix a credit card in the dashboard under Billing, then retry.
  • 404 — make sure the data source or data profile exists, and that the profile is ready to serve.
  • 409 on predict — ingest more history until the profile meets its minimum, then retry.
  • 409 on ingest — the data source is archived; unarchive it or write to another source.
  • 502 — transient. Retry with exponential backoff.

A simple branch on the status code covers all of these:

import time, requests

def predict(payload, token, retries=3):
    for attempt in range(retries):
        resp = requests.post(
            "https://api.temporis.co/v1/predict",
            headers={"Authorization": f"Bearer {token}"},
            json=payload,
        )
        if resp.status_code == 200:
            return resp.json()
        if resp.status_code == 502:
            time.sleep(2 ** attempt)   # transient: back off and retry
            continue
        detail = resp.json().get("detail", "")
        if resp.status_code == 402:
            raise RuntimeError(f"Billing: {detail} — add a card in the dashboard.")
        if resp.status_code == 409:
            raise RuntimeError(f"Not ready: {detail} — ingest more history.")
        resp.raise_for_status()        # 400 / 401 / 404: fix the request
    raise RuntimeError("Prediction failed after retries.")

Retries

Retry the right things

A 502 is safe to retry — it is transient. Ingest is idempotent (writes upsert on the (timestamp, name) key), so retrying a failed ingest is always safe. Avoid blindly retrying 4xx responses; fix the request first.

Related