Changelog debug

Cambios del API /api/v1 para front-end, mobile e integradores.

← Volver al índice
cliente conductor admin

2026-08-27 — Promociones por hito

Para el front-end y mobile del cliente y del conductor, y el panel admin.

Summary

Agüita ya puede correr promociones de enganche sin esperar un despliegue. El admin crea una campaña —a quién premia, en qué entrega, cuánto, desde cuándo, en qué ciudad y a cuánta gente como máximo— y al completarse la entrega que alcanza el hito el beneficio se otorga solo.

Al cliente se le otorga crédito, que se descuenta automáticamente al crear su próximo pedido — no hay que activarlo ni elegirlo. Al conductor se le acredita dinero real en su billetera, que sale en su próxima liquidación como una línea de ajuste.

Todo es aditivo: mientras no haya campañas activas nada cambia. Un pedido sin crédito trae promo_credit_usd: 0 y client_charged_usd igual a client_pays_usd.

New

Método Endpoint Rol Para qué sirve
GET /credit/me cliente Ver su crédito promocional disponible.
GET /credit/me/transactions cliente Historial de movimientos de su crédito.
GET /admin/promotions admin principal Listar campañas.
POST /admin/promotions admin principal Crear una campaña.
GET /admin/promotions/{promotionId} admin principal Ver una campaña.
PATCH /admin/promotions/{promotionId} admin principal Editar una campaña.
DELETE /admin/promotions/{promotionId} admin principal Eliminar una campaña.
GET /admin/promotions/{promotionId}/grants admin principal Ver quiénes la recibieron.
POST /admin/customers/{customerId}/credit/adjust admin Acreditar o debitar crédito a mano.
GET /admin/customers/{customerId}/credit/transactions admin Historial de crédito de un cliente.

Cómo se configura una campaña

milestone_orders cuenta entregas completadas, de cualquier tipo: un pedido a domicilio y un remate suman igual. El beneficio se otorga al cerrar esa entrega, así que el crédito se usa desde el pedido siguiente. Para "en tu 3er viaje tienes $10", se configura milestone_orders: 2.

audience decide a quién premia. Una campaña de CLIENT debe declarar credit_scope; una de DRIVER no puede declararlo, porque su bono es dinero, no se canjea.

Cada persona recibe una campaña una sola vez. max_grants limita a cuánta gente en total, y city_id la restringe a una ciudad (null = toda la plataforma).

El saldo del cliente son tres bolsas

credit_scope decide dónde puede gastarse el crédito:

Ámbito Se gasta en
ANY cualquier pedido
ORDERS solo pedidos a domicilio
SURPLUS solo remates

Por eso GET /credit/me devuelve las tres bolsas por separado y no un total disponible: con anyUSD: 10 y ordersUSD: 5, un pedido normal puede descontar $15 pero un remate solo $10. Para eso están usableOnOrdersUSD y usableOnSurplusUSD, ya calculados — no los sumes por tu cuenta.

Además vienen dos acumulados históricos: earnedUSD (todo lo que ganó en campañas, sin importar la bolsa) y redeemedUSD (lo que ya aplicó a pedidos y no le fue devuelto; lo reservado en un pedido en curso cuenta como usado). Sirven para el típico "has ganado $25 en créditos". Los ajustes manuales de un admin no entran en ninguno de los dos, así que earnedUSD − redeemedUSD no tiene por qué cuadrar con las bolsas.

Al aplicar el crédito se gasta primero la bolsa más restringida y después la libre. Es a propósito: al revés se quemaría el dinero flexible y quedaría varado el restringido.

El crédito se consume completo, no queda vuelto

Aplicar el crédito vacía todas las bolsas utilizables en ese pedido. Lo que alcanza a descontar rebaja el total; lo que sobre se pierde, no queda para el próximo pedido.

Con $50 de crédito y un pedido de $4: se descuentan $4 y se pierden $46. En el historial eso se ve como un movimiento ORDER_REDEMPTION de $4 y uno ORDER_FORFEIT de $46.

