Pagos POS (Terminal Fisico)
Los pagos POS permiten enviar un cobro directamente a un terminal fisico (TPV) conectado. El flujo es sincrono: la respuesta llega cuando el terminal procesa el pago (o expira por timeout).
Listar terminales
Antes de enviar un pago POS, necesitas conocer el identificador del terminal (poiId).
Live: GET https://aviratopayments.com/external/v1/pos/terminals?webcode={webcode}
Test: GET https://aviratopayments.com/external/v1/test/pos/terminals?webcode={webcode}Parametros de query
| Parametro | Tipo | Requerido | Descripcion |
|---|---|---|---|
webcode | string | Si | Identificador de tu negocio |
syncFromProvider | boolean | No | true para forzar sincronizacion con el proveedor. Por defecto: false |
Ejemplo
curl -X GET "https://aviratopayments.com/external/v1/pos/terminals?webcode=SHOP01" \
-H "X-API-KEY: tu_api_key_live"Respuesta (200)
{
"success": true,
"data": [
{
"poiId": "V400m-123456789",
"status": "boarded",
"name": "Mostrador Principal",
"model": "V400m",
"createdAt": "2026-01-15T10:00:00Z",
"updatedAt": "2026-06-20T08:30:00Z"
}
]
}Solo se devuelven terminales con estado boarded (activos y operativos).
- Con
syncFromProvider=false(por defecto): devuelve todos los terminales registrados comoboarded. - Con
syncFromProvider=true: solo devuelve los terminales que ademas estan actualmente conectados (online). Util para saber que terminales estan operativos en tiempo real.
Entorno Test: Se devuelven 3 terminales simulados, todos con estado
boarded: | poiId | Nombre | Modelo | Conectividad | |-------|--------|--------|-------------| |V400m-TEST-000001| Terminal Test 1 - Mostrador | V400m | Online | |S1F2-TEST-000002| Terminal Test 2 - Terraza | S1F2 | Online | |P400Plus-TEST-000003| Terminal Test 3 - Almacen | P400Plus | Offline | ConsyncFromProvider=true, solo se devuelven los 2 terminales online. ConsyncFromProvider=false, se devuelven los 3. El terminal offline (P400Plus-TEST-000003) permite probar el manejo del errorDeviceError(502, code 13004) al intentar cobrar en un terminal no conectado. Solo se aceptan lospoiIdde esta lista para enviar pagos POS en Test. Usar unpoiIdno listado devolvera error 400.
---
Crear pago POS
Envia un cobro a un terminal fisico. La peticion espera a que el terminal procese el pago.
Live: POST https://aviratopayments.com/external/v1/pos/payment
Test: POST https://aviratopayments.com/external/v1/test/pos/paymentParametros del body
| Campo | Tipo | Requerido | Descripcion |
|---|---|---|---|
webcode | string | Si | Identificador de tu negocio |
poiId | string | Si | Identificador del terminal (obtenido de /pos/terminals) |
amount.value | integer | Si | Importe en centimos |
amount.currency | string | Si | Codigo ISO 4217. Valores aceptados: EUR, GBP, USD |
description | string | No | Descripcion del cobro. Max 255 caracteres |
customReference | string | No | Tu referencia interna. Max 100 caracteres |
isPreAuth | boolean | No | true para preautorizacion. Por defecto: false |
Ejemplo (Live)
curl -X POST https://aviratopayments.com/external/v1/pos/payment \
-H "X-API-KEY: tu_api_key_live" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: pos-sale-67890" \
-d '{
"webcode": "SHOP01",
"poiId": "V400m-123456789",
"amount": {
"value": 5000,
"currency": "EUR"
},
"description": "Venta mostrador #205",
"customReference": "VENTA-205-20260628"
}'Respuesta exitosa (200)
{
"success": true,
"data": {
"posPaymentId": "SHOP01-POSX-1719500000",
"paymentReference": "SHOP01-POSX-1719500000",
"poiId": "V400m-123456789",
"amount": {
"value": 5000,
"currency": "EUR"
},
"status": "success",
"isPreAuth": false,
"pspReference": "KVGQSN3K2SKFNVNS",
"description": "Venta mostrador #205",
"customReference": "VENTA-205-20260628",
"createdAt": "2026-06-28 14:15:00"
}
}Formato de
posPaymentId: En Live el formato es{webcode}-POSX-{timestamp}. En Test el formato es{webcode}-POSXT-{timestamp}.
Timeout recomendado: Configura un timeout de al menos 240 segundos tanto en tu cliente HTTP como en tu servidor (por ejemplo,
max_execution_timeen PHP,proxy_read_timeouten Nginx, o el equivalente en tu stack). La peticion espera a que el cliente interactue con el terminal (insertar tarjeta, introducir PIN, etc.), lo cual puede tardar. Si tu servidor corta la conexion antes de recibir la respuesta, no recibiras el resultado directo — aunque el pago puede completarse igualmente en segundo plano.
Estados del pago POS
| Estado | Descripcion |
|---|---|
pending | Pago enviado al terminal, esperando resultado |
success | Pago completado con exito |
failed | El pago ha fallado (rechazado, error del terminal) |
timeout | El terminal no respondio a tiempo |
Manejo de timeouts
Si el terminal no responde dentro del tiempo limite, la respuesta tendra status: "timeout". En este caso:
- No reintentes inmediatamente: el pago podria estar en proceso
- Usa
Idempotency-Key: si reenvias la peticion con la misma key, recibiras la respuesta almacenada - Consulta el estado: usa
GET /pos/paymentspara verificar si el pago llego a completarse - El webhook llega igualmente: Si el pago se completa despues del timeout, recibiras un webhook de confirmacion (
AUTHORISATION) con el resultado final. Implementa webhooks como red de seguridad para no perder pagos completados que no pudiste capturar en la respuesta sincrona.
Errores especificos de POS
| Codigo | HTTP | Causa |
|---|---|---|
| 13005 | 409 | Terminal ocupado (DeviceBusy): hay otro pago en proceso |
| 13004 | 502 | Error del terminal (DeviceError): problema de comunicacion |
| 12001 | 400 | Parametros invalidos (falta poiId, amount incorrecto, etc.) |
Todos los errores de POS siguen el formato estandar de error:
{
"success": false,
"error": {
"message": "Terminal is busy processing another payment",
"code": 13005,
"statusCode": 409,
"traceId": "abc123def456..."
}
}---
Simulacion POS en entorno Test
En el entorno Test, los pagos POS no se envian a un terminal real. El sistema valida el poiId contra la lista de terminales simulados y determina el resultado:
Terminales simulados
Solo se aceptan los poiId devueltos por GET /test/pos/terminals. Si envias un poiId que no esta en la lista, recibiras error 400.
Si envias un pago al terminal offline (P400Plus-TEST-000003), se simula el error real que devuelve el procesador cuando un terminal no esta conectado:
{
"success": false,
"error": {
"message": "Error in POS payment response: Reject",
"code": 13004,
"statusCode": 502,
"traceId": "..."
}
}Para los terminales online (V400m-TEST-000001, S1F2-TEST-000002), el resultado se determina por los ultimos dos digitos del importe (amount.value):
Magic amounts (ultimos 2 digitos del importe)
| Terminacion | Resultado | Descripcion |
|---|---|---|
77 | failed | Pago rechazado (tarjeta declinada) |
99 | timeout | Timeout del terminal |
55 | Error 409 | Terminal ocupado |
| Cualquier otra | success | Pago exitoso |
Ejemplos
Importe (amount.value) | Ultimos 2 digitos | Resultado |
|---|---|---|
5000 (50.00 EUR) | 00 | Exito |
10077 (100.77 EUR) | 77 | Rechazado |
2599 (25.99 EUR) | 99 | Timeout |
1055 (10.55 EUR) | 55 | Terminal ocupado (error 409) |
15001 (150.01 EUR) | 01 | Exito |
Importante: En Test, la respuesta incluye un pequeno delay simulado (2-3 segundos) para emular el tiempo de comunicacion con el terminal.
Webhooks en Test: Cuando un pago POS se completa (exito o fallo) en entorno Test, se genera automaticamente un webhook simulado que se envia a tu URL de webhook, igual que ocurriria en Live cuando el procesador confirma la operacion.
---
Listar pagos POS
Consulta el historial de pagos POS con filtros y paginacion basada en cursor.
Live: GET https://aviratopayments.com/external/v1/pos/payments?webcode={webcode}
Test: GET https://aviratopayments.com/external/v1/test/pos/payments?webcode={webcode}Parametros de query
| Parametro | Tipo | Requerido | Descripcion |
|---|---|---|---|
webcode | string | Si | Identificador de tu negocio |
status | string | No | Filtrar por estado: pending, success, failed, timeout |
created_at_start | string | No | Fecha inicio (filtro) |
created_at_end | string | No | Fecha fin (filtro) |
cursor | string | No | Cursor de paginacion (obtenido de la respuesta anterior) |
take | integer | No | Numero de resultados por pagina (1-100, por defecto: 20) |
order | string | No | Orden de resultados: asc o desc (por defecto: asc) |
Ejemplo
curl -X GET "https://aviratopayments.com/external/v1/pos/payments?webcode=SHOP01&status=success&take=10" \
-H "X-API-KEY: tu_api_key_live"Respuesta (200)
{
"success": true,
"data": {
"posPayments": [
{
"posPaymentId": "SHOP01-POSX-1719500000",
"paymentReference": "SHOP01-POSX-1719500000",
"poiId": "V400m-123456789",
"amount": { "value": 5000, "currency": "EUR" },
"status": "success",
"isPreAuth": false,
"pspReference": "KVGQSN3K2SKFNVNS",
"description": "Venta mostrador #205",
"customReference": "VENTA-205-20260628",
"createdAt": "2026-06-28 14:15:00"
}
],
"meta": {
"cursor": "eyJpZCI6NDJ9",
"hasMore": true,
"total": 156
}
}
}Paginacion
La paginacion usa cursores en lugar de numeros de pagina:
- La primera peticion se hace sin
cursor - Si
meta.hasMoreestrue, usa el valor demeta.cursorcomo parametrocursoren la siguiente peticion - Repite hasta que
meta.hasMoreseafalse
# Pagina 1
curl ".../pos/payments?webcode=SHOP01&take=20"
# Pagina 2 (usando el cursor de la respuesta anterior)
curl ".../pos/payments?webcode=SHOP01&take=20&cursor=eyJpZCI6NDJ9"---
Diferencias entre pagos online y POS
| Aspecto | Online | POS |
|---|---|---|
| Flujo | Asincrono (crear sesion + redirect cliente) | Sincrono (respuesta inmediata del terminal) |
| Quien paga | Cliente en su navegador | Cliente en el terminal fisico |
| Referencia | sessionId (formato {webcode}-EXT-{ts}) | posPaymentId (formato {webcode}-POSX-{ts}) |
| Redirect | Si (urlOk / urlKo) | No |
| Timeout | Sesion expira en la pagina de pago | Terminal no responde (status timeout) |
| Modificaciones | Refund, capture, cancel, extend | Refund, capture, cancel, extend (mismos endpoints) |
| Test | Tarjetas ficticias (holderName) | Magic amounts (ultimos 2 digitos) |