Referencia de endpoints REST en JSON. Contratos de request y response.
Todos los endpoints usan POST salvo GET /health. Respuestas en JSON.
{ "error": "mensaje en minúsculas" }{ "mensaje": "..." }{
"status": "ok",
"service": "pzcollector-api",
"version": "2.x.x"
}Endpoints protegidos requieren credencial en body.key o header x-api-key (valor entregado por canal interno).
Exentos: GET /health, POST /auth/login y rutas /api/obtener_productos* (solo envían dispositivo).
{
"correo": "usuario@ejemplo.com",
"password": "tu_password"
}{
"token": "eyJhbGciOiJIUzI1NiIs...",
"usuario": {
"id": 1,
"nombre": "Nombre Apellido",
"correo": "usuario@ejemplo.com"
}
}Rutas bajo /api/. Body: solo dispositivo (ID del equipo).
{
"dispositivo": "98e9f34eb33cf873"
}{
"productos": [
{
"id": 12,
"identificador": "QWERTYUIOP",
"nombre": "casa madero",
"clave": "7503002087718",
"costo": 20
}
]
}{
"dispositivo": "98e9f34eb33cf873"
}{
"productos": [
{
"id": 12,
"identificador": "QWERTYUIOP",
"nombre": "casa madero",
"clave": "7503002087718",
"claves_alternas": "7503002087718",
"costo": 20
}
]
}{
"dispositivo": "98e9f34eb33cf873",
"productos": [
{
"identificador": "QWERTYUIOP",
"nombre": "Producto ejemplo",
"clave": "987654321123",
"claves_alternas": "987654321123|987654321124",
"costo": 10
}
]
}id solo al actualizar. claves_alternas separadas por |. eliminar: true + id para borrar.
{
"mensaje": "sincronización de productos terminada correctamente",
"resultados": []
}{
"dispositivo": "98e9f34eb33cf873"
}{
"validado": true,
"mensaje": "dispositivo validado y activo"
}{
"dispositivo": "98e9f34eb33cf873"
}{
"usuario": {
"id": 1,
"nombre": "Nombre Apellido",
"correo": "correo@ejemplo.com",
"telefono": "+523331234567"
},
"sucursal": {
"id": 1,
"nombre": "Sucursal Centro",
"foto": "",
"portada": ""
},
"productos": [
{
"id": 1,
"clave": "7503002087718",
"nombre": "Producto ejemplo",
"precio": 100,
"existencias": 5
}
]
}{
"dispositivo": "98e9f34eb33cf873"
}{
"mensaje": "dispositivo activado correctamente"
}obtener: dispositivo obligatorio; id opcional (un registro). Sin id devuelve lista plural; con id devuelve clave singular.
{
"dispositivo": "98e9f34eb33cf873",
"id": 19
}{
"inventarios": [
{
"id": 19,
"identificador": "QWERTYUIOP",
"fecha": "2023-01-30",
"costo total": 355,
"productos": 55,
"conceptos": [
{
"id": 19,
"identificador": "QWERTYUIOP",
"clave": "7501011126244",
"nombre": "producto 1",
"costo": 25,
"cantidad": 7
}
]
}
]
}Con id la clave es inventario (array). Misma forma en cada ítem.
{
"dispositivo": "98e9f34eb33cf873",
"id": 19
}{
"pickings": []
}Con id → picking.
{
"dispositivo": "98e9f34eb33cf873",
"id": 19
}{
"rompefilas": []
}Con id → rompefila.
{
"dispositivo": "98e9f34eb33cf873",
"factura": 123,
"total": 100,
"productos": 3,
"detalles": [
{
"claveUnidad": "7503002087718",
"valorUnitario": 10,
"cantidad": 1
}
]
}{
"mensaje": "inventario guardado correctamente"
}Mismo body y respuesta que /inventarios/guardar (mensaje: picking guardado).
Mismo body que inventarios/guardar (mensaje: rompefila guardado).
Formato: idproducto_cantidad#idproducto_cantidad#...
#_Ejemplo: 230_20.50#235_10#240_5#2300_2000#2500_55#
Todas las respuestas de error usan un solo campo error (string en minúsculas). No se expone statusCode ni stack traces.
{
"error": "no se encontro el dispositivo"
}{
"error": "envia la key"
}{
"error": "tabla de base de datos no encontrada — ejecuta migration.sql o import-mysql-dump.mjs"
}