Las bolsas que no aplican a ese pedido no se tocan: un crédito de remates sobrevive intacto a un pedido a domicilio.

Conviene avisarlo en la UI antes de confirmar un pedido chico con mucho crédito ("se aplicarán $50 de tu crédito"), porque el cliente no recupera la diferencia.

Si el pedido no llega a entregarse —lo cancela cualquiera de las partes, expira sin conductor o vence la ventana de pago— se devuelve todo, incluido lo que se había perdido: el excedente solo se quema en un pedido que efectivamente ocurre.

Notificaciones push

Tipo Rol Cuándo
promo_credit_granted cliente Ganó crédito (el texto dice dónde puede usarlo).
promo_bonus_granted conductor Ganó un bono en su billetera.

WebSocket

Evento Canal Rol
client.credit.updated users.{id} cliente

Se emite en cada movimiento de crédito (otorgado, aplicado a un pedido, devuelto o ajustado por un admin). payload: credit con las mismas siete cifras que GET /credit/me.

Changes

El objeto de orden

Dos campos nuevos en todos los endpoints que devuelven la orden completa:

Campo Tipo Para qué sirve
promo_credit_usd number Crédito promocional aplicado a este pedido.
client_charged_usd number Lo que el cliente realmente paga: client_pays_usd − promo_credit_usd.

También aparecen en el listado GET /orders, en el recibo GET /orders/{orderId}/receipt y en los eventos order.confirmed y order.awaiting_payment.

Cuando hay crédito aplicado, la orden suma una línea de desglose promo_credit (tipo adjustment) con monto negativo.

Ojo con qué campo mostrar: client_pays_usd sigue siendo el precio del pedido; client_charged_usd es lo que hay que cobrar. Para el monto a pagar usa siempre client_charged_usd.

Visibilidad para el conductor

En pedidos en efectivo el conductor ahora ve client_pays_usd, promo_credit_usd y client_charged_usd, y la línea promo_credit del desglose. Cobra en mano client_charged_usd, que puede ser menor al precio del pedido.

Su ganancia no cambia: Agüita le abona la diferencia en su billetera como un movimiento PROMO_REIMBURSEMENT, que se paga en su próxima liquidación. En pedidos online el conductor sigue sin ver ninguno de los tres campos.

Cobros

El monto del intent de pago (amount_cents en /payments) y la cotización de GET /orders/{orderId}/payment/form (amount.usd y amount.bs) ahora usan client_charged, no client_pays. Si el crédito cubre el pedido completo, la orden pasa directo a CONFIRMED con el pago ya confirmado en 0, sin pasar por WAITING_FOR_PAYMENT.

Devoluciones

Cancelar el pedido, que expire sin conductor, que venza la ventana de pago o que un admin lo cancele devuelven el crédito a la bolsa de la que salió, tanto lo descontado como lo que se había consumido de más. Cambiar el método de pago o aceptar una contraoferta con otro precio lo libera y lo vuelve a tomar sobre el total recalculado.

Desactivar una campaña solo corta nuevos otorgamientos: a quien ya lo ganó no se le quita el saldo, porque el crédito vive en su perfil, no en la campaña.

Billetera del conductor

Dos tipos nuevos de transacción en GET /wallet/me/transactions: PROMO_BONUS (bono de campaña) y PROMO_REIMBURSEMENT (reintegro del crédito del cliente en un pedido en efectivo). Ambos son CREDIT y entran a la liquidación como líneas de tipo ADJUSTMENT, sin afectar la comisión ni el IVA del recibo.

Panel admin

GET /admin/customers/{customerId} incluye un objeto credit, con la misma forma que GET /credit/me (bolsas, utilizables y acumulados). GET /admin/finance/summary suma costo_promociones_usd y ya lo descuenta de utilidad_neta_usd. En los reportes de clientes, el gasto acumulado pasa a calcularse sobre lo realmente cobrado.