Consultar y gestionar los errores
Lista, cuenta y abre los errores que ha enviado tu aplicación, y resuélvelos, reábrelos o siléncialos desde tu código, como tu equipo en el panel.
Actualizado el . 6 min de lectura
Incluido en todos los planes. Ver precios
Tu aplicación puede leer los errores que ella misma ha enviado y gestionarlos igual que tu equipo en la pestaña Errores: resolverlos cuando sale la corrección, reabrirlos o silenciarlos durante un incidente que ya conoces. Solo ve los suyos, nunca los de otra aplicación ni los internos de UTILIA OS, y cada cambio avisa a tu servidor. Cómo se envían está en Enviar los errores de tu aplicación.
Autenticación y permisos
Todas las peticiones llevan la cabecera X-Api-Key, y el plan de tu organización tiene que incluir el aplicativo Integraciones.
| Endpoint | Permiso de la API (scope) |
|---|---|
GET /external/v1/errors | analytics:errors:read |
GET /external/v1/errors/stats | analytics:errors:read |
GET /external/v1/errors/:hash | analytics:errors:read |
POST /external/v1/errors/:hash/resolve | analytics:errors:manage |
POST /external/v1/errors/:hash/reopen | analytics:errors:manage |
POST /external/v1/errors/:hash/silence | analytics:errors:manage |
DELETE /external/v1/errors/:hash/silence | analytics:errors:manage |
Las cuatro rutas de gestión actúan en nombre de la persona responsable de la aplicación. Esa persona necesita además el permiso Gestionar los errores de las aplicaciones externas, el mismo que pide la pestaña Errores: por la API no se puede hacer más que en el panel. Cada acción queda en el registro de auditoría a su nombre.
Como el envío, estas rutas admiten 120 peticiones por minuto cada una, por aplicación. A diferencia del envío, sí cuentan en el cupo por hora de tu clave, como cualquier otra petición de la API.
Listar los errores
/api/external/v1/errorsGrupos de errores que ha enviado esta aplicación, con filtros opcionales. Permiso: analytics:errors:read.
Parámetros de consulta
- severitystring | string[]
- critical, high, medium o low. Para varias, repite el parámetro (severity=critical&severity=high) o sepáralas con comas.
- statusstring
- active (sin resolver y sin silencio vigente), resolved, silenced o all. Sin status ni resolved, se devuelven todos.
- resolvedboolean
- Filtro anterior a status, que se mantiene: true, resueltos; false, sin resolver, también los silenciados. Se ignora si llega status.
- modulestring
- Módulo exacto, hasta 100 caracteres.
- firstReleasestring
- Versión exacta en la que el error apareció por primera vez: los nuevos de la 2.4.1.
- fromstring
- Última ocurrencia desde esta fecha, en ISO 8601 (2026-10-01T00:00:00Z).
- tostring
- Última ocurrencia hasta esta fecha, en ISO 8601.
- limitnumber
- Tamaño de la página, de 1 a 200. Por defecto, 50.
- offsetnumber
- Cuántos grupos saltar, para paginar. Por defecto, 0.
Los grupos salen de más a menos graves y, dentro de cada gravedad, del más reciente al más antiguo.
Respuesta
{
"data": [
{
"id": "cm9x2k1ab0001",
"hash": "5f2b7c1e9a0d4e3b8c6a1f7d2e9b0c4a",
"message": "Tiempo de espera agotado con la pasarela",
"module": "pagos",
"severity": "critical",
"file": "src/pagos.ts",
"line": 45,
"endpoint": "/api/pagos/cobrar",
"count": 37,
"firstOccurrence": "2026-10-20T09:12:00.000Z",
"lastOccurrence": "2026-10-22T08:41:00.000Z",
"resolved": false,
"resolvedAt": null,
"status": "active",
"silencedUntil": null,
"environment": "production",
"firstRelease": "2.4.0",
"lastRelease": "2.4.2",
"regressionCount": 1,
"lastRegressedAt": "2026-10-22T08:41:00.000Z"
}
],
"pagination": {
"page": 1,
"limit": 50,
"total": 1,
"totalPages": 1
}
}- statusstring
- active (sin resolver y sin silencio vigente), resolved o silenced.
- silencedUntilstring | null
- Hasta cuándo está silenciado, si lo está.
- environmentstring | null
- Entorno declarado al enviarlo. El entorno no separa grupos: si el mismo fallo llega de varios, queda el primero.
- firstRelease, lastReleasestring | null
- Primera y última versión en que se vio.
- regressionCountnumber
- Veces que ha vuelto a ocurrir después de darse por resuelto.
- lastRegressedAtstring | null
- Última vez que volvió tras darse por resuelto.
- paginationobject
- page (offset / limit + 1), limit, total y totalPages.
Ejemplos
curl 'https://os.utilia.ai/api/external/v1/errors?status=active&severity=critical&severity=high&limit=20' \
-H 'X-Api-Key: utl_xxx'En Python, from y to se escriben from_date y to_date, porque from es palabra reservada, y firstRelease, first_release.
Estadísticas
/api/external/v1/errors/statsCifras de los errores de esta aplicación. Permiso: analytics:errors:read.
{
"total": 156,
"unresolved": 42,
"silenced": 3,
"bySeverity": { "critical": 5, "high": 18, "medium": 12, "low": 7 },
"byModule": { "pagos": 15, "auth": 8, "importador": 19 },
"topErrors": [
{
"hash": "5f2b7c1e9a0d4e3b8c6a1f7d2e9b0c4a",
"message": "Tiempo de espera agotado con la pasarela",
"count": 37,
"severity": "critical"
}
]
}total: grupos de la aplicación, en cualquier estado.unresolved: los pendientes, sin resolver y sin silencio vigente. Es la misma cifra que la pestaña Errores.silenced: los que están sin resolver con un silencio vigente.bySeverityybyModule: los pendientes, por gravedad y por módulo.topErrors: los diez pendientes con más ocurrencias, con el mensaje recortado a 100 caracteres.
Con los SDK, sdk.errors.stats().
Detalle de un error
/api/external/v1/errors/:hashUn grupo con su pila, su contexto y lo que tiene vinculado. Permiso: analytics:errors:read.
Devuelve los campos del listado y, además:
{
"hash": "5f2b7c1e9a0d4e3b8c6a1f7d2e9b0c4a",
"status": "active",
"stack": "Error: Tiempo de espera agotado\n at cobrar (src/pagos.ts:45:12)",
"function": "cobrar",
"method": "POST",
"context": {
"pedidoId": "ped_456",
"tags": { "pasarela": "redsys" },
"externalUserRef": "usr-4821"
},
"resolutionNote": null,
"lastRequestId": "req-pagos-0042",
"linkedTicket": { "id": "tkt_123", "key": "SUP-482" },
"linkedIssue": null
}stackycontextllegan saneados, sin credenciales ni correos. El contexto es el de la última ocurrencia; las etiquetas están encontext.tagsy eluserIdque enviaste, encontext.externalUserRef.lastRequestId: el identificador de petición de la última ocurrencia que lo traía.linkedTicketylinkedIssue: el ticket de soporte o la tarea de Gestión de proyectos vinculados, con su clave visible, onull.
Un hash que no existe, que es de otra aplicación o que no es tuyo responde el mismo 404. Con los SDK, sdk.errors.get(hash).
Resolver, reabrir y silenciar
Las cuatro acciones cambian el estado del grupo igual que los botones de la pestaña Errores, y cada una avisa a tu servidor. Los estados y qué los cambia están en Estados de un grupo de errores. Responden 200.
Resolver
/api/external/v1/errors/:hash/resolveMarca el grupo como resuelto, con una nota opcional. Permiso: analytics:errors:manage.
note es opcional, de hasta 1.000 caracteres. La respuesta es { "hash": "…", "resolved": true, "alreadyResolved": false } y tu servidor recibe ERROR_RESOLVED. Si ya estaba resuelto, alreadyResolved: true: no cambia nada ni sale ningún aviso.
Si el error vuelve a ocurrir, se reabre solo: esa ocurrencia responde status: regressed, el grupo suma una en regressionCount y tu servidor recibe ERROR_REOPENED con reason: regression y la versión en release.
Reabrir
/api/external/v1/errors/:hash/reopenDevuelve a pendiente un grupo resuelto. Permiso: analytics:errors:manage.
Sin cuerpo. La respuesta es { "hash": "…", "alreadyOpen": false } y tu servidor recibe ERROR_REOPENED con reason: manual. Si ya estaba abierto, alreadyOpen: true y no sale ningún aviso.
Silenciar y quitar el silencio
/api/external/v1/errors/:hash/silenceSilencia el grupo de 1 a 672 horas. Permiso: analytics:errors:manage.
hours es obligatorio, un entero de 1 a 672 (cuatro semanas). Mientras dure, el grupo sigue sumando ocurrencias, pero no cuenta como pendiente ni avisa. Volver a silenciarlo sustituye el plazo. La respuesta trae el fin del silencio en silencedUntil y tu servidor recibe ERROR_SILENCED con esa fecha en until.
/api/external/v1/errors/:hash/silenceQuita el silencio antes de tiempo. Permiso: analytics:errors:manage.
La respuesta es { "hash": "…", "silencedUntil": null }; si el grupo no está resuelto, vuelve a contar como pendiente. Tu servidor recibe ERROR_SILENCED con until: null.
Ejemplos
HASH=5f2b7c1e9a0d4e3b8c6a1f7d2e9b0c4a
curl -X POST "https://os.utilia.ai/api/external/v1/errors/$HASH/resolve" \
-H 'Content-Type: application/json' -H 'X-Api-Key: utl_xxx' \
-d '{ "note": "Corregido en la 2.4.2" }'
curl -X POST "https://os.utilia.ai/api/external/v1/errors/$HASH/silence" \
-H 'Content-Type: application/json' -H 'X-Api-Key: utl_xxx' \
-d '{ "hours": 24 }'
curl -X DELETE "https://os.utilia.ai/api/external/v1/errors/$HASH/silence" \
-H 'X-Api-Key: utl_xxx'Errores
| HTTP | Cuándo |
|---|---|
400 | Un filtro no es válido (gravedad o estado desconocidos, fecha que no es ISO 8601), hours está fuera de 1 a 672 o note pasa de 1.000 caracteres. |
401 | Falta la clave de API o no es válida. |
403 | Falta el permiso de la ruta (INSUFFICIENT_SCOPE), el plan no incluye Integraciones (MODULE_NOT_ENABLED) o, en la gestión, la persona responsable no tiene el permiso (APP_RESPONSIBLE_PERMISSION_DENIED) o no está activa (APP_RESPONSIBLE_INACTIVE). |
404 | No hay ningún grupo con ese hash para esta aplicación. |
429 | Más de 120 peticiones por minuto en la ruta. Respeta Retry-After. |
APP_RESPONSIBLE_PERMISSION_DENIED no se arregla en los permisos de la aplicación, sino en los de su persona responsable.