GET /api/v1/systems
The organisation’s inventory of AI systems.
Filters: status
Fields: id, name, provider_name, status, is_agentic, created_at, updated_at
Available on the M2 and M3 plans and during the trial. The organisation Owner creates and revokes the key from Settings → API.
Every request carries the organisation key in the Authorization header, as a Bearer token.
Authorization: Bearer alx_live_…
The key starts with alx_live_. Its first 17 characters are the prefix shown in Settings → API. The full key is shown only once, when it is created: Alethexis stores only its SHA-256 fingerprint and cannot show it to you again.
A revoked key stops working on the next request.
A missing, unknown, wrong or revoked key gets the same 401 response: the API does not tell these cases apart.
Each key allows 120 requests per minute and 10,000 per day.
Every authenticated response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. When the quota runs out, the response is 429 with Retry-After, in seconds.
In addition, each IP address allows 60 requests every 10 seconds. Above that, requests are blocked for 10 seconds.
List responses return an object with data and next_cursor.
limit ranges from 1 to 200; the default is 50.
For the next page, repeat the request with cursor set to the next_cursor you received. On the last page, next_cursor is null.
The cursor is opaque: do not build or modify it.
All errors share one shape: an error object with code and message. The message is technical English; the code is stable.
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_cursor | The cursor is not valid for that resource. |
| 400 | invalid_parameter | A parameter does not exist, is repeated or has a value that is not accepted. |
| 401 | invalid_api_key | Missing, unknown, wrong or revoked key. |
| 403 | module_required | The organisation has neither M2 nor M3 active. |
| 404 | not_found | The resource does not exist. |
| 429 | rate_limited | The key’s quota is exhausted. |
| 500 | internal | Internal error. |
All of them accept limit, cursor and since (an ISO 8601 date with time zone).
The organisation’s inventory of AI systems.
Filters: status
Fields: id, name, provider_name, status, is_agentic, created_at, updated_at
Risk classifications for each system, with their history.
Filters: system_id, current
Fields: id, system_id, level, is_current, classified_at
Assigned controls and their status, per system or for the whole organisation.
Filters: system_id, status
Fields: control_id, code, title, module, kind, system_id, status, updated_at
Evidence index: category, size and date. The file itself is not included.
Filters: system_id
Fields: id, section_id, category, size_bytes, uploaded_at
Status of each section of the platform.
Filters: status
Fields: section_id, module, status, updated_at
Submission, review, approval, rejection, replacement and declaration acts, with their fingerprint.
Filters: subject_type
Fields: id, subject_type, subject_id, subject_version, action, decided_at, content_hash, statement_version
The organisation’s audit log, with the chained fingerprint of each row.
Filters: action
Fields: id, action, family, table_name, record_id, occurred_at, source, row_hash
AI use requests that have been submitted. Drafts are not included.
Filters: status
Fields: id, status, tool_name, provider_name, urgency, involves_personal_data, submitted_at, decided_at, system_id
The API returns no data about people and no hand-written text. Per resource, it leaves out:
systems: who created or edited the system, the person named in the prohibited-practices check, the purpose and the notes.classifications: who classified it and the written justification.controls: the assigned owner and approver, the notes and the links to evidence files.evidence: the file, its storage path, the title, the description and who uploaded it.sections: the review reason and its details.approvals: who recorded the act, their roles and the comment.audit-log: who acted, the IP address, the browser and the values before and after the change.requests: who raised, reviewed or decided it, the purpose, the intended users, the notes on personal data, the decision comment and the comments.A webhook notifies your system as soon as something happens, without polling the API. The Owner registers them in Settings → Webhooks: an https URL, the events you want and a secret shown only once.
Every delivery is a POST with this body:
{
"id": "0f3a…", // Alethexis-Event-Id
"type": "section.closed",
"created_at": "2026-09-18T09:12:03.412Z",
"api_version": "v1",
"data": { "account_id": "…", "section_id": "GOB-2", "status": "complete", "closed_at": "…" }
}Headers: Alethexis-Signature, Alethexis-Event-Id, Alethexis-Event-Type and User-Agent: Alethexis-Webhooks/1.
The v1 value is the HMAC-SHA256 of the timestamp, a dot and the exact body you receive, using the endpoint secret. Compare in constant time and reject anything more than five minutes old.
Verification:
// Node.js
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verify(rawBody, header, secret, toleranceSeconds = 300) {
const [t, v1] = header.split(',').map((part) => part.split('=')[1]);
if (Math.abs(Date.now() / 1000 - Number(t)) > toleranceSeconds) return false;
const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest();
const received = Buffer.from(v1, 'hex');
return expected.length === received.length && timingSafeEqual(expected, received);
}# Python
import hashlib, hmac, time
def verify(raw_body: bytes, header: str, secret: str, tolerance: int = 300) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
if abs(time.time() - int(parts["t"])) > tolerance:
return False
expected = hmac.new(
secret.encode(), f'{parts["t"]}.'.encode() + raw_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, parts["v1"])A 2xx response is a good delivery; anything else, or a 10-second timeout, is a failure. Retries happen after one, two, four, eight and sixteen hours; after the fifth attempt the delivery is exhausted and you can replay it by hand from Settings → Webhooks. Exhausted deliveries appear in Alethexis’s internal daily report.
Alethexis-Event-Id identifies the event, not the attempt: a retry repeats the same identifier. Keep the ones you have processed and discard repeats. The same event arrives once per subscribed endpoint.
v1 has eight events and the list is closed: a new event ships with a new catalogue version.
| Event | When it is emitted | data fields |
|---|---|---|
section.closed | When a section is closed. | section_id, status, closed_at |
section.reopened | When a section is reopened or moves to review. | section_id, status, reason_key, reopened_at |
system.created | When an AI system is added. | system_id, system_name, created_at |
system.reclassified | When a new classification is recorded for a system. | system_id, system_name, classification_from, classification_to, version, classified_at |
risk.high_registered | When a high inherent risk (15 or above) is recorded, or a risk crosses that threshold. | risk_id, system_id, system_name, risk_category, inherent_score, risk_level, registered_at |
approval.registered | When an approval is recorded. | approval_id, subject_type, subject_id, subject_version, content_hash, decided_at |
evidence.uploaded | When evidence is uploaded or a PDF is registered as evidence. | evidence_id, section_id, system_id, category, size_bytes, uploaded_at |
request.decided | When an AI use request is decided. | request_id, status, tool_name, system_id, decided_at |
Payloads carry identifiers, states, dates and the name of the system or tool. They never carry who performed the action, their roles, comments, hand-written reasons or email addresses. If your system needs the detail, read it afterwards with the API.
The URL must be https and resolve to a public address: webhooks are not delivered to private or internal addresses. Respond within 10 seconds; if you need longer, accept the delivery and process it afterwards.
v1 is a contract: its responses do not change in incompatible ways. An incompatible change ships as a new version, v2.
The OpenAPI 3.1 specification is generated from the same schemas that validate every response: /api/v1/openapi.json
curl -H "Authorization: Bearer $ALETHEXIS_API_KEY" \ "https://www.alethexis.com/api/v1/systems?limit=50"