Entradas

Mostrando las entradas de septiembre, 2026

Qué es n8n y qué tareas conviene automatizar

Copiar datos entre herramientas puede convertirse en una tarea diaria. Antes de automatizarla, necesitas saber qué la inicia, qué regla debes aplicar y cómo reconocer un resultado correcto. n8n permite conectar esos pasos en un editor visual.

En este artículo aprenderás a elegir una primera tarea y construirás una prueba pequeña: separar un producto ficticio cuando sus existencias estén por debajo del mínimo. El resultado será una salida que puedas inspeccionar, sin enviar correos ni modificar un inventario real.

Qué es n8n

n8n es una herramienta de automatización. Un workflow, o flujo de trabajo, reúne pasos conectados; cada paso se llama nodo. Un nodo puede iniciar el proceso, preparar datos, comparar valores o comunicarse con otra aplicación. La documentación oficial explica estos conceptos en su glosario.

Piensa en una instrucción cotidiana: «Cuando revise las existencias, separa los productos que tengan menos unidades que el mínimo». El inicio es revisar; los datos son las unidades y el mínimo; la regla es una comparación; el resultado es una lista para revisar.

No necesitas añadir inteligencia artificial a esta regla. n8n también permite construir procesos con IA, pero comparar dos números se resuelve directamente. El primer workflow de la documentación muestra cómo combinar pasos y condiciones.

Qué tareas conviene automatizar primero

Como criterio de Flujoteca, busca una tarea que puedas explicar con una frase y comprobar con un ejemplo. Antes de abrir el editor, responde:

  • ¿Se repite? Reunir el mismo dato cada semana suele justificar mejor el esfuerzo que una tarea de una sola vez.
  • ¿La entrada es clara? Debes saber de dónde sale cada dato y qué significa.
  • ¿La regla es explícita? «Menos de cinco unidades» es comprobable; «cuando parezca importante» necesita una decisión más precisa.
  • ¿El resultado es visible? Una fila, un borrador o una salida de prueba se pueden cotejar.
  • ¿Un error se puede contener? Empieza preparando información para revisar antes de automatizar envíos, compras o borrados.

Algunos candidatos son ordenar registros por estado, preparar un resumen o crear un borrador a partir de una fila aprobada. Si cada caso exige una excepción nueva, primero aclara el proceso. Automatizar reglas confusas puede repetir el mismo error más rápido.

También cuenta el mantenimiento. Una estimación sencilla es comparar el tiempo que hoy dedicas a la tarea con el tiempo de construir, revisar y mantener el flujo. Ese cálculo orienta una decisión; no garantiza un ahorro.

Dónde se ejecuta

Puedes usar n8n Cloud, con infraestructura administrada por n8n, o alojarlo por tu cuenta (self-hosted). En la segunda opción, también te corresponde mantener el entorno. Consulta las opciones oficiales de uso antes de elegir.

Este ejercicio parte de una instancia disponible. No requiere cambiar de plan, instalar extensiones ni conectar servicios de Google. Si usas Cloud, los datos del ejercicio se procesarán allí; por eso usaremos información ficticia.

Resultado que obtendrás

  • Un flujo de tres nodos que se inicia manualmente.
  • Un producto ficticio con existencias y mínimo numéricos.
  • Una salida true cuando falten unidades y false cuando no se cumpla esa regla.

Antes de comenzar

Necesitas acceso al editor de n8n y un workflow nuevo. Usa solo este dato ficticio: Cuaderno DEMO. No añadas credenciales, nodos de correo ni conexiones a una hoja real. Conserva el inicio manual durante toda la prueba.

Flujo completo

Este diagrama representa el ejercicio, no un sistema completo de compras:

Manual Trigger
      |
      v
Edit Fields: producto, existencias, minimo
      |
      v
If: existencias < minimo
      |
      +-- true  --> revisar faltante
      |
      +-- false --> no cumple la regla

Las dos salidas terminan en el propio nodo If. «Revisar faltante» describe lo que harías con el resultado; no hay un nodo que envíe un aviso o compre productos.

Paso 1: iniciar manualmente

Crea un workflow vacío y añade Manual Trigger. Este disparador te permite decidir cuándo ejecutar el ejemplo. Ponle al workflow un nombre reconocible, como Prueba de inventario DEMO.

Paso 2: preparar un solo producto

Conecta Edit Fields (Set) y selecciona Manual Mapping. Añade estos campos con valores fijos:

  • producto: tipo String, valor Cuaderno DEMO.
  • existencias: tipo Number, valor 3.
  • minimo: tipo Number, valor 5.

String significa texto y Number significa número. Mantén los nombres sin espacios ni tildes: minimo será el nombre que leerá la condición. El nodo Edit Fields permite crear o cambiar campos; aquí solo prepara el dato ficticio.

Paso 3: comparar existencias con el mínimo

Conecta un nodo If. En Conditions, configura una comparación de tipo Number con la operación is less than («es menor que»).

En el primer valor, activa Expression e introduce:

{{ $json.existencias }}

En el segundo valor, también como expresión, introduce:

{{ $json.minimo }}

Una expresión lee un dato en lugar de usar un valor fijo. Aquí $json representa los campos del elemento que entra al nodo. La condición pregunta si 3 es menor que 5. La documentación de If describe las comparaciones disponibles.

Cómo comprobar que funciona

Ejecuta el workflow completo con Execute workflow. Abre la salida de Edit Fields y comprueba que contiene un solo elemento con los tres campos. Después revisa ambas salidas de If.

Haz estas pruebas por separado, cambiando únicamente existencias y volviendo a ejecutar el flujo completo:

  • Con 3: un elemento en true y ninguno en false.
  • Con 5: ninguno en true y un elemento en false.
  • Con 8: ninguno en true y un elemento en false.

La prueba con 5 comprueba el límite: «menor que» excluye la igualdad. Cada resultado debe conservar el producto y los dos números. Una salida vacía en la rama que no corresponde es normal.

Verificación editorial: ejecutado en n8n 2.22.5 el 22 de septiembre de 2026, con datos ficticios. Los casos 3, 5 y 8 produjeron respectivamente true, false y false, conservando los tres campos. La documentación de Edit Fields e If se volvió a revisar en esa fecha.

Errores habituales

El resultado del límite no coincide

Si el valor 5 entra en true, revisa si seleccionaste «menor o igual que» en lugar de is less than. Comprueba también que el mínimo siga siendo 5.

La condición no recibe el dato esperado

Abre la entrada de If. Si no aparece existencias o minimo, coteja el nombre del campo con la expresión y ejecuta nuevamente el workflow desde el inicio. Escribir mínimo y leer minimo no identifica el mismo campo.

Aparece un problema de tipos

Revisa que ambos campos estén definidos como Number, no como String. No actives conversiones automáticas solo para ocultar un problema de datos: primero comprueba qué valor recibe la condición.

Estos son puntos de diagnóstico de la configuración; no significan que un aviso se haya enviado. El ejemplo solo compara datos dentro del flujo.

