POST /v1/score One endpoint. One number.

Right-level your AI. Programmatically.

Five questions about how your team uses AI. One HTTP call. A score per role, and what to do next.

No SDK required Free tier: 60 requests/minute

Quickstart

Your first score in 30 seconds

Five answers, one industry. The whole call:

shell
curl https://api.caiscore.com/v1/score \
  -H "Authorization: Bearer $CAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "answers": {
      "level": "integrated",
      "competence": "harness",
      "regulation": "mixed",
      "reversibility": "costly",
      "detection": "review"
    },
    "industry": "accounting-firm"
  }'

Assessment

Run the five-question assessment

Answer the five questions, choose a roster, and see the live score come back from POST /v1/score — no arithmetic runs in this page.

Reference

Every endpoint, straight from the spec

Generated from the OpenAPI document. It can’t drift.

GET /v1/health

Liveness probe

Response fields (200)
Field Type
status string
service string
api_version string
version string
GET /v1/auth/google

Begin Google sign-in

GET /v1/auth/google/callback

Complete Google sign-in

Parameters
Name In Required Type Constraints Description
code query Optional string
state query Optional string
POST /v1/auth/logout

Sign out

GET /v1/account

The signed-in caller's own account

Response fields (200)
Field Type
email string
created_at string
GET /v1/account/keys

The signed-in account's own keys

Response fields (200)
Field Type
keys array
POST /v1/account/keys

Mint a free-tier key owned by the signed-in account

Request body
Field Type Required
name string Required
origins array Optional
PATCH /v1/account/keys/{hash}

Replace or clear a key's origin allowlist

Parameters
Name In Required Type Constraints Description
hash path Required string
Request body
Field Type Required
origins array | null Required
Response fields (200)
Field Type
hash string
name string
tier string
created_at string
origins array | null
DELETE /v1/account/keys/{hash}

Revoke a key owned by the signed-in account

Parameters
Name In Required Type Constraints Description
hash path Required string
Request body
Field Type Required
name string Required
GET /v1/account/keys/{hash}/usage-series

One key's recorded requests as a bucketed time series

Parameters
Name In Required Type Constraints Description
hash path Required string
from query Optional string ISO 8601 start of the range, inclusive. Defaults to seven days before `to`.
to query Optional string ISO 8601 end of the range, exclusive. Defaults to the current time.
precision query Optional string one of minute, hour, day The bucket width. Defaults to `hour`.
Response fields (200)
Field Type
hash string
precision string
from string
to string
buckets array
GET /v1/key/usage

The presented key's own request totals

Response fields (200)
Field Type
hash string
last_24h integer
last_30d integer
GET /v1/key/usage-series

The presented key's own recorded requests as a bucketed time series

Parameters
Name In Required Type Constraints Description
from query Optional string ISO 8601 start of the range, inclusive. Defaults to seven days before `to`.
to query Optional string ISO 8601 end of the range, exclusive. Defaults to the current time.
precision query Optional string one of minute, hour, day The bucket width. Defaults to `hour`.
Response fields (200)
Field Type
hash string
precision string
from string
to string
buckets array
GET /v1/questions

The five CAI questions and their option values

Response fields (200)
Field Type
meta object
questions array
GET /v1/industries

Search the curated industry roster

Parameters
Name In Required Type Constraints Description
q query Optional string Free-text match against label and curated synonyms.
Response fields (200)
Field Type
meta object
industries array
GET /v1/industries/{id}

One industry, identifier and label only

Parameters
Name In Required Type Constraints Description
id path Required string
Response fields (200)
Field Type
industry object
GET /v1/occupations

Search-only occupation discovery

Parameters
Name In Required Type Constraints Description
q query Required string At least two characters.
limit query Optional integer min 1; max 10; default 10
Response fields (200)
Field Type
meta object
occupations array
GET /v1/occupations/{soc}

One occupation, identifier and label only

Parameters
Name In Required Type Constraints Description
soc path Required string
Response fields (200)
Field Type
occupation object
GET /v1/openapi.json

This document

POST /v1/score

Score a role roster against the five answers

Request body
Field Type Required
answers object Required
occupations array Optional
industry string Optional
Response fields (200)
Field Type
meta object
params object
posture array
roles array
aggregate object
suggestions array

Errors

Every error, one shape

Same envelope every time — { "error": { "code": "…", "message": "…" } }. Switch on code; message is for humans.

Code Status Where
unauthorized 401 A missing, malformed, or unknown key on any non-exempt route
origin_not_allowed 403 A key carrying an origin allowlist, presented from an origin it does not name — or with no Origin header at all
rate_limited 429 An exhausted rate limit on any non-exempt route
no_session 401 GET /v1/account — a missing or invalid session cookie
invalid_state 400 GET /v1/auth/google/callback — state is missing, expired, or fails its signature check
sign_in_failed 403 GET /v1/auth/google/callback — the code exchange failed, or the ID token's aud or exp is wrong
not_found 404 Any request whose path matches no route
method_not_allowed 405 A matched path with the wrong HTTP method
internal_error 500 An unhandled failure, including a misconfigured key or rate-limit binding
industry_not_found 404 GET /v1/industries/:id — unknown id
query_required 400 GET /v1/occupations — missing or too-short q
invalid_parameter 400 GET /v1/occupations — out-of-range limit, or an offset parameter
occupation_not_found 404 GET /v1/occupations/:soc — unknown soc
unsupported_media_type 415 POST /v1/score — Content-Type is not application/json
invalid_json 400 POST /v1/score — body is not valid JSON
invalid_body 400 POST /v1/score — body is not a JSON object
invalid_answers 400 POST /v1/score — answers missing or malformed
invalid_occupations 400 POST /v1/score — occupations is not an array of strings
invalid_industry 400 POST /v1/score — industry is not a string
industry_not_found 404 POST /v1/score — unknown industry id
missing_roster 400 POST /v1/score — neither occupations nor industry given
empty_roster 400 POST /v1/score — resolved roster has zero entries
roster_too_large 400 POST /v1/score — resolved roster exceeds 25 entries
occupation_not_found 400 POST /v1/score — an occupations entry is an unknown SOC code