MCPFactura desde tu IA
Factuarea
Developers

Webhooks de facturación: estados, reintentos e idempotencia

Patrones para consumir webhooks de facturación con verificación, duplicados seguros, orden no garantizado, recuperación por API y trazabilidad operativa.

Equipo FactuareaPublicado el 12 de agosto de 2026Actualizado el 12 de agosto de 20266 min de lectura
Secuencia de eventos con una puerta de verificación, un carril de reintento y un estado aceptado sin duplicados.

Un webhook acerca un cambio a tu aplicación sin obligarla a preguntar continuamente. Esa inmediatez no convierte el mensaje en una orden infalible ni en una copia completa del estado remoto. La entrega puede repetirse, retrasarse o llegar mientras otro cambio sobre el mismo recurso sigue en tránsito.

El consumidor robusto parte de esas condiciones. Verifica la procedencia, conserva la identidad del evento y procesa de forma idempotente. También dispone de una ruta para reconstruir el estado cuando la entrega no basta. El resultado es un sistema que soporta incidencias normales de red sin multiplicar efectos de negocio.

Un evento cuenta que algo ocurrió, no todo lo que existe

El evento es una observación en un momento determinado. Puede incluir datos suficientes para decidir qué hacer o limitarse a identificar el recurso afectado. En ninguno de los dos casos debería asumirse que sustituye para siempre a la fuente de verdad.

Separa dos conceptos en el modelo local:

  • evento recibido: una evidencia inmutable que puede procesarse una vez;
  • estado conocido: la representación que tu aplicación mantiene del recurso.

El primero ayuda a auditar y deduplicar. El segundo puede evolucionar con eventos posteriores o con una consulta de recuperación. Si se mezclan, una entrega antigua puede sobrescribir un estado más reciente sin dejar rastro de por qué ocurrió.

Antes de programar, revisa la documentación de webhooks para conocer el contrato disponible. Diseña tu consumidor alrededor de ese contrato, no alrededor de una muestra capturada durante una prueba.

Define el contrato del consumidor antes del endpoint

Escribe primero qué significa aceptar un evento: qué campos necesita, cómo identifica el mensaje, dónde se conserva y qué trabajo posterior desencadena.

Decide también qué no hará la recepción. Una operación costosa, una llamada a otro proveedor o un cálculo largo aumentan la probabilidad de que la conexión termine antes de completar el trabajo. Un patrón habitual es validar lo imprescindible, guardar el evento de forma duradera y delegar el procesamiento a un trabajador separado.

El contrato interno debe incluir un estado para la recepción y otro para el procesamiento. Así puedes distinguir “el mensaje llegó” de “todos sus efectos se aplicaron”. Esa separación permite reanudar el trabajo sin pedir que el emisor vuelva a enviar algo que ya posees.

Canal de recepción recomendado
1

Verificar

Valida firma, tamaño e identidad antes de confiar en el cuerpo.

2

Persistir

Guarda el evento y su identificador con una restricción única.

3

Procesar

Un trabajador aplica efectos idempotentes y registra cada paso.

4

Recuperar

Reintenta con límite o reconcilia contra la API si falta estado.

Verifica la firma antes de confiar en el contenido

La URL de recepción es pública para quien pueda encontrarla. Antes de interpretar el cuerpo, verifica la prueba de autenticidad siguiendo exactamente el esquema publicado por el emisor. No inventes una normalización ni reconstruyas el mensaje desde un objeto parseado si el procedimiento espera los bytes originales.

Mantén los secretos fuera del código y prepara su rotación. Registra el resultado de la verificación, pero nunca el secreto utilizado.

Rechaza los mensajes que no superen este control antes de producir efectos. Limita además el tamaño aceptado y trata el contenido como entrada no confiable incluso después de validar la firma: autenticidad no significa que todos los campos sean adecuados para cualquier consulta o registro.

Asume que habrá reintentos y entregas duplicadas

El emisor no siempre puede saber si tu aplicación procesó un mensaje. Puede perderse la respuesta aunque el receptor haya terminado, por lo que un mismo evento puede aparecer más de una vez.

Conserva un identificador estable del evento y aplica una restricción que impida registrarlo dos veces como nuevo. Si ya existe, responde según el contrato sin repetir sus efectos. La deduplicación en memoria no basta: desaparece al reiniciar y no coordina varias instancias.