Seguridad y privacidad

Trabaja con información ficticia hasta entender cada paso. Una ejecución manual puede tener efectos reales si después añades nodos que envían, escriben o borran información. Las credenciales de otros servicios se configuran en tu instancia y no deben aparecer en capturas ni archivos compartidos.

Antes de ampliar el flujo, decide qué ocurrirá si falta un número, llega un valor negativo o se ejecuta dos veces. Este ejemplo no valida esas situaciones, no gestiona inventario y no evita avisos duplicados. Tampoco realiza pedidos automáticos.

Cómo seguir

Ya tienes las piezas de una automatización: inicio, datos, regla y resultado verificable. El siguiente paso razonable es elegir una tarea pequeña de tu trabajo y escribir esas cuatro partes antes de conectar cuentas reales.

Para ver una aplicación con revisión humana, consulta cómo convertir una fila aprobada en un borrador de Blogger. Allí la preparación y la publicación siguen siendo pasos separados.

Fuentes oficiales

Convertir una fila aprobada de Google Sheets en un borrador de Blogger

Una hoja editorial puede funcionar como una cola de revisión sencilla: una persona prepara el título y el HTML, cambia el estado a aprobado y n8n crea un borrador en Blogger. Este tutorial usa la API oficial de Blogger mediante HTTP Request y fuerza isDraft=true, de modo que la revisión final sigue siendo manual.

El diseño también guarda el ID que devuelve Blogger en la misma fila. Tras una ejecución serial satisfactoria, esa marca evita que una nueva ejecución procese de nuevo el mismo content_id. No cubre un fallo entre crear el borrador y guardar el ID, ni dos ejecuciones simultáneas.

Estado de verificación: la prueba controlada quedó registrada el 2026-09-13 con n8n 2.22.5. Se usó un blog DEMO privado, una fila aprobada y una credencial dedicada con la cuenta conectada y el alcance de Blogger. La segunda ejecución serial no creó otro borrador. La prueba no acredita seguridad ante ejecuciones concurrentes ni autoriza activar el Schedule.

Resultado que obtendrás

  • Una hoja Editorial con una fila de ejemplo aprobada y sin blogger_post_id.
  • Un workflow que selecciona solo filas aprobadas que aún no tienen ID de Blogger.
  • Una llamada POST a posts.insert con isDraft=true y una actualización de la fila con el ID devuelto.
  • Un control serial para no publicar automáticamente ni volver a enviar una fila que ya tenga un ID guardado.

Antes de comenzar

  • Una instancia de n8n y un documento de Google Sheets de prueba.
  • Un blog de Blogger de prueba y su blogId. En este artículo se usa el marcador REEMPLAZAR_BLOG_ID; no lo sustituyas por un ID real dentro de una captura o exportación compartida.
  • Una credencial dedicada de Google para el nodo HTTP Request, configurada como Predefined Credential Type con Credential Type: Google OAuth2 API, autorizada para Blogger con el alcance https://www.googleapis.com/auth/blogger. La cuenta debe mostrar Account connected y tener acceso al blog de prueba. La autorización se configura en tu entorno; no se incluye ningún secreto.
  • Una pestaña Editorial con estos encabezados:
    content_id | titulo | html | etiquetas | estado | blogger_post_id | draft_url
    
  • Una sola fila de prueba:
    contenido-demo-001 | Webhooks de prueba | <h2>Una prueba controlada</h2><p>Contenido sin datos personales.</p> | n8n, borrador | aprobado |  |
    
  • La API de Blogger permite isDraft=true en posts.insert; no uses el endpoint de publicación en este flujo.

Flujo completo

Manual Trigger
      |
      v
Google Sheets: Get Row(s) de Editorial
      |
      v
Code: estado aprobado y sin ID
      |
      +------------------------------+
      |                              |
      v                              |
HTTP Request: Blogger posts.insert  +--> Merge: combinar respuesta y fila
                                     |
                                     v
                         Code: preparar actualización
                                     |
                                     v
                  Google Sheets: Update Row
                         (clave = content_id)

El Merge conserva los datos de la fila mientras incorpora la respuesta de Blogger. Si tu versión de n8n ofrece una opción equivalente para incluir los datos de entrada en HTTP Request, puedes usarla; en ambos casos, comprueba que content_id siga presente antes de escribir en Sheets.

Paso 1: leer la cola editorial

  1. Añade un Manual Trigger. No uses Schedule Trigger hasta completar la prueba manual.
  2. Conecta un nodo Google Sheets y selecciona la operación Get Row(s) (el nombre puede aparecer como “Get Rows”).
  3. Elige el documento de prueba y la pestaña Editorial.
  4. Usa la credencial de Google autorizada para ese documento.

La primera fila debe contener los encabezados. No incluyas una fila vacía antes de ellos. Devuelve una fila a la vez si tu documento contiene más datos durante la prueba.

Paso 2: aplicar la compuerta de idempotencia

Conecta un nodo Code después de Sheets, selecciona Run Once for All Items y pega este filtro:

const candidates = $input.all().filter((item) => {
  const estado = String(item.json?.estado ?? '').trim().toLowerCase();
  const postId = String(item.json?.blogger_post_id ?? '').trim();
  return estado === 'aprobado' && !postId;
});

return candidates.map((item) => {
  const row = item.json ?? {};
  const contentId = String(row.content_id ?? '').trim();
  const titulo = String(row.titulo ?? '').trim();
  const html = String(row.html ?? '').trim();
  const missing = [];

  if (!contentId) missing.push('content_id');
  if (!titulo) missing.push('titulo');
  if (!html) missing.push('html');

  if (missing.length) {
    throw new Error(`La fila aprobada no puede enviarse a Blogger; faltan: ${missing.join(', ')}`);
  }

  return {
    ...item,
    json: {
      ...row,
      content_id: contentId,
      titulo,
      html,
    },
  };
});

Si ninguna fila cumple las condiciones, la salida será vacía y no habrá llamada a Blogger. Una fila aprobada que sí pasaría el filtro, pero no tiene content_id, titulo o html, detiene el nodo antes del POST y muestra los campos faltantes. Eso evita enviar un borrador incompleto.

La validación detiene el flujo antes del envío, pero en un flujo editorial puedes añadir una rama de revisión que marque el error en otra columna. No borres silenciosamente contenido real mientras ajustas el prototipo.

Paso 3: preparar HTTP Request hacia Blogger

