API para integraciones
Una API key permite que un sistema externo lea y escriba en INSSACS sin usar la sesión de nadie. Esta sección documenta el contrato: qué endpoints existen, qué cuerpo espera cada uno y qué devuelve.
La key se crea desde el panel: API Keys.
Autenticación
Dos formas equivalentes, en cada petición:
curl https://api.inssacs.com/products \
-H 'x-api-key: ics_a1b2c3d4_e5f6...'
curl https://api.inssacs.com/products \
-H 'Authorization: Bearer ics_a1b2c3d4_e5f6...'
Con Authorization: Bearer, el secreto debe empezar por ics_; si no, el servidor lo interpreta
como un JWT de usuario y responde 401.
| Situación | Respuesta |
|---|---|
| Sin cabecera de autenticación | 401 |
| Secreto inválido, revocado o expirado | 401 Invalid API key |
| Key válida sin permiso o fuera de alcance | 403 |
Alcance: cliente o cuenta
La key se emite en uno de dos niveles, y todo lo que hace queda acotado a él:
| Nivel | Abarca | Cuándo elegirlo |
|---|---|---|
| Cliente | Todas las cuentas del cliente, incluidas las que se creen después | Una integración corporativa que consolida varias cuentas |
| Cuenta | Solo esa cuenta | Un sistema de una sede o filial concreta |
En ambos casos:
- en las listas, los filtros de cliente, cuenta y operación se ignoran si apuntan fuera del alcance: el servidor los reescribe con los de la key;
- en lectura o escritura de un recurso concreto, lo que quede fuera responde
403; - al crear, no hace falta enviar
clientId: sale de la key. Una key de cliente sí debe indicar a qué cuenta pertenece lo que crea (accountId); una de cuenta puede omitirlo.
El nivel de la key se ve en la columna Alcance de la tabla y en el campo scope de las
respuestas.
Qué puede hacer una key
Al crearla eliges qué permisos tiene: por defecto trae todos los que su creador puede otorgar, y se recortan desde ahí (ver API Keys). Una key no tiene rol: su lista de permisos es todo lo que puede hacer, y se puede cambiar después sin reemitirla.
Con todos los permisos, cubre:
| Recurso | Endpoints |
|---|---|
| Cuenta y etiquetas de usuarios | Cuenta y operaciones |
| Operaciones | Cuenta y operaciones |
| Productos y perfiles | Catálogo |
| Usuarios consumidores, códigos y huellas | Usuarios y códigos |
| Dispositivos e inventario (planograma) | Dispositivos |
| Entregas, recargas, devoluciones, crédito disponible, dashboard, exportaciones, auditoría | Reportes |
Qué NO puede hacer
| Bloqueado | Motivo |
|---|---|
Administrar API keys (/api-keys) | Excluido a propósito: una key no puede emitir otra key. |
Crear, editar o eliminar clientes (POST/PATCH/DELETE /clients) | Solo un operador global administra clientes (422 clients.actor_not_global). Leer GET /clients sí funciona y devuelve su cliente. |
Controladoras y licencias (/controllers) | Recurso reservado a INSSA. |
Crear o eliminar dispositivos (POST/DELETE /devices) | Reservado a INSSA (device_provisioning). El resto del recurso sí está disponible. |
Operadores y roles (/users, /roles) | Los use cases resuelven un usuario actor real; una key no lo es y responden 403. |
| Errores de servidor y de lambdas | Reservados a INSSA. |
/auth/* | Es el flujo de sesión de un operador humano. |
Límite de tasa
Ventana fija de 1 minuto por key: 120 solicitudes por defecto, o el valor que tenga la key en
Límite de tasa. Al excederlo, 429. Hay además un límite global por IP de 300 por minuto.
Conviene espaciar los procesos por lotes y reintentar con retroceso exponencial ante un 429.
Formato de las respuestas
- Éxito:
200con el recurso o la lista,201al crear,202al aceptar una exportación y204sin cuerpo en activar/desactivar/eliminar. - Listas paginadas (cuentas, operaciones, productos, perfiles, usuarios):
{ items, total, page, pageSize }, conpagedesde 1 ypageSizemáximo 1000. - Listas por cursor (movimientos):
{ items, nextCursor }. Se pide la página siguiente concursor=<nextCursor>ylimitmáximo 1000; cuandonextCursoresnull, no hay más. - Importes: enteros en unidades menores (ver Importes y moneda).
- Fechas: ISO 8601 en UTC (
2026-08-11T14:03:00.000Z). Los filtrosfromytoson obligatorios en los movimientos.
Formato de los errores
application/problem+json, con el código de dominio y —en las validaciones— el detalle campo por
campo:
{
"type": "https://api.inssacs.com/problems/profiles.device_not_in_account",
"title": "Bad Request",
"status": 400,
"code": "profiles.device_not_in_account",
"detail": "device 665f… not in account",
"traceId": "01J9…"
}
Validación de cuerpo:
{
"status": 400,
"code": "validation.failed",
"errors": [
{ "field": "cost", "rule": "isInt" },
{ "field": "businessLine", "rule": "isIn" }
]
}
| Código HTTP | Cuándo |
|---|---|
400 | Cuerpo o query inválidos (incluye campos no declarados: el servidor los rechaza, no los ignora). |
401 | Key ausente, inválida, revocada o expirada. |
403 | Sin permiso, fuera de alcance o recurso reservado. |
404 | El recurso no existe o no es visible para la key. |
409 | Conflicto de estado: duplicado, exportación en curso, perfil con códigos. |
422 | Regla de dominio incumplida (p. ej. huella inválida). |
429 | Límite de tasa. |
500 | Error del servidor. El traceId es lo que hay que pasar a soporte. |
Los códigos concretos de cada recurso están en Mensajes de error.
La app publica un Swagger en /docs, pero solo cuando no corre en producción y describe únicamente
el esquema de autenticación con JWT. Para integrar contra producción, esta sección del manual es la
referencia.