Nordlet

← Blog

Cómo integrar una API de contabilidad en la nube en una plataforma SaaS

Una guía práctica para construir una integración contable multiinquilino (multi-tenant) que sobreviva a OAuth, webhooks, reglas fiscales y la conciliación sin corromper el libro mayor.

Nordlet Team · · 17 min de lectura

La mayoría de los equipos que se proponen "añadir contabilidad" a su producto SaaS empiezan conectando un cliente HTTP al endpoint de un proveedor y publicando una factura. Eso funciona en una demostración. Deja de funcionar la primera vez que un cliente conecta dos organizaciones contables, la primera vez que un webhook llega por duplicado y la primera vez que un token de actualización (refresh token) rota y se pierde a mitad de la petición. La versión duradera de este trabajo no es un cliente; es una capa de integración.

Esa capa debe gestionar las conexiones de los inquilinos (tenants), el almacenamiento y la rotación de tokens, las reglas contables específicas del proveedor, el mapeo de registros, la sincronización inicial e incremental, la recepción de webhooks con reintentos y deduplicación, los límites de velocidad (rate limits), el control de versiones y una pista de auditoría (audit trail) que tu equipo de soporte pueda leer a las dos de la mañana. Este artículo detalla esa arquitectura y las decisiones que más importan.

Un modelo mental útil:

Producto SaaS → servicio de integración contable → adaptador de proveedor (o API unificada) → sincronización y conciliación asíncronas

El sistema contable sigue siendo la fuente de verdad (system of record) para los objetos del libro mayor: cuentas, códigos de impuestos, transacciones registradas y asientos contables (journal entries). Tu plataforma SaaS mantiene identificadores estables entre sistemas, el estado de sincronización, los metadatos de mapeo y un registro de auditoría operativa.

Qué cubre realmente una "API de contabilidad en la nube"

La frase suele referirse a la API de una plataforma de teneduría de libros alojada, como QuickBooks Online, Xero, Sage, Zoho Books o un sistema regional. También puede referirse a una API de contabilidad unificada que normaliza varios proveedores bajo una misma interfaz.

Conviene ser preciso, porque la implementación difiere según el objetivo. Leer facturas para informes no es lo mismo que crear facturas a partir de la actividad del SaaS, registrar facturas de proveedores (bills), sincronizar clientes y productos, redactar asientos contables o ejecutar una verdadera sincronización bidireccional. Decide cuál de estas opciones estás construyendo antes de tocar un endpoint.

Otra distinción importa para este artículo. Una API de pagos mueve dinero. Una API bancaria extrae datos de cuentas. Una API de facturación puede crear documentos sin exponer el libro mayor general. Un libro mayor contable incrustado (embedded accounting ledger) es otra cosa: la empresa SaaS es propietaria del propio motor contable. Este último enfoque es donde se ubica Nordlet. En lugar de conectar tu producto a los libros externos de un cliente, Nordlet proporciona a las plataformas y mercados (marketplaces) libros de contabilidad por partida doble reales, un libro mayor inmutable apto para auditorías, gestión del IVA de la UE y pagos dentro de su propio producto, mediante un diseño orientado a API con SDKs tipados y webhooks. Si eres un mercado que debe decidir si integrar el sistema contable de un cliente o llevar los libros por cuenta propia, estás ante una auténtica bifurcación en el camino, a la que volveremos más adelante.

Multiinquilino (Multi-tenancy): delimita cada conexión dos veces

En un producto SaaS, una aplicación se conecta a muchas organizaciones de clientes. Cada conexión debe estar delimitada tanto por el inquilino (tenant) del SaaS como por el identificador de la organización del proveedor, como un ID de inquilino de Xero o un ID de ámbito (realm ID) de QuickBooks.

No establezcas las claves de conexión basándote únicamente en el ID de usuario de OAuth. Un usuario puede autorizar varias organizaciones contables y una organización puede ser reconectada por diferentes usuarios a lo largo del tiempo. Si te equivocas en esto, acabarás publicando la factura de un cliente en los libros de otro, y ese no es un error del que te recuperes discretamente.

La primera decisión arquitectónica: conector directo, API unificada o libro mayor incrustado

Integraciones directas con proveedores

Una integración directa te ofrece el mayor control: características específicas del proveedor, campos personalizados, manejo de errores, frecuencia de sincronización, retención de datos y estructura de costos. El precio es real. Cada proveedor aporta su propio flujo OAuth, esquema, peculiaridades, límites de velocidad, comportamiento de webhooks, certificación y mantenimiento continuado.

APIs de contabilidad unificadas

