Saltar al contenido principal

Recibir una venta, de punta a punta

Un pago con tarjeta en el mostrador son dos llamadas de dos actores distintos: tu backend lo pide, el terminal lo confirma. Entre las dos, el pago existe pero todavía no es dinero.

Esta guía asume que ya tienes token y un terminal vinculado.

1. Tu backend crea el pago

Cuando el cajero cierra la venta en tu sistema, tú creas el pago y le dices a qué terminal va:

curl -X POST https://dev.api.spuntodeventa.com/api/v1/merchants/MERCHANT-001/transactions \
-H "Authorization: Bearer <tu-token>" \
-H "Content-Type: application/json" \
-d '{
"orderId": "ORD-123456",
"amountReference": 10.50,
"currencyReference": "USD",
"allowAmountChange": false,
"clientIdentification": "V12345678",
"terminalSerial": "98202003219630"
}'
{
"title": "Operación Procesada",
"detail": "La transacción ha sido procesada...",
"data": {
"merchantId": "MERCHANT-001",
"orderId": "ORD-123456",
"status": "PENDING",
"createdAt": "2024-04-10T15:00:00Z"
}
}

El orderId lo pones tú: es tu número de venta, y es la llave con la que consultarás este pago el resto de su vida. allowAmountChange decide si el terminal puede confirmar por un monto distinto al pedido (propinas, ajustes de caja).

Nace en PENDING. Todavía no ha pasado ninguna tarjeta.

Una errata del contrato en este endpoint

El OpenAPI marca como obligatorios currency y serial, dos nombres que no existen entre las propiedades del esquema. Los campos reales son currencyReference y terminalSerial, que son los del ejemplo de arriba. Está reportado a SPIDI; mientras tanto, la referencia navegable mostrará los nombres equivocados en la lista de obligatorios.

2. El terminal ve que tiene trabajo

El POS pregunta por lo que le toca. Esta llamada ya no lleva tu token: va firmada con la llave del propio aparato.

GET /api/v1/pos-terminals/98202003219630/transactions?status=PENDING
x-pos-signature: <firma>
x-pos-timestamp: 2026-07-29T14:03:11Z

El filtro status=PENDING es tuyo: el servidor no filtra nada por su cuenta. Si no lo pides, te llegan todas.

3. El terminal cobra y confirma

El cajero pasa la tarjeta. Con la respuesta del banco en la mano, el POS confirma:

POST /api/v1/pos-terminals/98202003219630/transactions/ORD-123456/commit
x-pos-signature: <firma>
x-pos-timestamp: 2026-07-29T14:05:02Z
Content-Type: application/json

{
"authorizationCode": "171599",
"processCode": "002000",
"commitAt": "2024-04-10T15:05:00Z",
"amountReference": 10.50,
"terminalNumber": "T-123",
"trace": "000535",
"utcDate": "1007151715",
"cardTypeForRpt": "C",
"visOrMccCard": "MCC",
"batchNumber": "998877"
}

Obligatorios: authorizationCode, processCode, commitAt y amountReference. Los demás son los datos del recibo bancario, y los vas a querer guardar para el cuadre del día.

Aquí el pago pasa a PAID. Ahora sí es dinero.

Consultar en qué va

Desde tu backend, en cualquier momento:

curl https://dev.api.spuntodeventa.com/api/v1/merchants/MERCHANT-001/transactions/ORD-123456 \
-H "Authorization: Bearer <tu-token>"

El detalle que sorprende

Si anulas un pago antes de que el terminal confirme, la orden queda en CANCELED — pero el terminal puede estar ya con la tarjeta en la mano. Si su commit llega después, gana el commit: la orden pasa de CANCELED a PAID y la cancelación se pierde.

No es un fallo: el aparato ya movió dinero en el banco y el sistema no puede negarlo. Tenlo en cuenta si tu backend cancela por timeout — mira siempre el estado final, no el que tú pediste.

→ Siguiente: Anular y cerrar el día · Estados de un pago