Conecta un nodo HTTP Request al Code. Configura:

  • Method: POST.
  • URL: https://www.googleapis.com/blogger/v3/blogs/REEMPLAZAR_BLOG_ID/posts.
  • Send Query Parameters: activado, con nombre isDraft y valor true.
  • Authentication: Predefined Credential Type.
  • Credential Type: Google OAuth2 API (googleOAuth2Api). Selecciona la credencial dedicada que muestre Account connected y que fue autorizada con el alcance Blogger indicado en los prerrequisitos. No añadas un Authorization: Bearer ... manual.
  • Send Body: activado.
  • Body Content Type: Raw; Content Type: application/json.
  • Body, en modo expresión:
    ={{ JSON.stringify({
      title: String($json.titulo ?? ''),
      content: String($json.html ?? ''),
      labels: String($json.etiquetas ?? $json.labels ?? '')
        .split(',')
        .map((label) => label.trim())
        .filter(Boolean),
    }) }}
    
  • Headers: Content-Type: application/json.

El blogId es un parámetro obligatorio. isDraft=true es obligatorio para el objetivo de este artículo; no lo elimines ni lo cambies a false. La API espera un recurso Post cuyo content puede contener HTML. Usa únicamente HTML editorial confiable y revisado; no trates HTML recibido de usuarios como seguro por defecto.

Conecta también la salida del Code de filtro a la primera entrada del nodo Merge y la salida de HTTP Request a la segunda. Configura Merge en Combine → By Position (o la opción equivalente “por posición”). Con una fila, la respuesta y la entrada ocupan la misma posición y se pueden combinar. Antes de continuar, inspecciona la salida: debe conservar content_id y mostrar el id devuelto por Blogger.

Paso 4: guardar el resultado en Sheets

Después de Merge, añade un nodo Code con Run Once for Each Item:

const postId = String($json.id ?? '').trim();
const contentId = String($json.content_id ?? '').trim();

if (!contentId) {
  throw new Error('Merge no conservó content_id; no se debe actualizar la fila');
}

if (!postId) {
  throw new Error('Blogger no devolvió id; no se debe marcar la fila como procesada');
}

return {
  json: {
    content_id: contentId,
    titulo: String($json.titulo ?? '').trim(),
    html: String($json.html ?? '').trim(),
    estado: 'borrador_creado',
    blogger_post_id: postId,
    draft_url: String($json.url ?? $json.selfLink ?? '').trim(),
  },
};

Conecta otro nodo Google Sheets:

  1. Selecciona la misma credencial, documento y pestaña Editorial.
  2. Usa Update Row para actualizar la fila existente, sin añadir otra.
  3. En Column to Match On, selecciona content_id.
  4. Usa Map Each Column Manually y conserva solo estos cuatro campos: content_id, estado, blogger_post_id y draft_url, con sus valores ={{ $json.nombre_del_campo }}. Retira titulo, html, etiquetas y row_number del mapeo si aparecen. El título y HTML ya pertenecen a la fila y se usan para construir el POST.

Si Blogger responde con error, el Code no debe ejecutarse y la fila no debe marcarse como borrador_creado. Investiga el error antes de volver a procesar la fila. Si la API creó el borrador pero la escritura en Sheets falló, busca el ID en la respuesta de la ejecución antes de reintentar para no crear un segundo borrador; la compuerta no puede adivinar un ID que aún no se guardó.

Paso 5: configurar la prueba y la programación

Usa Manual Trigger hasta comprobar el resultado. Cuando la prueba sea satisfactoria, puedes sustituirlo por un Schedule Trigger con la frecuencia que necesites. Un workflow programado debe estar activo/publicado para que el disparador se ejecute; la activación no forma parte de esta prueba y requiere una decisión editorial.

No conectes ningún nodo de Blogger publish, ni llames a posts/{postId}/publish. El siguiente paso, publicar, debe ser una acción separada con revisión humana.

Cómo comprobar que funciona: resultado de la prueba controlada

La prueba real se ejecutó el 2026-09-13 en n8n 2.22.5 con una sola fila editorial aprobada sin ID previo. El blog DEMO era privado y no tenía entradas antes de la prueba. La credencial dedicada de Google OAuth2 API mostró Account connected con el alcance Blogger.

  1. La primera ejecución dejó pasar una fila, hizo un POST con isDraft=true, creó un borrador y no publicó ninguna entrada.
  2. La respuesta devolvió el ID de Blogger; la actualización de Sheets conservó titulo, html y etiquetas, guardó ese ID y cambió estado a borrador_creado.
  3. La segunda ejecución serial devolvió No output data returned en el filtro porque la fila ya tenía ID. No hubo un segundo POST, Sheets permaneció idéntico y Blogger conservó un borrador y cero publicaciones.
  4. La comprobación del borrador se hizo desde Blogger por su ID. En esta respuesta de la API, draft_url contenía la portada del blog, no un enlace directo de edición; no uses ese campo como enlace de edición sin verificarlo en Blogger.

Al finalizar, el workflow quedó sin publicar, el Schedule deshabilitado y los tres nodos de escritura desactivados. El resultado prueba el reprocesamiento serial de esta fila; no prueba seguridad ante ejecuciones concurrentes.

Errores habituales

Blogger responde 401 o 403

  • Causa probable: la credencial no está autorizada, falta el alcance https://www.googleapis.com/auth/blogger o la cuenta no administra el blog.
  • Comprobación: revisa la credencial y la cuenta en n8n, y consulta el detalle de la respuesta sin copiar tokens a un registro público.
  • Corrección mínima: vuelve a autorizar una cuenta de prueba con acceso al blog y el alcance correcto. No sustituyas OAuth por una API key para una operación de escritura.

Blogger responde 404

  • Causa probable: REEMPLAZAR_BLOG_ID no se cambió por el ID correcto o la cuenta autorizada no puede ver ese blog.
  • Comprobación: confirma el ID desde la cuenta de prueba y revisa que la URL conserve /blogs/{blogId}/posts.
  • Corrección mínima: usa el ID del blog de prueba en la credencial correcta; no publiques ni compartas ese dato si es privado.

La respuesta no contiene id

  • Causa probable: el cuerpo no se interpretó como JSON, el Merge ocultó la respuesta o la API devolvió un error que se trató como éxito.
  • Comprobación: inspecciona la salida cruda de HTTP Request y del Merge.
  • Corrección mínima: revisa el cuerpo JSON, las dos entradas del Merge y conserva el throw del Code para no actualizar la fila sin ID.

Se crea más de un borrador para la misma fila

  • Causa probable: blogger_post_id no se escribió, la columna de coincidencia no es content_id o dos ejecuciones concurrentes pasaron la compuerta antes de actualizar Sheets.
  • Comprobación: busca el content_id y los IDs en Blogger y revisa el historial de ejecuciones.
  • Corrección mínima: detén el Schedule, conserva el ID del primer borrador y vuelve a dejar la fila fuera de la cola. Para alta concurrencia, añade un mecanismo de bloqueo o reserva transaccional; Sheets por sí solo no ofrece esa garantía.

La fila se marca como creada pero no aparece en Borradores

  • Causa probable: se usó isDraft=false, se llamó un endpoint de publicación o se revisó otro blog/cuenta.
  • Comprobación: inspecciona la URL completa y la cuenta que recibe la respuesta.
  • Corrección mínima: fuerza isDraft=true, elimina cualquier paso de publicación y vuelve a probar solo con una fila.

