Skip to main content
Toda integración de pagos necesita manejar fallos de red, timeouts y respuestas ambiguas. Si no reintentas con cuidado, puedes duplicar pagos. Este es el patrón que soporta la API de Vita.

Idea general

Cuando creas una transacción (POST /api/businesses/transactions), siempre envías un campo order — un identificador único generado por ti. Vita lo persiste con la transacción. Si pierdes la respuesta y necesitas saber si la operación se registró, consultas GET /api/businesses/transactions?order=<tu-order> antes de reintentar.

Tú generas order

Único por intención de operación en tu sistema. UUID v4, ULID, o un identificador propio que ya tengas (invoice ID, por ejemplo).

Vita consulta por order

GET /api/businesses/transactions?order=<tu-order> resuelve la ambigüedad después de un timeout.

Patrón recomendado

1

Genera un order único antes del POST

Guárdalo en tu base de datos junto con la intención (created, pendiente de envío). No lo generes dentro del request — si pierdes el response, tienes que poder recuperarlo.
2

Envía el POST

Timeout agresivo del lado cliente (ej. 30s). Si recibes 2xx, guarda el id que te devuelve Vita y marca la operación como sent.
3

Si recibes 5xx o timeout, NO reintentes aún

La transacción puede haberse creado del lado de Vita aunque no te llegó la respuesta.
4

Haz idempotency check

GET /api/businesses/transactions?order=<tu-order>. Si vuelve un resultado, significa que Vita sí la creó — guarda el ID y marca como sent. Si no vuelve nada, puedes reintentar el POST con el mismo order.
5

Limita reintentos y usa backoff

Reintenta con backoff exponencial (ej. 1s, 2s, 4s, 8s), máximo 5 veces. Después, marca para revisión manual y alerta a tu equipo.

Qué NO hacer

Rompe idempotencia. Vita no puede saber que estás reintentando una operación anterior y creará duplicados.
Riesgo alto de duplicar el pago. El 5xx no significa “no se creó” — significa “no sé si se creó”.
El 2xx del POST indica que la transacción fue aceptada, no que llegó a estado final. El estado final (completed, denied, failed) solo lo sabes vía webhook o re-consultando con GET /transactions/:id.
Vita reintenta webhooks que no reciben 200. Deduplica usando event_id (opaco, no asumas que es un UUID) + el id de la transacción + el estado.

Qué hacer con los webhooks

Los webhooks también requieren idempotencia del lado tuyo:
1

Responde 200 rápido (<5s)

Procesa la lógica pesada de forma asíncrona (queue). Si tardas en responder, Vita cierra la conexión y reintenta.
2

Deduplica antes de procesar

Guarda (event_id, transaction_id, status) como clave. Si ya lo procesaste, responde 200 y ya.
3

Valida la firma HMAC-SHA256

Rechaza (401) cualquier webhook con firma inválida. Ver Webhooks → Signature calculation.
4

Nunca re-serialices el body antes de validar

La firma se calcula sobre los bytes exactos que Vita envió. Un reformateo (incluso solo re-pretty-print) invalida la firma.

Reconciliación periódica

Aun con webhooks + idempotency check, agenda un job diario que:
  1. Consulte GET /api/businesses/transactions/get_all_transactions con un rango de fecha.
  2. Compare contra tu base de datos.
  3. Marque discrepancias para revisión (ej. transacción creada en Vita pero no en tu DB, o viceversa).
Esto captura casos borde que escaparon a los webhooks (DNS caído, deploys, timeouts en cascada) y es un requisito de auditoría estándar en pagos.