Una API unificada ofrece una interfaz común para varios sistemas contables, normalizando entidades como clientes, facturas, proveedores, cuentas, pagos y productos. Puede reducir el tiempo de desarrollo inicial. No elimina la complejidad de la integración, y tratarla como si lo hiciera es un error común.

Antes de comprometerte, pregunta: ¿Qué proveedores y operaciones son compatibles? ¿Funcionan las operaciones de escritura o solo las de lectura? ¿Las escrituras son síncronas o se encolan? ¿Están disponibles los campos específicos del proveedor mediante paso directo (passthrough)? ¿Se almacenan los datos en caché y qué tan frescos son? ¿Quién gestiona las caídas del proveedor y los cambios en la API? ¿El precio es por llamada, por cuenta vinculada, por registro o una tarifa de plataforma? ¿Puedes exportar tus mapeos y desconectarte limpiamente? La palabra "unificado" rara vez significa "equivalente en funciones entre proveedores".

Libro mayor incrustado

Si el problema principal de tu plataforma es llevar la contabilidad de tus usuarios, en lugar de reflejarla en sus libros existentes, un libro mayor incrustado cambia el cálculo. Un mercado con miles de vendedores, o un producto SaaS que necesita IVA de la UE apto para auditorías y cumplimiento normativo por país integrado desde el inicio, se beneficia más de poseer el motor contable que de cablear N conectores externos. Ese es el posicionamiento de Nordlet: libros reales como API, partida doble inmutable, IVA por país con validación VIES y generación del registro i.SAF, exportación SEPA y exportaciones de informes en XLSX, PDF o JSON, todo dentro de tu producto en lugar de un pago externo.

Una regla de decisión que utilizo:

Situación Mejor opción
Un proveedor de contabilidad domina tu base de clientes; el comportamiento específico del proveedor es fundamental Conector directo
La cobertura amplia de proveedores y la velocidad de salida al mercado importan más que el control API unificada
Eres una plataforma o mercado que necesita gestionar y poseer los libros, con IVA de la UE y pistas de auditoría Libro mayor incrustado (Nordlet)
Realidad mixta Híbrida: unificada para flujos comunes, conectores directos para proveedores estratégicos

Arquitectura de integración recomendada

Aísla la integración de la lógica de negocio central

No disperses las llamadas a proveedores entre la facturación, los pedidos, las suscripciones y los informes. Construye un servicio de integración dedicado que contenga adaptadores de proveedores, gestión de conexiones OAuth, modelos canónicos, mapeos de ID, trabajos y colas de sincronización, endpoints de webhooks, gestión de reintentos y mensajes fallidos (dead-letter), registros de auditoría y herramientas de conciliación. Esto evita que el nombre de un campo de Xero o QuickBooks se filtre en tu modelo de dominio.

Define un modelo canónico estricto

Modela únicamente los flujos de trabajo que admites. Objetos típicos: cliente, producto o artículo de servicio, factura, línea de factura, pago, nota de crédito, proveedor, cuenta, tasa de impuestos, moneda y asiento contable.

Conserva las distinciones que afectan a la contabilidad. No aplanes el concepto de borrador frente a aprobado frente a registrado, importes con impuestos incluidos frente a importes sin impuestos, notas de crédito frente a facturas negativas, asignación de pagos frente a existencia de pagos, o número de factura cara al cliente frente a ID de objeto del proveedor. Cada registro debe llevar el ID del SaaS, el ID del proveedor, el nombre del proveedor y la versión de la API, un indicador de la fuente de verdad, el estado, las marcas de tiempo, la hora de la última sincronización, la referencia externa y el estado de error o conciliación.

Mantén tablas de mapeo explícitas

Mapea el inquilino del SaaS con la organización contable, el cliente del SaaS con el contacto del proveedor, el producto del SaaS con el artículo o cuenta del proveedor, la factura del SaaS con la factura del proveedor, el pago del SaaS con el pago del proveedor, la categoría de impuestos con el código de impuestos y la categoría de ingresos con la cuenta del libro mayor.

Nunca utilices nombres o correos electrónicos como identificadores permanentes. Los nombres cambian, existen duplicados y dos clientes pueden compartir un correo electrónico. Almacena el ID inmutable del proveedor y conserva el ID original del SaaS.

Añade máquinas de estado

Asigna estados explícitos a una conexión: no conectada, autorización pendiente, conectada, sincronización inicial pendiente, sincronizando, saludable, limitada por velocidad (rate limited), reautorización requerida, proveedor no disponible, desconectada, fallida de forma permanente. Asigna a los registros sus propios estados: pendiente, enviada, confirmada, con error recuperable, con error que requiere acción del usuario, conciliada, conflicto detectado. Un indicador binario de "conectado/no conectado" no le aporta ninguna información útil a tu equipo de soporte.

