Saltar al contenido
Integración

Integración con Holded: que tu web, tu tienda y tu almacén hablen con tu facturación

Si llevas la facturación en Holded, el trabajo repetido está siempre en el mismo sitio: alguien copia a mano en el ERP lo que ya existe en la web o en el almacén. Conectamos ambos lados para que un pedido genere su documento solo, con los precios correctos y sin duplicar nada cuando algo falla y se reintenta.

En corto

  • Se conectan contactos, productos, albaranes, facturas y stock. Cada pieza tiene su propia trampa.
  • Todo documento creado por API en Holded nace en borrador y sin número. Validarlo lo hace una persona desde la interfaz. Cualquier diseño que prometa emisión automática está mintiendo.
  • La idempotencia no es un adorno: sin ella, un reintento tras un timeout duplica un documento fiscal que además mueve stock.
  • La API v2 devuelve los importes como texto con coma española, pero si los escribes con coma los trunca al entero sin avisar.
  • Yo verifico cada campo contra la API real creando un borrador y borrándolo, no contra la documentación.

Antes de seguir

No somos asesoría fiscal ni contable. Esta página describe cómo se integra software con Holded, no cómo debes facturar. Las decisiones fiscales y contables las valida tu asesor. El comportamiento de la API descrito aquí procede de pruebas reales contra cuentas en producción y puede cambiar cuando Holded actualice su plataforma.

Qué se conecta exactamente entre tu web y Holded

Una integración con Holded no es un botón. Son cuatro flujos distintos, y cada uno se puede activar o no según lo que necesites. Lo habitual es empezar por uno solo, el que más tiempo te está costando a mano, y ampliar después.

  • Contactos: el cliente que compra en tu web acaba como ficha en Holded, sin duplicarse.
  • Productos y tarifas: el catálogo del ERP alimenta la web, incluidos los precios por cliente.
  • Albaranes y facturas: cada pedido genera su documento con sus líneas, sus precios y sus impuestos.
  • Stock: el inventario de Holded y el de tu sistema dejan de contradecirse.
  • Documentos hacia el cliente final: el PDF oficial del albarán o la factura, servido desde tu propia web.

El caso típico: un pedido que genera su albarán sin teclearlo dos veces

El flujo que más se pide es este. Entra un pedido por la web, por el comercial o por el almacén. El sistema busca al cliente en Holded por su NIF normalizado y solo lo crea si de verdad no existe. Monta las líneas con el producto vinculado, con el precio que corresponde a ese cliente y con sus códigos de impuesto. Crea el albarán. Guarda el identificador interno del documento y deja constancia de qué pedido lo originó. Después, un barrido periódico vuelve a leer el documento hasta que aparece su número definitivo, y ese número es el que ve tu equipo y el que se usa para conciliar. Nadie vuelve a teclear el pedido. El trabajo humano que queda es el que tiene que quedar: aprobar el documento en Holded.

Por qué la idempotencia importa más que cualquier otra cosa

Idempotencia significa que repetir la misma operación no crea dos resultados. En una integración de facturación es la diferencia entre un sistema fiable y uno que genera trabajo. El escenario es banal: el POST llega a Holded, el documento se crea, y la respuesta se pierde por un timeout o porque el proceso muere. Tu lado no sabe que existe, reintenta, y ahora hay dos albaranes reales, con dos movimientos de stock, que alguien tiene que localizar, anular y explicarle al asesor. Y la API de Holded no ayuda: en la v2 no hay cabecera de idempotencia ni un campo propio donde colgar tu identificador. Así que la protección hay que construirla.

  • Escribo un marcador propio como prefijo de la descripción del documento y lo busco antes de cada creación.
  • La comparación es por prefijo exacto, nunca por igualdad ni por coincidencia parcial: un número como ALB-2026-0001 casaría con ALB-2026-00012.
  • La búsqueda no puede ser best-effort. Si falla la comprobación, no se crea el documento: se marca en error, se reintenta si el fallo es transitorio y salta aviso si persiste.
  • La ventana de búsqueda no pueden ser los cien últimos documentos. Tras una caída larga, el original ya no está ahí y el reintento duplica en silencio.
  • Al guardar la clave de API compruebo que tiene permiso de lectura de albaranes. Sin ese permiso la protección antiduplicados no existe, así que preferimos no dejar guardar la clave.

Todo documento creado por API nace en borrador, y eso no se puede saltar