Seguridad y privacidad

  • Blogger es una API de escritura: trata la credencial OAuth como un secreto y no la exportes con el workflow. La API requiere autorización para insertar posts.
  • Usa REEMPLAZAR_BLOG_ID en documentación, capturas y plantillas públicas. Los IDs reales y URLs privadas deben permanecer en el entorno del propietario.
  • No envíes HTML sin revisar. Sanitiza o limita el contenido si la hoja puede ser editada por personas que no pertenecen al equipo editorial.
  • Mantén el modo borrador y una revisión humana hasta validar títulos, enlaces, imágenes, etiquetas y contenido.
  • Separa la credencial de Blogger de la de Sheets cuando los permisos deban tener dueños distintos. Concede acceso de edición solo al documento de prueba durante la configuración.
  • Un reintento después de una respuesta ambigua puede crear otro borrador. Registra el resultado de la ejecución y busca el id antes de reintentar.
  • No programes ni actives el workflow como parte de la primera prueba. La activación es una acción externa que puede afectar contenido editorial.

Fuentes oficiales

Guardar correos de Gmail en Google Sheets sin duplicar mensajes

Los disparadores de correo pueden volver a entregar un mensaje cuando el workflow se reanuda, se cambia el filtro o se repite una ejecución. La forma práctica de hacer el registro idempotente (repetir la misma entrada sin crear otra fila) es guardar el message_id del correo y pedir a Google Sheets que agregue o actualice la fila que tenga esa misma clave.

Este tutorial registra metadatos mínimos: identificador, hilo, remitente, asunto, fecha y un fragmento corto. No guarda el cuerpo completo ni archivos adjuntos.

Estado de verificación: la prueba controlada real se completó el 13 de septiembre de 2026 con n8n 2.22.5. Gmail capturó el mensaje DEMO con el snippet Mensaje de prueba controlada --, sin firma personal. La primera ejecución agregó una fila a CorreoLog y la repetición serial de la captura real fijada con Pin data conservó una sola fila con el mismo message_id y contenido idéntico. La etiqueta Flujoteca-DEMO-procesado quedó aplicada; la respuesta de Gmail conservó UNREAD. Después se desactivaron las escrituras y el workflow quedó sin publicar. Estos resultados no acreditan seguridad ante ejecuciones simultáneas.

Resultado que obtendrás

  • Un workflow Gmail Trigger → Code → Google Sheets que conserva una fila por message_id.
  • Un filtro de búsqueda acotado para no leer el buzón completo durante la comprobación.
  • Una operación Append or Update Row que actualiza el registro si el mismo mensaje vuelve a aparecer.

Antes de comenzar

  • Una instancia de n8n y una cuenta de Gmail de prueba. No uses el buzón personal o de clientes para la primera ejecución.
  • Una cuenta de Google con permiso de edición sobre un documento de prueba.
  • Una pestaña llamada CorreoLog con estas columnas, en este orden:
    message_id | thread_id | de | asunto | recibido_en | snippet | estado
    
  • Un único correo de prueba enviado desde un buzón controlado, con [DEMO] en el asunto. El workflow rechazará cualquier elemento cuyo message_id esté vacío. No incluyas contraseñas, datos financieros ni información personal.
  • La credencial de Google para Gmail y Sheets se autoriza en n8n. No copies client secrets, tokens ni cookies al workflow.

Flujo completo

Gmail Trigger: Message Received
             |
             v
Code: normalizar metadatos
             |
             v
Google Sheets: Append or Update Row
  (Column to Match On = message_id)

El disparador consulta Gmail periódicamente, por lo que no es una garantía de entrega instantánea. Append or Update Row compara la clave que indiques; si message_id ya existe, actualiza esa fila. No uses el asunto como clave: dos mensajes distintos pueden tener el mismo asunto.

Paso 1: preparar la hoja

  1. Crea un documento de prueba y una pestaña CorreoLog.
  2. Escribe los encabezados message_id, thread_id, de, asunto, recibido_en, snippet y estado en la primera fila.
  3. No agregues filas con message_id vacío: el nodo Code las rechaza antes de llegar a Sheets.
  4. Comprueba que la cuenta que autorizarás en n8n puede editar el documento.

La clave message_id viene de Gmail y es distinta de thread_id: varios mensajes pueden pertenecer al mismo hilo. Conserva ambas para poder auditar qué mensaje produjo la fila.

Paso 2: configurar Gmail Trigger

Añade Gmail Trigger y selecciona el evento Message Received. Configura:

  • La credencial de Gmail de una cuenta de prueba.
  • Search, si está disponible, con subject:"[DEMO]" para limitar la consulta. Verifica que el correo de prueba use exactamente ese marcador.
  • Simplify, activado, para trabajar con campos de mensaje manejables. Si tu versión entrega otros nombres, inspecciona una ejecución y adapta el Code del paso siguiente.
  • El límite de mensajes por sondeo más bajo que permita tu prueba; un mensaje es suficiente.

El trigger puede consultar mensajes no leídos según la configuración de tu versión. No añadas todavía nodos que marquen mensajes como leídos, borren mensajes o agreguen etiquetas: son mutaciones adicionales de Gmail y requieren revisar permisos y recuperación.

Paso 3: normalizar los campos

Conecta un nodo Code. Déjalo en Run Once for All Items y usa este código defensivo. Acepta nombres simplificados y cabeceras comunes; revisa la entrada del trigger si tu cuenta devuelve una forma diferente.

return $input.all().map((item) => {
  const input = item.json;
  const headers = input.payload?.headers ?? [];

  function header(name) {
    const wanted = name.toLowerCase();
    const found = headers.find((candidate) =>
      String(candidate.name ?? '').toLowerCase() === wanted
    );
    return found?.value ?? '';
  }

  const messageId = String(
    input.id ?? input.messageId ?? input.message_id ?? ''
  ).trim();
  const threadId = String(input.threadId ?? input.thread_id ?? '').trim();
  const fromValue = input.From ?? input.from ?? header('From');
  const from = typeof fromValue === 'object'
    ? String(fromValue.value?.[0]?.address ?? '').trim()
    : String(fromValue).trim();
  const subject = String(input.Subject ?? input.subject ?? header('Subject')).trim();
  const received = String(
    input.internalDate ?? input.date ?? input.received_at ?? header('Date')
  ).trim();
  const snippet = String(input.snippet ?? input.textPlain ?? '').trim().slice(0, 500);

  if (!messageId) {
    throw new Error('Gmail no entregó un message_id; revisa la salida del trigger');
  }

  return {
    json: {
      message_id: messageId,
      thread_id: threadId,
      de: from,
      asunto: subject,
      recibido_en: received,
      snippet,
      estado: 'recibido',
    },
  };
});

El límite de 500 caracteres es una decisión de privacidad y de tamaño, no una propiedad de Gmail. Si necesitas conservar el cuerpo, define antes una política de retención y de acceso; no lo agregues a este ejemplo por defecto.