OAuth y alta de conexiones

Utiliza el flujo de código de autorización (authorization code flow). El cliente hace clic en Conectar, tu servidor crea una transacción de autorización de corta duración, el cliente se autentica en el proveedor y concede los permisos (scopes), tú intercambias el código por tokens, descubres la organización autorizada, almacenas la conexión asociada al inquilino correcto y encolas una sincronización inicial.

Valida la callback cuidadosamente: el parámetro state frente a una transacción del lado del servidor, la URI de redirección exacta, el emisor del proveedor y el contexto del inquilino. RFC 9700, Mejores prácticas actuales de seguridad para OAuth 2.0, formaliza la directriz actual: utiliza PKCE con los flujos de código de autorización, evita las concesiones implícitas y de contraseña, y utiliza la coincidencia exacta de la URI de redirección.

Solicita los permisos mínimos necesarios (least-privilege scopes). Utiliza solo lectura cuando no necesites escribir. Los modelos de permisos cambian, así que no copies ejemplos antiguos. La documentación de OAuth de Xero señala que los permisos contables amplios están siendo reemplazados por otros granulares, habiéndose asignado permisos granulares a las nuevas aplicaciones desde marzo de 2026 y estando previsto que los permisos amplios sigan disponibles hasta septiembre de 2027.

Almacena los tokens únicamente en el lado del servidor. No los expongas nunca al JavaScript del navegador, clientes móviles, registros del frontend (frontend logs), análisis ni mensajes de error orientados al cliente. Cifra en reposo, oculta (redact) los datos sensibles de los registros y mantén metadatos por conexión: tokens de acceso y de actualización cifrados, fecha de caducidad, ID de organización del proveedor, permisos concedidos, hora de emisión, último refresco exitoso y estado de revocación.

La rotación de tokens de actualización es donde fallan los entornos de producción

Una respuesta de actualización puede devolver un nuevo token de actualización. Debes persistir el valor más nuevo de forma atómica, o dejarás al cliente sin acceso. Según las preguntas frecuentes para desarrolladores de Xero, cada actualización produce un nuevo token de actualización, los tokens de actualización duran hasta 60 días y existe un periodo de gracia de 30 minutos para reintentar con el token existente si se pierde una respuesta. QuickBooks Online indica a los desarrolladores que almacenen el token de actualización más reciente de la respuesta más reciente: los tokens de actualización duran hasta 100 días y el valor puede rotar con una frecuencia de hasta 24 horas.

En la práctica: utiliza un bloqueo de actualización por conexión, reemplaza el token de actualización de forma atómica, gestiona los fallos transitorios del endpoint de tokens con reintentos, expone un estado de reautorización claro y nunca actualices en cada llamada a la API mientras se mantenga válido un token de acceso.

Sincronización inicial

Ejecuta la sincronización inicial como un trabajo en segundo plano (background job). No bloquees la callback de OAuth ni la interfaz de usuario con este proceso.

Una secuencia robusta: obtener metadatos de la organización, recuperar cuentas, tasas de impuestos, monedas, contactos y artículos, almacenar IDs del proveedor y mapeos, importar únicamente la ventana histórica que el producto necesita, encolar los registros dependientes en orden de dependencia, registrar un punto de control (checkpoint) y marcar la conexión como saludable solo después de la validación.

El orden de dependencia importa. Una factura puede requerir que primero existan un contacto, un artículo, una cuenta de ingresos, un código de impuestos y una moneda. No crees duplicados a ciegas. Realiza la coincidencia basándote en un ID externo almacenado, una referencia proporcionada por el cliente, una regla de coincidencia definida o un paso explícito de selección por parte del usuario para los casos ambiguos.

Sincronización incremental

Trata los webhooks como señales, no como registros autoritativos

Un webhook suele indicar que algo ha cambiado. Verifica la firma, registra el evento sin procesar, devuelve rápidamente la respuesta de éxito requerida, deduplica, encola una recuperación posterior, recupera el objeto actual del proveedor, aplica la actualización de forma transaccional, actualiza el punto de control y deriva los fallos al sistema de reintentos o conciliación. Esto permite gestionar cargas útiles incompletas y eventos desordenados.

