Circadify

Errors

Handle Circadify REST API errors — structured error responses, error codes, and retry strategies.

The Circadify API uses standard HTTP status codes and returns structured error responses to help you diagnose and handle failures.

Error Response Format

Most API errors follow this structure:

{
  "error": "RATE_LIMIT_EXCEEDED",
  "message": "Rate limit exceeded",
  "retryable": true
}
json
FieldTypeDescription
errorstringMachine-readable error code
messagestringHuman-readable description
retryablebooleanWhether the request can be retried

Rate-limited and quota responses use HTTP 429 with the body above; the API does not emit Retry-After or X-RateLimit-* headers, so apply your own backoff.

Session result failures return the session status plus an error message so SDKs can map the failure to their client-side error type.

Error Codes

Authentication Errors (401)

CodeDescriptionResolution
API_KEY_INVALIDThe API key is missing, malformed, revoked, or expiredCheck your key in the developer dashboard. Create a new key if needed.
UNAUTHORIZEDBearer token is missing or invalidRe-authenticate and obtain a fresh token.
Tip

All API key validation failures return the same API_KEY_INVALID code regardless of the specific reason (missing, revoked, expired, or malformed). This prevents attackers from enumerating valid keys.

Authorization Errors (403)

CodeDescriptionResolution
FORBIDDENYou do not have permission to access this resourceVerify the session belongs to your account.
DEVELOPER_PENDINGYour account is awaiting approvalWait for the approval email or contact support.
DEVELOPER_SUSPENDEDYour account has been suspendedContact support to resolve.
DEVELOPER_NOT_VERIFIEDYour email address has not been verifiedCheck your inbox for the verification email.

Request Errors (400)

CodeDescriptionResolution
INVALID_REQUESTMissing or invalid request parametersCheck the request body and path parameters against the endpoint documentation.
VERIFICATION_TOKEN_INVALIDEmail verification or password reset token is invalid or expiredRequest a new verification email or password reset.

Not Found (404)

CodeDescriptionResolution
SESSION_NOT_FOUNDThe session ID does not existSessions expire after a short time. Create a new session.
DEVELOPER_NOT_FOUNDNo developer account found for this identifierCheck the account exists and the ID is correct.

Conflict (409)

CodeDescriptionResolution
EMAIL_ALREADY_EXISTSAn account with this email already existsLog in with the existing account or use a different email.

Gone (410)

CodeDescriptionResolution
SESSION_EXPIREDThe session timed out before completionCreate a new session and retry the measurement.

Processing Failed (422)

CodeDescriptionResolution
failedA completed upload could not be processedStart a new measurement and retry under better scan conditions.

Rate Limiting & Quota (429)

CodeDescriptionResolution
RATE_LIMIT_EXCEEDEDSandbox (ck_test_) request rate limit exceeded (best-effort)Retryable. Back off with exponential delay and retry. See Rate Limits.
QUOTA_EXCEEDEDMonthly scan quota exhausted on a production (ck_live_) keyNot retryable this month. Check the Usage page in the developer portal.

Server Errors (500/503)

CodeDescriptionResolution
INTERNAL_ERRORAn unexpected server error occurredRetry with exponential backoff. If persistent, contact support.
INFERENCE_FAILEDThe measurement could not be processedRetryable. Retry the full session.
SERVICE_UNAVAILABLEA backend service is temporarily unavailableRetryable. Wait and retry with exponential backoff.

HTTP Status Code Summary

StatusMeaning
200Success
201Created (e.g., new API key)
400Bad Request — invalid parameters
401Unauthorized — invalid or missing credentials
403Forbidden — insufficient permissions
404Not Found — resource does not exist
409Conflict — resource state conflict
410Gone — resource has expired
422Unprocessable Entity — uploaded measurement could not be processed
429Rate Limited — too many requests
500Internal Error — server-side failure
503Service Unavailable — temporary backend issue

Retry Strategy

For retryable errors (retryable: true), implement exponential backoff:

async function fetchWithRetry(url: string, options: RequestInit, maxRetries = 3) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const response = await fetch(url, options);
 
    if (response.ok) return response;
 
    const body = await response.json();
 
    // Honor the `retryable` flag: don't retry non-retryable client errors.
    // Note a 429 can be QUOTA_EXCEEDED (retryable: false) — don't retry it.
    if (response.status < 500 && body.retryable === false) {
      throw new Error(body.message);
    }
 
    if (attempt === maxRetries) {
      throw new Error(body.message);
    }
 
    // No Retry-After header is emitted — use exponential backoff
    const delay = Math.min(1000 * Math.pow(2, attempt), 30000);
 
    await new Promise(resolve => setTimeout(resolve, delay));
  }
}
typescript

Recommended parameters:

ParameterValue
Max retries3
Initial delay1 second
Max delay30 seconds
Backoff multiplier2x
Caution

Never retry 401 or 403 errors — these indicate a credentials or permissions issue that will not resolve with retries. A 429 may be RATE_LIMIT_EXCEEDED (sandbox, retryable) or QUOTA_EXCEEDED (production quota, not retryable) — branch on the retryable flag. No Retry-After header is emitted, so use your own backoff.

Next Steps