n8n Webhooks: Tutorial Completo para Automatizar APIs y Eventos 2026
Los webhooks son uno de los patrones de integración más poderosos en el mundo de la automatización. En lugar de preguntar constantemente "¿Hay nuevos datos?", los webhooks permiten que los servidores externos te notifiquen cuando algo importante sucede. n8n hace que crear y gestionar webhooks sea increíblemente simple.
En este tutorial, aprenderás a crear webhooks en n8n, recibirlos desde Stripe, GitHub, Shopify y otros servicios, y construir workflows automáticos que reaccionen a eventos en tiempo real.
¿Qué Son Los Webhooks?
Un webhook es fundamentalmente una llamada HTTP POST que un servicio externo hace a tu aplicación cuando ocurre un evento.
Comparación: Polling vs Webhooks
Polling (El Viejo Método)
1Tu aplicación:2"¿Hay nuevas órdenes cada minuto?"3API Stripe:4"No"5"No"6"No"7"Sí, hay 1"8 9Problema: Desperdicia recursos, latencia alta
Webhooks (El Método Inteligente)
1Tu aplicación: Esperando...2Stripe (cuando hay nueva orden):3"¡PING! Nueva orden: #12345"4 5Tu aplicación: Procesa la orden al instante6 7Ventaja: Tiempo real, eficiente, bajo costo
Casos de Uso Reales
1✓ Procesar pagos de Stripe al instante2✓ Crear tickets en Jira cuando alguien abre un issue en GitHub3✓ Enviar notificaciones SMS cuando hay nuevas órdenes4✓ Sincronizar datos entre aplicaciones en tiempo real5✓ Ejecutar automáticamente cuando alguien se suscribe6✓ Generar reportes cuando se actualiza datos en Airtable7✓ Actualizar inventario cuando hay venta en Shopify
Conceptos Clave de Webhooks
El Flujo Completo
1Servicio Externo (Stripe)2 ↓3 [HTTP POST]4 (JSON payload)5 ↓6n8n Webhook Node7 ↓8 Procesa datos9 ↓10 [Acciones]11 (Send Email, etc)12 ↓13 Respuesta HTTP14 ↓15Servicio Externo16(Confirma recepción)
Payload de Webhook Típico
1{2 "id": "evt_1234567890",3 "object": "event",4 "api_version": "2023-10-16",5 "created": 1675857600,6 "data": {7 "object": {8 "id": "ch_1234567890",9 "object": "charge",10 "amount": 2000,11 "currency": "usd",12 "customer": "cus_1234567890",13 "description": "Order #12345"14 }15 },16 "livemode": false,17 "pending_webhooks": 1,18 "request": {19 "id": null,20 "idempotency_key": null21 },22 "type": "charge.succeeded"23}
El Webhook Node en n8n
Crear un Webhook
11. Abre n8n22. Crea nuevo workflow33. Click "+ Add Node"44. Busca "Webhook" y selecciona "Webhook"55. Elige "Webhook" (el que recibe, no el que envía)
Configuración Básica
1Authentication: None (o API Key si necesitas seguridad)2HTTP Method: POST (típicamente)3Response Code: 2004Webhook URL: auto-generado (ej: https://n8n.tudominio.com/webhook/12345)
Ejemplo Simplísimo
1Webhook Node:2├── Authentication: None3├── HTTP Method: POST4└── Response Code: 2005 6↓7Procesamiento:8├── Acceso a datos: $json.body9├── Logging: console.log()10└── Transformación: JavaScript node11 12↓13Acción:14├── Enviar email15├── Guardar en BD16└── Llamar otra API
Paso a Paso: Tu Primer Webhook en n8n
Paso 1: Crear el Webhook Node
11. Nuevo workflow22. Agregar "Webhook" node33. HTTP Method: POST44. Copiar la URL generada5 6URL Ejemplo:7https://n8n.example.com/webhook/webhook-test-1234
Paso 2: Recibir el Payload
1El webhook recibe automáticamente:2- Headers: headers HTTP enviados3- Body: JSON payload4- Query: parámetros de URL5- Method: POST, GET, etc.6 7Acceso en n8n:8- $json.body → accede al JSON9- $json.headers → headers HTTP10- $json.query → query parameters
Paso 3: Procesar los Datos
1// JavaScript Node en n8n2 3// Acceder payload4const payload = $json.body;5const orderId = payload.data.object.id;6const amount = payload.data.object.amount;7 8// Transformar9return {10 orderId: orderId,11 amountUSD: (amount / 100), // Stripe usa centavos12 timestamp: new Date().toISOString()13};
Paso 4: Ejecutar Acciones
1Ejemplos de acciones después del webhook:2- Enviar email notificando la orden3- Guardar en Airtable4- Crear issue en GitHub5- Actualizar CRM6- Enviar mensaje en Slack
Paso 5: Activar y Testar
11. Click "Activate" en el workflow22. Copiar Webhook URL33. Enviar test POST a la URL44. Ver ejecución en n8n55. Revisar logs
Integraciones: Recibir Webhooks de Servicios Reales
Integración 1: Stripe
Procesar pagos automáticamente con Stripe.
Configurar Webhook en Stripe:
11. Stripe Dashboard → Developers → Webhooks22. Click "+ Add endpoint"33. Pegar URL de n8n webhook44. Seleccionar eventos: charge.succeeded, charge.failed55. Copiar "Signing Secret" (importante para seguridad)
Verificar Firma de Stripe (Seguridad)
1// Stripe firma todos los webhooks con HMAC2// Necesario para verificar que viene de Stripe3 4const crypto = require('crypto');5const stripe_secret = process.env.STRIPE_WEBHOOK_SECRET;6 7const sig = $json.headers['stripe-signature'];8const body = $json.body;9 10const expectedSig = crypto11 .createHmac('sha256', stripe_secret)12 .update(body)13 .digest('base64');14 15if (sig !== expectedSig) {16 throw new Error('Firma de Stripe no válida');17}18 19// Si llegó aquí, es seguro procesar20return {21 verified: true,22 payload: JSON.parse(body)23};
Workflow Completo: Procesar Pagos Stripe
1[Webhook Node]2 ↓3[Verificar Firma]4 ↓5[Extraer Información]6 ├── orderId7 ├── amount8 ├── customer email9 └── status10 ↓11[If charge.succeeded?]12 ├─→ [Guardar en Airtable]13 ├─→ [Enviar Email de Confirmación]14 └─→ [Webhook Slack: Nueva venta!]15 ↓16[Else charge.failed]17 ├─→ [Guardar fallo en BD]18 └─→ [Email al cliente: Reintenta]
Integración 2: GitHub
Crear un ticket en Jira cuando alguien abre un issue en GitHub.
Setup GitHub Webhook:
1GitHub Repo → Settings → Webhooks2URL: https://n8n.example.com/webhook/github-issues3 4Eventos a disparar:5- Issues: Push, Pull Request, Issues
Payload de GitHub (Pull Request abierto)
1{2 "action": "opened",3 "pull_request": {4 "id": 1,5 "number": 1234,6 "title": "Add new feature",7 "body": "This PR adds XYZ functionality",8 "user": {9 "login": "octocat",10 "avatar_url": "..."11 },12 "head": {13 "ref": "feature-branch"14 },15 "base": {16 "ref": "main"17 }18 }19}
Workflow: GitHub → Jira
1// Recibir webhook de GitHub2const github = $json.body;3 4// Solo procesar PRs nuevos5if (github.action !== 'opened') {6 return null;7}8 9// Extraer información10const prTitle = github.pull_request.title;11const prBody = github.pull_request.body;12const prAuthor = github.pull_request.user.login;13const prUrl = github.pull_request.html_url;14 15// Crear issue en Jira16return {17 fields: {18 project: { key: 'PROJ' },19 summary: `[GitHub PR] ${prTitle}`,20 description: `${prBody}\n\nAutor: ${prAuthor}\nURL: ${prUrl}`,21 issuetype: { name: 'Task' }22 }23};
Integración 3: Shopify
Sincronizar nuevas órdenes de Shopify a Google Sheets.
Configurar Webhook en Shopify:
1Shopify Admin → Apps → Manage webhooks2Topic: Orders/create (nueva orden)3Delivery URL: https://n8n.example.com/webhook/shopify
Workflow: Shopify → Google Sheets
1[Webhook: Shopify Order]2 ↓3[Procesar Payload]4 ├── order.id5 ├── order.total_price6 ├── customer.email7 └── created_at8 ↓9[Google Sheets: Agregar fila]10 ├── Columna A: Order ID11 ├── Columna B: Email Cliente12 ├── Columna C: Total13 └── Columna D: Fecha14 ↓15[Enviar Slack Notification]16 └── "Nueva orden: $XXX de nombre@email.com"
Testing de Webhooks
Método 1: curl (Línea de Comandos)
1# Enviar POST simple2curl -X POST https://n8n.example.com/webhook/webhook-id \3 -H "Content-Type: application/json" \4 -d '{5 "order_id": "12345",6 "amount": 99.99,7 "email": "cliente@example.com"8 }'9 10# Con headers personalizados11curl -X POST https://n8n.example.com/webhook/webhook-id \12 -H "Content-Type: application/json" \13 -H "Authorization: Bearer token123" \14 -d @payload.json
Método 2: Postman (UI)
11. Abre Postman22. Method: POST33. URL: Pegar webhook URL de n8n44. Body → raw → JSON55. Agregar JSON de prueba66. Click Send77. Ver respuesta en n8n
Método 3: n8n Testing (Integrado)
11. En el Webhook node, click en el ícono de prueba22. n8n genera una URL de prueba33. Enviar POST a esa URL44. Ver datos en el node automáticamente
Autenticación y Seguridad
Autenticación con API Key
1Webhook Node:2├── Authentication: API Key3├── Header Name: X-API-Key4└── Value: tu-clave-secreta-1235 6Entonces el cliente debe enviar:7Headers:8 X-API-Key: tu-clave-secreta-123
Verificación de Firma (HMAC)
1// Patrón usado por Stripe, GitHub, etc.2 3const crypto = require('crypto');4const webhook_secret = process.env.WEBHOOK_SECRET;5 6const signature = $json.headers['x-signature'];7const payload = $json.body;8 9// Calcular HMAC esperado10const hmac = crypto11 .createHmac('sha256', webhook_secret)12 .update(JSON.stringify(payload))13 .digest('hex');14 15// Comparar (timing-safe)16const isValid = crypto.timingSafeEqual(17 Buffer.from(signature),18 Buffer.from(hmac)19);20 21if (!isValid) {22 throw new Error('Firma webhook inválida');23}24 25return { verified: true };
IP Whitelisting
1# Restricción a IPs conocidas2Webhook Node:3├── Authentication: None4├── Advanced Settings5└── Allowed IPs:6 - 1.2.3.4 # Servidor Stripe7 - 5.6.7.8 # Servidor GitHub8 - 9.10.11.12 # Servidor Shopify
Manejo de Errores y Reintentos
Responder al Servicio
1// El servicio necesita saber si el webhook se procesó2 3try {4 // Procesar webhook5 await procesarPago($json.body);6 7 // Responder con éxito8 return {9 statusCode: 200,10 body: {11 success: true,12 message: 'Webhook procesado correctamente'13 }14 };15 16} catch (error) {17 // Responder con error18 return {19 statusCode: 400,20 body: {21 success: false,22 error: error.message23 }24 };25}
Implementar Reintentos
1# Si el webhook falla, configurar reintentos2 3Webhook Node:4├── Retry on Failure: true5├── Max Retries: 36├── Retry Delay: 5 segundos7└── Exponential Backoff: true8 9Timing:101er intento: Inmediato112do intento: 5 seg123er intento: 25 seg134to intento: 125 seg
Queue de Webhooks Fallidos
1// Guardar webhooks fallidos para procesar luego2 3const failedPayload = $json.body;4const timestamp = new Date().toISOString();5 6// Guardar en tabla fallidos_webhooks7await db.insert('webhooks_fallidos', {8 id: generateUUID(),9 payload: JSON.stringify(failedPayload),10 timestamp: timestamp,11 error: error.message,12 servicio: 'stripe',13 reintentado: false14});15 16// Email al admin17await enviarEmail({18 to: 'admin@example.com',19 subject: `Webhook fallido: ${failedPayload.type}`,20 body: `Webhook ID: ${failedPayload.id}`21});
Casos Prácticos Completos
Caso 1: E-commerce Automático
Flujo: Shopify → Múltiples Integraciones
1[Webhook Shopify: Nueva Orden]2 ↓3[Extraer datos]4├── items5├── cliente6└── dirección7 ↓8[Paralelo]9├→ [Fulfillment API: Enviar a almacén]10├→ [Google Sheets: Registrar orden]11├→ [Stripe: Procesar pago]12└→ [Email: Confirmación al cliente]13 ↓14[Guardar en Base de Datos]15 ├── orders tabla16 ├── customers tabla17 └── order_items tabla18 ↓19[Slack Notification]20 └── "Orden #123 - $99.99"
Caso 2: Notificaciones en Tiempo Real
Flujo: Múltiples Fuentes → Usuarios
1[GitHub Webhook: Nuevo Issue]2[Jira Webhook: Issue Asignada]3[Slack Webhook: Menciono a equipo]4 ↓5[Deduplicación: Es el mismo issue?]6 ↓7[Normalizar datos]8 ├── titulo9 ├── descripción10 └── prioridad11 ↓12[Slack: Notificar equipo]13[Email: Notificar interesados]14[SMS: Para crítico]
Caso 3: Sincronización de Datos
Flujo: CRM ↔ Sheets ↔ Mailchimp
1[Webhook: Nuevo contacto en CRM]2 ↓3[Agregar a Google Sheets]4 ↓5[Subscribir a Mailchimp]6 ↓7[Enviar email bienvenida]8 ↓9[Slack: Nuevo lead!]10 ↓11[Webhook: Informar CRM de inscripción]
Best Practices en Producción
1. Logging Exhaustivo
1// Registrar todo para debugging2 3const webhook_id = $json.headers['x-webhook-id'];4const timestamp = new Date().toISOString();5 6console.log(`[${timestamp}] Webhook recibido: ${webhook_id}`);7console.log(`Payload: ${JSON.stringify($json.body)}`);8 9// Guardar en base de datos también10await db.insert('webhook_logs', {11 webhook_id: webhook_id,12 timestamp: timestamp,13 payload: $json.body,14 status: 'received'15});
2. Idempotencia (Procesar Solo Una Vez)
1// Los webhooks pueden llegar duplicados a veces2// Asegurar procesar solo una vez3 4const idempotency_key = $json.body.id;5 6// Verificar si ya procesamos7const exists = await db.query(8 'SELECT id FROM webhooks_procesados WHERE id = ?',9 [idempotency_key]10);11 12if (exists.length > 0) {13 return { statusCode: 200, message: 'Ya procesado' };14}15 16// Procesar17await procesarPago($json.body);18 19// Guardar como procesado20await db.insert('webhooks_procesados', { id: idempotency_key });21 22return { statusCode: 200 };
3. Monitoreo y Alertas
1# Monitorear salud de webhooks2 3Métricas a rastrear:4- Total webhooks/hora5- % de éxito vs fallo6- Latencia promedio7- Webhooks duplicados8- Errores más comunes9 10Alertas:11- Tasa de error > 5%12- Latencia > 10 segundos13- Sin webhooks en 1 hora
4. Versionado de Webhooks
1# Mantener compatibilidad hacia atrás2 3v1:4 payload:5 id: order_1236 amount: 99.997 8v2:9 payload:10 order:11 id: order_12312 total:13 amount: 99.9914 currency: USD15 16# En n8n:17if (payload.order) {18 // v219 const amount = payload.order.total.amount;20} else {21 // v122 const amount = payload.amount;23}
FAQ: Preguntas Sobre Webhooks en n8n
¿Cuál es la diferencia entre Webhook (entrante) y HTTP Request (saliente)?
Webhook Node es para RECIBIR eventos POST de servicios externos. HTTP Request Node es para ENVIAR datos a servicios externos. En un flujo típico: Webhook recibe → procesa → HTTP Request envía a otra API.
¿Qué pasa si el webhook falla en n8n?
Si configuraste reintentos, n8n intentará procesar el webhook de nuevo automáticamente. Si sigue fallando, n8n responde con un código de error al servicio (ej: 500), y el servicio reintentará según su política. Es buena idea guardar los webhooks fallidos en una tabla para procesarlos manualmente luego.
¿Cuántos webhooks puedo recibir simultáneamente?
Depende de tu plan n8n. Cloud Plan: aproximadamente 100 ejecutiones simultáneas. Self-hosted: depende de tus recursos (CPU, RAM). En producción, configura una queue de webhooks si esperas alto volumen.
¿Cómo evito procesar un webhook dos veces?
Usa idempotency keys. Cada webhook debe tener un ID único. Antes de procesar, verifica si ya existe ese ID en tu base de datos. Si existe, retorna 200 OK sin procesar de nuevo. Esto es crítico para transacciones financieras.
¿Puedo usar webhooks para datos sensibles como contraseñas?
NUNCA envíes contraseñas, tokens de API o PII sensible en webhooks. Usa variables de entorno para credenciales. Si necesitas enviar datos sensibles, encripta el payload y verifica la firma HMAC del servicio origen para asegurar autenticidad.