Las reglas de los proveedores difieren, así que no prometas un comportamiento universal. Los webhooks de Xero llevan una firma HMAC-SHA256 en la cabecera x-xero-signature, exigen HTTPS, reintentan con frecuencia decreciente durante un máximo de 24 horas, pueden desactivarse tras fallos repetidos y pueden guardar eventos hasta 31 días para su reproducción tras la recuperación. QuickBooks Online verifica mediante HMAC-SHA256 y un token verificador, espera un código HTTP 200 en un plazo de tres segundos y reintenta con un calendario fijo que eventualmente se estabiliza en intervalos de seis horas, recomendando Intuit el procesamiento asíncrono.

Deduplicación e idempotencia

La entrega al menos una vez (at-least-once delivery) es lo habitual. Espera webhooks duplicados, reintentos tras un tiempo de espera (timeout) en el que la escritura realmente tuvo éxito, eventos reordenados y clics duplicados de los usuarios. Utiliza un ID de evento del proveedor cuando esté disponible, una clave de evento única en el almacenamiento persistente, un ID de operación generado antes de cada escritura, restricciones de unicidad en la base de datos, semántica de inserción o actualización (upsert) y una consulta de conciliación tras tiempos de espera ambiguos.

No asumas que todas las APIs de contabilidad ofrecen claves de idempotencia nativas. Si el proveedor no lo hace, almacena una clave de operación interna y comprueba si el objeto remoto esperado ya existe antes de reintentar. Los patrones de las peticiones idempotentes de Stripe y la guía general sobre idempotencia en webhooks se adaptan muy bien aquí.

Sondeo (polling) y detección de cambios

Combina los webhooks con el sondeo periódico. Los webhooks se desactivan, se retrasan, se pierden por una mala configuración o se limitan a ciertos objetos. Xero es compatible con la cabecera If-Modified-Since para los cambios posteriores a una marca de tiempo UTC, pero su documentación advierte que no todos los cambios actualizan UpdatedDateUTC, por lo que algunas transacciones parcialmente pagadas y campos de contacto no aparecerán a través de ese filtro. El control de cambios de QuickBooks Online (Change Data Capture) rastrea los cambios de los últimos 30 días, limita las respuestas a 1.000 objetos, devuelve las entidades eliminadas con el estado Deleted y funciona mejor con ventanas de sondeo más cortas.

Almacena un punto de control por proveedor y por inquilino y utiliza ventanas de solapamiento. Solicita los cambios desde un momento ligeramente anterior al último punto de control, y luego deduplica por ID de proveedor y versión de modificación. Esto protege frente al desajuste de relojes (clock skew) y los fallos parciales.

Integridad de los datos específicos de contabilidad

Esta es la parte que separa una integración funcional de una confiable.

El comportamiento fiscal no es intercambiable. La documentación de Xero señala que las facturas, notas de crédito y órdenes de compra se configuran por defecto como excluyentes de impuestos cuando LineAmountTypes no está definido; los recibos y transacciones bancarias se configuran por defecto con impuestos incluidos; y los asientos manuales se configuran por defecto sin impuestos. Utiliza el campo TaxType, no el nombre de la tasa de impuestos. Nunca asumas que "IVA del 20%" identifica unívocamente un código de impuestos; puede variar según el país, el tipo de transacción, la fecha de entrada en vigor y la configuración de la organización. Aquí es donde el IVA multi-país de la UE se vuelve costoso de gestionar manualmente, y donde un libro mayor incrustado con cumplimiento normativo por país integrado justifica su valor.

Utiliza aritmética decimal o de precisión fija para el dinero, nunca coma flotante binaria. Persiste el código de moneda y su precisión, importe unitario, cantidad, descuento, importe de impuestos, neto, bruto y tipo de cambio. Decide claramente si envías importes a nivel de línea y dejas que el proveedor calcule los totales, o si envías un total precalculado. Mezclar ambos enfoques crea discrepancias por redondeo que tu contable encontrará.

Haz referencia a las cuentas del libro mayor por el ID o código del proveedor, no por el nombre visible. Antes de una escritura, valida que las cuentas, los códigos de impuestos, los clientes, los artículos y la moneda estén activos y sean compatibles. Un error al escribir una factura suele ser un problema de mapeo o configuración, no un error transitorio de la API, por lo que la interfaz de usuario debe explicar la solución en lugar de mostrar "sincronización fallida".

No asumas la equivalencia de objetos. Un "pago" puede significar un cobro, una asignación, un depósito, una transacción bancaria o un asiento contable. Una "suscripción" de SaaS puede no mapearse limpiamente a una "factura" contable. Define el evento contable que deseas representar antes de elegir un objeto de la API. Consulta la documentación sobre pagos de Xero para ver cómo modela esto un proveedor.

Límites de velocidad (rate limits) y control de versiones

