ExonaExona API
Data Reference

Errors

Every error from the Exona API uses the same envelope. This page lists all error codes.

Error envelope

All error responses use the same JSON structure. There are no surprise plain-text errors or empty bodies.

{
  "error": {
    "code": "INVALID_COMPANY_WEBSITE",
    "message": "company_website must be a valid URL including scheme (e.g. https://acme.com)",
    "param": "company_website",
    "hint": "Ensure the URL starts with https:// and points to a publicly accessible website.",
    "request_id": "req_01hx7m2d3e4f5g6"
  }
}
FieldTypeAlways presentDescription
codestringYesMachine-readable error code. Use this for programmatic error handling.
messagestringYesHuman-readable description of the error.
paramstringNoThe specific request parameter that caused the error, if applicable.
hintstringNoA suggested fix or next step.
request_idstringYesUnique identifier for this request. Always include this when contacting support.

The request_id is also returned in the X-Request-ID response header for all responses, including successes.


Authentication errors

CodeHTTPMeaning
AUTHENTICATION_REQUIRED401No Authorization header was provided.
INVALID_API_KEY401The API key is malformed, does not exist, or has been revoked.
FORBIDDEN_IP403The request origin IP is not in the key's allowlist.

Request validation errors

CodeHTTPMeaning
MISSING_REQUIRED_FIELD400A required field was not provided. The param field identifies which one.
INVALID_COMPANY_WEBSITE400company_website is not a valid URL. Must start with https://.
INVALID_MAX_AGE_DAYS400max_age_days must be an integer between 0 and 365.
QUESTIONNAIRE_TOO_LARGE400Questionnaire exceeds limits: maximum 50 questions, 5,000 chars per answer, 20,000 chars total.

Resource errors

CodeHTTPMeaning
SCAN_NOT_FOUND404No scan with the given ID exists under your API key.

Rate limiting errors

CodeHTTPMeaning
RATE_LIMIT_EXCEEDED429Your key has exceeded the rate limit. See Retry-After header for how long to wait.

Scan-level errors

These codes appear inside the error field of a failed scan (status: "failed"), not as HTTP error responses.

CodeMeaningRecommended action
ENRICHMENT_INSUFFICIENT_DATANot enough public information was found to generate a reliable profile.Verify the website URL is correct and publicly accessible. Very new companies or those with minimal web presence may not yield sufficient data.
ENRICHMENT_TIMEOUTThe enrichment pipeline took too long and was stopped.Retry the scan. This is usually transient.
ASSESSMENT_FAILEDThe risk assessment step failed after enrichment succeeded.Retry. If the error persists, contact support with the request_id.

Server errors

CodeHTTPMeaning
INTERNAL_ERROR500An unexpected error occurred on Exona's side. The request_id is always present: include it when contacting support.

Handling errors

import requests
 
def get_scan(scan_id, api_key):
    response = requests.get(
        f"https://platform.exonalab.com/api/v1/scans/{scan_id}",
        headers={"Authorization": f"Bearer {api_key}"},
    )
 
    if response.status_code == 200:
        return response.json()
 
    error = response.json().get("error", {})
    code = error.get("code", "UNKNOWN")
    message = error.get("message", "Unknown error")
    request_id = error.get("request_id", "N/A")
 
    if response.status_code == 401:
        raise PermissionError(f"Authentication failed [{code}]: {message}")
    elif response.status_code == 404:
        raise ValueError(f"Scan not found: {scan_id}")
    elif response.status_code == 429:
        retry_after = response.headers.get("Retry-After", "unknown")
        raise RuntimeError(f"Rate limited. Retry after {retry_after}s. [{request_id}]")
    else:
        raise RuntimeError(
            f"API error [{code}]: {message} (request_id: {request_id})"
        )

Getting help

If you encounter a 500 Internal Server Error or a persistent scan failure, contact support@exonalab.com and include:

  • The request_id from the error response (or X-Request-ID header)
  • The scan ID if applicable
  • A description of what you were trying to do

On this page