This workflow corresponds to n8n.io template #13690 — we link there as the canonical source.
This workflow follows the Agent → Airtable 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 →
{
"id": "uWGNuY0nZqgglGpm",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Automated Scholarship Eligibility Matcher",
"tags": [],
"nodes": [
{
"id": "fd2b4029-1979-4e20-9d21-5bde07251b9d",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-368,
-304
],
"parameters": {
"width": 960,
"height": 1848,
"content": "## Automated Scholarship Eligibility Matcher\n\nThis workflow ingests student profiles from a form submission or CRM, loads the active scholarship catalogue, uses Claude AI to score each student's eligibility against every available scholarship, filters strong matches, and automatically notifies eligible candidates with personalised application guidance.\n\n### How it works\n\n1. **Trigger** \u2014 Form submission webhook or nightly scheduled batch run\n2. **Load Student Profile** \u2014 Fetches or normalises the student's academic and personal data\n3. **Load Scholarship Catalogue** \u2014 Pulls active scholarships from Airtable / Google Sheets\n4. **Pair Students \u00d7 Scholarships** \u2014 Builds evaluation pairs for AI scoring\n5. **AI Eligibility Scoring** \u2014 Claude AI scores fit, flags eligibility, ranks scholarships\n6. **Parse & Rank Results** \u2014 Extracts structured scores, sorts by match strength\n7. **Filter Qualified Matches** \u2014 Keeps scholarships above configurable match threshold\n8. **Check Deadline Urgency** \u2014 Flags scholarships closing within 14 days\n9. **Personalise Notification** \u2014 Builds tailored email per student with top matches\n10. **Send Student Email** \u2014 Dispatches personalised scholarship digest\n11. **Notify Advisor on Slack** \u2014 Alerts academic advisor for high-value matches\n12. **Update CRM Record** \u2014 Writes matched scholarships back to Airtable student record\n13. **Log to Audit Sheet** \u2014 Appends full match report to Google Sheets\n14. **Return API Response** \u2014 Returns structured match results to caller\n\n### Setup Steps\n\n1. Import workflow into n8n\n2. Configure credentials:\n - **Anthropic API** \u2014 Claude AI for eligibility scoring\n - **Airtable** \u2014 Student profiles and scholarship catalogue\n - **Google Sheets** \u2014 Audit and match history log\n - **Slack OAuth** \u2014 Academic advisor notifications\n - **SendGrid / SMTP** \u2014 Student notification emails\n3. Set your Airtable base ID and table names for students and scholarships\n4. Configure match threshold (default: 70) in filter node\n5. Set urgency window (default: 14 days) in deadline check node\n6. Add your Slack advisor channel ID\n7. Activate the workflow\n\n### Sample Webhook Payload\n```json\n{\n \"studentId\": \"STU-2025-4821\",\n \"firstName\": \"Priya\",\n \"lastName\": \"Sharma\",\n \"email\": \"priya.sharma@university.edu\",\n \"gpa\": 3.8,\n \"major\": \"Computer Science\",\n \"yearOfStudy\": 2,\n \"nationality\": \"Indian\",\n \"residencyStatus\": \"International\",\n \"financialNeed\": true,\n \"extracurriculars\": [\"Robotics Club\", \"Volunteer Tutor\"],\n \"achievements\": [\"Dean's List 2024\", \"Hackathon Winner\"],\n \"intendedCareer\": \"AI Research\",\n \"disabilities\": false,\n \"firstGenStudent\": true\n}\n```\n\n### Scholarship Criteria Evaluated by Claude AI\n- **Academic Merit** \u2014 GPA, honours, academic awards\n- **Field of Study** \u2014 Major/discipline alignment\n- **Financial Need** \u2014 Demonstrated need indicators\n- **Demographic Eligibility** \u2014 Nationality, residency, gender, Indigenous status\n- **Year of Study** \u2014 Undergraduate, postgraduate, PhD level\n- **Extracurricular Profile** \u2014 Leadership, community service, sports\n- **Career Alignment** \u2014 Intended career path vs scholarship mission\n- **Special Circumstances** \u2014 First-gen, disability support, regional background\n\n### Features\n- Batch processing of entire student cohort nightly\n- AI-powered multi-criteria eligibility scoring (0\u2013100)\n- Deadline urgency detection and priority flagging\n- Personalised email with ranked scholarship list and tips\n- Academic advisor Slack digest for high-value matches\n- Full audit trail in Google Sheets\n- Airtable CRM auto-update with matched scholarships\n\n---\n\n**Explore More Automation:** \n[Contact us](https://www.oneclickitsolution.com/contact-us/) to design AI-powered lead nurturing, content engagement, and multi-platform reply workflows tailored to your growth strategy."
},
"typeVersion": 1
},
{
"id": "0bbac8b0-8bfc-4802-ba43-7683dc15b97e",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
1024,
416
],
"parameters": {
"color": 6,
"width": 428,
"height": 464,
"content": "## 1. Intake & Data Loading\n### Student Profiles \u00b7 Scholarship Catalogue"
},
"typeVersion": 1
},
{
"id": "de5ca0a7-a3fa-4ddc-8a0c-d9c057e85788",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
1488,
304
],
"parameters": {
"color": 4,
"width": 396,
"height": 592,
"content": "## 2. Profile Normalisation & Scholarship Pairing\n### Data Cleaning \u00b7 Criteria Extraction \u00b7 Pair Builder"
},
"typeVersion": 1
},
{
"id": "55433aba-5389-4d44-914b-f613c91ec70e",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1926,
424
],
"parameters": {
"color": 6,
"width": 564,
"height": 568,
"content": "## 3. Claude AI Eligibility Scoring & Ranking"
},
"typeVersion": 1
},
{
"id": "a8c123f1-ff12-49b1-b2ca-134ee307d08f",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
2528,
320
],
"parameters": {
"color": 4,
"width": 1148,
"height": 716,
"content": "## 4. Filtering \u00b7 Personalised Notifications \u00b7 CRM Update \u00b7 Audit Log"
},
"typeVersion": 1
},
{
"id": "d04cac7e-596b-4da1-945c-8da92ade6e9f",
"name": "Receive Student Profile Submission",
"type": "n8n-nodes-base.webhook",
"position": [
1104,
720
],
"parameters": {
"path": "match-scholarships",
"options": {
"allowedOrigins": "*"
},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "9bb3a2bc-9e57-406b-b555-78a76675b6d7",
"name": "Nightly Batch Schedule",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
1104,
528
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 22 * * *"
}
]
}
},
"typeVersion": 1.2
},
{
"id": "a8ff9cd3-5a6f-4886-b83e-8752a6f9d32b",
"name": "Load Student Profiles",
"type": "n8n-nodes-base.airtable",
"position": [
1328,
528
],
"parameters": {
"base": {
"__rl": true,
"mode": "id",
"value": "="
},
"table": {
"__rl": true,
"mode": "id",
"value": "="
},
"options": {},
"operation": "search",
"filterByFormula": "AND({Status} = 'Active', {MatchingRun} != TODAY())"
},
"credentials": {
"airtableTokenApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.1,
"continueOnFail": true
},
{
"id": "73644939-369a-451a-8559-12f0cb881941",
"name": "Load Scholarship Catalogue",
"type": "n8n-nodes-base.airtable",
"position": [
1328,
720
],
"parameters": {
"base": {
"__rl": true,
"mode": "id",
"value": "="
},
"table": {
"__rl": true,
"mode": "id",
"value": "="
},
"options": {},
"operation": "search",
"filterByFormula": "AND({Active} = TRUE(), IS_AFTER({Application Deadline}, TODAY()))"
},
"credentials": {
"airtableTokenApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.1,
"continueOnFail": true
},
{
"id": "ee8975c2-6bc9-453c-b44b-97b3a5787317",
"name": "Normalise Profiles & Build Pairs",
"type": "n8n-nodes-base.code",
"position": [
1552,
624
],
"parameters": {
"jsCode": "// Collect all items \u2014 students from Airtable or webhook payload\nconst allItems = $input.all();\n\n// Detect source: webhook vs batch\nconst webhookBody = allItems[0]?.json?.body || allItems[0]?.json || {};\nconst isWebhook = !!webhookBody.studentId || !!webhookBody.email;\n\n// Build student list\nlet students = [];\nif (isWebhook) {\n // Single student from webhook\n students = [{\n studentId: webhookBody.studentId || `STU-${Date.now()}`,\n firstName: webhookBody.firstName || '',\n lastName: webhookBody.lastName || '',\n email: webhookBody.email || '',\n gpa: parseFloat(webhookBody.gpa) || 0,\n major: webhookBody.major || '',\n yearOfStudy: parseInt(webhookBody.yearOfStudy) || 1,\n nationality: webhookBody.nationality || '',\n residencyStatus: (webhookBody.residencyStatus || 'domestic').toUpperCase(),\n financialNeed: webhookBody.financialNeed === true || webhookBody.financialNeed === 'true',\n extracurriculars: Array.isArray(webhookBody.extracurriculars) ? webhookBody.extracurriculars : (webhookBody.extracurriculars || '').split(',').map(s => s.trim()).filter(Boolean),\n achievements: Array.isArray(webhookBody.achievements) ? webhookBody.achievements : (webhookBody.achievements || '').split(',').map(s => s.trim()).filter(Boolean),\n intendedCareer: webhookBody.intendedCareer || '',\n disabilityStatus: webhookBody.disabilities === true || webhookBody.disabilities === 'true',\n firstGenStudent: webhookBody.firstGenStudent === true || webhookBody.firstGenStudent === 'true',\n indigenousStatus: webhookBody.indigenousStatus === true || webhookBody.indigenousStatus === 'true',\n gender: webhookBody.gender || '',\n regionalBackground: webhookBody.regionalBackground === true || webhookBody.regionalBackground === 'true',\n notes: webhookBody.notes || ''\n }];\n} else {\n // Batch from Airtable\n students = allItems\n .filter(i => i.json.fields?.['Student ID'])\n .map(i => {\n const f = i.json.fields;\n return {\n studentId: f['Student ID'],\n firstName: f['First Name'] || '',\n lastName: f['Last Name'] || '',\n email: f['Email'] || '',\n gpa: parseFloat(f['GPA']) || 0,\n major: f['Major'] || '',\n yearOfStudy: parseInt(f['Year of Study']) || 1,\n nationality: f['Nationality'] || '',\n residencyStatus: (f['Residency Status'] || 'DOMESTIC').toUpperCase(),\n financialNeed: f['Financial Need'] === true || f['Financial Need'] === 'Yes',\n extracurriculars: (f['Extracurriculars'] || '').split(',').map(s => s.trim()).filter(Boolean),\n achievements: (f['Achievements'] || '').split(',').map(s => s.trim()).filter(Boolean),\n intendedCareer: f['Intended Career'] || '',\n disabilityStatus: f['Disability Status'] === true || f['Disability Status'] === 'Yes',\n firstGenStudent: f['First Gen Student'] === true || f['First Gen Student'] === 'Yes',\n indigenousStatus: f['Indigenous Status'] === true || f['Indigenous Status'] === 'Yes',\n gender: f['Gender'] || '',\n regionalBackground: f['Regional Background'] === true || f['Regional Background'] === 'Yes',\n notes: f['Notes'] || ''\n };\n });\n}\n\n// Build scholarship list from Airtable results\nconst scholarships = allItems\n .filter(i => i.json.fields?.['Scholarship ID'])\n .map(i => {\n const f = i.json.fields;\n const deadline = f['Application Deadline'] ? new Date(f['Application Deadline']) : null;\n const daysToDeadline = deadline ? Math.ceil((deadline - new Date()) / (1000 * 60 * 60 * 24)) : 999;\n return {\n scholarshipId: f['Scholarship ID'],\n name: f['Name'] || '',\n provider: f['Provider'] || '',\n valueAUD: parseFloat(f['Value AUD']) || 0,\n deadline: f['Application Deadline'] || '',\n daysToDeadline,\n isUrgent: daysToDeadline <= 14,\n eligibleMajors: (f['Eligible Majors'] || 'ANY').split(',').map(s => s.trim()),\n minGPA: parseFloat(f['Min GPA']) || 0,\n yearLevels: (f['Year Levels'] || 'ANY').split(',').map(s => s.trim()),\n nationalityRequirements: f['Nationality Requirements'] || 'ANY',\n residencyRequirements: (f['Residency Requirements'] || 'ANY').toUpperCase(),\n financialNeedRequired: f['Financial Need Required'] === true || f['Financial Need Required'] === 'Yes',\n genderRequirement: f['Gender Requirement'] || 'ANY',\n disabilityPreference: f['Disability Preference'] === true || f['Disability Preference'] === 'Yes',\n firstGenPreference: f['First Gen Preference'] === true || f['First Gen Preference'] === 'Yes',\n indigenousPreference: f['Indigenous Preference'] === true || f['Indigenous Preference'] === 'Yes',\n extracurricularRequirements: f['Extracurricular Requirements'] || '',\n careerFocus: f['Career Focus'] || '',\n description: f['Description'] || '',\n applicationURL: f['Application URL'] || '',\n renewable: f['Renewable'] === true || f['Renewable'] === 'Yes',\n numberOfAwards: parseInt(f['Number of Awards']) || 1\n };\n });\n\n// Demo scholarships if none loaded from Airtable\nconst demoScholarships = scholarships.length > 0 ? scholarships : [\n { scholarshipId: 'SCH-001', name: 'STEM Excellence Award', provider: 'Tech Foundation', valueAUD: 10000, deadline: '2025-07-31', daysToDeadline: 30, isUrgent: false, eligibleMajors: ['Computer Science', 'Engineering', 'Mathematics', 'Physics'], minGPA: 3.5, yearLevels: ['1', '2', '3'], nationalityRequirements: 'ANY', residencyRequirements: 'ANY', financialNeedRequired: false, genderRequirement: 'ANY', disabilityPreference: false, firstGenPreference: false, indigenousPreference: false, extracurricularRequirements: '', careerFocus: 'Technology, AI, Data Science', description: 'For outstanding STEM students demonstrating academic excellence and innovation.', applicationURL: 'https://techfoundation.org/apply', renewable: true, numberOfAwards: 5 },\n { scholarshipId: 'SCH-002', name: 'First Generation Leaders Scholarship', provider: 'National Education Trust', valueAUD: 7500, deadline: '2025-06-20', daysToDeadline: 10, isUrgent: true, eligibleMajors: ['ANY'], minGPA: 3.0, yearLevels: ['1', '2'], nationalityRequirements: 'ANY', residencyRequirements: 'DOMESTIC', financialNeedRequired: true, genderRequirement: 'ANY', disabilityPreference: false, firstGenPreference: true, indigenousPreference: false, extracurricularRequirements: 'Community service preferred', careerFocus: 'ANY', description: 'Supporting first-generation university students with demonstrated financial need.', applicationURL: 'https://netedu.org/first-gen', renewable: false, numberOfAwards: 20 },\n { scholarshipId: 'SCH-003', name: 'International Women in Tech Grant', provider: 'Global Tech Alliance', valueAUD: 15000, deadline: '2025-08-15', daysToDeadline: 55, isUrgent: false, eligibleMajors: ['Computer Science', 'Information Technology', 'Data Science'], minGPA: 3.2, yearLevels: ['2', '3', '4'], nationalityRequirements: 'ANY', residencyRequirements: 'INTERNATIONAL', financialNeedRequired: false, genderRequirement: 'Female', disabilityPreference: false, firstGenPreference: false, indigenousPreference: false, extracurricularRequirements: 'Leadership role preferred', careerFocus: 'Technology, Engineering', description: 'Empowering international women pursuing technology careers.', applicationURL: 'https://globaltechalliance.org/women', renewable: true, numberOfAwards: 3 },\n { scholarshipId: 'SCH-004', name: 'Regional Access Bursary', provider: 'State Government', valueAUD: 5000, deadline: '2025-07-01', daysToDeadline: 25, isUrgent: false, eligibleMajors: ['ANY'], minGPA: 2.5, yearLevels: ['1', '2', '3', '4'], nationalityRequirements: 'Australian', residencyRequirements: 'DOMESTIC', financialNeedRequired: true, genderRequirement: 'ANY', disabilityPreference: false, firstGenPreference: false, indigenousPreference: false, extracurricularRequirements: '', careerFocus: 'ANY', description: 'Supporting students from regional and rural backgrounds relocating for university.', applicationURL: 'https://stategov.edu.au/regional', renewable: false, numberOfAwards: 50 },\n { scholarshipId: 'SCH-005', name: 'Future AI Researchers Fellowship', provider: 'AI Research Institute', valueAUD: 25000, deadline: '2025-09-30', daysToDeadline: 90, isUrgent: false, eligibleMajors: ['Computer Science', 'Mathematics', 'Cognitive Science'], minGPA: 3.7, yearLevels: ['3', '4', 'Postgraduate'], nationalityRequirements: 'ANY', residencyRequirements: 'ANY', financialNeedRequired: false, genderRequirement: 'ANY', disabilityPreference: false, firstGenPreference: false, indigenousPreference: false, extracurricularRequirements: 'Research experience or publications preferred', careerFocus: 'Artificial Intelligence, Machine Learning', description: 'Prestigious fellowship for students committed to advancing AI research.', applicationURL: 'https://airesearch.org/fellowship', renewable: true, numberOfAwards: 2 }\n];\n\nconst finalScholarships = demoScholarships;\n\n// Demo student if none loaded\nconst demoStudents = students.length > 0 ? students : [{\n studentId: 'STU-DEMO-001', firstName: 'Priya', lastName: 'Sharma',\n email: 'user@example.com', gpa: 3.8,\n major: 'Computer Science', yearOfStudy: 2,\n nationality: 'Indian', residencyStatus: 'INTERNATIONAL',\n financialNeed: true, extracurriculars: ['Robotics Club', 'Volunteer Tutor'],\n achievements: [\"Dean's List 2024\", 'Hackathon Winner'],\n intendedCareer: 'AI Research', disabilityStatus: false,\n firstGenStudent: true, indigenousStatus: false,\n gender: 'Female', regionalBackground: false, notes: ''\n}];\n\nconst finalStudents = demoStudents;\n\n// Emit one item per student (scholarships passed as context)\nreturn finalStudents.map(student => ({\n json: {\n student,\n scholarships: finalScholarships,\n totalScholarships: finalScholarships.length,\n runId: `MATCH-${Date.now()}-${Math.random().toString(36).substr(2,5).toUpperCase()}`\n }\n}));"
},
"typeVersion": 2
},
{
"id": "ab1f5be9-6c81-48c1-a992-9b036f5ce828",
"name": "Pre-Filter Hard Ineligibility",
"type": "n8n-nodes-base.code",
"position": [
1776,
624
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// Hard-filter out scholarships the student is definitively ineligible for\n// before sending to Claude \u2014 reduces token cost and improves accuracy\nconst { student, scholarships, runId } = $input.item.json;\n\nconst candidateScholarships = scholarships.filter(sch => {\n // GPA hard cutoff\n if (student.gpa < sch.minGPA) return false;\n\n // Year of study check\n if (!sch.yearLevels.includes('ANY')) {\n const yearStr = String(student.yearOfStudy);\n const yearMatch = sch.yearLevels.some(y =>\n y.trim() === yearStr ||\n (y.toLowerCase().includes('post') && student.yearOfStudy > 4) ||\n y.trim() === 'ANY'\n );\n if (!yearMatch) return false;\n }\n\n // Residency hard check\n if (sch.residencyRequirements !== 'ANY') {\n if (sch.residencyRequirements === 'DOMESTIC' && student.residencyStatus === 'INTERNATIONAL') return false;\n if (sch.residencyRequirements === 'INTERNATIONAL' && student.residencyStatus === 'DOMESTIC') return false;\n }\n\n // Gender hard check\n if (sch.genderRequirement && sch.genderRequirement !== 'ANY') {\n if (student.gender && student.gender.toLowerCase() !== sch.genderRequirement.toLowerCase()) return false;\n }\n\n // Financial need hard check\n if (sch.financialNeedRequired && !student.financialNeed) return false;\n\n return true;\n});\n\nreturn {\n json: {\n student,\n candidateScholarships,\n eliminatedCount: scholarships.length - candidateScholarships.length,\n runId\n }\n};"
},
"typeVersion": 2
},
{
"id": "97fed899-22cb-4a2a-b01c-0af8be176f15",
"name": "AI Eligibility Scorer",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
2000,
624
],
"parameters": {
"text": "=You are a university scholarships advisor with deep expertise in matching students to funding opportunities. Evaluate the following student profile against all provided scholarship opportunities and produce a detailed eligibility assessment for each.\n\n**Student Profile:**\n- Student ID: {{ $json.student.studentId }}\n- Name: {{ $json.student.firstName }} {{ $json.student.lastName }}\n- Email: {{ $json.student.email }}\n- GPA: {{ $json.student.gpa }} / 4.0\n- Major: {{ $json.student.major }}\n- Year of Study: Year {{ $json.student.yearOfStudy }}\n- Nationality: {{ $json.student.nationality }}\n- Residency Status: {{ $json.student.residencyStatus }}\n- Financial Need: {{ $json.student.financialNeed }}\n- Gender: {{ $json.student.gender || 'Not specified' }}\n- First Generation Student: {{ $json.student.firstGenStudent }}\n- Indigenous Status: {{ $json.student.indigenousStatus }}\n- Disability Status: {{ $json.student.disabilityStatus }}\n- Regional Background: {{ $json.student.regionalBackground }}\n- Extracurriculars: {{ $json.student.extracurriculars.join(', ') || 'None listed' }}\n- Achievements: {{ $json.student.achievements.join(', ') || 'None listed' }}\n- Intended Career: {{ $json.student.intendedCareer || 'Not specified' }}\n- Additional Notes: {{ $json.student.notes || 'None' }}\n\n**Candidate Scholarships ({{ $json.candidateScholarships.length }} pre-filtered):**\n{{ JSON.stringify($json.candidateScholarships, null, 2) }}\n\n---\n\n**Scoring Rubric (0\u2013100):**\n- 90\u2013100: Exceptional fit \u2014 student meets all criteria with standout alignment\n- 75\u201389: Strong fit \u2014 meets all mandatory criteria, good profile alignment\n- 60\u201374: Good fit \u2014 meets most criteria, worth applying with strong statement\n- 40\u201359: Moderate fit \u2014 some criteria met, possible with compelling case\n- 0\u201339: Weak fit \u2014 missing key requirements, not recommended\n\n**Instructions:**\n- Score each scholarship independently and honestly\n- Consider nuanced eligibility (e.g., career alignment, extracurricular fit) beyond hard rules\n- Generate a personalised tip for each scholarship above 60\n- Identify the student's single strongest selling point per scholarship\n- Flag any application risks or missing elements per scholarship\n\n**Response Format (JSON only, no markdown):**\n{\n \"studentId\": \"{{ $json.student.studentId }}\",\n \"studentName\": \"{{ $json.student.firstName }} {{ $json.student.lastName }}\",\n \"overallProfile\": \"2-sentence summary of the student's scholarship appeal\",\n \"topStrengths\": [\"strength 1\", \"strength 2\", \"strength 3\"],\n \"profileGaps\": [\"gap or area to strengthen 1\"],\n \"scholarshipMatches\": [\n {\n \"scholarshipId\": \"SCH-001\",\n \"scholarshipName\": \"name\",\n \"provider\": \"provider name\",\n \"valueAUD\": 10000,\n \"deadline\": \"2025-07-31\",\n \"isUrgent\": false,\n \"matchScore\": 85,\n \"eligibilityStatus\": \"ELIGIBLE | LIKELY_ELIGIBLE | POSSIBLY_ELIGIBLE | INELIGIBLE\",\n \"meetsAllHardCriteria\": true,\n \"sellingPoint\": \"student's strongest angle for this scholarship\",\n \"applicationTip\": \"specific advice for this application\",\n \"risksOrGaps\": [\"any concerns or missing elements\"],\n \"recommendApply\": true,\n \"applicationURL\": \"https://...\"\n }\n ],\n \"topRecommendations\": [\"SCH-001\", \"SCH-003\"],\n \"generalApplicationAdvice\": \"overarching advice for this student's scholarship search\"\n}",
"options": {
"systemMessage": "You are a scholarships matching expert. Return JSON only \u2014 no markdown, no code blocks, no preamble. Evaluate every scholarship in the list. Sort scholarshipMatches by matchScore descending. Be encouraging but realistic \u2014 do not inflate scores. Only set recommendApply to true if matchScore >= 60."
},
"promptType": "define"
},
"typeVersion": 1.6
},
{
"id": "bf374fba-c7eb-461b-97ab-bfe815768f07",
"name": "Claude AI Model",
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"position": [
2072,
848
],
"parameters": {
"model": "=claude-sonnet-4-20250514",
"options": {
"temperature": 0.2
}
},
"credentials": {
"anthropicApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "bcc5634b-6f4c-4f0d-a9e3-f55b69c7ffef",
"name": "Parse & Rank Match Results",
"type": "n8n-nodes-base.code",
"position": [
2352,
624
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "const aiResponse = $input.item.json;\nlet aiText = aiResponse.response || aiResponse.output || aiResponse.text || '';\n\nif (aiResponse.content && Array.isArray(aiResponse.content)) {\n aiText = aiResponse.content[0]?.text || '';\n}\n\nconst clean = aiText.replace(/```json\\s*/g, '').replace(/```\\s*/g, '').trim();\nlet result;\ntry {\n result = JSON.parse(clean);\n} catch (e) {\n const match = clean.match(/\\{[\\s\\S]*\\}/);\n if (match) {\n try { result = JSON.parse(match[0]); }\n catch (e2) {\n result = { studentId: 'PARSE_ERROR', scholarshipMatches: [], overallProfile: 'Processing error \u2014 manual review needed', topStrengths: [], profileGaps: [], topRecommendations: [], generalApplicationAdvice: '' };\n }\n }\n}\n\nconst upstream = $('Pre-Filter Hard Ineligibility').item.json;\n\n// Sort matches by score descending\nconst sortedMatches = (result.scholarshipMatches || []).sort((a, b) => b.matchScore - a.matchScore);\n\n// Compute stats\nconst eligible = sortedMatches.filter(m => m.eligibilityStatus === 'ELIGIBLE' || m.eligibilityStatus === 'LIKELY_ELIGIBLE');\nconst recommended = sortedMatches.filter(m => m.recommendApply);\nconst urgent = recommended.filter(m => m.isUrgent);\nconst totalValue = recommended.reduce((sum, m) => sum + (m.valueAUD || 0), 0);\n\nreturn {\n json: {\n student: upstream.student,\n runId: upstream.runId,\n aiResult: { ...result, scholarshipMatches: sortedMatches },\n stats: {\n totalEvaluated: sortedMatches.length,\n eligibleCount: eligible.length,\n recommendedCount: recommended.length,\n urgentDeadlineCount: urgent.length,\n maxPotentialValueAUD: totalValue\n },\n recommendedMatches: recommended,\n urgentMatches: urgent,\n scoredAt: new Date().toISOString()\n }\n};"
},
"typeVersion": 2
},
{
"id": "a1fa618d-05c2-45e2-9bb2-a65ddf6a089b",
"name": "Filter Qualified Matches",
"type": "n8n-nodes-base.filter",
"position": [
2576,
624
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": false,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"operator": {
"type": "number",
"operation": "gte"
},
"leftValue": "={{ $json.stats.recommendedCount }}",
"rightValue": 1
}
]
}
},
"typeVersion": 2.2
},
{
"id": "9761a356-a5b6-4434-9aee-097e51377535",
"name": "Build Personalised Student Email",
"type": "n8n-nodes-base.code",
"position": [
2800,
624
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "const d = $input.item.json;\nconst student = d.student;\nconst ai = d.aiResult;\nconst matches = d.recommendedMatches.slice(0, 6); // top 6\nconst stats = d.stats;\n\nconst urgentBanner = d.urgentMatches.length > 0\n ? `<div style=\"background:#fff3cd;border:2px solid #ffc107;border-radius:8px;padding:14px 18px;margin:0 0 18px;\">\u26a1 <strong>${d.urgentMatches.length} scholarship(s) closing within 14 days!</strong> Apply immediately.</div>`\n : '';\n\nconst scholarshipCards = matches.map(m => {\n const badgeColor = m.matchScore >= 80 ? '#28a745' : m.matchScore >= 65 ? '#ffa500' : '#6c757d';\n const urgentTag = m.isUrgent ? '<span style=\"background:#e94560;color:white;padding:2px 7px;border-radius:3px;font-size:0.75em;margin-left:8px;\">\u26a1 URGENT</span>' : '';\n return `\n<div style=\"border:1px solid #e0e0e0;border-left:5px solid ${badgeColor};border-radius:6px;padding:16px 20px;margin:12px 0;\">\n <div style=\"display:flex;justify-content:space-between;align-items:flex-start;\">\n <div>\n <strong style=\"font-size:1.05em;color:#1a1a2e;\">${m.scholarshipName}</strong>${urgentTag}\n <p style=\"margin:3px 0;color:#555;font-size:0.9em;\">by ${m.provider}</p>\n </div>\n <div style=\"text-align:right;\">\n <span style=\"background:${badgeColor};color:white;padding:4px 10px;border-radius:4px;font-weight:bold;\">${m.matchScore}% Match</span>\n <p style=\"margin:4px 0;font-size:0.9em;color:#28a745;font-weight:bold;\">A$${m.valueAUD?.toLocaleString()}</p>\n </div>\n </div>\n <p style=\"margin:8px 0 4px;color:#333;\"><strong>Your edge:</strong> ${m.sellingPoint}</p>\n <p style=\"margin:4px 0;color:#555;font-size:0.9em;\"><strong>Tip:</strong> ${m.applicationTip}</p>\n <p style=\"margin:6px 0 2px;color:#888;font-size:0.85em;\">\ud83d\udcc5 Deadline: ${m.deadline} | Status: <strong>${m.eligibilityStatus.replace(/_/g,' ')}</strong></p>\n <a href=\"${m.applicationURL}\" style=\"display:inline-block;margin-top:10px;background:#1a1a2e;color:white;padding:7px 16px;border-radius:4px;text-decoration:none;font-size:0.9em;\">Apply Now \u2192</a>\n</div>`;\n}).join('');\n\nconst htmlBody = `\n<html><body style=\"font-family:Arial,sans-serif;max-width:680px;margin:0 auto;padding:24px;color:#222;background:#f9f9f9;\">\n<div style=\"background:linear-gradient(135deg,#1a1a2e 0%,#16213e 100%);padding:28px;border-radius:10px 10px 0 0;\">\n <h1 style=\"color:white;margin:0;font-size:1.5em;\">\ud83c\udf93 Your Scholarship Matches Are Ready</h1>\n <p style=\"color:#aaa;margin:8px 0 0;\">Personalised for ${student.firstName} ${student.lastName}</p>\n</div>\n<div style=\"background:white;padding:24px;border:1px solid #ddd;\">\n <p style=\"font-size:1.05em;\">Hi <strong>${student.firstName}</strong>,</p>\n <p>Great news! Our AI scholarship matcher has found <strong>${stats.recommendedCount} scholarship opportunity${stats.recommendedCount !== 1 ? 'ies' : 'y'}</strong> matching your profile, with a combined potential value of <strong style=\"color:#28a745;\">A$${stats.maxPotentialValueAUD.toLocaleString()}</strong>.</p>\n\n ${urgentBanner}\n\n <div style=\"background:#f0f4ff;border-radius:8px;padding:14px 18px;margin:14px 0;\">\n <p style=\"margin:0;color:#1a1a2e;\"><strong>Your Profile Strengths:</strong></p>\n <ul style=\"margin:8px 0 0;color:#333;\">${(ai.topStrengths || []).map(s => `<li>${s}</li>`).join('')}</ul>\n </div>\n\n <h2 style=\"color:#1a1a2e;border-bottom:2px solid #e94560;padding-bottom:6px;\">Your Top Matches</h2>\n ${scholarshipCards}\n\n ${ai.generalApplicationAdvice ? `<div style=\"background:#f8f9fa;border-radius:8px;padding:14px 18px;margin:18px 0;\"><p style=\"margin:0;\"><strong>\ud83d\udca1 Advisor Tip:</strong> ${ai.generalApplicationAdvice}</p></div>` : ''}\n\n <p style=\"font-size:0.85em;color:#999;margin-top:24px;\">This is an automated match based on your profile. Results are indicative \u2014 always read the full scholarship criteria before applying. Eligibility is not guaranteed.</p>\n</div>\n<div style=\"background:#1a1a2e;padding:14px 24px;border-radius:0 0 10px 10px;text-align:center;\">\n <p style=\"color:#aaa;font-size:0.8em;margin:0;\">AI Scholarship Matcher • Unsubscribe | View in Browser</p>\n</div>\n</body></html>`;\n\nreturn {\n json: {\n ...d,\n email: {\n to: student.email,\n subject: `\ud83c\udf93 ${stats.recommendedCount} Scholarship Match${stats.recommendedCount !== 1 ? 'es' : ''} Found \u2014 Up to A$${stats.maxPotentialValueAUD.toLocaleString()} Available`,\n htmlBody\n }\n }\n};"
},
"typeVersion": 2
},
{
"id": "53e65a9a-33b2-438f-8368-49e8c7d37500",
"name": "Send Scholarship Email to Student",
"type": "n8n-nodes-base.emailSend",
"position": [
3024,
432
],
"parameters": {
"html": "={{ $json.email.htmlBody }}",
"options": {
"appendAttribution": false
},
"subject": "={{ $json.email.subject }}",
"toEmail": "={{ $json.student.email }}",
"fromEmail": "="
},
"credentials": {
"smtp": {
"name": "<your credential>"
}
},
"typeVersion": 2.1,
"continueOnFail": true
},
{
"id": "cfc9871e-cc66-46d1-b67d-75b31479a397",
"name": "Notify Academic Advisor on Slack",
"type": "n8n-nodes-base.httpRequest",
"position": [
3024,
624
],
"parameters": {
"url": "https://slack.com/api/chat.postMessage",
"method": "POST",
"options": {
"timeout": 10000
},
"jsonBody": "={\n \"channel\": \"#scholarship-advisors\",\n \"text\": \"\ud83c\udf93 New Scholarship Matches \u2014 {{ $json.student.firstName }} {{ $json.student.lastName }}\",\n \"blocks\": [\n {\n \"type\": \"header\",\n \"text\": { \"type\": \"plain_text\", \"text\": \"\ud83c\udf93 Scholarship Match Report\" }\n },\n {\n \"type\": \"section\",\n \"fields\": [\n { \"type\": \"mrkdwn\", \"text\": \"*Student:*\\n{{ $json.student.firstName }} {{ $json.student.lastName }}\" },\n { \"type\": \"mrkdwn\", \"text\": \"*Student ID:*\\n{{ $json.student.studentId }}\" },\n { \"type\": \"mrkdwn\", \"text\": \"*Major:*\\n{{ $json.student.major }} (Year {{ $json.student.yearOfStudy }})\" },\n { \"type\": \"mrkdwn\", \"text\": \"*GPA:*\\n{{ $json.student.gpa }} / 4.0\" },\n { \"type\": \"mrkdwn\", \"text\": \"*Matches Found:*\\n{{ $json.stats.recommendedCount }} scholarships\" },\n { \"type\": \"mrkdwn\", \"text\": \"*Potential Value:*\\nA${{ $json.stats.maxPotentialValueAUD.toLocaleString() }}\" }\n ]\n },\n {\n \"type\": \"section\",\n \"text\": { \"type\": \"mrkdwn\", \"text\": \"*Top Match:* {{ $json.recommendedMatches[0]?.scholarshipName }} \u2014 {{ $json.recommendedMatches[0]?.matchScore }}% (A${{ $json.recommendedMatches[0]?.valueAUD?.toLocaleString() }})\\n*Student Profile:* {{ $json.aiResult.overallProfile }}\" }\n },\n {{ $json.urgentMatches.length > 0 ? JSON.stringify({ type: 'section', text: { type: 'mrkdwn', text: '\u26a1 *URGENT:* ' + $json.urgentMatches.length + ' scholarship(s) closing within 14 days \u2014 follow up with student immediately.' } }) + ',' : '' }}\n {\n \"type\": \"section\",\n \"text\": { \"type\": \"mrkdwn\", \"text\": \"*Top Strengths:*\\n{{ $json.aiResult.topStrengths?.map((s,i) => (i+1)+'. '+s).join('\\\\n') }}\" }\n }\n ]\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "slackApi"
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 4.2,
"continueOnFail": true
},
{
"id": "49594012-3fc9-4021-90d5-51eff246e015",
"name": "Update Student CRM Record",
"type": "n8n-nodes-base.airtable",
"position": [
3024,
816
],
"parameters": {
"base": {
"__rl": true,
"mode": "id",
"value": "="
},
"table": {
"__rl": true,
"mode": "id",
"value": "="
},
"columns": {
"value": {},
"schema": [],
"mappingMode": "autoMapInputData",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "update"
},
"credentials": {
"airtableTokenApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.1,
"continueOnFail": true
},
{
"id": "3d38ac05-8006-4fdd-bd09-e8ed3c5de13d",
"name": "Write Match Audit Log",
"type": "n8n-nodes-base.googleSheets",
"position": [
3248,
624
],
"parameters": {
"columns": {
"value": {},
"schema": [],
"mappingMode": "autoMapInputData",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": true
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "id",
"value": "=YOUR_SHEET_TAB_ID"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "=YOUR_GOOGLE_SHEET_ID"
},
"authentication": "serviceAccount"
},
"credentials": {
"googleApi": {
"name": "<your credential>"
}
},
"typeVersion": 4.5,
"continueOnFail": true
},
{
"id": "97634972-1920-41ca-ab63-d4a203a260ce",
"name": "Return Match Results to Caller",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
3472,
624
],
"parameters": {
"options": {
"responseHeaders": {
"entries": [
{
"name": "Content-Type",
"value": "application/json"
}
]
}
},
"respondWith": "json",
"responseBody": "={\n \"success\": true,\n \"studentId\": \"{{ $json.student.studentId }}\",\n \"studentName\": \"{{ $json.student.firstName }} {{ $json.student.lastName }}\",\n \"stats\": {{ JSON.stringify($json.stats) }},\n \"topMatches\": {{ JSON.stringify($json.recommendedMatches.slice(0,5).map(m => ({ scholarshipId: m.scholarshipId, name: m.scholarshipName, matchScore: m.matchScore, valueAUD: m.valueAUD, deadline: m.deadline, isUrgent: m.isUrgent, eligibilityStatus: m.eligibilityStatus }))) }},\n \"overallProfile\": \"{{ $json.aiResult.overallProfile }}\",\n \"generalAdvice\": \"{{ $json.aiResult.generalApplicationAdvice }}\",\n \"processedAt\": \"{{ $json.scoredAt }}\"\n}"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "e0b59931-5815-4d65-9edc-55ee72f5f82f",
"connections": {
"Claude AI Model": {
"ai_languageModel": [
[
{
"node": "AI Eligibility Scorer",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"AI Eligibility Scorer": {
"main": [
[
{
"node": "Parse & Rank Match Results",
"type": "main",
"index": 0
}
]
]
},
"Load Student Profiles": {
"main": [
[
{
"node": "Normalise Profiles & Build Pairs",
"type": "main",
"index": 0
}
]
]
},
"Write Match Audit Log": {
"main": [
[
{
"node": "Return Match Results to Caller",
"type": "main",
"index": 0
}
]
]
},
"Nightly Batch Schedule": {
"main": [
[
{
"node": "Load Student Profiles",
"type": "main",
"index": 0
}
]
]
},
"Filter Qualified Matches": {
"main": [
[
{
"node": "Build Personalised Student Email",
"type": "main",
"index": 0
}
]
]
},
"Update Student CRM Record": {
"main": [
[
{
"node": "Write Match Audit Log",
"type": "main",
"index": 0
}
]
]
},
"Load Scholarship Catalogue": {
"main": [
[
{
"node": "Normalise Profiles & Build Pairs",
"type": "main",
"index": 0
}
]
]
},
"Parse & Rank Match Results": {
"main": [
[
{
"node": "Filter Qualified Matches",
"type": "main",
"index": 0
}
]
]
},
"Pre-Filter Hard Ineligibility": {
"main": [
[
{
"node": "AI Eligibility Scorer",
"type": "main",
"index": 0
}
]
]
},
"Build Personalised Student Email": {
"main": [
[
{
"node": "Send Scholarship Email to Student",
"type": "main",
"index": 0
},
{
"node": "Notify Academic Advisor on Slack",
"type": "main",
"index": 0
},
{
"node": "Update Student CRM Record",
"type": "main",
"index": 0
}
]
]
},
"Normalise Profiles & Build Pairs": {
"main": [
[
{
"node": "Pre-Filter Hard Ineligibility",
"type": "main",
"index": 0
}
]
]
},
"Notify Academic Advisor on Slack": {
"main": [
[
{
"node": "Write Match Audit Log",
"type": "main",
"index": 0
}
]
]
},
"Send Scholarship Email to Student": {
"main": [
[
{
"node": "Write Match Audit Log",
"type": "main",
"index": 0
}
]
]
},
"Receive Student Profile Submission": {
"main": [
[
{
"node": "Load Scholarship Catalogue",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
airtableTokenApianthropicApigoogleApislackApismtp
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow ingests student profiles from a form submission or CRM, loads the active scholarship catalogue, uses Claude AI to score each student's eligibility against every available scholarship, filters strong matches, and automatically notifies eligible candidates with…
Source: https://n8n.io/workflows/13690/ — 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.
This workflow continuously monitors CVE databases, threat intelligence feeds, and public security advisories to surface emerging zero-day threats, correlates them against your registered infrastructur
This workflow monitors active construction projects in real time, ingests weather forecasts, supplier delivery statuses, and crew/resource availability, then uses Claude AI to predict delay risk, esti
Automatically transforms your travel photos and notes into beautiful journals, highlight reels, and review drafts using Claude's vision and language capabilities. Trip Completion Trigger - Webhook or
This workflow provides real-time detection of ransomware encryption patterns using Claude AI, with automated system isolation and incident response. File System Monitoring - Continuously monitors file
This workflow provides personalized travel destination recommendations by analyzing past trip history, user preferences, travel behavior patterns, and current trends. It uses Claude AI to generate int