Error Messages

Common error responses, what they mean, and how to fix them.

When a request fails, Surfact returns a standard HTTP status code and a JSON body describing the problem. Four body shapes are in production, so branch on the HTTP status code, not on the shape of the body:

ShapeExampleWhere it shows up
{code, message}{"code": 404001, "message": "The request was not found."}Authentication failures (401), missing objects (404), retention violations (403003)
{detail}{"detail": "You do not have permission to perform this action."}Malformed JSON bodies, permission-denied 403s, and out-of-range pagination 404s
{code, message, detail}{"code": 400001, "message": "Validation Error.", "detail": {"aggregation": ["\"stddev\" is not a valid choice."]}}Field validation (400001) and method-not-allowed (405001). detail is sometimes a string, sometimes an array, sometimes an object keyed by field name
{description, status, message}{"description": "Bad Request", "status": 400, "message": "Invalid request body: VariablesAggregationRequestSchema. Error: …"}Query- and body-schema validation on the Data API, including start/end range errors. message embeds the internal schema name and a pydantic URL — log it, but don't parse it

Authentication errors

Surfact returns a single authentication-failure code. A missing X-Auth-Token header, an empty header, an empty ?token= and a wrong or expired token all produce the same 401:

{
  "code": 401002,
  "message": "Incorrect authentication credentials."
}

There is no separate code for "credentials not provided", so the response won't tell you whether the token was absent or simply wrong — check that the header is being sent on your side. See Authentication.

Error codes

CodeHTTPMeaningFix
400001400Validation ErrorRead detail — it names the offending fields or values
401002401Incorrect authentication credentialsThe token is missing, wrong, or expired; generate a fresh one (tokens are valid 6 hours)
403003403The requested time range is older than the account's retention limit (24 months by default)Clamp start to the retention window — see Data retention below
404001404The request was not foundCheck the label/id and the ~ prefix — see Identifiers — Key vs. ID
405001405HTTP method not allowedCheck the verb; the Data API aggregation and raw-series endpoints are POST-only

A 403 without a code{"detail": "You do not have permission to perform this action."} — means the token is valid but the account lacks permission for that resource. A wrong or missing token returns 401, never 403.

Data retention

Requests whose time range reaches further back than the account's retention window (24 months by default) are rejected outright, not clipped — the in-window portion of the range is not returned either:

curl -X GET 'https://api.surfact.com/api/v1.6/variables/<variable_id>/values/?start=1634792400000&end=1634794200000' \
  -H 'X-Auth-Token: <your_token>'
{
  "code": 403003,
  "message": "The time range you're trying to retrieve is older than the retention limit in your account (24 months). Please contact your administrator to increase your data retention period."
}

This applies to start alone, end alone, and both together, on /values/, on the aggregated-data endpoints, and on both Data API POST endpoints. It is easy to trip by accident: start and end are milliseconds, and passing POSIX seconds by mistake lands you decades in the past. Clamp start yourself before querying a long reefer history.

Validation & request errors

SituationResponseFix
Malformed JSON body{"detail": "JSON parse error - …"} (HTTP 400)Validate your JSON; check commas, quotes, and types
Failed field validation{"code": 400001, "message": "Validation Error.", "detail": { … }} (HTTP 400)detail is keyed by field name; fix the fields it names
Invalid enum on a Data API POST{"description": "Bad Request", "status": 400, "message": "Invalid request body: …"} (HTTP 400)The message lists the accepted values; pick one of those
Page number past the last page{"detail": "Invalid page."} (HTTP 404)Stop paging when next is null rather than incrementing blindly
Unknown device/variable label{"code": 404001, "message": "The request was not found."} (HTTP 404)Check the label/id and the ~ prefix — see Identifiers — Key vs. ID

A filter "isn't working"

If a filter has invalid syntax, Surfact ignores it silently and returns all objects — you won't get an error. If a query returns more than you expect, re-check the __ separator and attribute name. See the FAQ.

Cold-chain example

A request to read a tracker's temperature with an expired token:

curl -X GET 'https://api.surfact.com/api/v1.6/variables/<variable_id>/values/?page_size=1' \
  -H 'X-Auth-Token: expired_token'
{
  "code": 401002,
  "message": "Incorrect authentication credentials."
}

Generate a new token and retry. For the full status-code reference, see Response Codes.


Did this page help you?