Cuenta de cliente: saldo y puntos de fidelidad¶
Cada cliente (api/v1/customers) mantiene dos cuentas separadas y permanentes:
- Saldo prepago (
accountBalance) — saldo en dinero real que el cliente ingresa por adelantado y luego utiliza como medio de pago en sus compras. Se puede pagar (retirar). - Puntos de fidelidad / bono (
loyaltyPoints/bonusBalance) — puntos/bono que se abonan y se canjean en las compras. No se pueden pagar (el bono caduca al realizar una retirada de saldo).
Esta página corrige una indicación incorrecta anterior en el Resumen de la API REST: no
existe POST /customers/{id}/credit ni GET /customers/{id}/transactions — estas rutas no existen
en el código. Las rutas reales se documentan a continuación.
Endpoints¶
CustomersController — base api/v1/customers:
| Método | Endpoint | Descripción |
|---|---|---|
GET |
/{id}/account-transactions |
Movimientos de saldo/cuenta (libro prepago) |
GET |
/{id}/point-transactions |
Movimientos de puntos de fidelidad |
POST |
/{id}/payout |
Pagar el saldo restante (solo accountBalance, no el bono) |
POST |
/{id}/settle |
Compensar un saldo pendiente (p. ej. un pagaré del Disco) mediante un ingreso |
GET |
/card/{cardId} |
Resolver el cliente a partir de la tarjeta de cliente |
GET |
/{id}/invoice-summary |
Resumen de facturas/suscripciones del cliente |
Ambos endpoints de transacciones aceptan opcionalmente dateFrom/dateTo como parámetros de
consulta para acotar el periodo.
Movimientos de cuenta (account-transactions)¶
GET /api/v1/customers/cus_a1b2c3/account-transactions?dateFrom=2026-07-01&dateTo=2026-07-31
Authorization: Bearer eyJ...
{
"success": true,
"data": [
{
"id": "cat_001",
"customerId": "cus_a1b2c3",
"customerName": "Max Mustermann",
"receiptId": "rec_9f8e7d",
"type": 0,
"amount": 50.00,
"balanceAfter": 50.00,
"bonusBalanceAfter": 2.50,
"description": "Guthaben-Aufladung: Guthaben 50€ x 1",
"personalId": "usr_kasse1",
"transactionDate": "2026-07-05T18:22:00Z"
}
]
}
type es un int sin un esquema de enum público propio; valores observados en la práctica: 0
recarga/ingreso, 1 uso (pago con saldo), 2 corrección (rectificación manual de anulación), 3
abono de bono, 4 uso/caducidad de bono, 5 pago (retirada).
Movimientos de puntos (point-transactions)¶
{
"success": true,
"data": [
{
"id": "cpt_001",
"customerId": "cus_a1b2c3",
"customerName": "Max Mustermann",
"receiptId": "rec_9f8e7d",
"articleId": "art_cola",
"articleName": "Cola 0,3l",
"type": 0,
"points": 3.5,
"pointsAfter": 42.5,
"description": "Punkte für Verkauf",
"transactionDate": "2026-07-05T18:22:00Z"
}
]
}
type: 0 = abonado (Earned), 1 = canjeado (Redeemed), 2 = corrección (Correction).
Pagar (payout)¶
Paga saldo del accountBalance (no del bono — este caduca en el proceso).
POST /api/v1/customers/cus_a1b2c3/payout
Authorization: Bearer eyJ...
Content-Type: application/json
{ "amount": 20.00 }
Caso de error (saldo insuficiente) — 400 con errorCode: "INSUFFICIENT_BALANCE".
Compensar saldo (settle)¶
Para un saldo pendiente (negativo) — p. ej. un pagaré del Disco (importe restante no cubierto al salir, véase API de Disco) — el cliente realiza un ingreso y el saldo se acerca a cero:
POST /api/v1/customers/cus_a1b2c3/settle
Authorization: Bearer eyJ...
Content-Type: application/json
{ "amount": 15.00, "method": "EC" }
method es libre (por defecto "Bar") y solo se refleja en la descripción del movimiento — sin
vinculación a un terminal de pago.
Recargar saldo — la vía real¶
No existe un endpoint /credit propio. En su lugar, un saldo prepago se recarga exactamente igual
que cualquier otra venta: a través de los endpoints de pago normales (POST /api/v1/payments/direct
o POST /api/v1/payments/table), con dos condiciones:
- El artículo vendido tiene
extraOption: 1(KundenAufladung) — un «artículo de recarga» (p. ej. «Saldo 50 €»), creado mediante la API de artículos normal (POST /api/v1/articles). - El pago está vinculado al cliente mediante
customerId.
El precio del artículo (× cantidad) se abona entonces automáticamente al accountBalance del
cliente — además de la propia gestión del pago (el invitado paga el importe de recarga con total
normalidad mediante payments[], p. ej. en efectivo o con tarjeta). Si en el artículo hay
configurado un bono de recarga (cardUploadPercent/cardUploadAmount), se abona automáticamente
también un bono adicional.
POST /api/v1/payments/direct
Authorization: Bearer eyJ...
Idempotency-Key: 6f1c2a9e-3b7d-4e21-9b0a-1f2e3d4c5b6a
Content-Type: application/json
{
"items": [ { "articleId": "art_aufladung50", "quantity": 1 } ],
"payments": [ { "method": "Cash", "amount": 50.00 } ],
"customerId": "cus_a1b2c3"
}
La recarga aparece después como una entrada type: 0 en account-transactions (véase arriba),
vinculada mediante receiptId con el recibo de caja generado.
Flujo¶
- Crear cliente —
POST /api/v1/customers(mínimo:name/customerNumber). - Recargar saldo — venta de un artículo
KundenAufladungconcustomerId(POST /api/v1/payments/direct, véase arriba). - Cargar en la cuenta — las compras posteriores del cliente con
payments[].method = "CustomerAccount"se deducen delaccountBalance(se debita, no se recarga). - Control —
GET /{id}/account-transactionspermite comprobar el historial. - Puntos — se abonan/canjean en el proceso de venta normal, consultables mediante
GET /{id}/point-transactions. - Pagar/Compensar —
POST /{id}/payout(devolver el saldo restante) oPOST /{id}/settle(liquidar un saldo pendiente/pagaré).
Diferencia: saldo de cuenta de cliente frente a saldo de tarjeta Disco¶
Dos conceptos distintos que se confunden fácilmente:
| Saldo de cuenta de cliente | Saldo de tarjeta Disco | |
|---|---|---|
| Endpoint | payments/* + customers/* |
POST /api/v1/disco/guest/{cardId}/topup |
| Vinculación | al registro del cliente, permanente | a la tarjeta física, para una estancia |
| Pago | POST /{id}/payout |
saldo restante en el checkout (disco/guest/{cardId}/checkout) |
→ Detalles sobre la variante de tarjeta: API de Disco (club sin efectivo).