Módulo 4: Slack
Mini-Proyecto: Notificaciones Interactivas
Descripción de la cápsula
Hora de juntar el módulo en un workflow real — y de cumplir la promesa del proyecto que la STRATEGY de esta guía describe para el Módulo 4: un workflow que notifica y recibe interacción.
El proyecto: un sistema de aprobación de gastos. Llega una solicitud de gasto (quién, cuánto, concepto). El workflow la notifica al canal del equipo con formato claro, registra la solicitud en una hoja como "pendiente", y le da al equipo una forma de responder desde Slack. Cuando alguien aprueba o rechaza con un slash command, un segundo workflow recibe esa respuesta, actualiza la hoja, y confirma de vuelta en el canal.
No es una sola automatización — son dos workflows que conversan a través de Slack y una hoja compartida. Eso es lo que significa "notificaciones interactivas": Slack no es solo el tablero de avisos, es la interfaz desde la que el equipo actúa. El proyecto usa todo el módulo (enviar, formato, menciones, recibir) más Sheets del Módulo 1.
Lo que vas a construir
Workflow A — Notificar:
- Recibe una solicitud de gasto (solicitante, monto, concepto)
- La registra en una hoja con estado
pendingy un ID de solicitud - La notifica al canal del equipo, con formato, mencionando al aprobador
- Le dice al equipo cómo responder (
/aprobaro/rechazar)
Workflow B — Recibir la decisión:
- Se dispara cuando alguien usa
/aprobar [ID]o/rechazar [ID]en Slack - Busca la solicitud en la hoja por su ID
- Actualiza su estado a
approvedorejected - Confirma de vuelta en el canal quién decidió qué
Lo que vas a practicar
- ✅ Enviar con formato y menciones (cápsulas 03-04)
- ✅ Recibir desde slash commands (cápsula 06)
- ✅ El ciclo completo notificar → el equipo actúa → confirmar (cápsula 06)
- ✅ Buscar antes de actuar y registrar/actualizar en Sheets (Módulo 1)
- ✅ Dos workflows que conversan a través de un estado compartido
- ✅ El patrón "notificaciones interactivas" — Slack como interfaz de trabajo
Preparación
La hoja de solicitudes
Crea una hoja Solicitudes Gastos con estas columnas en la fila 1:
| request_id | date | requester | amount | concept | status | decided_by |
|---|
Formatea request_id como Texto sin formato.
El canal y el bot
Usa un canal #aprobaciones con el bot invitado.
El slash command
En tu app de Slack, crea dos slash commands — /aprobar y /rechazar — apuntando a la URL del Slack Trigger del Workflow B. (O un solo comando /decidir con la decisión como argumento — tú eliges; las instrucciones asumen dos comandos.)
WORKFLOW A — Notificar
Arquitectura
Manual Trigger (o Webhook en producción)
│
▼
Set: normalizar la solicitud + generar request_id
│
▼
Google Sheets (Append): registrar como "pending"
│
▼
Slack (Send): notificar al canal con formato y mención
Paso A1: el trigger y la solicitud
Manual Trigger → Set que simula la solicitud:
requester = Ana López
amount = 2300
concept = Licencias de software
Paso A2: normalizar y generar el ID
Amplía el Set (o agrega otro) para preparar todo:
requester = {{ $json.requester.trim() }}
amount = {{ $json.amount }}
concept = {{ $json.concept.trim() }}
request_id = {{ 'EXP-' + $now.toFormat('yyyyLLdd-HHmmss') }}
date = {{ $now.toFormat('yyyy-LL-dd HH:mm') }}
El request_id es la clave que conectará los dos workflows. Usamos la fecha/hora para que sea único y legible.
Paso A3: registrar en la hoja
Un nodo Google Sheets:
- Operation:
Append Row - Document:
Solicitudes Gastos - Mapping (manual):
request_id→{{ $json.request_id }}date→{{ $json.date }}requester→{{ $json.requester }}amount→{{ $json.amount }}concept→{{ $json.concept }}status→pending(texto fijo)decided_by→ (déjalo vacío — se llena en el Workflow B)
Paso A4: notificar al canal
Un nodo Slack (Send) a #aprobaciones, con el formato de la cápsula 04:
*💰 Nueva solicitud de gasto — pendiente*
• *Solicitante:* {{ $('Set').item.json.requester }}
• *Monto:* `${{ $('Set').item.json.amount }}`
• *Concepto:* {{ $('Set').item.json.concept }}
• *ID:* `{{ $('Set').item.json.request_id }}`
<@TU_ID_DE_USUARIO> — para decidir, responde:
`/aprobar {{ $('Set').item.json.request_id }}` o `/rechazar {{ $('Set').item.json.request_id }}`
(Usa tu propio ID de usuario como "aprobador" para la prueba.)
Nota cómo el mensaje incluye el ID y le dice al equipo exactamente qué escribir. El equipo no tiene que recordar la sintaxis — el mensaje se la da.
WORKFLOW B — Recibir la decisión
Arquitectura
Slack Trigger (/aprobar [ID] o /rechazar [ID])
│
▼
Set: extraer la decisión y el ID del comando
│
▼
Google Sheets (Get Row(s)): buscar la solicitud por request_id
│
▼
IF: ¿se encontró la solicitud?
│
┌──────────────┴──────────────┐
▼ SÍ ▼ NO
Google Sheets (Update): Slack (Send): "no encontré
status + decided_by la solicitud [ID]"
│
▼
Slack (Send): confirmar la decisión en el canal
Paso B1: el Slack Trigger
Configúralo para recibir los slash commands /aprobar y /rechazar. Cuando alguien escribe /aprobar EXP-20260514-103000, el trigger recibe el comando y el texto.
Paso B2: extraer decisión e ID
Un nodo Set:
decision = {{ $json.command === '/aprobar' ? 'approved' : 'rejected' }}
request_id = {{ $json.text.trim() }}
decider = {{ $json.user }}
channel = {{ $json.channel }}
El command te dice si fue aprobar o rechazar; el text es el ID que el equipo escribió después del comando. (Ajusta los nombres de campo a lo que veas en el output real del trigger — cápsula 06.)
Paso B3: buscar la solicitud
Un nodo Google Sheets:
- Operation:
Get Row(s) - Document:
Solicitudes Gastos - Filter: Column
request_id, Value{{ $json.request_id }}
Renómbralo a Find Request.
Paso B4: el IF — ¿existe la solicitud?
{{ $('Find Request').all().length > 0 }}
true→ la solicitud existe → actualizarfalse→ ID inválido (typo, no existe) → avisar
Paso B5: rama TRUE — actualizar la hoja
Un nodo Google Sheets:
- Operation:
Update Row - Column to match on:
request_id - Mapping (solo lo que cambia):
request_id→{{ $('Set').item.json.request_id }}(la clave)status→{{ $('Set').item.json.decision }}decided_by→{{ $('Set').item.json.decider }}
Paso B6: rama TRUE — confirmar en el canal
Un nodo Slack (Send) al canal ({{ $('Set').item.json.channel }}):
{{ $('Set').item.json.decision === 'approved' ? '✅' : '🔴' }} Solicitud `{{ $('Set').item.json.request_id }}` *{{ $('Set').item.json.decision }}* por <@{{ $('Set').item.json.decider }}>
Paso B7: rama FALSE — avisar del ID inválido
Un nodo Slack (Send) al canal:
⚠️ No encontré ninguna solicitud con el ID `{{ $('Set').item.json.request_id }}`. Verifica el ID e intenta de nuevo.
Esta rama es lo que hace el workflow robusto: si el equipo escribe mal el ID, no falla en silencio — se lo dice.
Probar el sistema completo
Prueba 1: el ciclo feliz
- Activa el Workflow B (el Workflow A puede ser manual)
- Ejecuta el Workflow A → aparece la notificación en
#aprobaciones, hay una filapendingen la hoja - Copia el
request_iddel mensaje y escribe en Slack:/aprobar [ese-ID] - Verifica: el Workflow B disparó, la fila en la hoja pasó a
approvedcon tu ID endecided_by, y apareció la confirmación✅en el canal
Prueba 2: rechazo
- Ejecuta el Workflow A otra vez (nueva solicitud, nuevo ID)
- Escribe
/rechazar [el-nuevo-ID] - Verifica: la fila pasó a
rejected, confirmación🔴en el canal
Prueba 3: ID inválido
- Escribe
/aprobar EXP-INVENTADO-123 - Verifica: apareció el aviso
⚠️ No encontré...— el workflow no falló, te avisó
Checklist de éxito
- El Workflow A notifica con formato claro, menciona al aprobador, e incluye el ID y la sintaxis
- La solicitud queda registrada como
pendingen la hoja -
/aprobar [ID]y/rechazar [ID]disparan el Workflow B - El Workflow B actualiza el estado y el
decided_byen la hoja - La decisión se confirma de vuelta en el canal
- Un ID inválido recibe un aviso, no un fallo silencioso
- Los dos workflows "conversan" a través del ID y la hoja compartida
Cómo llevar esto a producción
Lo que construiste es un esqueleto reutilizable. Para producción:
- Cambia el Manual Trigger del Workflow A por un Webhook conectado a un formulario de solicitud de gastos.
- Botones en vez de comandos: en lugar de pedir
/aprobar [ID], el mensaje del Workflow A podría tener botones "Aprobar" / "Rechazar" (Block Kit interactivo, cápsula 04). Es más cómodo para el equipo — el ID viaja en el botón, nadie lo copia a mano. - Enrutar al aprobador correcto: según el monto o el área, mencionar a un aprobador distinto (búsqueda de usuario por email, cápsula 05).
- Evitar doble decisión: antes de actualizar, verificar que la solicitud sigue
pending— si ya fue decidida, avisar en vez de re-decidir. - Maneja errores: si Slack o Sheets fallan, el workflow se detiene. G10 (Production) cubre la resiliencia.
Resumen del módulo
Con este proyecto cierras el Módulo 4 — Slack. Recapitulando lo que ahora dominas:
- Conectar Slack creando una app con scopes (cápsula 02)
- Enviar mensajes a canales y personas, con threading (cápsula 03)
- Formato y menciones que hacen que un mensaje se lea y le llegue a quien debe (cápsula 04)
- Gestionar canales y usuarios para enrutamiento dinámico (cápsula 05)
- Recibir eventos y slash commands — Slack como interfaz de trabajo (cápsula 06)
- Diagnosticar scopes, permisos de canal y rate limits (cápsula 07)
- Notificaciones interactivas — dos workflows que conversan a través de Slack (esta cápsula)
El patrón estrella del módulo: Slack es el canal interno de alta frecuencia — y bien usado, no es solo donde el equipo se entera, es donde el equipo actúa.
Lo que sigue (Módulo 5):
Sheets, Gmail, Calendar y Slack son herramientas de Google y de comunicación. El Módulo 5 — Airtable y Notion sube el nivel de los datos: bases de datos flexibles, relacionales, con vistas. Vas a aprender cuándo una hoja se queda corta y necesitas una base de datos de verdad — sin dejar de ser no-dev.
Recursos adicionales
- n8n Slack node Docs - Operaciones Send y Update.
- n8n Slack Trigger Docs - Para el Workflow B.
- Slack Block Kit Builder - Para la versión con botones interactivos en producción.
Creado: Mayo 14, 2026 Versión: 1.0