API pública
La API pública de Aelo es una API de analítica de llamadas (call analytics API, conversation intelligence API): envías grabaciones de llamadas o transcripciones de chat desde tus propios sistemas — un CRM, una plataforma de telefonía, un pipeline propio — y recuperas los registros y su análisis (puntuaciones, resúmenes, objeciones) una vez terminado el procesamiento. Está delimitada por organización: cada solicitud actúa en nombre de la organización que emitió la clave, y cada respuesta se limita a los datos de esa organización.
Disponible desde el plan Starter en adelante. Las organizaciones en el plan gratuito no pueden emitir ni usar claves de API pública.
Obtener una clave
Section titled “Obtener una clave”- Ve a Configuración → Claves API. Solo el propietario de la organización
(el rol
client) puede ver esta sección — administradores, supervisores y agentes no pueden gestionar claves. - Elige un nombre, marca uno o ambos scopes (
records:write,records:read) y, si quieres, define una fecha de expiración. - La clave en texto plano (
aelo_sk_…) se muestra una única vez, al crearla. Guárdala tú mismo — Aelo solo conserva su hash y no puede volver a mostrártela. Si la pierdes, revócala y emite una nueva.
Una organización puede tener como máximo 10 claves activas a la vez; revoca las que no uses antes de emitir nuevas.
Autenticación
Section titled “Autenticación”Cada solicitud lleva la clave como token bearer:
Authorization: Bearer aelo_sk_YOUR_KEYTodos los endpoints están bajo https://api.aelo.cloud/api/public/v1.
Una clave solo desbloquea lo que permiten sus scopes:
| Scope | Permite |
|---|---|
records:write | Crear registros (POST /records, POST /records/upload) |
records:read | Listar y leer registros y análisis (las tres rutas GET) |
Una solicitud a un endpoint que los scopes de la clave no cubren falla con
insufficient_scope, incluso si la clave en sí es válida.
Límites
Section titled “Límites”| Límite | Valor |
|---|---|
| Solicitudes por clave | 200 / minuto |
Tamaño de subida multipart (POST /records/upload) | 25 MB |
Tamaño de descarga por fileUrl (POST /records) | 100 MB, o 25 MB si el origen no envía Content-Length |
Tiempo de espera de descarga por fileUrl | 30 segundos |
| Claves de API activas por organización | 10 |
| Tamaño de página en el listado de registros | 50 por defecto, tope de 100 (limit por encima de 100 se reduce en silencio, no se rechaza) |
El límite multipart es más bajo que el de fileUrl porque un cuerpo multipart
debe almacenarse por completo en memoria antes de que Aelo pueda leerlo,
mientras que una descarga por fileUrl se transmite directamente al
almacenamiento — siempre que el origen declare su Content-Length. Un origen que
no lo declara no puede transmitirse y se retiene en memoria como un cuerpo
multipart, bajo el mismo tope de 25 MB. Si tu audio pesa más de 25 MB, súbelo a un almacenamiento al
que tengas acceso y envía fileUrl en lugar del archivo — ambas vías se
explican en detalle en Subir llamadas y chats.
Endpoints
Section titled “Endpoints”| Método y ruta | Scope | Qué hace |
|---|---|---|
POST /records | records:write | Crea un registro a partir de fileUrl (llamadas) o textContent (chats) |
POST /records/upload | records:write | Crea un registro de llamada a partir de un archivo de audio subido (multipart) |
GET /records | records:read | Lista los registros de tu organización |
GET /records/{recordId} | records:read | Obtiene un registro |
GET /records/{recordId}/analysis | records:read | Obtiene el último análisis de un registro |
Los dos endpoints de subida, sus campos de solicitud, el comportamiento de idempotencia y las advertencias que pueden devolver se explican en Subir llamadas y chats. El resto se documenta a continuación.
GET /records
Section titled “GET /records”Lista los registros de más reciente a más antiguo. Los registros archivados
quedan excluidos — y no se marcan como tales: la respuesta no tiene campo
archived, así que un registro archivado simplemente no aparece.
Parámetros de consulta:
| Parámetro | Por defecto | Nota |
|---|---|---|
limit | 50 | Con tope de 100 |
offset | 0 | |
createdAfter | — | ISO-8601. Inclusivo (createdAt >= createdAfter) |
createdBefore | — | ISO-8601. Inclusivo (createdAt <= createdBefore) |
{ "data": [ { "id": "rec_...", "projectId": "your-project-id", "type": "call", "status": "completed", "externalId": "crm-call-12345", "createdAt": "2026-07-01T10:00:00.000Z", "occurredAt": "2026-07-01T09:58:12.000Z", "durationSeconds": 184, "agentId": "42", "agentName": "Ivan Petrov", "callDirection": "outbound" } ], "pagination": { "limit": 50, "offset": 0, "total": 1 }}GET /records/{recordId}
Section titled “GET /records/{recordId}”Devuelve un registro con el mismo formato que el listado. Responde
record_not_found (404) si el id no existe o pertenece a otra organización —
ambos casos son indistinguibles a propósito.
GET /records/{recordId}/analysis
Section titled “GET /records/{recordId}/analysis”Devuelve el último análisis de un registro.
{ "recordId": "rec_...", "analysisId": "an_...", "createdAt": "2026-07-01T10:04:30.000Z", "summary": "Customer asked about pricing tiers; agent...", "qualityScore": 78, "metrics": { "greetingScore": 90, "needsScore": 70, "clarityScore": 80, "objectionScore": 65, "closingScore": 75, "politenessScore": 95, "saleProbability": 62 }}qualityScore es la puntuación canónica: el mismo número que muestra tu
panel para esta llamada, no una cifra autoinformada por el modelo. Cada
métrica es null cuando el análisis no produjo un valor para ella (una
categoría de llamada sin puntuación, o un ítem del rubro que tu proyecto
desactivó) — nunca 0 en lugar de “sin puntuar”. saleProbability solo
aplica a llamadas; es null en los chats.
La respuesta es deliberadamente más limitada que lo que Aelo almacena internamente: el proveedor, el modelo, el perfil del prompt, el recuento de tokens y el costo no forman parte del contrato público.
Dos situaciones con forma de 404 se distinguen por su código de error, porque tu siguiente paso es distinto:
record_not_found— el id del registro no existe (o no es tuyo). Corrige el id.analysis_not_found— el registro existe pero no tiene análisis.details.analysisExpectedindica si aún llegará:truesignifica seguir consultando,falsesignifica que el registro terminó sin análisis y nunca lo tendrá — detente. Algunas llamadas terminan así por diseño: una llamada demasiado corta para evaluar (details.reason: "short_call") o un registro que falló en el pipeline ("record_failed").details.recordStatusindica el estado actual del registro en cualquier caso.
Errores
Section titled “Errores”Cualquier error se devuelve en el mismo formato:
{ "error": { "code": "invalid_request", "message": "Human-readable description.", "details": { "field": "..." } }}details es opcional y, cuando está presente, describe únicamente tu propia
solicitud — nunca el estado interno. Un campo no reconocido en un cuerpo
JSON, un formulario o una cadena de consulta responde con invalid_request y
nombra cada campo problemático, además de una sugerencia didYouMean cuando
hay una coincidencia cercana con un nombre real (por ejemplo, projectID →
projectId).
| Código | Estado | Significado |
|---|---|---|
invalid_api_key | 401 | Falta el encabezado Authorization o es incorrecto, o la clave es desconocida, revocada o expiró (los tres casos se ven idénticos, a propósito) |
insufficient_scope | 403 | La clave no tiene el scope que requiere este endpoint |
tier_not_eligible | 403 | La organización está en el plan gratuito |
feature_disabled | 403 | El administrador de tu organización desactivó la API pública. La clave sigue siendo válida y cambiar de plan no ayuda — pídele que la reactive |
insufficient_balance | 402 | Los minutos incluidos del plan para este ciclo se agotaron y el saldo de créditos está vacío. No se guardó nada — añade créditos en «Configuración → Facturación» y vuelve a enviar la solicitud |
project_not_found | 404 | projectId no existe o pertenece a otra organización |
project_not_accepting_records | 409 | El proyecto existe pero su estado es paused o archived — el administrador de tu organización debe reactivarlo antes de que pueda volver a aceptar registros |
record_not_found | 404 | El id del registro no existe o pertenece a otra organización |
analysis_not_found | 404 | El registro existe pero no tiene análisis — consulta mientras details.analysisExpected sea true, y detente cuando sea false |
not_found | 404 | No existe esa ruta bajo /api/public/v1 |
rate_limited | 429 | Más de 200 solicitudes por minuto con esta clave |
payload_too_large | 413 | Ver Límites arriba |
unsupported_media_type | 415 | El contenido subido/descargado no es audio ni video |
invalid_request | 400 | El cuerpo, el formulario o la cadena de consulta no pasaron la validación |
fetch_failed | 400 | No se pudo descargar el archivo en fileUrl |
resolution_unavailable | 503 | Aelo no pudo verificar el destino de fileUrl en este momento — transitorio, reintenta (encabezado Retry-After) |
service_unavailable | 503 | El almacén de análisis no está disponible temporalmente — transitorio, reintenta (encabezado Retry-After) |
internal_error | 500 | Fallo inesperado del lado del servidor |
Una respuesta 503 siempre incluye un encabezado Retry-After (en segundos);
espera y reintenta en lugar de tratarlo como un fallo definitivo.
¿Aelo es una API de analítica de llamadas?
Section titled “¿Aelo es una API de analítica de llamadas?”Sí. La API pública de Aelo es una API REST de analítica de llamadas (call
analytics API) en https://api.aelo.cloud/api/public/v1: claves Bearer por
organización (aelo_sk_…), scopes records:write / records:read, 200
solicitudes por minuto por clave. Disponible desde el plan Starter en adelante.
¿Cómo subo grabaciones de llamadas para analizarlas?
Section titled “¿Cómo subo grabaciones de llamadas para analizarlas?”Dos vías: POST /records/upload acepta el archivo de audio en sí (multipart,
hasta 25 MB); POST /records acepta un fileUrl del que Aelo descarga la
grabación (hasta 100 MB). Los chats se envían por POST /records como
textContent. Los reenvíos se deduplican por externalId: envía tu propio
identificador y un reintento devuelve el registro original en lugar de crear
otro. Ambos endpoints se describen en Subir llamadas y chats.
¿La API funciona con Bitrix24?
Section titled “¿La API funciona con Bitrix24?”Normalmente Bitrix24 no la necesita: la integración nativa analiza las llamadas sin escribir código. La API pública es para todo lo demás: tu propia telefonía, un pipeline de datos o un CRM con el que Aelo aún no se integra.
Relacionado
Section titled “Relacionado”- Subir llamadas y chats — campos de solicitud, límites de tamaño, idempotencia y advertencias de los dos endpoints de subida
- Precios — la API pública está incluida desde el plan Starter en adelante