Paso 4: actualizar o agregar la fila

Conecta un nodo Google Sheets al Code. En la plantilla este nodo de escritura está desactivado; mantenlo así mientras configuras el documento y la credencial, y habilítalo solo para la prueba controlada:

  1. Selecciona la credencial de Google que tenga acceso al documento de prueba.
  2. Elige el documento y la pestaña CorreoLog.
  3. Selecciona la operación Append or Update Row.
  4. En Column to Match On, selecciona message_id.
  5. Usa Map Automatically si aparece esa opción y revisa que las siete claves del Code coincidan con los encabezados.
  6. No selecciones asunto, thread_id ni de como clave de coincidencia.

La primera llegada debe agregar una fila. En reprocesos seriales, si n8n vuelve a entregar el mismo mensaje, la misma clave debe conducir a una actualización, no a una segunda fila. Si el message_id está vacío, el Code detiene el flujo y no debe llegar a Sheets. Si quieres detectar manualmente una posible colisión, deja message_id visible y no lo trunques.

Esta configuración no constituye un bloqueo transaccional: dos ejecuciones simultáneas pueden consultar la hoja antes de que la otra escriba. Mantén una sola ejecución activa durante la prueba y, antes de automatizar en paralelo, añade una reserva o mecanismo de serialización adecuado.

Cómo comprobar que funciona

La prueba controlada real del 13 de septiembre de 2026 se ejecutó con un único mensaje DEMO, el filtro exacto por asunto y n8n 2.22.5. El snippet observado fue Mensaje de prueba controlada --, sin firma personal. La primera ejecución terminó con Workflow executed successfully y CorreoLog pasó de solo encabezados a encabezados más una fila. La repetición serial utilizó el mismo item de la captura real fijada con Pin data; también terminó correctamente, conservó el contenido de la fila y dejó una sola fila con el mismo message_id. La etiqueta Flujoteca-DEMO-procesado se aplicó al mensaje; la respuesta de Gmail incluyó su identificador junto con UNREAD. Al finalizar, los nodos de escritura y etiqueta quedaron desactivados y el workflow permaneció sin publicar.

Para repetir esta comprobación en una instancia propia, usa este orden con un único mensaje:

  1. Activa el modo de prueba del trigger o ejecuta el workflow según la modalidad de tu instancia.
  2. Envía desde el buzón controlado un correo con asunto [DEMO] prueba n8n y sin información sensible.
  3. Espera un ciclo de sondeo y revisa la entrada del Gmail Trigger. Confirma que existe un id o messageId.
  4. Verifica que Code produzca un message_id no vacío y un snippet de como máximo 500 caracteres. Si el ID está vacío, debe fallar con un error explícito y no escribir nada.
  5. Confirma en Sheets que existe una sola fila con ese message_id.
  6. Cuando la primera ejecución haya terminado, repite el mismo mensaje solo para probar la idempotencia serial. El número de filas debe seguir siendo uno; el valor de estado puede actualizarse.

La primera prueba requiere un entorno real porque Gmail Trigger y Google Sheets necesitan OAuth. Si no dispones todavía de credenciales, puedes revisar el Code con el siguiente objeto fijado en el editor, pero eso no valida la autorización ni la operación de Sheets:

{
  "id": "demo-message-001",
  "threadId": "demo-thread-001",
  "From": "remitente@example.com",
  "Subject": "[DEMO] prueba n8n",
  "Date": "2026-08-27T10:00:00-06:00",
  "snippet": "Solicitud de demostración sin datos personales"
}

Etapa opcional: etiquetar el mensaje procesado

La plantilla incluye Añadir etiqueta procesado, desactivado por defecto. Esta etapa cambia el buzón y debe probarse solo con el mensaje DEMO autorizado, después de verificar que Sheets guardó su fila. No sustituye la comparación por message_id.

  1. Crea una etiqueta de prueba, por ejemplo Flujoteca-DEMO-procesado, en el buzón elegido.
  2. Selecciona la credencial Gmail de ese buzón y revisa los permisos de modificación de etiquetas antes de autorizarla.
  3. En el nodo Gmail, configura Resource: Message, Operation: Add Label y Message ID: ={{ $json.message_id }}. Comprueba que la salida real de Sheets conserva ese identificador.
  4. En Label Names or IDs, selecciona la etiqueta de prueba y sustituye REPLACE_LABEL_ID en la copia importada. No copies su ID real a la plantilla distribuible.
  5. Habilita el nodo solo para la prueba. Verifica en Gmail que el mensaje correcto tiene la etiqueta y repite serialmente el mismo mensaje: CorreoLog debe mantener una sola fila.
  6. Al terminar, deja el workflow inactivo y los nodos de escritura y etiqueta desactivados. Si la etiqueta falla después de guardar la fila, inspecciona ambos destinos antes de repetir.

Este procedimiento sigue la operación Add Label de n8n.

Errores habituales

El trigger no encuentra el correo

  • Causa probable: el filtro de búsqueda no coincide, el mensaje aún no entró en el ciclo de sondeo o el trigger está configurado para otro estado de lectura.
  • Comprobación: busca manualmente [DEMO] en Gmail y revisa la última ejecución de n8n.
  • Corrección mínima: usa temporalmente un filtro más amplio en el buzón de prueba y reduce después la consulta; no proceses todo el buzón como primera prueba.

Code falla por message_id vacío

  • Causa probable: el trigger entrega el identificador con otro nombre o se desactivó la salida simplificada.
  • Comprobación: abre la entrada del nodo y localiza id, messageId o la cabecera Message-ID.
  • Corrección mínima: el flujo debe detenerse; inspecciona la salida real del trigger y adapta solo la expresión de extracción para obtener una clave no vacía antes de volver a probar.

Cada ejecución agrega una fila nueva

  • Causa probable: se eligió Append Row, la columna de coincidencia está vacía o se está usando thread_id en vez de message_id.
  • Comprobación: compara literalmente los valores de message_id y revisa la operación del nodo.
  • Corrección mínima: selecciona Append or Update Row, elige message_id como columna de coincidencia y vuelve a ejecutar el mismo elemento.

El nodo de Sheets devuelve 403

  • Causa probable: la credencial no tiene acceso de edición o el consentimiento de Google no incluye el documento.
  • Comprobación: abre el documento con la cuenta autorizada y revisa la configuración de credenciales en n8n.
  • Corrección mínima: autoriza una cuenta de prueba con acceso de edición; no compartas el documento públicamente para resolver el error.

Se guarda demasiado contenido del correo

  • Causa probable: se desactivó Simplify o se mapeó el payload completo en Sheets.
  • Comprobación: revisa qué campos entran a Google Sheets.
  • Corrección mínima: conserva el Code de normalización y mapea solo las siete columnas del contrato.

