ExonaExona API
API Reference

Create a Scan

Create a new AI risk scan for a company. Returns immediately with a scan ID and processing status.

Endpoint

POST https://platform.exonalab.com/api/v1/scans

Request body

company_namestringrequired

The full legal or trading name of the company to scan.

Example: "Acme AI Ltd"

company_websitestringrequired

The company's primary website URL, including scheme. Used as the canonical identifier for caching purposes.

Example: "https://acme.ai"

questionnairearray

Optional. An array of question-and-answer pairs from the insured company's application. Providing this data improves the accuracy of the risk assessment. See Questionnaire Data.

Each item must have:

  • question (string, required): the question as asked
  • answer (string, required): the insured's answer

Maximum 50 questions. Maximum 5,000 characters per answer.

max_age_daysinteger

Optional. If a completed scan for the same company_website was completed within this many days, return that cached scan instead of creating a new one. Set to 0 or omit to always create a fresh scan.

When a cache hit occurs, "cached": true is included in the response and no credit is consumed.

Range: 0–365. Default: 0 (no caching).

Note: Ignored if questionnaire data is provided.

force_refreshboolean

Optional. If true, always create a new scan even if a valid cached scan exists. Takes precedence over max_age_days. Default: false.

include_field_citationsboolean

Optional. If true, include the raw source URLs cited for each enrichment field in the response. Useful for audit trails. Default: false.


Request headers

Authorizationstringrequired

Bearer exo_live_... or Bearer exo_test_...

Content-Typestringrequired

Must be application/json.


Response

Returns 201 Created when a new scan is created, or 200 OK when a cached scan is returned.

idstring

The unique scan identifier. Store this to retrieve the result later. Example: "scn_01hx7m2d3e4f5g6h7j8k9l0mn"

statusstring

Current status of the scan. "processing" when newly created; "completed" when returned from cache.

cachedboolean

true if this response was returned from cache (no new scan was created). Omitted or false when a new scan is created.

cached_atstring

ISO 8601 timestamp of when the cache hit occurred. Present only when cached: true.

created_atstring

ISO 8601 timestamp of when the scan was originally created.

resultobject

Present only when status is "completed" (i.e. on a cache hit). See Scan Result for the full schema.


Examples

Minimal request

import requests
 
response = requests.post(
    "https://platform.exonalab.com/api/v1/scans",
    headers={
        "Authorization": "Bearer exo_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "Content-Type": "application/json",
    },
    json={
        "company_name": "Acme AI Ltd",
        "company_website": "https://acme.ai",
    },
)
 
print(response.json())

With questionnaire

import requests
 
response = requests.post(
    "https://platform.exonalab.com/api/v1/scans",
    headers={
        "Authorization": "Bearer exo_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "Content-Type": "application/json",
    },
    json={
        "company_name": "Acme AI Ltd",
        "company_website": "https://acme.ai",
        "questionnaire": [
            {
                "question": "Does your AI system make autonomous decisions without human review?",
                "answer": "Yes, for claims under £10,000."
            },
            {
                "question": "Is your system subject to any regulatory investigation?",
                "answer": "We are in dialogue with the FCA regarding Consumer Duty obligations."
            },
        ],
    },
)

With caching

import requests
 
response = requests.post(
    "https://platform.exonalab.com/api/v1/scans",
    headers={
        "Authorization": "Bearer exo_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "Content-Type": "application/json",
    },
    json={
        "company_name": "Acme AI Ltd",
        "company_website": "https://acme.ai",
        "max_age_days": 30,
    },
)

Response: New scan created

{
  "id": "scn_01hx7m2d3e4f5g6h7j8k9l0mn",
  "status": "processing",
  "created_at": "2026-04-03T09:00:00Z",
  "company": {
    "name": "Acme AI Ltd",
    "website": "https://acme.ai"
  }
}

Response: Cache hit

{
  "id": "scn_01hx7m2d3e4f5g6h7j8k9l0mn",
  "status": "completed",
  "cached": true,
  "cached_at": "2026-04-03T09:00:00Z",
  "created_at": "2026-03-10T14:20:00Z",
  "completed_at": "2026-03-10T14:21:45Z",
  "company": {
    "name": "Acme AI Ltd",
    "website": "https://acme.ai"
  },
  "result": { ... }
}

Error codes

CodeHTTPDescription
MISSING_REQUIRED_FIELD400company_name or company_website was not provided. The param field identifies which.
INVALID_COMPANY_WEBSITE400company_website is not a valid URL. Must include scheme (https://).
QUESTIONNAIRE_TOO_LARGE400Questionnaire exceeds size limits (50 questions, 5,000 chars per answer).
INVALID_MAX_AGE_DAYS400max_age_days must be an integer between 0 and 365.
RATE_LIMIT_EXCEEDED429Too many requests. See Retry-After header.

On this page