/v1/health Liveness probe
| Field | Type |
|---|---|
status | string |
service | string |
api_version | string |
version | string |
Five questions about how your team uses AI. One HTTP call. A score per role, and what to do next.
Quickstart
Five answers, one industry. The whole call:
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" }'
import os import requests r = requests.post( "https://api.caiscore.com/v1/score", headers={"Authorization": f"Bearer {os.environ['CAI_API_KEY']}"}, json={ "answers": { "level": "integrated", "competence": "harness", "regulation": "mixed", "reversibility": "costly", "detection": "review", }, "industry": "accounting-firm", }, ) print(r.json()["aggregate"]["score"])
type ScoreResponse = { aggregate: { score: number; lt: number; zone: "stranded" | "right" | "risk"; target_level: string | null; }; }; const response = await fetch("https://api.caiscore.com/v1/score", { method: "POST", headers: { Authorization: `Bearer ${process.env.CAI_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ answers: { level: "integrated", competence: "harness", regulation: "mixed", reversibility: "costly", detection: "review", }, industry: "accounting-firm", }), }); const { aggregate } = (await response.json()) as ScoreResponse; console.log(aggregate.score);
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
Generated from the OpenAPI document. It can’t drift.
/v1/health Liveness probe
| Field | Type |
|---|---|
status | string |
service | string |
api_version | string |
version | string |
/v1/questions The five CAI questions and their option values
| Field | Type |
|---|---|
meta | object |
questions | array |
/v1/industries Search the curated industry roster
| Name | In | Required | Type | Constraints | Description |
|---|---|---|---|---|---|
q | query | Optional | string | Free-text match against label and curated synonyms. |
| Field | Type |
|---|---|
meta | object |
industries | array |
/v1/industries/{id} One industry, identifier and label only
| Name | In | Required | Type | Constraints | Description |
|---|---|---|---|---|---|
id | path | Required | string |
| Field | Type |
|---|---|
industry | object |
/v1/occupations Search-only occupation discovery
| Name | In | Required | Type | Constraints | Description |
|---|---|---|---|---|---|
q | query | Required | string | At least two characters. | |
limit | query | Optional | integer | min 1; max 10; default 10 |
| Field | Type |
|---|---|
meta | object |
occupations | array |
/v1/occupations/{soc} One occupation, identifier and label only
| Name | In | Required | Type | Constraints | Description |
|---|---|---|---|---|---|
soc | path | Required | string |
| Field | Type |
|---|---|
occupation | object |
/v1/openapi.json This document
/v1/score Score a role roster against the five answers
| Field | Type | Required |
|---|---|---|
answers | object | Required |
occupations | array | Optional |
industry | string | Optional |
| Field | Type |
|---|---|
meta | object |
params | object |
posture | array |
roles | array |
aggregate | object |
suggestions | array |
Errors
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 |
rate_limited | 429 | An exhausted rate limit on any non-exempt route |
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 |