Seguridad y privacidad

  • Gmail contiene información de alta sensibilidad. Usa una cuenta de prueba, un filtro explícito y el mínimo conjunto de campos.
  • Las credenciales OAuth y sus alcances dependen del nodo y de la modalidad de n8n. Revisa la pantalla de consentimiento y no guardes tokens ni client secrets en el workflow.
  • Un snippet puede incluir datos personales aunque sea corto. En producción, considera omitirlo o redactarlo antes de almacenarlo.
  • No borres ni respondas correos durante esta prueba. La etiqueta opcional requiere el mensaje y los permisos autorizados descritos arriba; el nodo de etiqueta y el nodo de escritura en Sheets se entregan desactivados.
  • Restringe el acceso al documento de Sheets y define retención. Una hoja compartida puede exponer remitentes y asuntos.
  • La garantía de no duplicación depende de que message_id sea estable, no vacío y se compare en la misma columna. Revisa colisiones antes de procesar lotes.

Fuentes oficiales

Registrar leads de prueba en Google Sheets con n8n

Una hoja bien estructurada es suficiente para empezar a centralizar solicitudes sin contratar una base de datos. En este tutorial crearás una hoja de leads y un workflow de n8n que agrega exactamente dos filas de prueba con columnas predecibles. Después podrás reemplazar el origen de prueba por un Webhook, un formulario o cualquier nodo que entregue los mismos campos.

Estado de verificación: prueba real completada el 13 de septiembre de 2026 en n8n 2.22.5 con OAuth de Google Sheets y una hoja privada de demostración. Una ejecución agregó exactamente dos filas con las seis columnas esperadas. El workflow quedó sin publicar y el nodo de escritura volvió a desactivarse al terminar. Cada lector debe comprobar sus propios permisos y documento antes de ejecutar.

Resultado que obtendrás

  • Una pestaña Leads con encabezados estables: lead_id, nombre, email, tema, estado y recibido_en.
  • Un workflow Manual Trigger → Code → Google Sheets que prepara exactamente dos registros de prueba.
  • Un contrato de datos que permite conectar después un Webhook sin cambiar el nodo de Sheets.

Antes de comenzar

  • Una instancia de n8n Cloud o self-hosted.

  • Una cuenta de Google y una hoja de cálculo de prueba. La escritura en Google Sheets requiere autorizar una credencial de Google dentro de tu instancia; el flujo no incluye ninguna credencial.

  • Permiso de edición sobre el documento de prueba. No uses una hoja con datos de clientes.

  • Crea un documento con una pestaña llamada Leads y escribe estos encabezados en la primera fila, en este orden:

    lead_id | nombre | email | tema | estado | recibido_en
    
  • El ejemplo usa demo-001, ana@example.com, demo-002 y carlos@example.com, datos reservados para documentación.

Flujo completo

Manual Trigger
      |
      v
Code: crear dos leads de muestra
      |
      v
Google Sheets: Append Row en Leads

Append Row agrega una nueva fila al final de la tabla. No lo presentes como deduplicación: si ejecutas el mismo ejemplo dos veces, la segunda ejecución agregará otras dos filas y terminarás con cuatro. La deduplicación es otro requisito y se trata en el artículo de Gmail.

Paso 1: preparar la hoja

  1. En Google Sheets, crea un archivo de prueba y una pestaña Leads.
  2. Coloca los seis encabezados en la fila 1, sin celdas combinadas y sin espacios adicionales.
  3. Deja las filas siguientes vacías.
  4. Copia solo el ID del documento o usa el selector de documentos de n8n. Si lo escribes manualmente, reemplaza el texto REEMPLAZAR_DOCUMENTO por un ID de prueba, nunca por el de un lector.

El nodo de Google Sheets usa la primera fila como encabezado para mapear columnas. Cambiar email por correo en la hoja sin cambiar el objeto de entrada rompe el mapeo automático.

Paso 2: crear un dato controlado

Añade un Manual Trigger. Conecta un nodo Code, selecciona Run Once for All Items y usa estos dos elementos:

return [
  { json: { lead_id: 'demo-001', nombre: 'Ana López', email: 'ana@example.com', tema: 'Webhook seguro', estado: 'nuevo', recibido_en: '2026-08-27T15:00:00Z' } },
  { json: { lead_id: 'demo-002', nombre: 'Carlos Méndez', email: 'carlos@example.com', tema: 'Google Sheets', estado: 'nuevo', recibido_en: '2026-08-27T15:01:00Z' } },
];

Los identificadores y las fechas son constantes para que puedas reconocer las dos filas de prueba. En un flujo real, genera lead_id en el origen o con un nodo de transformación y genera recibido_en en el momento de recepción. No utilices las fechas fijas como reloj de producción.

Paso 3: configurar Google Sheets

Conecta un nodo Google Sheets al Code y configúralo así. El workflow descargable entrega este nodo desactivado para impedir una escritura accidental; mantenlo así mientras sustituyes el ID y eliges tu credencial, y habilítalo solo para la prueba controlada.

  1. Selecciona o crea una credencial de Google en n8n. La autorización sucede en la interfaz de n8n; nunca pegues un token en este artículo ni en una expresión.
  2. En Resource, selecciona Sheet Within Document si tu interfaz lo muestra.
  3. En Operation, selecciona Append Row.
  4. En Document, selecciona el documento de prueba o usa su ID marcado como reemplazable.
  5. En Sheet, selecciona Leads.
  6. En el modo de mapeo, selecciona Map Automatically para que las claves del JSON coincidan con los encabezados.
  7. Si tu versión muestra el mapeo manual, asigna cada campo a la columna con el mismo nombre. No dejes que el nodo adivine columnas cuando existan nombres parecidos.

Guarda el workflow, pero no lo programes todavía. Un Manual Trigger permite inspeccionar los dos elementos antes de automatizar la entrada.

Paso 4: conectar un origen real más adelante

Cuando las dos filas de prueba sean correctas, reemplaza Manual Trigger y Code por un Webhook u otro nodo de entrada que produzca las mismas seis claves. Conserva el nodo de Google Sheets. Si el formulario usa correo, transforma ese campo a email antes de Append Row. Si recibes más elementos, ejecuta primero con el lote mínimo y comprueba que la correspondencia de columnas no se desplace.

Para muchos registros o una operación crítica, considera un almacenamiento con controles de acceso, validación de esquema y copias de seguridad. Google Sheets es una tabla colaborativa, no una cola transaccional ni un sistema de deduplicación por sí mismo.

Cómo comprobar que funciona

La prueba del 13 de septiembre de 2026 partió de una pestaña con solo encabezados. n8n confirmó una ejecución satisfactoria y la lectura posterior de Sheets mostró exactamente demo-001 y demo-002, con las seis columnas correctas. Para reproducirla, configura la credencial y habilita el nodo de escritura solo para esta prueba; ejecuta manualmente una vez con tu documento autorizado. Debes observar:

  • Dos elementos de entrada con las seis claves en Code.
  • Una ejecución satisfactoria en Google Sheets.
  • Exactamente dos filas nuevas en Leads, debajo de los encabezados: demo-001 con ana@example.com y demo-002 con carlos@example.com.
  • Ninguna credencial, token o URL privada dentro de los datos de la fila.

