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": "Alerta inteligente con Gemini",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "hours",
"hoursInterval": 6
}
]
}
},
"id": "schedule",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [
200,
300
]
},
{
"parameters": {
"method": "GET",
"url": "http://host.docker.internal:3001/trpc/lotes.list",
"options": {
"response": {
"response": {
"fullResponse": false
}
}
},
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer {{ $env.BACKEND_JWT_TOKEN }}"
}
]
}
},
"id": "fetch-lotes",
"name": "Fetch Lotes",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
420,
300
]
},
{
"parameters": {
"method": "GET",
"url": "http://host.docker.internal:3001/trpc/suelo.list",
"options": {
"response": {
"response": {
"fullResponse": false
}
}
},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer {{ $env.BACKEND_JWT_TOKEN }}"
}
]
}
},
"id": "fetch-suelo",
"name": "Fetch Suelo",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
640,
200
]
},
{
"parameters": {
"method": "GET",
"url": "http://host.docker.internal:3001/trpc/clima.list",
"options": {
"response": {
"response": {
"fullResponse": false
}
}
},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer {{ $env.BACKEND_JWT_TOKEN }}"
}
]
}
},
"id": "fetch-clima",
"name": "Fetch Clima",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
640,
400
]
},
{
"parameters": {
"mode": "combine",
"mergeByFields": {},
"combinationMode": "mergeByPosition",
"options": {}
},
"id": "merge-data",
"name": "Merge Data",
"type": "n8n-nodes-base.merge",
"typeVersion": 2.1,
"position": [
860,
300
]
},
{
"parameters": {
"method": "POST",
"url": "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key={{ $env.GEMINI_API_KEY }}",
"sendBody": true,
"contentType": "json",
"body": "={{ JSON.stringify({ contents: [{ parts: [{ text: `Eres un agr\u00f3nomo experto en agricultura de precisi\u00f3n en Argentina. Analiza los siguientes datos de campo y genera alertas agron\u00f3micas accionables. DATOS DE LOTES: ${JSON.stringify($node['Fetch Lotes'].json.result?.data ?? [])} DATOS DE SUELO (\u00faltimos registros): ${JSON.stringify(($node['Fetch Suelo'].json.result?.data ?? []).slice(-10))} DATOS DE CLIMA (\u00faltimos 7 d\u00edas): ${JSON.stringify(($node['Fetch Clima'].json.result?.data ?? []).slice(-7))} INSTRUCCIONES: - Eval\u00faa condiciones de estr\u00e9s h\u00eddrico, anomal\u00edas de suelo, riesgos clim\u00e1ticos y tendencias de rendimiento. - Genera entre 0 y 3 alertas relevantes. Si todo est\u00e1 dentro de par\u00e1metros normales, devuelve un array vac\u00edo. - Cada alerta debe ser un objeto JSON con EXACTAMENTE estos campos: tipo (string: humedad-baja|ph-acido|ph-alcalino|ola-calor|lluvia-intensa|rendimiento-bajo-pred|nutriente-deficiente|estres-hidrico), severidad (string: critica|alta|media|baja), categoria (string: hidrico|quimico|climatico|predictivo), mensaje (string: descripci\u00f3n concisa del problema detectado, max 120 chars), racional (string: explicaci\u00f3n t\u00e9cnica de por qu\u00e9 se genera la alerta con datos espec\u00edficos), recomendacion (string: acci\u00f3n concreta que el agr\u00f3nomo debe tomar), confianza (number: 0.0 a 1.0), loteId (number: ID del lote afectado, usar los IDs de los datos proporcionados) - RESPONDE SOLO con un JSON array v\u00e1lido, sin markdown, sin explicaciones. Ejemplo: [{ \"tipo\": \"humedad-baja\", \"severidad\": \"alta\", \"categoria\": \"hidrico\", \"mensaje\": \"Humedad de suelo cr\u00edtica en Lote Norte: 22%\", \"racional\": \"Lectura del 2026-05-03: humedad=22%, muy por debajo del umbral de 35% para soja.\", \"recomendacion\": \"Aplicar riego de 20mm en las pr\u00f3ximas 24hs.\", \"confianza\": 0.91, \"loteId\": 1 }]` }] }] }) }}",
"options": {
"response": {
"response": {
"fullResponse": false
}
}
}
},
"id": "gemini",
"name": "Gemini Analizar",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
1080,
300
]
},
{
"parameters": {
"jsCode": "// Parse Gemini response and extract alerts array\nconst geminiResponse = $input.first().json;\nconst text = geminiResponse.candidates?.[0]?.content?.parts?.[0]?.text ?? '[]';\n\n// Clean potential markdown fences\nconst cleaned = text.replace(/```json\\n?/g, '').replace(/```\\n?/g, '').trim();\n\ntry {\n const alertas = JSON.parse(cleaned);\n if (!Array.isArray(alertas) || alertas.length === 0) {\n return [{ json: { _skip: true, reason: 'No alerts generated' } }];\n }\n return alertas.map(a => ({\n json: {\n tipo: a.tipo || 'general',\n severidad: a.severidad || 'media',\n categoria: a.categoria || 'climatico',\n mensaje: (a.mensaje || '').substring(0, 200),\n racional: a.racional || '',\n recomendacion: a.recomendacion || '',\n confianza: typeof a.confianza === 'number' ? a.confianza : 0.8,\n loteId: a.loteId || null,\n fecha: new Date().toISOString().split('T')[0]\n }\n }));\n} catch (e) {\n return [{ json: { _skip: true, reason: 'Parse error: ' + e.message } }];\n}"
},
"id": "parse-alertas",
"name": "Parse Alertas",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1300,
300
]
},
{
"parameters": {
"conditions": {
"boolean": [],
"string": [
{
"value1": "={{ $json._skip }}",
"operation": "isEmpty"
}
]
}
},
"id": "filter-valid",
"name": "Filter Valid",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
1520,
300
]
},
{
"parameters": {
"method": "POST",
"url": "http://host.docker.internal:3001/webhooks/n8n/alertas",
"sendBody": true,
"contentType": "json",
"body": "={{ $json }}"
},
"id": "post-alerta",
"name": "POST Alerta",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
1740,
240
]
}
],
"connections": {
"Schedule Trigger": {
"main": [
[
{
"node": "Fetch Lotes",
"type": "main",
"index": 0
}
]
]
},
"Fetch Lotes": {
"main": [
[
{
"node": "Fetch Suelo",
"type": "main",
"index": 0
},
{
"node": "Fetch Clima",
"type": "main",
"index": 0
}
]
]
},
"Fetch Suelo": {
"main": [
[
{
"node": "Merge Data",
"type": "main",
"index": 0
}
]
]
},
"Fetch Clima": {
"main": [
[
{
"node": "Merge Data",
"type": "main",
"index": 1
}
]
]
},
"Merge Data": {
"main": [
[
{
"node": "Gemini Analizar",
"type": "main",
"index": 0
}
]
]
},
"Gemini Analizar": {
"main": [
[
{
"node": "Parse Alertas",
"type": "main",
"index": 0
}
]
]
},
"Parse Alertas": {
"main": [
[
{
"node": "Filter Valid",
"type": "main",
"index": 0
}
]
]
},
"Filter Valid": {
"main": [
[
{
"node": "POST Alerta",
"type": "main",
"index": 0
}
],
[]
]
}
}
}
About this workflow
Alerta inteligente con Gemini. Uses scheduleTrigger, httpRequest. Scheduled trigger; 9 nodes.
Source: https://github.com/RobertoA1/lab03-soft/blob/b2fb1c72103960d5cc72a5197d3cac9b6019811d/.n8n/workflows/alerta-periodica-backend.json — original creator credit. Request a take-down →