Esta es la expectativa que más conviene romper antes de empezar. Un documento creado por la API de Holded se queda en borrador y sin numerar. Puedes pedir explícitamente que no sea borrador, actualizarlo después, o llamar al endpoint que parece aprobarlo: sigue en borrador. La validación, que es la que elige serie y asigna número, la hace una persona con el botón de aprobar de la interfaz. Peor todavía: el endpoint de aprobación de albaranes deja el documento marcado como aprobado sin validarlo, y con eso la interfaz esconde el botón que sí lo validaba. El resultado es un documento aprobado pero en borrador que ya no puede validar ni la API ni la interfaz. Los que salen así hay que borrarlos y rehacerlos. Por eso en el código que escribo esa llamada está eliminada a conciencia, con un comentario en el sitio exacto donde estuvo, para que nadie la reintroduzca al topar otra vez con el problema. La consecuencia de diseño es clara: el estado sincronizado de tu lado significa que el borrador existe en Holded, nunca que el documento está emitido. Y la interfaz tiene que decírselo al usuario como aviso normal, pendiente de aprobar, no como error. Si no, nadie entiende por qué sus documentos no tienen número.

Las trampas reales del minado con la API de Holded

Ninguna de estas está en la documentación. Todas se pagan en producción, y varias tardan meses en detectarse porque no dan error.

  • La v1 está muerta para cualquier clave emitida hoy, y las credenciales son incompatibles en los dos sentidos: no puedes migrar endpoint a endpoint. Hay que ir a la v2 entera de golpe y asumir a la vez el cambio de errores, de paginación por cursor, de nombres de campo y de formato de fechas.
  • Los importes son asimétricos. La v2 devuelve los números como texto con coma española, pero si escribes con coma la API corta en la coma y guarda el entero: 6,83 se convierte en 6,00 euros, sin error y sin aviso. Las unidades se salvan por casualidad porque suelen ser enteras, así que el documento parece correcto y solo los precios están mal.
  • El esquema de escritura no es el de lectura. Si construyes el cuerpo copiando lo que te devolvió la lectura del mismo recurso, la API lo rechaza: las líneas se leen con un nombre y se escriben con otro.
  • La creación no devuelve el número del documento, y ese número puede tardar semanas en existir porque depende de que un humano valide. Hay que ir a buscarlo con un barrido, y ponerle freno para no preguntar cien veces al día por algo que solo cambia cuando alguien actúa.
  • Forzar la serie de numeración puede reasignar números ya emitidos, porque el contador que expone la API puede ir muy por detrás de los documentos que existen. Y Holded no impone que el número visible sea único: he visto un contador retroceder y dejar pares de albaranes reales compartiendo número.
  • El filtro por cliente funciona con un nombre concreto de parámetro; sus variantes no filtran y devuelven el listado completo. En un portal donde cada cliente ve sus documentos, eso significa enseñarle los de todos los demás. Es el fallo más peligroso de todos porque aparenta funcionar.
  • La fecha final de un rango es exclusiva: los documentos de hoy no vienen si pides hasta hoy. Y las fechas hay que anclarlas a la zona de Madrid en los dos sentidos, o un documento emitido de madrugada se registra con fecha del día anterior.

Cuidado con el stock: una línea vinculada mueve inventario real

La diferencia entre una línea de texto y una línea vinculada a un producto no es cosmética. La vinculada descuenta stock del almacén, y lo hace ya con el documento en borrador. Lo he comprobado: el inventario baja con el borrador vivo. Esto es una herramienta, no un problema, siempre que se sepa: es el canal por el que sale el stock. Pero significa que crear un borrador de prueba con líneas vinculadas mueve inventario real de tu empresa. Borrar el documento restituye el movimiento, así que un test completo puede dejar el almacén exactamente como estaba. Por el otro lado, el ajuste de stock por API funciona por diferencia, no por valor absoluto, y exige un campo obligatorio que no es evidente. Como el esquema de escritura es terreno resbaladizo, dejamos siempre un fusible: tras la primera escritura de cada pasada releemos el dato y, si no coincide con lo que escribí, corto la pasada entera.

Precios e impuestos: lo que la API no rellena sola

Dos comportamientos que parecen contradictorios y son los dos ciertos. Una línea vinculada a un producto pero sin precio se queda a cero: Holded no va a buscar el precio de la ficha, hay que enviárselo. Y reescribir las líneas de un documento las sustituye todas, así que una simple modificación de pedido puede borrar los precios que alguien había puesto a mano en el ERP. Por eso antes de reescribir leo lo que ya tiene el documento y lo conservo: si una persona lo tocó allí, esa es la última decisión. Con el precio por cliente pasa algo parecido. Holded lo modela con listas de tarifas y no hay ningún sitio que te diga el precio de este producto para este cliente: hay que cruzar la tarifa del contacto con la entrada correspondiente en la ficha del producto, y coger de ahí también los impuestos, que pueden ser distintos de los de la ficha base. Si no envías los códigos de impuesto en las líneas de texto suelto, el documento sale con la leyenda de IVA no incluido y hay que retocarlo a mano uno por uno.

