Skip to main content

Error Codes

Most AirQo API endpoints share one error response format; the Forecast API has one additional validation-specific shape. Match your error handling to the endpoint you are calling.


Error response formats​

Devices, Analytics, and Metadata API​

Used by: measurement endpoints (/api/v2/devices/...), Analytics API (/api/v3/public/analytics/...), and metadata endpoints (/api/v2/devices/metadata/...).

{
"success": false,
"message": "Detailed error message",
"errors": {
"message": "More specific detail, or a field-by-field validation breakdown"
}
}
FieldTypeDescription
successbooleanfalse on failure
messagestringHuman-readable summary
errorsobjectAdditional detail — often { "message": "..." }, or one entry per invalid field on a validation error

Forecast API​

Used by: /api/v2/predict/daily-forecasting/ and /api/v2/predict/hourly-forecasting/.

The validation error unique to this API — providing more than one of site_id, grid_id, or cohort_id — returns:

{
"success": false,
"message": "Please specify only one of site_id, grid_id, or cohort_id.",
"data": { "forecasts": [] }
}

Other error conditions on this API (no forecast available, an unresolved grid/cohort, or the service being temporarily unavailable) follow the same {success, message} shape with a data object appropriate to the failure.


HTTP status codes​

StatusMeaningCommon causes
200 OKRequest succeeded—
400 Bad RequestInvalid requestMissing required fields, bad date format, invalid parameter values
401 UnauthorizedAuthentication failedMissing, expired, invalid or suspended token; request from a blocked IP address; API client not yet approved
403 ForbiddenInsufficient permissions or access deniedAccessing a feature not included in your tier (e.g. forecasts on Free); request blocked by our security checks (see Blocked Requests)
404 Not FoundResource not foundInvalid Cohort ID, Grid ID, Site ID, or Device ID — or no data for the requested range
429 Too Many RequestsRate limit exceededToo many requests in a short period
500 Internal Server ErrorServer errorAirQo-side issue; retry after a short delay

Common errors and solutions​

Empty measurements array​

Symptom: Response is 200 OK with "measurements": [] or "data": [].

Possible causes:

  • No data exists for the requested device(s), site(s), or date range
  • The device was offline for the entire period
  • The ID you provided doesn't match an active resource

Solution: Verify the ID using the Finding IDs guide, and try a shorter or more recent date range. If the problem persists, contact network@airqo.net.


400 Bad Request — conflicting forecast parameters​

{
"success": false,
"message": "Please specify only one of site_id, grid_id, or cohort_id.",
"data": {
"forecasts": []
}
}

Cause: More than one of site_id, grid_id, or cohort_id was provided in a single forecast request.

Solution: Provide exactly one identifier per request.


401 Unauthorized​

{
"success": false,
"message": "Invalid authentication",
"errors": { "message": "Token is missing, invalid, or expired" }
}

Causes:

  • Token is missing from the request
  • Token has expired (tokens are valid for 7 months)
  • Token was copied incorrectly
  • The request came from an IP address that is blocked for this token
  • The token was automatically suspended after unusual activity
  • The API client that owns the token is still awaiting approval

Solution: If the token is missing, expired or mistyped, generate a new token from Account Settings and update it in your application.

If the token is correct but still rejected, check the response for an errors.code:

{
"success": false,
"message": "Unauthorized",
"errors": {
"message": "Requests from IP address 203.0.113.25 are blocked for this token. ...",
"code": "IP_BLOCKED",
"docs": "https://platform.airqo.net/docs/api/reference/blocked-requests/"
}
}
errors.codeMeaning
IP_BLOCKEDYour server's IP address is blocked and is not on the client's IP Addresses list
TOKEN_SUSPENDEDThe token was suspended after unusual activity
CLIENT_INACTIVEThe API client is awaiting approval or has been deactivated
TOKEN_EXPIREDThe token has expired
401 or 403

A blocked request can return either 401 Unauthorized or 403 Forbidden, depending on where it was stopped. Don't rely on the status code alone. Check errors.code: IP_BLOCKED means your request's IP address was blocked.

See Troubleshooting blocked requests for how to fix each one.


403 Forbidden — access denied​

Symptom: A request with a valid token that previously worked now returns 403 Forbidden or "Access Denied", often after you received a Daily Security Alert Summary email.

Cause: The request was stopped by our security checks. Check errors.code in the response to find out why. IP_BLOCKED means your server's IP address is not on your API client's IP Addresses list, or it changes between runs.

Solution: Follow Troubleshooting blocked requests.


403 Forbidden — tier restriction​

{
"success": false,
"message": "Forecast access requires Premium Tier subscription",
"errors": { "message": "Upgrade your subscription to access this feature" }
}

Cause: You are trying to access a feature (e.g. forecasts, historical data) not included in your current tier.

Solution: Upgrade your subscription at nexus.airqo.net → Account Settings → Subscription.


404 Not Found​

{
"success": false,
"message": "No data found for the requested device(s) or time range",
"errors": { "message": "Not found" }
}

Causes:

  • The ID you provided does not exist or is incorrect
  • No measurements exist for the device in the requested date range
  • The device was offline for the entire period

Solution: Verify the ID using the Finding IDs guide. Try a shorter or more recent date range.


429 Too Many Requests​

Cause — GET endpoints (measurements, metadata): you have exceeded the rate limit for your tier.

Solution: Implement exponential backoff, cache responses to avoid repeating identical queries, or upgrade to a higher tier for increased limits.

Cause — raw-data and data-download: these two endpoints enforce a fixed limit of 10 requests per minute per client, regardless of tier.

Solution: Pace your pagination loop with a short delay between requests — upgrading tiers doesn't raise this particular limit.

import time
import requests

def request_with_retry(method, url, max_retries=3, **kwargs):
for attempt in range(max_retries):
response = requests.request(method, url, **kwargs)
if response.status_code == 429:
wait = 2 ** attempt # 1s, 2s, 4s
print(f"Rate limited. Retrying in {wait}s...")
time.sleep(wait)
else:
return response
raise Exception("Max retries exceeded")

# GET endpoint
request_with_retry("GET", url, params=params)

# POST endpoint (raw-data, data-download)
request_with_retry("POST", url, params={"token": token}, json=payload)

Support​

If you consistently receive 500 errors or unexpected responses, contact network@airqo.net with:

  • The endpoint you called
  • The request body or query parameters (redact your token)
  • The full response you received
  • The timestamp of the request