n8n: HTTP Request per cridar i Code per verificar
Tampoc no hi ha node oficial, i aquí importa menys que enlloc: n8n té un node de codi, i això és el que cal per comprovar la signatura d'un webhook abans de fiar-se'n.
L'API està en marxa. Això és el que hi ha avui i el que no
Funciona. Les rutes d'aquesta documentació estan desplegades i responent a https://erp.cairos.es/api/v1/. Els exemples d'aquestes pàgines es poden copiar i executar. L'especificació completa és a openapi.json, que és el que importen Make i n8n.
Les claus te les crees tu, des de Desenvolupadors al teu compte de Cairos. Comença amb una cai_test_: treballa contra les teves dades de veritat però no registra a VeriFactu ni envia correus, així que pots muntar la teva integració sense embrutar una sèrie de facturació.
I el que encara NO hi ha, dit sense adorns: cap connector oficial. Ni app de Shopify, ni plugin de WooCommerce, ni mòdul publicat a Make o n8n. Amb l'API i la seva especificació es poden construir —per això hi ha les guies d'aquesta secció— però construir-los és feina, i aquesta feina no està feta.
Si muntes alguna cosa amb això, escriu-nos a hola@cairos.es. Ens interessa especialment el que et falti del contracte: és el que decideix què s'amplia primer.
No hi ha node oficial de Cairos a n8n
No està publicat i no hi ha data. El que hi ha és l'API —amb la seva llista d'esdeveniments, la seva OpenAPI i els seus webhooks— i aquesta pàgina, que et diu exactament què connectar i amb quin codi. Dins de Cairos hi ha, a més, receptes ja muntades i un flux d'n8n descarregable, a API i integracions → Comença.
Si la teva botiga és de PrestaShop, aquest és el teu camí
Cairos connecta només amb Shopify, WooCommerce i Odoo. Amb PrestaShop encara no, i està a mitges a propòsit: el tipus d'IVA de cada línia no ve a la línia —cal resoldre'l contra dos recursos més de la seva API—, els cupons són un recurs a part que s'aplica a la comanda i no a les línies, i cada botiga anomena d'una manera diferent l'estat que significa «venut», perquè aquests estats els edita el comerciant. Facturar tres de cada quatre comandes i inventar-se l'IVA de la quarta és pitjor que dir que no: el «no» es veu el primer dia i l'IVA mal posat es veu al 303.
Mentrestant, les seves comandes entren perfectament per aquí: PrestaShop sap avisar una adreça quan entra una comanda, i el que hi ha a sota és exactament el mateix recorregut que explica aquesta pàgina.
La credencial, que es munta un sol cop
n8n no té node de Cairos, i no cal: el node HTTP Request crida qualsevol API. El que sí que convé muntar bé des del principi és la credencial, per no repetir la clau a cada node ni deixar-la escrita al flux.
Es crea una credencial de tipus Header Auth amb aquests dos valors:
Name: Authorization
Value: Bearer cai_live_TU_CLAVEA partir d'aquí, cada node HTTP Request fa servir aquesta credencial i no torna a saber res de la clau. Quan la rotis, es canvia en un sol lloc.
Cridar Cairos
Un node HTTP Request per operació. El que cal omplir és sempre el mateix:
| Camp del node | Valor |
|---|---|
| Method | POST |
| URL | https://erp.cairos.es |
| Authentication | Genèrica, amb la credencial Header Auth de dalt |
| Send Body | Activat, en JSON |
| Headers | Idempotency-Key, amb l'identificador de la comanda del node anterior |
I activa el reintent del mateix node només si has posat la clau d'idempotència. Un reintent d'un POST sense clau és la manera més ràpida d'acabar amb dues factures.
El cos, en mode JSON, amb les expressions d'n8n per prendre les dades del node 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
}
]
}Els noms van tal qual: fecha_emision, descripcion i tipo_iva. Un camp que no existeix no s'ignora, retorna 422 i el nomena a error.detalles.campos, així que aquest és el primer lloc on mirar quan el node es posa vermell.
Rebre esdeveniments de Cairos, que és on n8n brilla
Aquí és on n8n guanya les alternatives sense codi: té un node de codi on es pot comprovar la signatura d'un webhook, que és l'única cosa que no és negociable en obrir un extrem públic.
El muntatge són tres nodes:
| # | Node | Què fa |
|---|---|---|
| 1 | Webhook | Rep el POST de Cairos. Cal activar l'opció de cos sense processar: sense ella no es pot comprovar la signatura. |
| 2 | Code | Comprova la signatura amb el secret de la subscripció i talla si no quadra. |
| 3 | El que vulguis | Avisar per Slack, escriure en un full, actualitzar la comanda a la teva botiga. |
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) }];Com es calcula aquesta signatura i per què la marca de temps va a dins és a webhooks. I l'adreça que et dóna el node Webhook és la que es registra amb POST /webhooks.
Recórrer llistes llargues
Per llegir totes les factures d'un any no serveix una sola crida: l'API pagina amb cursor. I aquí n8n ho posa fàcil, perquè siguiente ja és la URL sencera de la pàgina que segueix, amb els teus filtres a dins: no cal recompondre cap consulta.
- Demana amb
?limite=200&orden=antiguo, que és l'ordre que no es mou mentre el recorres. - Agafa
siguientede la resposta i fes-lo servir com a URL tal qual. No és l'id de l'últim element ni un cursor que s'hagi d'enganxar a mà a?desde=: és l'adreça completa. - Para quan
siguientevingui anull, no quandatosvingui buit.
Al paginat del mateix node HTTP Request això es configura amb el mode de «següent URL» i l'expressió {{ $response.body.siguiente }}, i la condició d'aturada és que aquest camp sigui nul.
El detall de la paginació, amb el bucle escrit en JavaScript i en PHP, és a errors i paginació.
Preguntes sobre n8n
Authorization i valor Bearer més la clau. Els nodes la referencien i no la contenen, així que en rotar-la es canvia en un sol lloc.Idempotency-Key. Un reintent d'un POST sense clau és exactament com s'acaba amb dues factures de la mateixa comanda.Munta el flux i omple la credencial
Les rutes, les capçaleres i la signatura són les que fa servir el servidor avui. La clau te la crees tu des del teu compte, i amb una de proves pots llançar el flux sense embrutar res.
HTTP Request · Header Auth · Cos sense processar al Webhook