Qué hace falta para conectar tu sistema con Holded

Poco, y todo de tu lado. Una clave de API de la versión 2 con los permisos concretos que necesita el flujo, ni más ni menos: lectura de contactos, lectura de envíos, que es la pata que sostiene la protección antiduplicados, y escritura de envíos. Cuando falta un permiso, la API dice exactamente cuál, y ese mensaje se lo traslado al administrador tal cual, para que sepa qué conceder en lugar de recibir un error opaco, revocar la clave y volver a fallar igual. También hace falta acordar dos cosas de proceso: quién aprueba los documentos en Holded y cada cuánto, y qué se hace con un cliente sin NIF, porque a ese no se le crea ficha a ciegas. Del resto me ocupo yo, y lo verifico contra tu cuenta real antes de que nada se ponga en marcha.

Preguntas frecuentes

¿Se puede emitir la factura automáticamente desde mi web con Holded?+

No. Un documento creado por la API de Holded nace en borrador y sin número, y no hay ninguna forma por API de validarlo: ni pidiendo que no sea borrador, ni actualizándolo después, ni llamando al endpoint que parece aprobarlo. La validación la hace una persona desde la interfaz de Holded. Lo que sí se automatiza es todo lo anterior: el contacto, las líneas, los precios, los impuestos y el propio borrador. El clic final es humano, y la interfaz debe avisar de que ese paso existe.

¿Qué pasa si la conexión falla justo después de crear un documento?+

Ese es el escenario para el que se diseña la integración. Si la petición llega a Holded pero la respuesta se pierde, el documento existe y tu sistema no lo sabe. Sin protección, el reintento crea un duplicado que además mueve stock. La solución es marcar cada documento con un identificador propio y buscarlo antes de cada creación. Y si esa comprobación no se puede hacer, no se crea nada: el documento queda en error y se reintenta o se avisa, pero nunca se crea a ciegas.

Tengo una integración con Holded que funciona desde hace años. ¿Me afecta el cambio de versión?+

Si está construida sobre la versión 1 de la API, sí. Una clave emitida hoy no funciona contra la v1, y la clave antigua no funciona contra la v2. No hay convivencia, así que no se puede migrar poco a poco con la misma credencial. La integración sigue viva mientras nadie rote la clave, y se rompe el día que alguien la rota. Merece la pena planificar el salto antes de que lo decida un incidente.

¿Puedo enseñarle a mi cliente sus albaranes y facturas desde mi propia web?+

Sí, con el PDF oficial. El portal de documentos de Holded exige sesión de Holded, así que cualquier enlace que construyas desde fuera muere en su pantalla de acceso. En cambio el PDF sí es accesible por API. Lo sirvo desde una función propia con enlace firmado y caducidad, generado siempre en el servidor, de modo que tu cliente ve el documento oficial sin tocar Holded ni conocer identificadores internos.

¿Por qué mi catálogo se duplica al importarlo desde Holded?+

Porque Holded no tiene niveles de empaquetado. Las cajas y los palés no son un campo de unidades por caja: son productos independientes de tipo pack que apuntan al producto simple con un factor. Si importas el catálogo tal cual, cada artículo aparece tantas veces como formatos tenga. Hay que agrupar por la referencia interna del pack, no por parecido de nombres, y colapsar cada grupo en un producto con sus códigos de barras y sus factores.

¿Cómo verificas que la integración hace lo que dice?+

Contra la API real, no contra la documentación. Cada campo de escritura se comprueba creando un documento en borrador, leyéndolo de vuelta y borrándolo, que además restituye el stock movido. La documentación de Holded tiene puntos donde no coincide con el comportamiento, y hay respuestas que devuelven éxito sin aplicar nada. Un endpoint que contesta que todo ha ido bien y no persiste el cambio es el peor tipo de fallo que puede tener una integración de facturación.

¿Llevas la facturación en Holded y sigues copiando datos a mano?

Cuéntanos qué se teclea dos veces en tu empresa y desde dónde: la web, la tienda, el almacén o el comercial. Revisamos el flujo y te decimos qué parte se puede conectar de verdad, qué parte va a seguir necesitando un clic humano y por qué. Sin compromiso y sin venderte automatización que la API no permite.

Cuéntanos tu caso