Cairos
Facturación
Programa de facturaciónPresupuestosFacturas recurrentesGastos y proveedoresCobros y tesorería
Contabilidad e impuestos
ContabilidadModelos de HaciendaLibros registroInmovilizadoIGIC y Canarias
Operaciones
Inventario y almacenesCRMControl horarioProyectosSubvenciones y ayudas
Cumplimiento
VeriFactuTicketBAIFactura electrónicaToda la normativaSeguridad y datos
Por tipo de negocio
AutónomosPymesAsesorías y gestoríasExtranjeros en EspañaStartupsComercios y tiendas
Por sector
Hostelería y restaurantesConstrucción y reformasServicios profesionalesComercio electrónicoTodos los sectores
Por forma jurídica
AsociacionesFundacionesCooperativasClubes deportivosTodas las formas jurídicas
Cambiar de programa
ComparativasAlternativa a HoldedMigrar tus datos
Herramientas gratis
Plantilla de facturaCalculadora de IVACalculadora de IRPFTodas las herramientas
Aprender
GuíasGlosarioCalendario fiscalBlog
Desarrolladores
API y documentaciónEmpezar en cinco minutosReferencia de recursosWebhooks
Ayuda
Centro de ayudaContacto
Precios
Empieza gratis Iniciar sesión
Automatización

n8n: HTTP Request para llamar y Code para verificar

Tampoco hay nodo oficial, y aquí importa menos que en ningún sitio: n8n tiene un nodo de código, y eso es lo que hace falta para comprobar la firma de un webhook antes de fiarse de él.

Credencial Header AuthFirma comprobada en un nodo CodePaginación por cursor

La API está en marcha. Esto es lo que hay hoy y lo que no

Funciona. Las rutas de esta documentación están desplegadas y respondiendo en https://erp.cairos.es/api/v1/. Los ejemplos de estas páginas se pueden copiar y ejecutar. La especificación completa está en openapi.json, que es lo que importan Make y n8n.

Las claves te las creas tú, desde Desarrolladores en tu cuenta de Cairos. Empieza con una cai_test_: trabaja contra tus datos de verdad pero no registra en VeriFactu ni envía correos, así que puedes montar tu integración sin ensuciar una serie de facturación.

Y lo que todavía NO hay, dicho sin adornos: ningún conector oficial. Ni app de Shopify, ni plugin de WooCommerce, ni módulo publicado en Make o n8n. Con la API y su especificación se pueden construir —para eso están las guías de esta sección— pero construirlos es trabajo, y ese trabajo no está hecho.

Si montas algo con esto, escríbenos a info@cairos.es. Nos interesa especialmente lo que te falte del contrato: es lo que decide qué se amplía primero.

No hay nodo oficial de Cairos en n8n

No está publicado y no hay fecha. Lo que hay es la API —con su lista de eventos, su OpenAPI y sus webhooks— y esta página, que te dice exactamente qué enganchar y con qué código. Dentro de Cairos hay además recetas ya montadas y un flujo de n8n descargable, en API e integraciones → Empezar.

Si tu tienda es de PrestaShop, éste es tu camino

Cairos conecta solo con Shopify, WooCommerce y Odoo. Con PrestaShop todavía no, y está a medias a propósito: el tipo de IVA de cada línea no viene en la línea —hay que resolverlo contra otros dos recursos de su API—, los cupones son un recurso aparte que se aplica al pedido y no a las líneas, y cada tienda llama de una manera distinta al estado que significa «vendido», porque esos estados los edita el comerciante. Facturar tres de cada cuatro pedidos e inventarse el IVA del cuarto es peor que decir que no: el «no» se ve el primer día y el IVA mal puesto se ve en el 303.

Mientras tanto, sus pedidos entran perfectamente por aquí: PrestaShop sabe avisar a una dirección cuando entra un pedido, y lo que hay debajo es exactamente el mismo recorrido que cuenta esta página. Contado para quien vende y no para quien programa, está en Cairos y PrestaShop.

La credencial, que se monta una vez

n8n no tiene nodo de Cairos, y no hace falta: el nodo HTTP Request llama a cualquier API. Lo que sí conviene montar bien desde el principio es la credencial, para no repetir la clave en cada nodo ni dejarla escrita en el flujo.

Se crea una credencial de tipo Header Auth con estos dos valores:

Credencial Header Auth
Name:  Authorization
Value: Bearer cai_live_TU_CLAVE

A partir de ahí, cada nodo HTTP Request usa esa credencial y no vuelve a saber nada de la clave. Cuando la rotes, se cambia en un sitio.

Llamar a Cairos

Un nodo HTTP Request por operación. Lo que hay que rellenar es siempre lo mismo:

Campo del nodoValor
MethodPOST
URLhttps://erp.cairos.es/api/v1/facturas
AuthenticationGenérica, con la credencial Header Auth de arriba
Send BodyActivado, en JSON
HeadersIdempotency-Key, con el identificador del pedido del nodo anterior

Y activa el reintento del propio nodo sólo si has puesto la llave de idempotencia. Un reintento de un POST sin llave es la forma más rápida de acabar con dos facturas.

El cuerpo, en modo JSON, con las expresiones de n8n para tomar los datos del nodo anterior:

