Idempotencia y Reintentos en la API de Hacienda Costa Rica
Guía técnica para implementar idempotencia y reintentos seguros en la API del Ministerio de Hacienda de Costa Rica sin generar facturas duplicadas.
Cuando un sistema ISV envía una factura electrónica al ATV de Hacienda y la conexión se interrumpe antes de recibir respuesta, el desarrollador enfrenta una decisión crítica: ¿el documento llegó o no llegó? Reenviar sin control puede crear un comprobante duplicado con el mismo número consecutivo; no reenviar puede dejar una transacción sin respaldo fiscal. Ninguna especificación técnica del Ministerio de Hacienda de Costa Rica define un mecanismo nativo de idempotencia, y eso significa que cada ISV que opera bajo la v4.4 debe resolver este problema por cuenta propia antes de llegar a producción.
Esta guía cubre el diseño de una estrategia de idempotencia completa en el lado del ISV: cómo construir y almacenar claves de idempotencia, qué semántica tienen los códigos HTTP de la API de Hacienda, cómo implementar reintentos con backoff exponencial y cuándo activar un circuit breaker. Al terminar, usted tendrá una arquitectura de referencia que evita facturas duplicadas sin perder transacciones legítimas.
¿Qué significa idempotencia en el contexto de factura electrónica?
En el diseño de APIs, una operación es idempotente cuando ejecutarla múltiples veces produce el mismo resultado que ejecutarla una sola vez. Para factura electrónica, esto implica que enviar el mismo comprobante dos veces al receptor fiscal no debe generar dos documentos distintos ni dos efectos fiscales independientes. El problema es que la API del Ministerio de Hacienda de Costa Rica fue diseñada bajo el estándar XML-CR con una arquitectura orientada a documentos, no a operaciones REST idempotentes. No existe un header X-Idempotency-Key ni un mecanismo de deduplicación en el servidor del ATV.
Por qué Hacienda no ofrece idempotencia nativa en su API
La arquitectura del ATV de Hacienda procesa documentos XML firmados digitalmente. El identificador único del documento es la clave numérica consecutiva generada por el emisor, no un token de transacción gestionado por el servidor. Esto significa que si usted envía el mismo XML firmado dos veces, el ATV puede aceptarlo, rechazarlo por clave duplicada o devolver un error según el estado interno del sistema en ese momento. El comportamiento no es determinístico ante reintentos en todos los escenarios, y la documentación oficial no especifica de forma exhaustiva qué ocurre al reenviar un documento ya procesado. Esta ambigüedad obliga al ISV a implementar control de idempotencia completamente en el lado del cliente.
Las consecuencias de un reintento sin control de estado
Los efectos de un reintento no controlado van desde errores operativos menores hasta problemas de cumplimiento fiscal. Si el primer envío fue aceptado por Hacienda pero usted no recibió confirmación, y luego reenvía el mismo documento, puede ocurrir que Hacienda acepte el segundo envío como un documento nuevo si la clave consecutiva no fue registrada correctamente, generando una doble emisión. En el otro extremo, si usted no reintenta y el primer documento fue rechazado por un error de red antes de llegar al ATV, la factura queda sin respaldo. Cualquiera de estos escenarios puede traducirse en inconsistencias en el libro fiscal del emisor y reclamos del receptor.
Cómo responde la API de Hacienda ante fallos de red y errores del sistema
Antes de definir una estrategia de reintentos, es necesario comprender la semántica de las respuestas del ATV de Hacienda. No todos los errores son recuperables, y reintentar ante un error de validación (4xx) sin corregir el documento es inútil. La distinción entre errores de cliente, errores de servidor y fallos de red determina qué acción tomar en cada caso.
Semántica de los códigos HTTP y estados internos del ATV
La API de Hacienda devuelve respuestas HTTP estándar con un cuerpo de estado fiscal adicional. Un código 200 con estado aceptado indica procesamiento exitoso y no debe reintentarse bajo ninguna circunstancia. Un código 400 indica un error de validación en el documento XML: firma incorrecta, estructura mal formada, campos obligatorios ausentes o clave consecutiva inválida. Estos errores son determinísticos y no se resuelven con reintentos sin corregir el documento fuente. Un código 500 indica un error del servidor de Hacienda: en este caso el estado del documento en el ATV es desconocido. Un timeout de red sin código HTTP significa que la solicitud no llegó a procesarse o se interrumpió en tránsito. Los códigos 500 y los timeouts son los únicos escenarios donde un reintento con control de idempotencia está justificado.
Timeouts, ventanas de proceso y comportamiento del ATV bajo carga alta
La API de Hacienda puede presentar latencias elevadas en horarios de alta demanda fiscal, típicamente en los días de cierre de período y durante las primeras horas del día hábil. Los ISVs que integran directamente sin un middleware de cola reportan timeouts que oscilan entre 15 y 45 segundos en estos períodos. Una buena práctica es configurar el timeout de la solicitud HTTP en no más de 30 segundos para el envío inicial, y asumir que toda respuesta que supere ese umbral debe tratarse como estado desconocido. Este umbral debe estar documentado en la configuración del sistema y ser ajustable sin necesidad de redespliegue de la aplicación.
Diseño de la clave de idempotencia en el sistema del ISV
La clave de idempotencia es el mecanismo central que permite al ISV detectar si una solicitud ya fue procesada antes de reintentarla. A diferencia de un token UUID genérico, la clave de idempotencia para factura electrónica debe derivarse de datos que sean únicos para ese documento fiscal específico, no para la solicitud HTTP. Esto garantiza que aunque el sistema se reinicie entre intentos, la clave siga siendo la misma y la deduplicación funcione correctamente.
Qué datos deben componer la clave de idempotencia
La clave de idempotencia debe combinar el NIT del emisor, el tipo de documento, el consecutivo del comprobante y opcionalmente un hash del cuerpo XML normalizado. Una estructura recomendada es: SHA-256(emisor_nit + tipo_documento + consecutivo + fecha_emision). Este hash es determinístico: si usted genera el mismo documento dos veces, la clave resultante será idéntica, lo que permite detectar el reintento antes de enviarlo al ATV. No incluya timestamps de la solicitud HTTP ni UUIDs aleatorios en la composición de la clave, ya que esos valores cambian entre reintentos y rompen la deduplicación. La clave debe almacenarse junto al registro del documento en la base de datos del ISV desde el momento en que el documento es generado, no cuando se envía.
Ciclo de vida y estados internos de la clave de idempotencia
La clave de idempotencia debe almacenarse con al menos cuatro estados: PENDIENTE (documento generado, no enviado), EN_PROCESO (envío en curso), ACEPTADO (confirmación del ATV recibida), RECHAZADO (error definitivo de validación). El estado EN_PROCESO debe incluir un timestamp de expiración: si el proceso lleva más tiempo del umbral definido sin transicionar a ACEPTADO o RECHAZADO, el sistema debe marcarlo como TIMEOUT_DESCONOCIDO y activar el protocolo de consulta de estado antes de reintentar. Este mecanismo evita el escenario de reintento ciego ante un estado real de éxito que no fue confirmado por un fallo de red en la respuesta, no en el envío.
Implementación de reintentos con backoff exponencial y jitter
El backoff exponencial es el algoritmo estándar para reintentos en sistemas distribuidos. La idea central es espaciar los reintentos de forma creciente para evitar saturar el servidor destino cuando este está bajo presión. Para la API de Hacienda, este patrón es especialmente relevante porque los picos de error suelen ser sistémicos: si el ATV está bajo carga, un enjambre de reintentos inmediatos de múltiples emisores empeora el problema en lugar de resolverlo.
Fórmula de backoff y tiempos de espera recomendados
El algoritmo recomendado para la integración con Hacienda Costa Rica es el backoff exponencial con jitter aleatorio. La fórmula base es: espera = base_delay × (2 ^ intento) + random(0, jitter_ms). Con un base_delay de 2 segundos, un máximo de 4 reintentos y un jitter de 500ms, los tiempos de espera aproximados son: primer reintento entre 2 y 2.5 segundos, segundo entre 4 y 4.5, tercero entre 8 y 8.5, cuarto entre 16 y 16.5. Este espaciamiento es suficiente para superar fallos transitorios del ATV sin acumular documentos en cola durante períodos de fallo prolongado. Si el cuarto reintento falla, el documento debe marcarse en estado FALLO_DEFINITIVO y enviarse a una cola de revisión manual.
Circuit breaker: cuándo dejar de reintentar para proteger el sistema
El circuit breaker es un patrón complementario al backoff: cuando la tasa de fallos supera un umbral en una ventana de tiempo definida, el sistema deja de enviar solicitudes al ATV durante un período de apertura para dar tiempo a que el servidor se recupere. Para implementaciones directas con Hacienda, una configuración conservadora es abrir el circuito si 5 de los últimos 10 intentos en 60 segundos resultan en error 500 o timeout. Durante el período abierto, los documentos se encolan localmente con estado EN_CONTINGENCIA. El circuito pasa a estado semiabierto después de 2 minutos: si el siguiente intento de prueba es exitoso, se cierra; si falla, vuelve a abrirse con el contador reiniciado.
Observabilidad del flujo de reintentos: métricas y alertas en producción
Un sistema de reintentos sin observabilidad es opaco ante fallos reales. Es frecuente que los ISVs implementen el algoritmo correctamente pero no instrumenten el número de documentos en estado TIMEOUT_DESCONOCIDO, lo que hace imposible detectar si hay una degradación sistemática del ATV. La observabilidad del flujo de reintentos requiere al menos tres niveles: registro de eventos por documento, métricas agregadas en tiempo real y alertas configuradas sobre umbrales operativos críticos.
Métricas esenciales para monitorear el flujo de envíos al ATV
Las métricas mínimas que un ISV que integra con Hacienda debe registrar son: tasa de éxito en primer intento (documentos ACEPTADOS sin reintento), tasa de reintento exitoso (ACEPTADOS en segundo o tercer intento), tasa de fallo definitivo (documentos que llegan al máximo de reintentos sin confirmar), tiempo promedio hasta ACEPTADO desde la generación del documento, y número de documentos en estado TIMEOUT_DESCONOCIDO por hora. Estas métricas permiten identificar si un aumento en el tiempo de respuesta del ATV está generando más estados desconocidos, lo que es una señal temprana de degradación del servicio antes de que usted reciba reportes de clientes finales.
Alertas recomendadas en un entorno de producción fiscal
Las alertas deben configurarse sobre los siguientes umbrales: más de 5 documentos en estado TIMEOUT_DESCONOCIDO en una ventana de 10 minutos (posible degradación del ATV), tasa de reintento exitoso por encima del 15% en el último período de facturación (posible problema de conectividad estructural), y cualquier documento que llegue a fallo definitivo sin revisión manual en menos de 30 minutos. Para ISVs que buscan externalizar esta capa de resiliencia, la API de facturación electrónica para Costa Rica de Alanube incluye manejo de reintentos, control de idempotencia y observabilidad del flujo como parte de su infraestructura base, eliminando la necesidad de implementar estas capas desde cero en el ISV.
¿Cuál es el número máximo de reintentos recomendado para envíos al ATV de Hacienda Costa Rica? No existe una regla oficial de Hacienda al respecto. La práctica recomendada para ISVs es entre 3 y 5 reintentos con backoff exponencial. Superar 5 reintentos sin éxito en un período de menos de 2 minutos generalmente indica un fallo sistémico del ATV, no un problema transitorio. En ese caso, es más efectivo activar el circuit breaker, encolar los documentos localmente con estado EN_CONTINGENCIA y esperar a que el servicio se restablezca antes de reintentar en bloque controlado.
¿Cómo puedo verificar si un documento fue aceptado por Hacienda sin haber recibido confirmación HTTP? Hacienda Costa Rica permite consultar el estado de un comprobante enviado usando el endpoint de consulta del ATV con la clave numérica del documento. Si usted envió un documento y no recibió respuesta por timeout, debe consultar el estado antes de reintentar. Si la consulta devuelve que el documento fue aceptado, no reenvíe. Si la consulta indica que el documento no existe en el sistema, el envío inicial no llegó y el reintento es seguro. Esta consulta previa es el paso más importante del protocolo de idempotencia en la integración directa con Hacienda.
¿Qué diferencia hay entre backoff exponencial y backoff lineal para reintentos en integración fiscal? El backoff lineal incrementa el tiempo de espera en intervalos fijos (2s, 4s, 6s, 8s), mientras que el backoff exponencial lo duplica en cada intento (2s, 4s, 8s, 16s). Para APIs fiscales con picos de carga como el ATV de Hacienda, el backoff exponencial es preferible porque reduce más rápidamente la presión sobre el servidor durante fallos sistémicos. El backoff lineal puede mantener una tasa de solicitudes demasiado alta durante una degradación prolongada, contribuyendo al problema en lugar de mitigarlo bajo escenarios de múltiples emisores simultáneos.
¿Es posible implementar idempotencia sin modificar el esquema de base de datos del sistema de facturación? Técnicamente sí, usando una capa de caché externa como Redis con TTL para almacenar las claves de idempotencia y sus estados. Sin embargo, esta arquitectura introduce un nuevo punto de fallo: si Redis cae, se pierde el control de idempotencia. La solución más robusta es persistir el estado en la base de datos principal. Si usted no puede modificar la tabla de documentos existente, puede crear una tabla auxiliar de control de envíos sin tocar el modelo de datos principal, manteniendo la clave idempotente ligada al ID interno del documento.
Artículos Relacionados
Nota de Débito Electrónica en República Dominicana: e-CF Tipo 35 Paso a Paso
Guía técnica para implementar la nota de débito electrónica (e-CF Tipo 35) en República Dominicana: estructura XML, campos obligatorios, flujo DGII y errores frecuentes.
Idempotencia y Reintentos en la API del DGI Panamá: Guía para ISVs
Cómo implementar idempotencia y reintentos seguros en la integración con la API del DGI en Panamá. Guía técnica para evitar documentos duplicados en el SFEP.
Observabilidad y Logging en la Integración con la API de Hacienda Costa Rica
Cómo implementar logging estructurado, métricas y alertas en su integración con la API de Hacienda Costa Rica. Guía técnica para ISVs con volumen en producción.