Los límites suelen establecerse por inquilino, organización, aplicación o una combinación de ellos. Según las preguntas frecuentes sobre límites de Xero: cinco peticiones simultáneas por inquilino, 60 por minuto por inquilino, 5.000 por día por inquilino y 10.000 por minuto en toda la aplicación, con cabeceras de límite restante y Retry-After en las respuestas 429. QuickBooks Online documenta 500 peticiones por minuto y 10 por segundo por ID de ámbito, con un endpoint por lotes (batch endpoint) que admite hasta 30 operaciones por petición.

Implementa limitación de velocidad por inquilino, estrangulamiento global (global throttling), retroceso exponencial (exponential backoff) con fluctuación (jitter), respeto por la cabecera Retry-After, concurrencia acotada, paginación y métricas sobre respuestas 429 y cuota restante. No utilices paralelismo ilimitado para las importaciones; un solo cliente grande puede agotar los recursos destinados a cualquier otro trabajo de ese inquilino.

Fija o gestiona explícitamente las versiones de la API. QuickBooks Online utiliza por defecto la versión menor 75 cuando no se especifica ninguna. Centraliza las versiones en la configuración, ejecuta pruebas de contrato frente a entornos de pruebas (sandboxes), supervisa las notas de lanzamiento y trata los campos de respuesta desconocidos como compatibles con versiones futuras. Los entornos de pruebas no reproducirán todas las condiciones de producción, así que prueba la desconexión, la reconexión, el consentimiento revocado, los tokens caducados, los límites de velocidad y las modificaciones del lado del proveedor antes del lanzamiento.

Qué construiría primero

Si empezara con esto mañana, lo haría en este orden:

  1. Define el flujo de trabajo contable exacto: qué eventos y objetos lees o escribes.
  2. Elige la estrategia de proveedores: directa, unificada, incrustada o híbrida.
  3. Construye un modelo de conexión delimitado por inquilino con IDs de organización del proveedor, permisos, estado y metadatos de tokens.
  4. Implementa OAuth con el flujo de código de autorización, PKCE, validación de estado, permisos mínimos y almacenamiento de tokens en el servidor.
  5. Construye un adaptador de proveedor detrás de una interfaz interna estable.
  6. Crea mapeos de ID basados en IDs de proveedores inmutables.
  7. Implementa primero las lecturas; importa los datos de referencia antes de realizar cualquier escritura.
  8. Añade un trabajo de sincronización inicial con paginación, limitación de velocidad, puntos de control y orden de dependencia.
  9. Implementa una única escritura restringida (crear una factura) solo después de validar los mapeos de cliente, artículo, impuestos y cuenta.
  10. Haz que las escrituras sean tolerantes a reintentos con IDs de operación internos, restricciones de unicidad y comprobaciones de estado remoto.
  11. Añade webhooks firmados que respondan rápidamente y se procesen de forma asíncrona.
  12. Añade sondeo y conciliación para que los webhooks sean un acelerador y no la única fuente de verdad.
  13. Prueba deliberadamente los escenarios de fallo.
  14. Añade herramientas de soporte y auditoría que permitan explicar y reparar los fallos.
  15. Amplía la cobertura de objetos de forma gradual.

FAQ

¿Debo usar una API unificada o construir conectores directos?

Utiliza un conector directo cuando un proveedor domine a tus clientes o el comportamiento específico del proveedor sea fundamental. Considera una API unificada cuando la cobertura amplia y la velocidad importen más que el control. Si tu verdadera necesidad es llevar los libros por ti mismo en lugar de sincronizarlos con el sistema de un cliente, ninguna de las dos opciones responde a la pregunta; echa un vistazo a un libro mayor incrustado como Nordlet en su lugar.

¿Son suficientes los webhooks para mantener la sincronización?

No. Los webhooks se desactivan, se retrasan o se pierden, y las cargas útiles pueden estar incompletas o desordenadas. Trátalos como señales de cambio, recupera el objeto actual después y respalda el proceso con sondeos periódicos y conciliación.

¿Cómo evito que los fallos en el token de actualización dejen a los clientes sin acceso?

Persiste el nuevo token de actualización de forma atómica en cada actualización, utiliza un bloqueo por conexión, reintenta los fallos transitorios del endpoint de tokens y expone un estado de reautorización claro. El periodo de gracia de 30 minutos de Xero ayuda, pero la persistencia atómica es lo que te salva.

¿Puedo hacer coincidir los registros por el nombre o el correo electrónico del cliente?

No como identificador permanente. Los nombres cambian, ocurren duplicados y dos clientes pueden compartir un correo electrónico. Almacena el ID inmutable del proveedor y mantén tu propio ID de SaaS junto a él.

Lecturas adicionales