Body · JSON
{
  "contacto_id": "{{ $json.id }}",
  "serie": "WEB",
  "fecha_emision": "{{ $now.format('yyyy-MM-dd') }}",
  "lineas": [
    {
      "descripcion": "{{ $('Pedido').item.json.titulo }}",
      "cantidad": 1,
      "precio": 180.00,
      "tipo_iva": 21
    }
  ]
}

Los nombres van tal cual: fecha_emision, descripcion y tipo_iva. Un campo que no existe no se ignora, devuelve 422 y lo nombra en error.detalles.campos, así que ése es el primer sitio donde mirar cuando el nodo se pone rojo.

Recibir sucesos de Cairos, que es donde n8n brilla

Aquí es donde n8n gana a las alternativas sin código: tiene un nodo de código donde se puede comprobar la firma de un webhook, que es lo único que no es negociable al abrir un extremo público.

El montaje son tres nodos:

#NodoQué hace
1WebhookRecibe el POST de Cairos. Hay que activar la opción de cuerpo sin procesar: sin ella no se puede comprobar la firma.
2CodeComprueba la firma con el secreto de la suscripción y corta si no cuadra.
3Lo que quierasAvisar por Slack, escribir en una hoja, actualizar el pedido en tu tienda.
Nodo Code · comprobar la firma
const crypto = require("crypto");

const secreto = $env.CAIROS_SECRETO;
const entrada = $input.first().json;

// El cuerpo CRUDO, tal y como llegó. Si aquí usas el JSON ya
// convertido, la firma no cuadrará nunca y perderás una tarde.
const crudo = entrada.rawBody || entrada.body;
// La cabecera se llama "x-cairos-firma", en minuscula.
const cabecera = entrada.headers["x-cairos-firma"] || "";

const partes = Object.fromEntries(
  cabecera.split(",").map((t) => t.trim().split("="))
);

const ahora = Math.floor(Date.now() / 1000);
if (!partes.t || Math.abs(ahora - Number(partes.t)) > 300) {
  throw new Error("Suceso caducado o sin marca de tiempo");
}

const esperada = crypto
  .createHmac("sha256", secreto)
  .update(partes.t + "." + crudo)
  .digest("hex");

if (esperada !== partes.v1) {
  throw new Error("Firma no valida");
}

return [{ json: JSON.parse(crudo) }];

Cómo se calcula esa firma y por qué la marca de tiempo va dentro está en webhooks. Y la dirección que te da el nodo Webhook es la que se registra con POST /webhooks.

Recorrer listas largas

Para leer todas las facturas de un año no vale una sola llamada: la API pagina con cursor. Y aquí n8n lo pone fácil, porque siguiente ya es la URL entera de la página que sigue, con tus filtros dentro: no hay que recomponer ninguna consulta.

  • Pide con ?limite=200&orden=antiguo, que es el orden que no se mueve mientras recorres.
  • Coge siguiente de la respuesta y úsalo como URL tal cual. No es el id del último elemento ni un cursor que haya que pegar a mano en ?desde=: es la dirección completa.
  • Para cuando siguiente venga a null, no cuando datos venga vacío.

En el paginado del propio nodo HTTP Request eso se configura con el modo de «siguiente URL» y la expresión {{ $response.body.siguiente }}, y la condición de parada es que ese campo sea nulo.

El detalle de la paginación, con el bucle escrito en JavaScript y en PHP, está en errores y paginación.

Preguntas sobre n8n

No. Se usa el nodo HTTP Request con una credencial de tipo Header Auth. Para todo lo que describe esta documentación, es suficiente.
Con una credencial Header Auth: nombre Authorization y valor Bearer más la clave. Los nodos la referencian y no la contienen, así que al rotarla se cambia en un sitio.
Sí, y es donde n8n va mejor que las alternativas sin código: nodo Webhook con la opción de cuerpo sin procesar activada, y un nodo Code que comprueba la firma HMAC antes de seguir.
Casi siempre porque estás firmando contra el JSON ya convertido a objeto y vuelto a serializar, que no es idéntico al que llegó. Hay que activar el cuerpo sin procesar en el nodo Webhook y firmar contra eso.
Sí, pero sólo si mandas Idempotency-Key. Un reintento de un POST sin llave es exactamente cómo se acaba con dos facturas del mismo pedido.
Sí, y hoy es el camino. Cairos conecta solo con Shopify, WooCommerce y Odoo; con PrestaShop todavía no, porque su API no deja deducir con seguridad el tipo de IVA de cada línea ni los cupones. Con el webhook de pedido de PrestaShop entrando en el nodo Webhook y el recorrido de esta página, el pedido acaba en una factura emitida igual.
Sí, y se descarga desde el propio Cairos: API e integraciones → Empezar. Trae los nodos y las conexiones hechas, y la clave no va dentro del fichero: al importarlo, n8n te pide crear la credencial y ahí es donde se pega, una sola vez.

Monta el flujo y rellena la credencial

Las rutas, las cabeceras y la firma son las que usa el servidor hoy. La clave te la creas tú desde tu cuenta, y con una de pruebas puedes lanzar el flujo sin ensuciar nada.

HTTP Request · Header Auth · Cuerpo sin procesar en el Webhook

Soporte