API: usuarios y códigos
Contrato general en Cómo funciona la API. Es la parte de la API que más se integra: sincronizar la nómina del cliente con los consumidores de INSSACS.
Usuarios consumidores
POST /consumers
GET /consumers
GET /consumers/summary
GET /consumers/:id
PATCH /consumers/:id
PATCH /consumers/:id/active
DELETE /consumers/:id
GET /consumers/:id/entitlements
Crear — 201
| Campo | Tipo | Obligatorio | Notas |
|---|---|---|---|
name | string | sí | — |
identification | string | sí | único dentro de la cuenta |
tags | { key, value }[] | no | key debe existir en las etiquetas de la cuenta |
accountId | string | no | se ignora: manda la cuenta de la key |
initialCode | objeto | no | crea el primer código en la misma llamada |
curl -X POST https://api.inssacs.com/consumers \
-H 'x-api-key: ics_…' -H 'content-type: application/json' \
-d '{
"name": "Juan Pérez",
"identification": "1023456789",
"tags": [{ "key": "departamento", "value": "Producción" }],
"initialCode": { "codeId": "1023456789", "codeType": "QR", "operationId": "665f…c7" }
}'
Respuesta: el consumidor con sus códigos.
{
"id": "665f…e1",
"clientId": "665f…c5",
"accountId": "665f…c6",
"name": "Juan Pérez",
"identification": "1023456789",
"isActive": true,
"tags": [{ "key": "departamento", "value": "Producción" }],
"codes": [
{
"codeId": "1023456789",
"codeType": "QR",
"operationId": "665f…c7",
"isActive": true,
"vendingProfileId": null,
"easProfileId": null,
"vendingBalance": 0,
"vendingRecharge": 0
}
],
"createdAt": "2026-08-11T14:03:00.000Z"
}
Editar y estado
PATCH /consumers/:id→name,identification,tags(opcionales).200.PATCH /consumers/:id/activecon{ "active": false }→ desactiva al usuario y con él todos sus códigos.200.DELETE /consumers/:id→204; borra códigos, etiquetas y productos EAS asignados. Las entregas históricas se conservan.
Consultar
GET /consumers— query:operationId,isActive,search(nombre, identificación o código),page,pageSize(máx. 1000).GET /consumers/summary— conteos de usuarios y códigos, activos e inactivos.GET /consumers/:id/entitlements— lo que ese usuario puede sacar hoy: útil para mostrar cupos en un portal propio.
Errores: 409 consumers.identification_exists, 404 consumers.not_found,
400 consumers.unknown_tag_key, 400 consumers.too_many_tags.
Códigos
POST /consumers/:id/codes
PATCH /consumers/:id/codes/:codeId
DELETE /consumers/:id/codes/:codeId
PATCH /consumers/:id/codes/:codeId/active
PUT /consumers/:id/codes/:codeId/profile
DELETE /consumers/:id/codes/:codeId/profile/:businessLine
Agregar un código — 201
| Campo | Tipo | Obligatorio | Notas |
|---|---|---|---|
codeId | string | sí | el valor que lee la máquina |
codeType | string | sí | QR, NFC, FINGERPRINT, CODE128, CODE39, PDF417, EAN13, UPCA, MAXICODE, MRZ |
operationId | string | no | omitir = código de cuenta: mismo valor, saldo y cupo en todas las operaciones |
vending.balance | entero | no | saldo inicial en unidades menores |
El código nace sin perfiles: sus líneas se definen asignándolos.
Asignar y quitar perfil
PUT /consumers/:id/codes/:codeId/profile { "profileId": "665f…d1" }
DELETE /consumers/:id/codes/:codeId/profile/vending
DELETE /consumers/:id/codes/:codeId/profile/eas
La línea sale del perfil: si el perfil es vending, ocupa la ranura vending. El perfil debe ser de la
cuenta del usuario (400 consumers.profile_not_for_this_account) y el código debe conservar al
menos un perfil (409 consumers.code_requires_profile).
Editar un código
PATCH /consumers/:id/codes/:codeId:
| Campo | Tipo | Notas |
|---|---|---|
newCodeId | string | cambia el valor; se revalida su unicidad |
codeType | string | cambiar desde FINGERPRINT borra las huellas |
vendingBalance | entero | fija el saldo de subsidio |
operationId | string | null | mueve de nivel; null = pasa a nivel cuenta. Conserva saldo y perfiles |
lineProfiles | objeto | fija los dos perfiles de una vez |
Conflictos de valor al mover de nivel: 409 consumers.code_value_taken_in_operation y
409 consumers.code_value_taken_at_account.
Estado y baja
PATCH …/activecon{ "active": false }→ deshabilita solo ese código.DELETE …→204. El histórico se conserva.
Huellas
GET /consumers/:consumerId/codes/:codeId/fingerprints
POST /consumers/:consumerId/codes/:codeId/fingerprints
DELETE /consumers/:consumerId/codes/:codeId/fingerprints/:fingerId
Solo en códigos FINGERPRINT. El POST espera el dedo y sus muestras ya capturadas por el lector:
| Campo | Tipo | Obligatorio | Notas |
|---|---|---|---|
fingerId | entero 0–9 | sí | qué dedo |
fingerLabel | string | no | Índice derecho |
fingerprints | objeto[] | sí | las muestras (template en base64) |
Errores: 422 consumers.no_fingerprint_template, 409 consumers.fingerprint_already_enrolled,
409 consumers.too_many_fingerprints, 400 consumers.code_not_fingerprint.
La API no captura huellas: recibe los templates que genera el agente local del lector. Sin ese agente no hay enrolamiento posible.
Cargas en lote
POST /consumers/bulk { "items": [ … ] }
POST /consumers/codes/bulk { "items": [ … ] }
Cada item lleva su campo op y los datos de esa operación:
| Endpoint | Valores de op |
|---|---|
/consumers/bulk | create, update, delete, upsert |
/consumers/codes/bulk | create, update, delete |
{
"items": [
{ "op": "create", "name": "Juan Pérez", "identification": "1023456789" },
{ "op": "update", "identification": "1010087922", "name": "Ana Ruiz" }
]
}
La respuesta es 201 con el resultado por fila: una fila inválida no aborta el lote.
{
"summary": { "created": 1, "updated": 1, "deleted": 0, "failed": 0 },
"results": [{ "index": 0, "op": "create", "status": "created", "id": "665f…e9" }]
}
Es el camino recomendado para sincronizar nóminas: una llamada en vez de N.
Como el lote es multi-op, no exige una acción concreta sino al menos una de create, update o
delete sobre el recurso (consumers para el primero, codes para el segundo). Sin ninguna, responde
403. Después, cada fila se autoriza por su propia operación: con solo create las filas update o
delete fallan individualmente y el resto del lote sigue.