Cierre de turno
Identificador del evento: shift.closed
En pocas palabras
Sección titulada «En pocas palabras»IDPOS le avisa de que una caja cerró su turno. El aviso trae el resumen de lo cobrado en ese turno: la cantidad de ventas y el total por medio de pago y moneda.
Cuándo llega
Sección titulada «Cuándo llega»Cuando se cierra el turno de una caja. Llega una vez por cada cierre.
Para qué le sirve
Sección titulada «Para qué le sirve»- Registrar el cierre de caja en su sistema, con su número de turno y sus totales.
- Cuadrar lo cobrado por medio de pago y moneda contra lo que registró de cada venta.
- Detectar ventas que no le llegaron: si los totales no coinciden, falta al menos un Pago completo de esa caja.
- Identificar el cierre con el mismo número que figura en el ticket de cierre de la caja (
correlative).
Qué hacer al recibirlo
Sección titulada «Qué hacer al recibirlo»-
Verifique la firma.
Calcule el HMAC con el cuerpo crudo y compárelo con
X-Webhook-Signature. Si no coincide, no procese el evento. Los pasos están en Autenticación y firma. -
Responda
2xxde inmediato.Guarde el evento en una cola y responda sin esperar a procesarlo. Si tarda más que el tiempo de espera, IDPOS lo trata como fallido y lo reintenta.
-
Descarte los duplicados.
Si ya procesó ese
event_iddel cuerpo, ya verificado, no lo procese otra vez. Como segunda clave useevent_typejunto condata.id(por ejemplo, shift.closed y el id del turno). -
Procese el evento en segundo plano.
Registre el cierre con
data.idycorrelative. Comparesummarycon las ventas que registró de la misma caja (cashier.id) entreopens_atycloses_at.
Cómo cuadrar el turno con las ventas
Sección titulada «Cómo cuadrar el turno con las ventas»IDPOS calcula el resumen con la misma consulta que usa el cierre de caja en el punto de venta, por lo que los totales coinciden con el reporte de cierre que se imprime.
| En Cierre de turno | Con qué compararlo en Pago completo |
|---|---|
cashier.id | data.cashier.id |
Turno entre opens_at y closes_at | payments[].paid_at dentro de ese rango, con ambos extremos incluidos |
summary.payments[], por method_id y currency | Suma de payments[].amount por method_id |
summary.payments[].tip | Suma de payments[].tip por method_id |
summary.sales_count | Cantidad de órdenes distintas |
Una diferencia no siempre es una venta perdida:
- Los pagos de adelantos no generan Pago completo y no se incluyen en el resumen.
- Una orden pagada en partes en distintos turnos suma en cada turno lo que se cobró en él, pero envía Pago completo una sola vez, cuando se termina de pagar.
summary.payments[].amountes el monto neto del vuelto entregado, en la moneda en que se recibió el pago. Un cobro con vuelto o en una moneda distinta a la de la orden puede no coincidir conpayments[].amountde Pago completo.data.cashierde Pago completo es la caja donde se registró la orden. Si se cobró en otra caja, el cobro suma en el turno de la caja que cobró.
Ejemplo
Sección titulada «Ejemplo»{ "event_id": "01J9ZM8T2W5K7Q3N6R1D4F0G8H", "event_type": "shift.closed", "timestamp": "2026-10-12T23:05:00Z", "api_version": "v1", "data": { "id": "7b9d1f3a-5c7e-4a2b-8d4f-6e8a0c2b4d71", "correlative": 128, "store": { "id": "6a8c0e2f-5b7d-4d9b-9e3a-4f6b8d0c2e53", "name": "Tienda Centro", "external_id": "T01" }, "cashier": { "id": "9d2f4b6c-8e0a-4c3b-9d5f-7a1b3c5e7f82", "name": "Caja 1" }, "opens_at": "2026-10-12T13:00:00Z", "closes_at": "2026-10-12T23:04:58Z", "closed_by": { "id": "8c1e3a5b-7d9f-4b2a-8c4e-6f0a2b4d6e71", "name": "Ana Torres" }, "summary": { "sales_count": 42, "payments": [ { "method_id": "2a4c6e8b-0d2f-4b6a-9c1e-3f5a7b9d1c04", "method_name": "Efectivo", "currency": "PEN", "amount": "1250.40", "tip": "15.00" }, { "method_id": "1b3d5f7a-9c2e-4d6b-8f1a-3c5e7a9b2d93", "method_name": "Visa", "currency": "PEN", "amount": "2380.00", "tip": "95.50" }, { "method_id": "2a4c6e8b-0d2f-4b6a-9c1e-3f5a7b9d1c04", "method_name": "Efectivo", "currency": "USD", "amount": "60.00", "tip": "0.00" } ] } }}Cómo leer las tablas: el tipo aparece debajo del nombre del campo y «nulo» indica que puede venir como null. Los demás términos están en la guía de lectura de campos.
| Campo | Descripción |
|---|---|
idstring (UUID) | Identificador del turno |
correlativeentero · nulo | Número del turno. Es único por caja y es el que se imprime en el ticket de cierre |
opens_atstring (fecha) | Fecha y hora de apertura del turno |
closes_atstring (fecha) | Fecha y hora de cierre del turno |
Tienda (store)
Sección titulada «Tienda (store)»| Campo | Descripción |
|---|---|
storeobjeto | Tienda |
store.idstring (UUID) · nulo | Identificador de la tienda |
store.namestring · nulo | Nombre de la tienda |
store.external_idstring · nulo | Código externo de la tienda |
Caja (cashier)
Sección titulada «Caja (cashier)»| Campo | Descripción |
|---|---|
cashierobjeto | Caja que cerró el turno |
cashier.idstring (UUID) · nulo | Identificador de la caja. Usa el mismo identificador que cashier.id de Pago completo |
cashier.namestring · nulo | Nombre de la caja |
Usuario que cerró (closed_by)
Sección titulada «Usuario que cerró (closed_by)»| Campo | Descripción |
|---|---|
closed_byobjeto · nulo | Usuario que cerró el turno. Es null si no se registró quién lo cerró o si ese usuario fue eliminado |
closed_by.idstring (UUID) | Identificador del usuario |
closed_by.namestring | Nombre del usuario |
Resumen (summary)
Sección titulada «Resumen (summary)»| Campo | Descripción |
|---|---|
summary.sales_countentero | Cantidad de órdenes distintas con al menos un pago aprobado de la caja entre opens_at y closes_at, ambos incluidos. No cuenta adelantos |
summary.paymentslista | Total cobrado, con una fila por medio de pago y moneda. Vacía si no hubo cobros. Las filas vienen ordenadas por currency, luego por method_name y luego por method_id |
summary.payments[].method_idstring (UUID) | Identificador del medio de pago. Es el mismo method_id que llega en Pago completo |
summary.payments[].method_namestring | Nombre del medio de pago |
summary.payments[].currencystring | Moneda en que se recibió el pago, por ejemplo PEN o USD |
summary.payments[].amountstring (2 dec) | Monto cobrado neto del vuelto entregado: monto recibido menos vuelto, igual que en el reporte de cierre de caja. Puede ser negativo. No incluye propinas ni adelantos |
summary.payments[].tipstring (2 dec) | Propinas de ese medio de pago y moneda |