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.
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