This workflow follows the Emailsend → Google Drive recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "Convalidaciones Acad\u00e9micas - Estructura Base",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "solicitud-convalidacion",
"responseMode": "onReceived",
"authentication": "basicAuth",
"options": {
"responseHeaders": {
"entries": [
{
"name": "Content-Type",
"value": "application/json"
}
]
}
}
},
"name": "Webhook - Recepci\u00f3n",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [
250,
300
]
},
{
"parameters": {
"functionCode": "// Validaci\u00f3n de campos requeridos\nconst requiredFields = ['nombre', 'carrera', 'materias', 'documentos'];\nconst errors = [];\n\nfor (const field of requiredFields) {\n if (!$input.item.json[field]) {\n errors.push(`Campo requerido: ${field}`);\n }\n}\n\nif (errors.length > 0) {\n return {\n json: {\n success: false,\n errors: errors\n }\n };\n}\n\nreturn {\n json: {\n ...$input.item.json,\n documentosCompletos: true,\n fechaSolicitud: new Date().toISOString()\n }\n};"
},
"name": "Function - Validar",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
450,
300
]
},
{
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{$json.documentosCompletos}}",
"value2": true
}
]
}
},
"name": "IF - Documentaci\u00f3n",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
650,
300
]
},
{
"parameters": {
"functionCode": "// Comprueba que todos los archivos tengan extensi\u00f3n .pdf (case-insensitive)\nconst docs = $input.item.json.documentos || [];\nconst badFiles = [];\nfor (const d of docs) {\n const fn = d.fileName || d.name || (d.url ? d.url.split('/').pop() : '');\n if (!fn) continue;\n if (!fn.toLowerCase().endsWith('.pdf')) {\n badFiles.push(fn);\n }\n}\nreturn { json: { ...$input.item.json, pdfsOk: badFiles.length === 0, badFiles } };"
},
"name": "Function - Check PDFs",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
800,
300
]
},
{
"parameters": {
"functionCode": "// Registra el estado tras la validaci\u00f3n\nconst status = $json.success === false ? 'Validaci\u00f3n fallida' : 'Validado';\nconst details = $json.success === false ? ($json.errors || []).join('; ') : '';\nreturn { json: { ...$json, status, details, statusTimestamp: new Date().toISOString() } };"
},
"name": "Function - Status: Validaci\u00f3n",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
550,
300
]
},
{
"parameters": {
"functionCode": "// Registra el resultado de la comprobacion de PDFs\nconst status = $json.pdfsOk ? 'PDFs OK' : 'PDFs inv\u00e1lidos';\nconst details = ($json.badFiles || []).join(', ');\nreturn { json: { ...$json, status, details, statusTimestamp: new Date().toISOString() } };"
},
"name": "Function - Status: PDF Check",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
900,
300
]
},
{
"parameters": {
"functionCode": "// Estado: documentos almacenados\nreturn { json: { ...$input.item.json, status: 'Documentos almacenados', details: '', statusTimestamp: new Date().toISOString() } };"
},
"name": "Function - Status: Stored",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
1000,
180
]
},
{
"parameters": {
"functionCode": "// Estado: registro creado\nreturn { json: { ...$input.item.json, status: 'Registro creado', details: '', statusTimestamp: new Date().toISOString() } };"
},
"name": "Function - Status: Registered",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
1000,
420
]
},
{
"parameters": {
"functionCode": "// Estado: acta generada\nreturn { json: { ...$input.item.json, status: 'Acta generada', details: '', statusTimestamp: new Date().toISOString() } };"
},
"name": "Function - Status: Acta Generada",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
1750,
260
]
},
{
"parameters": {
"operation": "append",
"sheetName": "Logs",
"columns": [
{
"column": "Timestamp",
"value": "={{$json.statusTimestamp || new Date().toISOString()}}"
},
{
"column": "ID",
"value": "={{$json.id || ''}}"
},
{
"column": "Status",
"value": "={{$json.status || ''}}"
},
{
"column": "Details",
"value": "={{$json.details || ''}}"
}
]
},
"name": "DB - Log",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 1,
"position": [
1300,
360
]
},
{
"parameters": {
"operation": "append",
"sheetName": "Logs",
"columns": [
{
"column": "Timestamp",
"value": "={{$json.statusTimestamp || new Date().toISOString()}}"
},
{
"column": "ID",
"value": "={{$json.id || ''}}"
},
{
"column": "Status",
"value": "={{$json.status || ''}}"
},
{
"column": "Details",
"value": "={{$json.details || ''}}"
}
]
},
"name": "DB - Log - Validaci\u00f3n",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 1,
"position": [
950,
300
]
},
{
"parameters": {
"operation": "append",
"sheetName": "Logs",
"columns": [
{
"column": "Timestamp",
"value": "={{$json.statusTimestamp || new Date().toISOString()}}"
},
{
"column": "ID",
"value": "={{$json.id || ''}}"
},
{
"column": "Status",
"value": "={{$json.status || ''}}"
},
{
"column": "Details",
"value": "={{$json.details || ''}}"
}
]
},
"name": "DB - Log - PDFCheck",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 1,
"position": [
1150,
300
]
},
{
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{$json.pdfsOk}}",
"value2": true
}
]
}
},
"name": "IF - PDFs OK?",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
1000,
300
]
},
{
"parameters": {
"fromEmail": "sistema@ejemplo.com",
"toEmail": "={{$json.estudianteEmail}}",
"subject": "Archivo no v\u00e1lido",
"text": "Estimado alumno, el archivo enviado no es del formato adecuado .PDF"
},
"name": "Email - Not PDF",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 1,
"position": [
1200,
380
]
},
{
"parameters": {
"resource": "file",
"operation": "upload"
},
"name": "Storage - Documentos",
"type": "n8n-nodes-base.googleDrive",
"typeVersion": 1,
"position": [
850,
200
]
},
{
"parameters": {
"operation": "append",
"sheetName": "Solicitudes",
"columns": [
{
"column": "ID",
"value": "={{$json.id}}"
},
{
"column": "Fecha",
"value": "={{$json.fechaSolicitud}}"
},
{
"column": "Estudiante",
"value": "={{$json.nombre}}"
},
{
"column": "Estado",
"value": "Pendiente"
}
]
},
"name": "DB - Registro",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 1,
"position": [
850,
400
]
},
{
"parameters": {
"fromEmail": "sistema@ejemplo.com",
"toEmail": "={{$json.directorEmail}}",
"subject": "Nueva Solicitud de Convalidaci\u00f3n",
"text": "=Plantilla de correo con datos"
},
"name": "Email - Director",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 1,
"position": [
1050,
300
]
},
{
"parameters": {
"httpMethod": "GET",
"path": "decision-director",
"responseMode": "onReceived"
},
"name": "Webhook - Decisi\u00f3n",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [
1250,
300
]
},
{
"parameters": {
"functionCode": "// Procesar decisi\u00f3n del director\n// Se espera que la llamada al webhook incluya query params: decision y id\nconst decision = $input.item.json.query && $input.item.json.query.decision ? $input.item.json.query.decision : ($input.item.json.decision || null);\nconst solicitudId = $input.item.json.query && $input.item.json.query.id ? $input.item.json.query.id : ($input.item.json.solicitudId || null);\n\nreturn [{\n json: {\n decision,\n solicitudId,\n timestamp: new Date().toISOString(),\n ...$input.item.json\n }\n}];"
},
"name": "Function - Procesar Decisi\u00f3n",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
1450,
300
]
},
{
"parameters": {
"conditions": {
"string": [
{
"value1": "={{$json.decision}}",
"operation": "equal",
"value2": "Aceptada"
},
{
"value1": "={{$json.decision}}",
"operation": "equal",
"value2": "Rechazada"
},
{
"value1": "={{$json.decision}}",
"operation": "equal",
"value2": "Revisi\u00f3n Adicional"
}
]
}
},
"name": "Switch - Decision",
"type": "n8n-nodes-base.switch",
"typeVersion": 1,
"position": [
1650,
300
]
},
{
"parameters": {
"operation": "append",
"sheetName": "Solicitudes",
"updateKey": "ID",
"updateKeyColumn": "ID",
"columns": [
{
"column": "Estado",
"value": "Convalidada"
}
]
},
"name": "Sheets - Update Aceptada",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 1,
"position": [
1850,
220
]
},
{
"parameters": {
"operation": "append",
"sheetName": "Solicitudes",
"updateKey": "ID",
"updateKeyColumn": "ID",
"columns": [
{
"column": "Estado",
"value": "No Convalidada"
}
]
},
"name": "Sheets - Update Rechazada",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 1,
"position": [
1850,
360
]
},
{
"parameters": {
"operation": "append",
"sheetName": "Solicitudes",
"updateKey": "ID",
"updateKeyColumn": "ID",
"columns": [
{
"column": "Estado",
"value": "En revisi\u00f3n"
}
]
},
"name": "Sheets - Update Revision",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 1,
"position": [
1850,
440
]
},
{
"parameters": {
"fromEmail": "sistema@ejemplo.com",
"toEmail": "={{$json.estudianteEmail}}",
"subject": "Solicitud Aceptada - Convalidaci\u00f3n",
"text": "Estimado/a {{$json.nombre}},\n\nSu solicitud ha sido ACEPTADA. Se adjunta el acta de convalidaci\u00f3n."
},
"name": "Email - Estudiante Aceptada",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 1,
"position": [
2050,
220
]
},
{
"parameters": {
"fromEmail": "sistema@ejemplo.com",
"toEmail": "={{$json.estudianteEmail}}",
"subject": "Solicitud Rechazada - Convalidaci\u00f3n",
"text": "Estimado/a {{$json.nombre}},\n\nSu solicitud ha sido RECHAZADA. Consulte las observaciones."
},
"name": "Email - Estudiante Rechazada",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 1,
"position": [
2050,
360
]
},
{
"parameters": {
"fromEmail": "sistema@ejemplo.com",
"toEmail": "comite@universidad.edu",
"subject": "Solicitud para Revisi\u00f3n Adicional",
"text": "Se solicita revisi\u00f3n adicional para la solicitud ID: {{$json.solicitudId}}"
},
"name": "Email - Comit\u00e9 Revision",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 1,
"position": [
2050,
440
]
},
{
"parameters": {
"resource": "file",
"operation": "create"
},
"name": "PDF - Generar Acta",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 1,
"position": [
1650,
300
]
},
{
"parameters": {
"notes": "Recepci\u00f3n: Webhook que recibe solicitudes de convalidaci\u00f3n. Espera JSON con datos del estudiante y documentos."
},
"name": "Note - Recepci\u00f3n",
"type": "n8n-nodes-base.comment",
"typeVersion": 1,
"position": [
250,
220
]
},
{
"parameters": {
"notes": "Validaci\u00f3n: Comprueba campos requeridos y marca la solicitud con fecha."
},
"name": "Note - Validaci\u00f3n",
"type": "n8n-nodes-base.comment",
"typeVersion": 1,
"position": [
450,
220
]
},
{
"parameters": {
"notes": "Comprobaci\u00f3n de archivos: Verifica que todos los documentos tengan extensi\u00f3n .pdf. Si no, notifica y termina."
},
"name": "Note - PDF Check",
"type": "n8n-nodes-base.comment",
"typeVersion": 1,
"position": [
900,
220
]
},
{
"parameters": {
"notes": "Almacenamiento y registro: Guarda documentos en Google Drive y registra la solicitud en Google Sheets."
},
"name": "Note - Storage & Registro",
"type": "n8n-nodes-base.comment",
"typeVersion": 1,
"position": [
950,
120
]
},
{
"parameters": {
"notes": "Decisi\u00f3n del director: Se env\u00eda correo al director con enlaces/opciones. La decisi\u00f3n llega al webhook /decision-director."
},
"name": "Note - Decisi\u00f3n Director",
"type": "n8n-nodes-base.comment",
"typeVersion": 1,
"position": [
1250,
220
]
},
{
"parameters": {
"notes": "Ramas de decisi\u00f3n: Aceptada -> genera acta y notifica; Rechazada -> notifica al estudiante; Revisi\u00f3n -> notifica comit\u00e9 y estudiante."
},
"name": "Note - Ramas Decision",
"type": "n8n-nodes-base.comment",
"typeVersion": 1,
"position": [
1750,
360
]
},
{
"parameters": {
"fromEmail": "sistema@ejemplo.com",
"toEmail": "={{$json.estudianteEmail}}",
"subject": "Solicitud en revisi\u00f3n - Convalidaci\u00f3n",
"text": "Estimado/a {{$json.nombre}},\n\nSu solicitud ha pasado a revisi\u00f3n adicional. Le notificaremos cuando haya una resoluci\u00f3n."
},
"name": "Email - Estudiante Revision",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 1,
"position": [
2050,
380
]
},
{
"parameters": {
"operation": "append"
},
"name": "DB - Hist\u00f3rico",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 1,
"position": [
2050,
300
]
}
],
"connections": {
"Webhook - Recepci\u00f3n": {
"main": [
[
{
"node": "Function - Validar",
"type": "main",
"index": 0
}
]
]
},
"Function - Validar": {
"main": [
[
{
"node": "Function - Status: Validaci\u00f3n",
"type": "main",
"index": 0
}
]
]
},
"Function - Status: Validaci\u00f3n": {
"main": [
[
{
"node": "DB - Log - Validaci\u00f3n",
"type": "main",
"index": 0
}
]
]
},
"DB - Log - Validaci\u00f3n": {
"main": [
[
{
"node": "IF - Documentaci\u00f3n",
"type": "main",
"index": 0
}
]
]
},
"IF - Documentaci\u00f3n": {
"main": [
[
{
"node": "Function - Check PDFs",
"type": "main",
"index": 0
}
]
]
},
"Function - Check PDFs": {
"main": [
[
{
"node": "Function - Status: PDF Check",
"type": "main",
"index": 0
}
]
]
},
"Function - Status: PDF Check": {
"main": [
[
{
"node": "DB - Log - PDFCheck",
"type": "main",
"index": 0
}
]
]
},
"DB - Log - PDFCheck": {
"main": [
[
{
"node": "IF - PDFs OK?",
"type": "main",
"index": 0
}
]
]
},
"IF - PDFs OK?": {
"main": [
[
{
"node": "Function - Status: Stored",
"type": "main",
"index": 0
},
{
"node": "Function - Status: Registered",
"type": "main",
"index": 0
}
],
[
{
"node": "Email - Not PDF",
"type": "main",
"index": 0
}
]
]
},
"Function - Status: Stored": {
"main": [
[
{
"node": "DB - Log",
"type": "main",
"index": 0
}
]
]
},
"Function - Status: Registered": {
"main": [
[
{
"node": "DB - Log",
"type": "main",
"index": 0
}
]
]
},
"DB - Log": {
"main": [
[
{
"node": "Storage - Documentos",
"type": "main",
"index": 0
},
{
"node": "DB - Registro",
"type": "main",
"index": 0
}
]
]
},
"Storage - Documentos": {
"main": [
[
{
"node": "Email - Director",
"type": "main",
"index": 0
}
]
]
},
"DB - Registro": {
"main": [
[
{
"node": "Email - Director",
"type": "main",
"index": 0
}
]
]
},
"Email - Director": {
"main": [
[
{
"node": "Webhook - Decisi\u00f3n",
"type": "main",
"index": 0
}
]
]
},
"Webhook - Decisi\u00f3n": {
"main": [
[
{
"node": "Function - Procesar Decisi\u00f3n",
"type": "main",
"index": 0
}
]
]
},
"Function - Procesar Decisi\u00f3n": {
"main": [
[
{
"node": "Switch - Decision",
"type": "main",
"index": 0
}
]
]
},
"Switch - Decision": {
"main": [
[
{
"node": "Sheets - Update Aceptada",
"type": "main",
"index": 0
}
],
[
{
"node": "Sheets - Update Rechazada",
"type": "main",
"index": 0
}
],
[
{
"node": "Sheets - Update Revision",
"type": "main",
"index": 0
}
]
]
},
"Sheets - Update Aceptada": {
"main": [
[
{
"node": "PDF - Generar Acta",
"type": "main",
"index": 0
}
]
]
},
"PDF - Generar Acta": {
"main": [
[
{
"node": "Function - Status: Acta Generada",
"type": "main",
"index": 0
}
]
]
},
"Function - Status: Acta Generada": {
"main": [
[
{
"node": "Email - Estudiante Aceptada",
"type": "main",
"index": 0
}
]
]
},
"Email - Estudiante Aceptada": {
"main": [
[
{
"node": "DB - Hist\u00f3rico",
"type": "main",
"index": 0
}
]
]
},
"Sheets - Update Rechazada": {
"main": [
[
{
"node": "Email - Estudiante Rechazada",
"type": "main",
"index": 0
}
]
]
},
"Email - Estudiante Rechazada": {
"main": [
[
{
"node": "DB - Hist\u00f3rico",
"type": "main",
"index": 0
}
]
]
},
"Sheets - Update Revision": {
"main": [
[
{
"node": "Email - Comit\u00e9 Revision",
"type": "main",
"index": 0
}
]
]
},
"Email - Comit\u00e9 Revision": {
"main": [
[
{
"node": "Email - Estudiante Revision",
"type": "main",
"index": 0
}
]
]
},
"Email - Estudiante Revision": {
"main": [
[
{
"node": "DB - Hist\u00f3rico",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {},
"staticData": null,
"tags": [
"convalidaciones",
"acad\u00e9mico"
],
"triggerCount": 0
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Convalidaciones Académicas - Estructura Base. Uses googleSheets, emailSend, googleDrive, httpRequest. Webhook trigger; 35 nodes.
Source: https://github.com/FelipeNVR/Proyecto-n8n-main/blob/14560b61d5bf600175b94523e570e877d0100d96/Proyecto-n8n-main/n8n/flow.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
FlowV4. Uses googleSheets, emailSend, googleDrive, httpRequest. Webhook trigger; 31 nodes.
This workflow automates invoice generation from form submissions, ensuring unique order IDs, creating PDF invoices, storing files, emailing customers, and logging invoice data — all seamlessly integra
Student Resume Review & Feedback. Uses httpRequest, googleDrive, googleSheets, emailSend. Webhook trigger; 7 nodes.
Resume Screening & Behavioral Interviews with Gemini, Elevenlabs, & Notion ATS copy. Uses googleDrive, httpRequest, notion, formTrigger. Webhook trigger; 67 nodes.
This workflow sends post-purchase review request emails for WooCommerce orders, stores expiring form links in Google Sheets, optionally shortens links with Dub.co and delays delivery, serves a hosted