POS vía chat, turnos, dispositivos y entregas
POS vía chat, turnos, dispositivos y entregas
Estado documental: Contrato propuesto. Las rutas, campos, límites y tiempos pasan a estado confirmado solo después de su implementación y verificación.
Objetivo: Inventariar turnos, dispositivos/terminales, entregas y configuración administrativa del POS vía chat manteniendo separadas la identidad de la Persona, la Cuenta WhatsApp/canal, el Counter y la Payment Order.
Regla de turno
Un turno
= una Persona identificada
+ un dispositivo o terminal operativo
+ un canal/contexto de atención
+ una ventana operativa
La Persona y la Cuenta WhatsApp son identidades diferentes. La Persona se identifica con sus propias credenciales; la Cuenta WhatsApp conserva su identidad y routing aunque cambie la persona que atiende. Un número operativo no identifica a una Persona.
No existe cambio de Persona dentro de un turno. Para otro vendedor se cierra el turno actual y se abre uno nuevo. El turno registra quién está operando y desde qué contexto operativo, sin convertir a la Cuenta WhatsApp en propietaria de la Payment Order ni del QR.
Turnos
| Audiencia | Método | Ruta propuesta | Uso | Idempotencia | Eventos o callbacks relacionados |
|---|---|---|---|---|---|
| Integración | POST |
/v1/shifts |
Abrir turno después de identificar a la Persona. | Obligatoria | shift.opened |
| Integración | GET |
/v1/shifts |
Listar turnos. | No | Ninguno |
| Integración | GET |
/v1/shifts/{shift_id} |
Consultar turno. | No | Ninguno |
| Integración | POST |
/v1/shifts/{shift_id}/close |
Cerrar turno. | Obligatoria | shift.closed |
| Integración | GET |
/v1/shifts/{shift_id}/payment-orders |
Consultar Payment Orders del turno. | No | Ninguno |
| Integración | GET |
/v1/shifts/{shift_id}/pending-cases |
Consultar pendientes del turno. | No | Ninguno |
| Integración | GET |
/v1/shifts/{shift_id}/summary |
Obtener resumen operativo. | No | Ninguno |
Ejemplo: abrir turno
POST /v1/shifts
Idempotency-Key: 1cf08e71-6484-4d08-b772-45573a4beec4
{
"username": "david",
"pin": "<PROTECTED_VALUE>",
"device_id": "dev_01JXYZ",
"channel": "whatsapp"
}
{
"shift_id": "shf_01JXYZ",
"person_id": "per_01JXYZ",
"device_id": "dev_01JXYZ",
"channel": "whatsapp",
"opened_at": "2026-08-09T08:00:00-05:00",
"maximum_duration_seconds": 28800,
"expiration_mode": "warning_and_renewal",
"status": "active",
"request_id": "req_01JXYZ"
}
username + PIN identifican a la Persona. El valor protegido nunca debe almacenarse en texto plano. El contexto de canal/routing —por ejemplo la Cuenta WhatsApp desde la que opera el turno— se resuelve y conserva de forma separada de person_id.
Crear una Payment Order para el turno
La Payment Order se crea mediante POST /v1/payment-orders. El caller expresa la intención de cobro y el contexto público necesario; no selecciona el QR concreto ni envía counter_id, QR ID, WhatsApp Account ID o Agencia.
{
"external_transaction_id": "TICKET-88412",
"amount": "80.00",
"currency": "PEN",
"payment_method": "qr",
"payment_instrument_type": "qr_bbva",
"requested_at": "2026-08-09T08:14:25-05:00",
"buyer": {
"first_name": "Carlos",
"last_name": "Vega"
},
"business_context": {
"shift_id": "shf_01JXYZ",
"device_id": "dev_01JXYZ"
}
}
El API Engine autentica, identifica al cliente, valida, aplica idempotencia y normaliza. El Adapter del origen resuelve el contexto interno y el Counter correspondiente. Mientras la Payment Order permanezca abierta, el Counter asignado es exclusivo para esa orden y se libera al llegar a un estado terminal.
En el flujo QR actual, payment_method = "qr" y payment_instrument_type = "qr_bbva". Yape y Plin son mecanismos que el pagador puede utilizar para pagar ese QR, no instrumentos concretos pares de qr_bbva.
Dispositivos y entregas
| Audiencia | Método | Ruta propuesta | Uso | Idempotencia | Eventos o callbacks relacionados |
|---|---|---|---|---|---|
| Integración | GET |
/v1/devices/{device_id} |
Consultar dispositivo/terminal autorizado. | No | Ninguno |
| Integración | GET |
/v1/devices/{device_id}/active-shift |
Consultar turno activo. | No | Ninguno |
| Integración | GET |
/v1/devices/{device_id}/inbox |
Consultar operaciones por entregar. | No | Ninguno |
| Integración | POST |
/v1/devices/{device_id}/inbox/{item_id}/acknowledge |
Confirmar recepción operacional. | Obligatoria | device.delivery_received |
| Integración | GET |
/v1/devices/{device_id}/pending-cases |
Consultar pendientes operativos. | No | Ninguno |
| Integración | POST |
/v1/payment-orders/{id}/deliveries |
Crear entrega de instrucciones de una Payment Order. | Obligatoria | delivery.queued |
| Integración | GET |
/v1/payment-orders/{id}/deliveries |
Listar entregas. | No | Ninguno |
| Integración | GET |
/v1/deliveries/{delivery_id} |
Consultar estado de entrega. | No | Ninguno |
| Integración | POST |
/v1/deliveries/{delivery_id}/retry |
Reintentar entrega fallida. | Obligatoria | delivery.queued |
| Integración | POST |
/v1/deliveries/{delivery_id}/cancel |
Cancelar antes del envío. | Obligatoria | delivery.cancelled |
Ejemplo: crear entrega
POST /v1/payment-orders/pay_01JXYZ/deliveries
{
"delivery_target": {
"type": "shift_device",
"shift_id": "shf_01JXYZ",
"device_id": "dev_01JXYZ"
},
"content_type": "payment_instructions"
}
{
"delivery_id": "dly_01JXYZ",
"payment_order_uid": "pay_01JXYZ",
"status": "queued",
"request_id": "req_01JXYZ"
}
delivery.queued y device.delivery_received describen el flujo operativo de entrega. No prueban por sí solos que la instrucción haya sido presentada efectivamente a la persona que cobra o al pagador. Cuando corresponda, la presentación efectiva se registra de forma separada mediante payment_instruction.presented, con datos como presented_at, delivery_channel, ack_type y external_reference.
Personas/usuarios administrativos
Las rutas administrativas de /v1/admin/users se conservan como nomenclatura propuesta de esta biblioteca, pero el recurso representa la identidad de la Persona/usuario operativo. No representa una Cuenta WhatsApp, un número telefónico ni un destino de routing.
| Audiencia | Método | Ruta propuesta | Uso | Idempotencia | Eventos o callbacks relacionados |
|---|---|---|---|---|---|
| Administración | POST |
/v1/admin/users |
Registrar Persona/usuario operativo. | Sí | user.created |
| Administración | GET |
/v1/admin/users |
Listar Personas/usuarios. | No | Ninguno |
| Administración | GET |
/v1/admin/users/{id} |
Consultar Persona/usuario. | No | Ninguno |
| Administración | PATCH |
/v1/admin/users/{id} |
Actualizar datos permitidos. | Sí | user.updated |
| Administración | POST |
/v1/admin/users/{id}/activate |
Activar Persona/usuario. | Sí | user.activated |
| Administración | POST |
/v1/admin/users/{id}/deactivate |
Desactivar Persona/usuario. | Sí | user.deactivated |
| Administración | POST |
/v1/admin/users/{id}/reset-credential |
Restablecer credencial de identificación. | Sí | security.user_credential_reset |
| Administración | GET |
/v1/admin/users/{id}/history |
Consultar auditoría. | No | Ninguno |
Dispositivos administrativos
| Audiencia | Método | Ruta propuesta | Uso | Idempotencia | Eventos o callbacks relacionados |
|---|---|---|---|---|---|
| Administración | POST |
/v1/admin/devices |
Registrar dispositivo/terminal. | Sí | device.created |
| Administración | GET |
/v1/admin/devices |
Listar dispositivos/terminales. | No | Ninguno |
| Administración | GET |
/v1/admin/devices/{id} |
Consultar dispositivo/terminal. | No | Ninguno |
| Administración | PATCH |
/v1/admin/devices/{id} |
Actualizar configuración. | Sí | device.updated |
| Administración | POST |
/v1/admin/devices/{id}/activate |
Activar. | Sí | device.activated |
| Administración | POST |
/v1/admin/devices/{id}/deactivate |
Desactivar. | Sí | device.deactivated |
| Administración | POST |
/v1/admin/devices/{id}/pair |
Vincular canal o terminal. | Sí | device.paired |
| Administración | POST |
/v1/admin/devices/{id}/unpair |
Desvincular. | Sí | device.unpaired |
| Administración | POST |
/v1/admin/devices/{id}/assign-supervisor |
Asignar supervisor. | Sí | device.supervisor_assigned |
| Administración | GET |
/v1/admin/devices/{id}/history |
Consultar auditoría. | No | Ninguno |
Política de turnos y alertas
| Audiencia | Método | Ruta propuesta | Uso | Idempotencia | Eventos o callbacks relacionados |
|---|---|---|---|---|---|
| Administración | GET |
/v1/admin/shift-policy |
Consultar duración y modalidad. | No | Ninguno |
| Administración | PATCH |
/v1/admin/shift-policy |
Configurar política de turnos. | Sí | shift_policy.updated |
| Administración | POST |
/v1/admin/shift-policy/test |
Probar política. | Sí | Ninguno |
| Administración | POST |
/v1/admin/alert-rules |
Crear regla de alerta. | Sí | alert_rule.created |
| Administración | GET |
/v1/admin/alert-rules |
Listar reglas. | No | Ninguno |
| Administración | GET |
/v1/admin/alert-rules/{id} |
Consultar regla. | No | Ninguno |
| Administración | PATCH |
/v1/admin/alert-rules/{id} |
Modificar regla. | Sí | alert_rule.updated |
| Administración | DELETE |
/v1/admin/alert-rules/{id} |
Desactivar regla. | Sí | alert_rule.deactivated |
| Administración | POST |
/v1/admin/alert-rules/{id}/test |
Enviar alerta de prueba. | Sí | alert.test_sent |
| Administración | GET |
/v1/admin/alerts |
Consultar historial. | No | Ninguno |
| Administración | POST |
/v1/admin/alerts/{id}/acknowledge |
Registrar atención. | Sí | alert.acknowledged |
Ejemplo: política de turnos
PATCH /v1/admin/shift-policy
{
"maximum_duration_seconds": 28800,
"expiration_mode": "warning_and_renewal",
"warning_after_each_transaction": true,
"auto_close": false
}
Ejemplo: regla de alerta
{
"event_types": [
"payment.late_detected",
"payment.amount_difference"
],
"recipients": [
{
"type": "seller"
},
{
"type": "supervisor"
}
],
"channels": [
"whatsapp",
"email"
],
"active": true
}
Errores principales
| HTTP | Código | Descripción |
|---|---|---|
| 404 | shift_not_available |
Turno inexistente o no disponible. |
| 409 | shift_closed |
El turno ya fue cerrado. |
| 409 | shift_device_mismatch |
Dispositivo distinto al del turno. |
| 403 | user_not_authorized |
Persona/usuario sin autorización. |
| 404 | device_not_available |
Dispositivo no disponible. |
| 404 | delivery_not_found |
Entrega inexistente. |
| 409 | delivery_retry_not_allowed |
La entrega no puede reintentarse. |
Changelog — Payment Order / API Engine
2026-08-09 — Payment Order / API Engine v1.0: se separaron explícitamente Persona, Cuenta WhatsApp/canal, dispositivo/terminal y Counter; el ejemplo de turno pasó de la identidad genérica user_id + PIN a identificación de Persona mediante username + PIN y respuesta con person_id; se retiró integration_experience de la creación activa de Payment Order; se incorporaron payment_method, payment_instrument_type, qr_bbva, requested_at y business_context; las entregas usan payment_order_uid/pay_... en lugar del identificador histórico ypt_...; se documentó que el Adapter resuelve internamente el Counter y que el caller no envía IDs internos de QR/WhatsApp/Agencia; y se separó la entrega/recepción operacional de payment_instruction.presented.