n8n: HTTP Request para chamar e Code para verificar
Tampouco hai nodo oficial, e aquí importa menos ca en ningún sitio: n8n ten un nodo de código, e iso é o que fai falta para comprobar a sinatura dun webhook antes de fiarse del.
A API está en marcha. Isto é o que hai hoxe e o que non
Funciona. As rutas desta documentación están despregadas e respondendo en https://erp.cairos.es/api/v1/. Os exemplos destas páxinas pódense copiar e executar. A especificación completa está en openapi.json, que é o que importan Make e n8n.
As claves créalas ti, desde Desenvolvedores na túa conta de Cairos. Comeza cunha cai_test_: traballa contra os teus datos de verdade pero non rexistra en VeriFactu nin envía correos, así que podes montar a túa integración sen enlixar unha serie de facturación.
E o que aínda NON hai, dito sen adornos: ningún conector oficial. Nin app de Shopify, nin plugin de WooCommerce, nin módulo publicado en Make ou n8n. Coa API e a súa especificación pódense construír —para iso están as guías desta sección— pero construílos é traballo, e ese traballo non está feito.
Se montas algo con isto, escríbenos a hola@cairos.es. Interésanos especialmente o que che falte do contrato: é o que decide que se amplía primeiro.
Non hai nodo oficial de Cairos en n8n
Non está publicado e non hai data. O que hai é a API —coa súa lista de eventos, o seu OpenAPI e os seus webhooks— e esta páxina, que che di exactamente que enganchar e con que código. Dentro de Cairos hai ademais receitas xa montadas e un fluxo de n8n descargable, en API e integracións → Comezar.
Se a túa tenda é de PrestaShop, este é o teu camiño
Cairos conecta só con Shopify, WooCommerce e Odoo. Con PrestaShop aínda non, e está a medias a propósito: o tipo de IVE de cada liña non vén na liña —hai que resolvelo contra outros dous recursos da súa API—, os cupóns son un recurso aparte que se aplica ao pedido e non ás liñas, e cada tenda chámalle dun xeito distinto ao estado que significa «vendido», porque eses estados edítaos o comerciante. Facturar tres de cada catro pedidos e inventar o IVE do cuarto é peor ca dicir que non: o «non» vese o primeiro día e o IVE mal posto vese no 303.
Mentres tanto, os seus pedidos entran perfectamente por aquí: PrestaShop sabe avisar a un enderezo cando entra un pedido, e o que hai debaixo é exactamente o mesmo percorrido que conta esta páxina.
A credencial, que se monta unha vez
n8n non ten nodo de Cairos, e non fai falta: o nodo HTTP Request chama a calquera API. O que si convén montar ben desde o principio é a credencial, para non repetir a clave en cada nodo nin deixala escrita no fluxo.
Créase unha credencial de tipo Header Auth con estes dous valores:
Name: Authorization
Value: Bearer cai_live_TU_CLAVEA partir de aí, cada nodo HTTP Request usa esa credencial e non volve saber nada da clave. Cando a rotes, cámbiase nun sitio.
Chamar a Cairos
Un nodo HTTP Request por operación. O que hai que cubrir é sempre o mesmo:
| Campo do nodo | Valor |
|---|---|
| Method | POST |
| URL | https://erp.cairos.es |
| Authentication | Xenérica, coa credencial Header Auth de arriba |
| Send Body | Activado, en JSON |
| Headers | Idempotency-Key, co identificador do pedido do nodo anterior |
E activa o reintento do propio nodo só se puxeches a chave de idempotencia. Un reintento dun POST sen chave é a forma máis rápida de acabar con dúas facturas.
O corpo, en modo JSON, coas expresións de n8n para tomar os datos do nodo anterior:
{
"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
}
]
}Os nomes van tal cal: fecha_emision, descripcion e tipo_iva. Un campo que non existe non se ignora, devolve 422 e noméao en error.detalles.campos, así que ese é o primeiro sitio onde mirar cando o nodo se pon vermello.
Recibir sucesos de Cairos, que é onde n8n brilla
Aquí é onde n8n gaña ás alternativas sen código: ten un nodo de código onde se pode comprobar a sinatura dun webhook, que é o único que non é negociable ao abrir un extremo público.
A montaxe son tres nodos:
| # | Nodo | Que fai |
|---|---|---|
| 1 | Webhook | Recibe o POST de Cairos. Hai que activar a opción de corpo sen procesar: sen ela non se pode comprobar a sinatura. |
| 2 | Code | Comproba a sinatura co segredo da subscrición e corta se non cadra. |
| 3 | O que queiras | Avisar por Slack, escribir nunha folla, actualizar o pedido na túa tenda. |
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) }];Como se calcula esa sinatura e por que a marca de tempo vai dentro está en webhooks. E o enderezo que che dá o nodo Webhook é o que se rexistra con POST /webhooks.
Percorrer listas longas
Para ler todas as facturas dun ano non vale unha soa chamada: a API paxina con cursor. E aquí n8n ponno fácil, porque siguiente xa é a URL enteira da páxina que segue, cos teus filtros dentro: non hai que recompoñer ningunha consulta.
- Pide con
?limite=200&orden=antiguo, que é a orde que non se move mentres percorres. - Colle
siguienteda resposta e úsao como URL tal cal. Non é o id do último elemento nin un cursor que haxa que pegar a man en?desde=: é o enderezo completo. - Para cando
siguienteveña anull, non candodatosveña baleiro.
Na paxinación do propio nodo HTTP Request iso configúrase co modo de «seguinte URL» e a expresión {{ $response.body.siguiente }}, e a condición de parada é que ese campo sexa nulo.
O detalle da paxinación, co bucle escrito en JavaScript e en PHP, está en erros e paxinación.
Preguntas sobre n8n
Authorization e valor Bearer máis a clave. Os nodos referéncianna e non a conteñen, así que ao rotala cámbiase nun sitio.Idempotency-Key. Un reintento dun POST sen chave é exactamente como se acaba con dúas facturas do mesmo pedido.Monta o fluxo e cobre a credencial
As rutas, as cabeceiras e a sinatura son as que usa o servidor hoxe. A clave créala ti desde a túa conta, e cunha de probas podes lanzar o fluxo sen enlixar nada.
HTTP Request · Header Auth · Corpo sen procesar no Webhook