Ejecuta el workflow una segunda vez solo si necesitas comprobar el comportamiento de Append Row; el resultado esperado serán otras dos filas (cuatro filas de prueba en total), porque esa operación no impide duplicados. Borra las filas de prueba manualmente en la hoja antes de conectar datos reales.

Errores habituales

The resource you are requesting could not be found

  • Causa probable: el documento, la pestaña o el ID indicado no existe o la credencial no tiene acceso.
  • Comprobación: abre el documento con la misma cuenta que autorizaste en n8n y confirma que la pestaña se llama exactamente Leads.
  • Corrección mínima: selecciona de nuevo el documento y la pestaña desde el selector; no pegues un ID perteneciente a otra cuenta.

Las columnas quedan vacías o desordenadas

  • Causa probable: los encabezados no coinciden con las claves JSON, la primera fila está vacía o se usó mapeo manual incorrecto.
  • Comprobación: compara lead_id, nombre, email, tema, estado y recibido_en letra por letra.
  • Corrección mínima: restaura la fila de encabezados y vuelve a seleccionar Map Automatically o asigna cada columna de forma explícita.

La autorización falla o devuelve 403

  • Causa probable: la cuenta canceló el consentimiento, el documento pertenece a otra cuenta o la instancia necesita una configuración OAuth propia.
  • Comprobación: abre la configuración de credenciales de Google en n8n y revisa el mensaje que aparece, sin copiar tokens al chat o a un issue.
  • Corrección mínima: vuelve a autorizar con una cuenta de prueba que tenga permiso de edición y revisa la guía de credenciales de n8n para tu modalidad Cloud o self-hosted.

Se insertan duplicados

  • Causa probable: Append Row siempre agrega al final; además, una ejecución manual repetida vuelve a enviar el mismo elemento.
  • Comprobación: busca el mismo lead_id en la hoja.
  • Corrección mínima: usa una operación de búsqueda y actualización por una clave única, o implementa la estrategia de Append or Update Row cuando el caso lo requiera. No describas Append Row como idempotente.

La fecha aparece con otro formato

  • Causa probable: la configuración regional de la hoja interpreta el texto de fecha de otra forma.
  • Comprobación: observa el valor recibido y la configuración regional del documento.
  • Corrección mínima: guarda fechas en ISO 8601, define el formato de la columna en la hoja y verifica las dos filas de muestra antes de importar un lote.

Seguridad y privacidad

  • Usa un documento separado para pruebas y limita el uso compartido a las personas que realmente necesitan editarlo.
  • example.com es un dominio de ejemplo; reemplázalo por datos ficticios, no por correos de clientes, mientras validas el flujo.
  • No incluyas credenciales, tokens OAuth, enlaces de documentos privados ni IDs reales en el artículo, capturas o exportaciones.
  • Mantén en la hoja solo los campos necesarios para la finalidad del lead y define retención y borrado. Un enlace compartido puede exponer todas las filas.
  • Revisa el alcance que solicita la credencial de Google. drive.file puede ser preferible cuando sea suficiente; los alcances sensibles de Sheets deben evaluarse antes de distribuir una integración.
  • La escritura en Sheets es una mutación externa. Confirma el resultado de las dos filas de muestra antes de activar un origen que pueda entregar muchos elementos.

Fuentes oficiales

Validar una petición de webhook y responder con JSON en n8n

Un webhook es una URL que recibe una petición HTTP y la convierte en datos para un workflow. En este tutorial construirás un endpoint pequeño para recibir un posible lead, comprobar sus campos y devolver una respuesta JSON clara. El resultado es útil para formularios, scripts o integraciones que necesiten saber inmediatamente si n8n aceptó o rechazó la petición.

Prueba documentada: n8n 2.36.7 con Node.js 24.19.0, el 31 de agosto de 2026. En una instancia local aislada se comprobaron las respuestas HTTP 200 y 400, la normalización de los datos válidos y la ausencia de datos del lead en la respuesta inválida. El workflow quedó inactivo al terminar. No se conectaron servicios externos.

Resultado que obtendrás

  • Una URL de webhook POST que acepta nombre, email y tema.
  • Una validación en un nodo Code que normaliza el correo y devuelve los errores sin procesar datos inválidos.
  • Una respuesta 200 para un registro válido y 400 para uno inválido, siempre en JSON.

Antes de comenzar

  • Una instancia de n8n Cloud o self-hosted con los nodos Webhook, Code, IF (condición) y Respond to Webhook disponibles.
  • PowerShell 7 o posterior para ejecutar el ejemplo con Invoke-RestMethod. Comprueba la versión con $PSVersionTable.PSVersion; Windows PowerShell 5.1 no admite los parámetros usados aquí.
  • Un payload de prueba sin datos personales. Este artículo usa Ana Demo <ana@example.com>.
  • No necesitas credenciales de Google, un proveedor de correo ni un servicio de pago.

El nodo Webhook tiene una URL de prueba y otra de producción. La URL de prueba solo responde mientras el editor está escuchando una ejecución; la de producción requiere que el workflow esté activo. Usa primero la de prueba y no copies una URL real a un artículo o captura.

Flujo completo

Webhook «Recibir datos» (POST /flujoteca-intake-v1)
        |
        v
Code «Validar y normalizar»
        |
        v
IF «¿Datos válidos?» ---- no ----> «Responder 400»
        |
       sí
        v
«Responder 200»

El contrato canónico del flujo usa ok, data y errores en la salida del nodo de validación. La rama válida devuelve los campos normalizados dentro de lead; la rama inválida devuelve solo mensajes de validación, nunca el payload ni los datos normalizados.

Paso 1: crear el webhook

  1. Crea un workflow nuevo y añade un nodo Webhook.
  2. En HTTP Method, selecciona POST.
  3. En Path, escribe flujoteca-intake-v1.
  4. En Respond, selecciona Using "Respond to Webhook" Node. Así el status code y el cuerpo se controlan al final del flujo.
  5. Para una prueba local, deja la autenticación en None y no expongas la URL fuera de tu entorno de prueba. Para un endpoint real, configura Basic Auth, Header Auth o JWT y guarda el secreto solo en la credencial de n8n.
  6. Pulsa Listen for test event y conserva la URL de prueba que muestra n8n solo en tu sesión. No la publiques.

El cuerpo suele estar disponible como $json.body cuando la petición llega al nodo Webhook. El código del siguiente paso acepta también $json como respaldo para que puedas reutilizarlo con datos fijados en el editor.

Paso 2: validar y normalizar los datos

Conecta un nodo Code al Webhook. Déjalo en Run Once for All Items y pega este código. El try/catch evita que un cuerpo de texto que no sea JSON detenga el workflow con un error poco claro.

const raw = $json.body ?? $json;
let body = raw;

