API de lectura

Acceso de solo lectura, con una clave de organización, a los registros de gobernanza de IA de tu cuenta.

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.

Autenticación

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.

Cuota

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.

Paginación

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.

Errores

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.

EstadoCódigoSignificado
400invalid_cursorEl cursor no es válido para ese recurso.
400invalid_parameterUn parámetro no existe, está repetido o tiene un valor no admitido.
401invalid_api_keyClave ausente, desconocida, incorrecta o revocada.
403module_requiredLa organización no tiene activo M2 ni M3.
404not_foundEl recurso no existe.
429rate_limitedCuota de la clave agotada.
500internalError interno.

Recursos

Todos admiten limit, cursor y since (fecha ISO 8601 con zona horaria).

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

GET /api/v1/classifications

Clasificaciones de riesgo de cada sistema, con su historial.

Filtros: system_id, current

Campos: id, system_id, level, is_current, classified_at

GET /api/v1/controls

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

GET /api/v1/evidence

Í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

GET /api/v1/sections

Estado de cada sección de la plataforma.

Filtros: status

Campos: section_id, module, status, updated_at

GET /api/v1/approvals

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

GET /api/v1/audit-log

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

GET /api/v1/requests

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

Qué no devuelve la API

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.

Webhooks

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.

Firma

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"])

Reintentos

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.

Idempotencia

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.

Catálogo v1

v1 tiene nueve eventos. Cada endpoint recibe solo los eventos a los que se suscribe.

EventoCuándo se emiteCampos de data
section.closedAl cerrarse una sección.section_id, status, closed_at
section.reopenedAl reabrirse una sección o quedar en revisión.section_id, status, reason_key, reopened_at
system.createdAl dar de alta un sistema de IA.system_id, created_at
system.reclassifiedAl registrarse una clasificación nueva de un sistema.system_id, classification_from, classification_to, version, classified_at
risk.high_registeredAl 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.registeredAl registrarse una aprobación.approval_id, subject_type, subject_id, subject_version, content_hash, decided_at
evidence.uploadedAl subirse una evidencia o registrarse un PDF como evidencia.evidence_id, section_id, system_id, category, size_bytes, uploaded_at
request.decidedAl decidirse una solicitud de uso de IA.request_id, status, system_id, decided_at
product.corrective_actionAl 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

Qué no viaja en un webhook

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.

Cómo obtener el detalle a partir de un webhook

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&current=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.

Requisitos del receptor

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.

Versiones

v1 es un contrato: sus respuestas no cambian de forma incompatible. Un cambio incompatible se publica como una versión nueva, v2.

Especificación OpenAPI

La especificación OpenAPI 3.1 se genera desde los mismos esquemas que validan cada respuesta: /api/v1/openapi.json

Ejemplo

curl -H "Authorization: Bearer $ALETHEXIS_API_KEY" \
  "https://www.alethexis.com/api/v1/systems?limit=50"