La protección debe continuar dentro del procesamiento. Si el primer intento actualizó un pedido pero falló antes de enviar una notificación, el siguiente necesita reconocer qué pasos están completos. Modelar efectos independientes o una transición transaccional evita repetir todo desde el principio.

const event = await storeEventOnce(payload.id, payload);

if (event.alreadyProcessed) return accepted();

await applyIdempotentEffect({
  operationKey: `invoice-paid:${payload.invoiceId}`,
  eventId: payload.id,
});

No dependas del orden de llegada

Dos eventos relacionados pueden recorrer caminos distintos y llegar invertidos. También pueden procesarse en paralelo aunque se recibieran en orden. Diseñar bajo la suposición contraria produce regresiones difíciles de reproducir.

Antes de aplicar un cambio, compara lo que sabes con la transición propuesta. Si el contrato ofrece una versión, secuencia o fecha útil, consérvala y úsala según su semántica documentada. Si no existe una señal suficiente, consulta el estado actual antes de ejecutar una acción irreversible.

Coordina los eventos por la entidad afectada cuando no necesites un orden global; así una factura no bloquea el procesamiento de todas las demás.

Haz idempotentes los efectos de negocio

Deduplicar mensajes evita procesar dos veces el mismo identificador, pero no cubre eventos distintos que expresan una situación equivalente. El consumidor debe proteger la intención de negocio: marcar un documento como pagado, registrar una referencia o activar una tarea no debería duplicarse porque lleguen varias señales compatibles.

Define una clave o condición estable para cada efecto y comprueba el estado previo. La transición “pendiente → completado” es más segura que “incrementar contador”, porque repetirla conserva el resultado. Cuando un efecto externo admita idempotencia, propaga una clave relacionada con la operación local.

Guarda la relación entre evento y efectos para distinguir lo completado de lo que aún permanece pendiente.

Recupera el estado mediante la API

Los webhooks reducen consultas, pero no eliminan la necesidad de reconciliar. Tu servicio puede estar detenido, una configuración puede ser incorrecta o una incidencia prolongada puede superar la ventana de reintentos del emisor. Debe existir un camino para detectar y reparar huecos.

Utiliza la API como fuente de recuperación según su documentación. Un proceso periódico puede revisar recursos cambiados, operaciones locales atascadas o diferencias entre estados. No es necesario replicarlo todo en cada ejecución: elige un alcance que pueda repetirse y deje registro de lo corregido.

Si reactivas un consumidor después de una pausa, reconcilia el intervalo afectado en lugar de asumir que todos los mensajes llegarán de nuevo.

Observa la cola, el procesamiento y la antigüedad

Contar webhooks recibidos no revela si generan el resultado esperado. Mide cuántos esperan procesamiento, cuánto tiempo llevan allí, cuántos fallaron, cuántos fueron duplicados y qué efectos siguen incompletos. La antigüedad del más viejo suele ser más útil que una media que oculta casos bloqueados.

Propaga un identificador de correlación desde la recepción hasta los trabajos derivados. Los registros deben permitir seguir el evento sin guardar secretos ni cargas completas innecesarias. Agrupa errores por causa para distinguir una entrada inválida de una dependencia temporalmente caída.

Define alertas que lleven a una acción: reanudar un trabajador, corregir configuración, reconciliar un periodo o revisar un tipo de mensaje. Una alerta sin propietario solo transforma un fallo silencioso en ruido visible.

Prueba la recuperación, no solo la recepción

Las pruebas deben repetir eventos, invertir su orden, detener el consumidor entre dos efectos y simular una respuesta perdida. Comprueba que reiniciar no duplica cambios y que una reconciliación puede completar lo pendiente sin borrar la evidencia anterior.

Mantén un procedimiento para pausar, reanudar, localizar un evento y reparar un intervalo. Ensáyalo antes de necesitarlo.

Un webhook está bien integrado cuando una entrega rápida mejora la experiencia, pero una entrega repetida, tardía o ausente no cambia la corrección del sistema. La velocidad es la ventaja visible; la idempotencia y la recuperación son lo que permite conservarla en producción.

Lleva estas ideas a tus facturas.

Prueba Factuarea durante 10 días, sin tarjeta, y comprueba cuánto trabajo puedes quitar de tu próxima semana.