n8n
Lo mismo que con Make, con nodos de n8n: un flujo que recibe los avisos de tu cuenta, comprueba que vienen de Kaptativa y sigue con la API o con otra aplicación.
Para qué sirve
n8n es una herramienta de automatización que se puede usar en su nube o instalar en un servidor propio. A diferencia de Make, permite escribir un trozo de código en un nodo, y por eso es la opción para verificar la firma de cada aviso antes de confiar en él.
Esta guía arma un flujo con el evento inmobiliaria.consulta.recibida («Consulta recibida»), cuyos datos son consulta_id, sobre y canal, y que termina en una fila de Google Sheets. Cualquier otro evento de Webhooks se arma igual.
Qué necesitás
- Una instancia de n8n con dirección pública en https. La nube de n8n la trae; si la instalás vos, el servidor tiene que ser alcanzable desde internet.
- Una cuenta de Kaptativa con API y MCP activo y permiso para crear destinos de webhook.
- Un token de Solo ver para el paso de la API, de Administración > API y MCP con Crear el token. Empieza con
kpt_; acá lo escribimoskpt_....
Pasos
1. El nodo Webhook
- En n8n, creá un flujo nuevo con Create workflow y agregá el nodo Webhook como primer paso.
- Configuralo así: HTTP Method en
POST, Path enkaptativa-consultas, Authentication enNone(la autenticación es la firma, que verificás más abajo) y Respond enImmediately, para contestar200enseguida. - Tocá Add option, elegí Raw Body y activalo. Este paso es imprescindible: la firma se calcula sobre el texto original, y sin esto n8n entrega el cuerpo ya separado en campos.
- El nodo muestra dos direcciones: Test URL y Production URL. Para probar usás la de test; para dejarlo andando, la de producción. Copiá la de test por ahora.
2. Registrar la dirección en Kaptativa
- En el panel, abrí Administración > API y MCP y tocá Webhooks.
- En Agregar un destino, ponele un nombre, pegá la dirección y elegí el evento
inmobiliaria.consulta.recibida. Tocá Agregar el destino. - Copiá el secreto de firma (
whsec_...): se muestra una sola vez. En n8n, guardalo como variable de entornoKAPTATIVA_WEBHOOK_SECRETO. Si tu plan de n8n trae Variables (Settings > Variables), también podés cargarlo ahí y leerlo como$vars.KAPTATIVA_WEBHOOK_SECRETOen lugar de$env. - En n8n, tocá Listen for test event en el nodo Webhook y, en Kaptativa, tocá Probar en el destino. El aviso llega como un evento
webhook.prueba.
3. El nodo de código que verifica la firma
- Agregá, a continuación del Webhook, un nodo Code. En Mode elegí Run Once for All Items y en Language, JavaScript.
- Pegá este código. Es el mismo de Verificar la firma, con el import cambiado por
requirey la lectura del cuerpo crudo al final.
const { createHmac, timingSafeEqual } = require("crypto");
// cuerpo: el texto crudo del pedido, sin volver a armarlo. secreto: el whsec_ del destino
function firmaValida(encabezados, cuerpo, secreto) {
const id = encabezados["webhook-id"];
const momento = encabezados["webhook-timestamp"];
const firmas = encabezados["webhook-signature"] ?? "";
// Un aviso de hace más de cinco minutos no se acepta
if (!id || !momento || Math.abs(Date.now() / 1000 - Number(momento)) > 300) return false;
// La clave son los bytes del secreto: lo que viene después de whsec_, decodificado de base64
const clave = Buffer.from(secreto.replace(/^whsec_/, ""), "base64");
const esperada = createHmac("sha256", clave).update(`${id}.${momento}.${cuerpo}`).digest();
// Puede venir más de una firma, separadas por espacios: alcanza con que una coincida
return firmas.split(" ").some((f) => {
const recibida = Buffer.from(f.replace(/^v1,/, ""), "base64");
return recibida.length === esperada.length && timingSafeEqual(recibida, esperada);
});
}
// El texto crudo del pedido: el nodo Webhook lo guarda como archivo (propiedad "data") cuando Raw Body está activo
const crudo = (await this.helpers.getBinaryDataBuffer(0, "data")).toString("utf8");
const encabezados = $input.first().json.headers;
// El secreto whsec_ del destino. Mejor en una variable de entorno de n8n; si tu n8n no deja leerlas, pegalo acá
const secreto = $env.KAPTATIVA_WEBHOOK_SECRETO;
const valido = firmaValida(encabezados, crudo, secreto);
// Si la firma no coincide, no se pasa nada: el flujo sigue solo con { valido: false }
return [{ json: valido ? { valido, id: encabezados["webhook-id"], evento: JSON.parse(crudo) } : { valido } }];En un n8n instalado por tu cuenta, el módulo crypto se habilita con la variable de entorno NODE_FUNCTION_ALLOW_BUILTIN=crypto, y las versiones nuevas bloquean por defecto la lectura de $env dentro de los nodos (N8N_BLOCK_ENV_ACCESS_IN_NODE). Si no podés cambiar eso, cargá el secreto como variable de n8n ($vars, si tu plan las incluye) o, como último recurso, pegalo en el código y no compartas ni exportes el flujo. En la nube de n8n, la disponibilidad de crypto en el nodo de código no la pudimos comprobar: si no está, preguntale al soporte de n8n.
4. Cortar si la firma no coincide
- Agregá un nodo If. En Conditions, elegí el campo
validocomo booleano, is true. - Seguí el flujo por la salida true. La salida false la dejás sin conectar o la mandás a un nodo Stop and Error con el mensaje «Aviso con firma inválida»: así queda registrado en las ejecuciones.
- Para descartar repetidos, guardá el
id(que es elwebhook-iddel aviso) de lo que ya procesaste, por ejemplo en una hoja aparte o con el nodo Remove Duplicates de n8n, usandoidcomo clave.
5. Llamar a la API con el nodo HTTP Request
Si querés sumar datos que el aviso no trae, agregá un nodo HTTP Request:
| Campo | Qué poner |
|---|---|
| Method | GET |
| URL | https://panel.kaptativa.app/api/v1/inmobiliaria/consultas |
| Authentication | Elegí Generic Credential Type y, en Generic Auth Type, Header Auth. En Header Auth account tocá Create new credential: Name Authorization, Value Bearer kpt_.... El token queda en las credenciales de n8n, no a la vista en el flujo. |
| Send Query Parameters | Activalo y sumá estado con el valor abiertas y limite con 25. |
| Options | Sin cambios. Si la respuesta es un error (401, 403, 429), el nodo corta el flujo. |
Con curl:
curl "https://panel.kaptativa.app/api/v1/inmobiliaria/consultas?estado=abiertas&limite=25" \
-H "Authorization: Bearer kpt_..."La respuesta tiene datos (una entrada por consulta: numero, persona, propiedad, canal, estado, asesor, demorada, mensaje) y paginacion, con siguiente para pedir la página que sigue (Paginación). Igual que con Make: la API no busca una consulta por el consulta_id del aviso; sirve para traer las abiertas. El límite es de 120 pedidos por minuto por token (Límites de uso), y las operaciones que cambian algo piden Idempotency-Key (Idempotencia).
6. Terminar en Google Sheets y activar
- Agregá el nodo Google Sheets con la operación Append Row. Conectá tu cuenta de Google con Create new credential si es la primera vez.
- Elegí la planilla y la hoja. En las columnas, arrastrá
evento.datos.consulta_id,evento.datos.sobre,evento.datos.canalyevento.creado. - Pasá la dirección al destino de Kaptativa: copiá la Production URL del nodo Webhook y, en el panel, tocá Editar en el destino, cambiá la dirección y guardá.
- Arriba a la derecha de n8n, activá el flujo con el interruptor Active (en las versiones nuevas, Publish). Un flujo sin activar no recibe nada en la dirección de producción.
Cómo comprobar que anda
- Con el flujo activo, tocá Probar en el destino de Kaptativa.
- En n8n, abrí Executions: tiene que haber una ejecución correcta, con el nodo If yendo por true.
- En Kaptativa, mirá el Registro de entregas del destino (con Actualizar): Entregada, código
200. - Para ver que la verificación sirve, mandá un POST a mano a la dirección de producción con un cuerpo cualquiera y sin firma: el flujo tiene que cortar en false.
Problemas comunes
| Qué pasa | Por qué y qué hacer |
|---|---|
Siempre da valido: false | Casi siempre es que falta activar Raw Body en el Webhook, o que el secreto está mal copiado o es de otro destino (si lo cambiaste con Cambiar el secreto, el anterior dejó de valer). Otra causa: el reloj del servidor de n8n difiere más de cinco minutos del real. |
El nodo de código dice que no encuentra data | Raw Body no está activo, o el nodo Webhook no es el que está justo antes del nodo Code. |
| Kaptativa muestra la entrega como fallida | El flujo está sin activar (la dirección de producción solo responde con el flujo activo) o n8n tardó más de 10 segundos. Con Respond en Immediately contesta enseguida. |
| Kaptativa no deja guardar la dirección | Tiene que ser https pública y sin puerto. Una instalación de n8n en un puerto como :5678 hay que ponerla detrás de un dominio con https normal. |
El nodo HTTP dice 401 | El token está mal escrito (Bearer, un espacio y el token), venció o se revocó. |
El nodo HTTP dice 403 o alcance | El token no ve el módulo Inmobiliaria. Revisá sus alcances en Administración > API y MCP. |
Para usarlo con cuidado
- El secreto de firma y el token son contraseñas: variables o credenciales de n8n, nunca en una nota del flujo ni en una captura.
- Dale al flujo un token de Solo ver si solo lee. Si algún día tiene que cambiar algo, un token aparte, con escritura solo en ese módulo.
- Un aviso puede llegar repetido o fuera de orden: descartá por
idy, si el orden importa, pedí el estado actual a la API.