if (typeof raw === 'string') {
  try {
    body = JSON.parse(raw);
  } catch {
    return [{
      json: {
        ok: false,
        errores: ['El cuerpo no contiene JSON válido'],
      },
    }];
  }
}

if (!body || typeof body !== 'object' || Array.isArray(body)) {
  return [{
    json: {
      ok: false,
      errores: ['El cuerpo debe ser un objeto JSON'],
    },
  }];
}

const data = {
  nombre: String(body.nombre ?? '').trim(),
  email: String(body.email ?? '').trim().toLowerCase(),
  tema: String(body.tema ?? '').trim(),
};

const errores = [];
if (data.nombre.length < 2) errores.push('nombre debe tener al menos 2 caracteres');
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email)) {
  errores.push('email no tiene un formato válido');
}
if (data.tema.length < 2) errores.push('tema debe tener al menos 2 caracteres');

if (errores.length > 0) {
  return [{ json: { ok: false, errores } }];
}

return [{ json: { ok: true, data, errores: [] } }];

La salida válida tiene la forma { ok: true, data, errores: [] }; la inválida, { ok: false, errores } y no incluye data. La expresión regular es una comprobación básica, no una prueba de que el buzón exista. En una aplicación real también conviene aplicar límites de longitud y una protección contra abuso antes de enviar el dato a otros sistemas.

Paso 3: separar las ramas

Añade el nodo IF «¿Datos válidos?» después de Validar y normalizar:

  • Primera condición: Boolean.
  • Valor: ={{ $json.ok }}.
  • Operador: is true.

Conecta la salida verdadera al nodo Responder 200 y la salida falsa a Responder 400. Comprueba el nombre de cada salida en el lienzo: una conexión invertida puede devolver 200 para datos rechazados.

Paso 4: responder al cliente

En la rama verdadera, el nodo Responder 200 usa esta configuración:

  • Respond With: JSON.

  • Response Code: 200.

  • Response Body:

    ={{ { ok: true, lead: $json.data, message: "Validación correcta" } }}
    

Si la versión de tu editor muestra el cuerpo como texto, usa JSON.stringify({ ok: true, lead: $json.data, message: 'Validación correcta' }) como expresión. No escribas el correo de prueba directamente en el nodo.

En la rama falsa, el nodo Responder 400 usa esta configuración:

  • Respond With: JSON.

  • Response Code: 400.

  • Response Body:

    ={{ { ok: false, errores: $json.errores, message: "Revisa los campos enviados" } }}
    

Guarda el workflow. Para usar la URL de producción más adelante, activa o publica el workflow según la interfaz de tu instancia y vuelve a comprobar que la autenticación está configurada.

Cómo comprobar que funciona

El registro anterior confirma las ramas válida e inválida mediante una URL local con el workflow publicado temporalmente. Los siguientes pasos permiten repetir la comprobación con la URL de prueba del editor; esa modalidad debe comprobarse en tu instancia. Con el webhook en modo de escucha, sustituye <URL_DE_PRUEBA> por la URL que n8n muestra en tu editor y ejecuta una sola petición:

$payload = @{
  nombre = 'Ana Demo'
  email = 'ana@example.com'
  tema = 'Webhooks en n8n'
} | ConvertTo-Json

$respuesta = Invoke-RestMethod `
  -Method Post `
  -Uri '<URL_DE_PRUEBA>' `
  -ContentType 'application/json' `
  -Body $payload `
  -SkipHttpErrorCheck `
  -StatusCodeVariable codigoHttp

$codigoHttp
$respuesta | ConvertTo-Json -Depth 5

Debes observar el código HTTP 200 y un objeto con ok: true, lead.email: "ana@example.com" y lead.nombre: "Ana Demo". Antes de la segunda petición, pulsa de nuevo Listen for test event y comprueba la URL de prueba. Cambia el email del bloque inicial a 'no-es-un-correo' y ejecuta el bloque completo una sola vez para reconstruir el JSON. El resultado esperado es código 400, ok: false, un arreglo errores y ningún campo lead. -SkipHttpErrorCheck permite inspeccionar el cuerpo de la respuesta 400; no convierte el error en éxito ni omite la validación TLS. Si la primera petición llega al Webhook pero no obtiene respuesta, revisa que ambos caminos terminen en Respond to Webhook.

No pases a la URL de producción hasta revisar el resultado y eliminar cualquier dato de prueba. Si usas una herramienta que reintenta automáticamente, desactiva los reintentos durante esta comprobación para no crear varias ejecuciones.

Errores habituales

Recibes 404 o n8n no muestra la petición

  • Causa probable: usaste el path equivocado, la URL de prueba cambió o el editor no estaba escuchando.
  • Comprobación: copia de nuevo la URL de prueba visible en el nodo Webhook y pulsa Listen for test event.
  • Corrección mínima: vuelve a enviar una única petición al endpoint recién generado. La URL de producción solo funciona con el workflow activo.

Recibes 401 o 403

  • Causa probable: la autenticación del Webhook está activa y el cliente no envía el encabezado esperado.
  • Comprobación: revisa el tipo de autenticación configurado y prueba únicamente con un valor de ejemplo.
  • Corrección mínima: configura la credencial en n8n y usa el método de autenticación documentado; no pegues el secreto en el código ni en una captura.

Todos los datos caen en la rama inválida

  • Causa probable: el cliente envía un nombre de campo diferente (correo en vez de email) o un cuerpo no JSON.
  • Comprobación: abre la entrada del nodo Webhook y verifica si los campos están dentro de body.
  • Corrección mínima: ajusta el payload al contrato nombre, email, tema; conserva la validación en el servidor.

El endpoint devuelve 200 aunque falte un campo

  • Causa probable: las conexiones del nodo IF están invertidas o el Respond de error tiene código 200.
  • Comprobación: ejecuta la petición inválida y revisa la ruta resaltada en el lienzo.
  • Corrección mínima: conecta true al Respond 200, false al Respond 400 y guarda otra vez.

La petición es rechazada por tamaño

  • Causa probable: el payload supera el límite documentado del Webhook.
  • Comprobación: mide el cuerpo y elimina archivos o campos innecesarios.
  • Corrección mínima: envía metadatos pequeños y almacena archivos en un sistema apropiado; el Webhook de n8n documenta un máximo de 16 MB.

Seguridad y privacidad

  • Un endpoint sin autenticación debe considerarse público. Úsalo solo en una prueba local o añade autenticación antes de ponerlo en producción.
  • No registres tokens, contraseñas ni el cuerpo completo si contiene datos personales. El ejemplo usa example.com y no representa un buzón real.
  • Valida siempre en n8n aunque el cliente ya valide. La validación del navegador no es un control de seguridad.
  • Define límites de longitud, protección contra repetición y un mecanismo de rate limiting en el proxy o infraestructura cuando el endpoint vaya a Internet.
  • No reflejes en la respuesta campos que no necesitas. Si procesas datos personales, documenta la finalidad, retención y quién tiene acceso.

Fuentes oficiales