AutomationFlowsData & Sheets › Academic Validation Base Structure

Academic Validation Base Structure

Original n8n title: Convalidaciones Académicas - Estructura Base

Convalidaciones Académicas - Estructura Base. Uses googleSheets, emailSend, googleDrive, httpRequest. Webhook trigger; 35 nodes.

Webhook trigger★★★★★ complexity35 nodesGoogle SheetsEmail SendGoogle DriveHTTP RequestComment
Data & Sheets Trigger: Webhook Nodes: 35 Complexity: ★★★★★ Added:

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 →

Download .json
{
  "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
}
Pro

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 →

More Data & Sheets workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Data & Sheets

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

Google Sheets, HTTP Request, Google Drive +1
Data & Sheets

Transform your n8n instance management with this advanced automation system featuring artificial intelligence-driven workflow selection. This template provides comprehensive maintenance operations wit

n8n, HTTP Request, Google Sheets +1
Data & Sheets

Are you tired of manually entering open house visitor information into your CRM? Losing hot leads because you didn't follow up fast enough? This powerful n8n workflow automatically syncs every SignSna

Email Send, Google Sheets, HubSpot +3
Data & Sheets

TrackCollect. Uses googleSheets, httpRequest, @n-octo-n/n8n-nodes-json-database, moveBinaryData. Webhook trigger; 31 nodes.

Google Sheets, HTTP Request, @N Octo N/N8N Nodes Json Database +2
Data & Sheets

This workflow automatically saves files received via LINE Messaging API into Google Drive and logs the file details into a Google Sheet. It checks the file type against allowed types, organizes files

Google Sheets, Google Drive, HTTP Request