GET /api/v1/systems
Inventario de sistemas de IA de la organización.
Filtros: status
Campos: id, name, provider_name, status, is_agentic, created_at, updated_at
Disponible en los planes M2 y M3 y durante el periodo de prueba. La clave la crea y la revoca el Owner de la organización desde Ajustes → Integraciones → API.
Cada petición lleva la clave de la organización en la cabecera Authorization, como Bearer.
Authorization: Bearer alx_live_…
La clave empieza por alx_live_. Sus primeros 17 caracteres son el prefijo que ves en Ajustes → Integraciones → API. La clave completa se muestra una sola vez, al crearla: Alethexis guarda solo su huella SHA-256 y no puede volver a enseñártela.
Una clave revocada deja de funcionar en la petición siguiente.
Una clave ausente, desconocida, incorrecta o revocada recibe la misma respuesta 401: la API no distingue entre esos casos.
Cada clave admite 120 peticiones por minuto y 10.000 al día.
Toda respuesta autenticada lleva X-RateLimit-Limit, X-RateLimit-Remaining y X-RateLimit-Reset. Al agotarse la cuota, la respuesta es 429 con Retry-After, en segundos.
Además, cada dirección IP admite 60 peticiones cada 10 segundos. Por encima, la petición se bloquea durante 10 segundos.
Los listados devuelven un objeto con data y next_cursor.
limit va de 1 a 200; si no se indica, 50.
Para la página siguiente, repite la petición con cursor igual al next_cursor recibido. En la última página, next_cursor es null.
El cursor es opaco: no lo construyas ni lo modifiques.
Todos los errores tienen la misma forma: un objeto error con code y message. El message está en inglés técnico; el code es estable.
| Estado | Código | Significado |
|---|---|---|
| 400 | invalid_cursor | El cursor no es válido para ese recurso. |
| 400 | invalid_parameter | Un parámetro no existe, está repetido o tiene un valor no admitido. |
| 401 | invalid_api_key | Clave ausente, desconocida, incorrecta o revocada. |
| 403 | module_required | La organización no tiene activo M2 ni M3. |
| 404 | not_found | El recurso no existe. |
| 429 | rate_limited | Cuota de la clave agotada. |
| 500 | internal | Error interno. |
Todos admiten limit, cursor y since (fecha ISO 8601 con zona horaria).
Inventario de sistemas de IA de la organización.
Filtros: status
Campos: id, name, provider_name, status, is_agentic, created_at, updated_at
Clasificaciones de riesgo de cada sistema, con su historial.
Filtros: system_id, current
Campos: id, system_id, level, is_current, classified_at
Controles asignados y su estado, por sistema o para toda la organización.
Filtros: system_id, status
Campos: control_id, code, title, module, kind, system_id, status, updated_at
Índice de evidencias: categoría, tamaño y fecha. No incluye el fichero.
Filtros: system_id
Campos: id, section_id, category, size_bytes, uploaded_at
Estado de cada sección de la plataforma.
Filtros: status
Campos: section_id, module, status, updated_at
Actos de envío, revisión, aprobación, rechazo, sustitución y declaración, con su huella.
Filtros: subject_type
Campos: id, subject_type, subject_id, subject_version, action, decided_at, content_hash, statement_version
Registro de auditoría de la organización, con la huella encadenada de cada fila.
Filtros: action
Campos: id, action, family, table_name, record_id, occurred_at, source, row_hash
Solicitudes de uso de IA enviadas. Los borradores no se incluyen.
Filtros: status
Campos: id, status, tool_name, provider_name, urgency, involves_personal_data, submitted_at, decided_at, system_id
Por diseño, la API no incluye campos destinados a datos personales (autores, correos, direcciones IP, valores de cambio) ni textos escritos a mano. Los nombres de sistemas y herramientas los pone tu organización: no incluyas en ellos datos de personas. Por recurso, queda fuera:
systems: quién creó o editó el sistema, la persona indicada en la verificación de prácticas prohibidas, la finalidad y las notas.classifications: quién clasificó y la justificación escrita.controls: el responsable y el aprobador asignados, las notas y los enlaces a ficheros de evidencia.evidence: el fichero, su ruta de almacenamiento, el título, la descripción y quién lo subió.sections: el motivo de revisión y sus detalles.approvals: quién registró el acto, sus roles y el comentario.audit-log: quién actuó, la dirección IP, el navegador y los valores anteriores y posteriores al cambio.requests: quién la pidió, la revisó o la decidió, la finalidad, los usuarios previstos, las notas sobre datos personales, el comentario de la decisión y los comentarios.Un webhook avisa a tu sistema en cuanto pasa algo, sin que tengas que consultar la API. Los registra el Owner en Ajustes → Integraciones → Webhooks: una URL https, los eventos que quieres y un secreto que se muestra una sola vez.
Cada entrega es un POST con este cuerpo:
{
"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": "…" }
}Cabeceras: Alethexis-Signature, Alethexis-Event-Id, Alethexis-Event-Type y User-Agent: Alethexis-Webhooks/1.
El valor v1 es el HMAC-SHA256 de la marca de tiempo, un punto y el cuerpo exacto que recibes, con el secreto del endpoint. Compara en tiempo constante y rechaza lo que llegue con más de cinco minutos de diferencia.
Verificación:
// 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"])Una respuesta 2xx es una entrega buena; cualquier otra cosa, o un tiempo de espera de 10 segundos, es un fallo. El primer intento sale en el momento; si falla, se reintenta una hora después del fallo, y luego a las dos, a las cuatro y a las ocho horas del fallo anterior. Son cinco intentos en total: tras el quinto fallo la entrega queda agotada y puedes relanzarla a mano desde Ajustes → Integraciones → Webhooks. Las entregas agotadas aparecen en el informe diario interno de Alethexis.
Alethexis-Event-Id identifica el evento, no el intento: un reintento repite el mismo identificador. Guarda los que ya has procesado y descarta los repetidos. Un mismo evento llega una vez a cada endpoint suscrito.
v1 tiene nueve eventos. Cada endpoint recibe solo los eventos a los que se suscribe.
| Evento | Cuándo se emite | Campos de data |
|---|---|---|
section.closed | Al cerrarse una sección. | section_id, status, closed_at |
section.reopened | Al reabrirse una sección o quedar en revisión. | section_id, status, reason_key, reopened_at |
system.created | Al dar de alta un sistema de IA. | system_id, created_at |
system.reclassified | Al registrarse una clasificación nueva de un sistema. | system_id, classification_from, classification_to, version, classified_at |
risk.high_registered | Al registrarse un riesgo inherente alto (15 o más) o al cruzar un riesgo ese umbral. | risk_id, system_id, risk_category, inherent_score, risk_level, registered_at |
approval.registered | Al registrarse una aprobación. | approval_id, subject_type, subject_id, subject_version, content_hash, decided_at |
evidence.uploaded | Al subirse una evidencia o registrarse un PDF como evidencia. | evidence_id, section_id, system_id, category, size_bytes, uploaded_at |
request.decided | Al decidirse una solicitud de uso de IA. | request_id, status, system_id, decided_at |
product.corrective_action | Al registrarse una medida correctora del art. 20 sobre una versión de un producto propio. | corrective_action_id, system_id, version_id, measure, taken_on |
Las cargas llevan identificadores, estados y fechas. Nunca nombres, textos ni datos de personas. El detalle se lee después con la API. Hasta el 18 de septiembre de 2026 algunos eventos llevaban también el nombre del sistema o de la herramienta; ya no, porque ese nombre lo escribe tu organización y nada impide que contenga el de una persona.
Cada carga trae los identificadores necesarios para pedirle el resto a la API con tu clave. Del `system_id` de un evento cuelgan su clasificación, sus controles y sus evidencias:
# data.system_id from a system.created / system.reclassified payload SYSTEM_ID="8f2c…" curl -H "Authorization: Bearer $ALETHEXIS_API_KEY" \ "https://www.alethexis.com/api/v1/classifications?system_id=$SYSTEM_ID¤t=true" curl -H "Authorization: Bearer $ALETHEXIS_API_KEY" \ "https://www.alethexis.com/api/v1/controls?system_id=$SYSTEM_ID" curl -H "Authorization: Bearer $ALETHEXIS_API_KEY" \ "https://www.alethexis.com/api/v1/evidence?system_id=$SYSTEM_ID"
Los riesgos todavía no tienen recurso propio en la API: de `risk.high_registered` puedes resolver el sistema por su `system_id`, y el riesgo se consulta en la plataforma.
La URL tiene que ser https y resolver a una dirección pública: no se entregan webhooks a direcciones privadas ni internas. Responde en menos de 10 segundos; si necesitas más tiempo, acepta la entrega y procesa después.
v1 es un contrato: sus respuestas no cambian de forma incompatible. Un cambio incompatible se publica como una versión nueva, v2.
La especificación OpenAPI 3.1 se genera desde los mismos esquemas que validan cada respuesta: /api/v1/openapi.json
curl -H "Authorization: Bearer $ALETHEXIS_API_KEY" \ "https://www.alethexis.com/api/v1/systems?limit=50"