{
  "name": "AI Farmer SMS Assistant",
  "nodes": [
    {
      "id": "46774c52-59fa-46c6-b8cf-fd209c75ed46",
      "name": "Normalize Incoming SMS",
      "type": "n8n-nodes-base.set",
      "position": [
        -2064,
        1632
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "demo-phone",
              "name": "phone",
              "type": "string",
              "value": "={{ $json.body?.from ?? $json.from ?? '+0000000000' }}"
            },
            {
              "id": "demo-message",
              "name": "message_text",
              "type": "string",
              "value": "={{ ($json.body?.text ?? $json.text ?? 'RAIN').trim() }}"
            },
            {
              "id": "demo-received-at",
              "name": "received_at",
              "type": "string",
              "value": "={{ $now.toISO() }}"
            },
            {
              "id": "demo-message-id",
              "name": "message_id",
              "type": "string",
              "value": "={{ $json.body?.id ?? $json.id ?? 'demo-message-001' }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "26979920-3107-4430-bc3b-59c146588949",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -2288,
        1632
      ],
      "parameters": {
        "path": "farmer-sms-demo",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 2.1
    },
    {
      "id": "4e5a7f13-bb13-4188-ba7d-a1267c954701",
      "name": "Lookup Farmer",
      "type": "n8n-nodes-base.code",
      "position": [
        -1840,
        2336
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, demo_backend_note: 'Replace this demo node with your own Google Sheets, database, or CRM action.' } }];"
      },
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "7b669617-d3a9-479a-a7bd-e3014324358c",
      "name": "Farmer Exists",
      "type": "n8n-nodes-base.if",
      "position": [
        -1616,
        2336
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "034a6bab-bc3d-42ca-bf6f-737490e8e3a0",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.farmer_id }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "b3abb2cc-20a4-4d7a-a3e4-710aa990021f",
      "name": "Merge SMS + Farmer",
      "type": "n8n-nodes-base.merge",
      "position": [
        -1392,
        592
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2
    },
    {
      "id": "155dda39-9655-4b3a-9bb9-0c6bea99a975",
      "name": "Route SMS Intent",
      "type": "n8n-nodes-base.switch",
      "position": [
        -1168,
        496
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "weather_request",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "c1018a13-7eae-4522-b08b-01f1b993d331",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.message_text }}",
                    "rightValue": "RAIN"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "fire_alert",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "047400e8-1709-487d-8b04-84745d699a3f",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.message_text }}",
                    "rightValue": "FIRE"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "supplier_lookup",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "f812b7ec-866f-4af3-a3d6-e43a54e521a6",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.message_text }}",
                    "rightValue": "SEEDS"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "equipment_lookup",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "cb41a68e-3391-4083-a5a3-5f116517a943",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.message_text }}",
                    "rightValue": "EQUIPMENT"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "registration",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "44e4271e-7872-4496-990f-a19ccb388c3f",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.message_text.toUpperCase().trim() }}",
                    "rightValue": "REGISTER"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "planting_advice",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "0159762e-28b2-4cbe-80dd-326eb2e88d99",
                    "operator": {
                      "type": "string",
                      "operation": "contains"
                    },
                    "leftValue": "={{ $json.message_text }}",
                    "rightValue": "PLANT"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "harvest_advice",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "20f5f71d-700c-4677-beb1-7b272c3932b1",
                    "operator": {
                      "type": "string",
                      "operation": "contains"
                    },
                    "leftValue": "={{ $json.message_text }}",
                    "rightValue": "HARVEST"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra",
          "renameFallbackOutput": "Unknown"
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "cbef8543-4f1b-4c2b-9467-74611df21638",
      "name": "Get Weather Forecast",
      "type": "n8n-nodes-base.code",
      "position": [
        -144,
        944
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: {\n  ...data,\n  weather_source: 'Demo data - replace with your weather provider',\n  daily: { time: ['2026-08-01'], precipitation_probability_max: [45], temperature_2m_max: [27] },\n} }];"
      },
      "typeVersion": 2
    },
    {
      "id": "728e3022-4cf8-4c99-b348-89ca9a7be9b6",
      "name": "Build Rain Reply",
      "type": "n8n-nodes-base.code",
      "position": [
        304,
        944
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, reply_text: \"Demo forecast: rain is possible tomorrow. Check local conditions before making a farm decision.\", delivery_mode: 'Demo Preview - Not Sent' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "e429e569-fbb2-4b16-a1b2-e00a54c4e367",
      "name": "Send SMS Reply",
      "type": "n8n-nodes-base.code",
      "position": [
        976,
        1024
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: {\n  ...data,\n  send_status: 'Demo Preview - Not Sent',\n  provider_message_id: 'demo-message-id',\n  provider_note: 'No SMS provider is connected in this public template.',\n} }];"
      },
      "typeVersion": 2
    },
    {
      "id": "8fdc1ecf-00f4-4632-9e5f-57602b89aa38",
      "name": "Log SMS Send Result",
      "type": "n8n-nodes-base.code",
      "position": [
        1424,
        944
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, demo_backend_note: 'Replace this demo node with your own Google Sheets, database, or CRM action.' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "85535053-2495-4de3-8f15-22815f3a550e",
      "name": "Test Phone Allowed?",
      "type": "n8n-nodes-base.if",
      "position": [
        752,
        944
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "f1d89d05-44b3-4697-b2a9-e6d2b55d5a67",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.phone }}",
              "rightValue": "=+0000000000"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "984915cc-8037-4abd-81af-924b0e197a43",
      "name": "SMS Opt-In?",
      "type": "n8n-nodes-base.if",
      "position": [
        608,
        944
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "3d6a6a30-9038-43c3-801a-68fc5062db04",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.sms_opt_in }}",
              "rightValue": "Yes"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "9587b63f-44d4-424e-aa9c-b798b3ff5279",
      "name": "Build Unknown Reply",
      "type": "n8n-nodes-base.code",
      "position": [
        -144,
        1360
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, reply_text: \"I can help with RAIN, FIRE, SEEDS, EQUIPMENT, PLANT MAIZE, HARVEST MAIZE, or REGISTER.\", delivery_mode: 'Demo Preview - Not Sent' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "a584951b-dad9-4063-8353-71e43543c1ac",
      "name": "Merge Reply + Send Result",
      "type": "n8n-nodes-base.merge",
      "position": [
        1200,
        944
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2
    },
    {
      "id": "05fb553e-2b37-4c5c-aa68-f9e0bd2fd284",
      "name": "Lookup Seed Suppliers",
      "type": "n8n-nodes-base.code",
      "position": [
        -144,
        752
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, demo_backend_note: 'Replace this demo node with your own Google Sheets, database, or CRM action.' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "2f338a8d-8692-46e5-9933-a97b25d6f329",
      "name": "Build Seeds Reply",
      "type": "n8n-nodes-base.code",
      "position": [
        80,
        752
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, reply_text: \"Demo seed supplier result: connect your own directory to return local suppliers.\", delivery_mode: 'Demo Preview - Not Sent' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "f42fbbfe-ad88-4980-acce-fb71f15bade8",
      "name": "Log Seeds Reply",
      "type": "n8n-nodes-base.code",
      "position": [
        304,
        752
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, demo_backend_note: 'Replace this demo node with your own Google Sheets, database, or CRM action.' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "bb316bfd-585f-4ddd-a8da-68640da101e5",
      "name": "Log Unknown Message",
      "type": "n8n-nodes-base.code",
      "position": [
        80,
        1360
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, demo_backend_note: 'Replace this demo node with your own Google Sheets, database, or CRM action.' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "5e9e61fd-296a-403b-8bfd-18d356ad5717",
      "name": "Lookup Equipment Suppliers",
      "type": "n8n-nodes-base.code",
      "position": [
        -144,
        560
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, demo_backend_note: 'Replace this demo node with your own Google Sheets, database, or CRM action.' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "12e54b30-09e6-4174-b7a7-c6a190959a0d",
      "name": "Build Equipment Reply",
      "type": "n8n-nodes-base.code",
      "position": [
        80,
        560
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, reply_text: \"Demo equipment result: connect your own directory to return local suppliers.\", delivery_mode: 'Demo Preview - Not Sent' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "4668c889-2246-46e5-95fe-e529e99bd78f",
      "name": "Log Equipment Reply",
      "type": "n8n-nodes-base.code",
      "position": [
        304,
        560
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, demo_backend_note: 'Replace this demo node with your own Google Sheets, database, or CRM action.' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "c98d431e-1334-4875-955e-e3802880586c",
      "name": "Build Fire Reply",
      "type": "n8n-nodes-base.code",
      "position": [
        -144,
        368
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, reply_text: \"If there is a fire risk, move to safety and contact local emergency or community support. This is not an emergency service.\", delivery_mode: 'Demo Preview - Not Sent' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "049bfb95-66db-4cac-bfbb-4bf9cbb4931a",
      "name": "Lookup Planting Rule",
      "type": "n8n-nodes-base.code",
      "position": [
        -144,
        1632
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, demo_backend_note: 'Replace this demo node with your own Google Sheets, database, or CRM action.' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "4fe6b374-d861-4f11-8ddd-e2815a3fedc7",
      "name": "Log Fire Reply",
      "type": "n8n-nodes-base.code",
      "position": [
        80,
        368
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, demo_backend_note: 'Replace this demo node with your own Google Sheets, database, or CRM action.' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "6006ee0e-2c26-4f59-ba9d-9fbe432b0202",
      "name": "Build Planting Reply",
      "type": "n8n-nodes-base.code",
      "position": [
        80,
        1632
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, reply_text: \"Demo planting guidance: use local extension advice and current weather before planting.\", delivery_mode: 'Demo Preview - Not Sent' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "554156af-cac0-4447-901c-4b172b0d439d",
      "name": "Lookup Harvest Rule",
      "type": "n8n-nodes-base.code",
      "position": [
        -144,
        1824
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, demo_backend_note: 'Replace this demo node with your own Google Sheets, database, or CRM action.' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "f2f51668-2ad1-4ffa-8734-01482230688c",
      "name": "Build Harvest Reply",
      "type": "n8n-nodes-base.code",
      "position": [
        80,
        1824
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, reply_text: \"Demo harvest guidance: inspect crop maturity and check local advice before harvesting.\", delivery_mode: 'Demo Preview - Not Sent' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "f2e4ce2b-399b-403a-a312-d474ca9250f6",
      "name": "Log Harvest Reply",
      "type": "n8n-nodes-base.code",
      "position": [
        304,
        1824
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, demo_backend_note: 'Replace this demo node with your own Google Sheets, database, or CRM action.' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "59c539eb-f696-4a4a-b24c-84e627d244dd",
      "name": "Build Registration Prompt",
      "type": "n8n-nodes-base.code",
      "position": [
        -1168,
        2560
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, reply_text: \"To register, send: REGISTER Your Name, District, Main Crop.\", delivery_mode: 'Demo Preview - Not Sent' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "c8ab3a8e-aac9-4448-9ac6-494079e1df9b",
      "name": "Log Registration Prompt",
      "type": "n8n-nodes-base.code",
      "position": [
        -880,
        2560
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, demo_backend_note: 'Replace this demo node with your own Google Sheets, database, or CRM action.' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "7452a90a-bbd6-442f-a3ac-f48e174b5714",
      "name": "Is Registration Message?",
      "type": "n8n-nodes-base.if",
      "position": [
        -1392,
        2384
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "c3af4414-6bb8-4c4a-ac3f-34b1251299cb",
              "operator": {
                "type": "string",
                "operation": "contains"
              },
              "leftValue": "={{ $('Normalize Incoming SMS').item.json.message_text.toUpperCase().trim() }}",
              "rightValue": "REGISTER"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "f44ddc75-2392-4f09-9696-b733836b2923",
      "name": "Parse Registration",
      "type": "n8n-nodes-base.code",
      "position": [
        -1168,
        2288
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nconst raw = String(data.message_text ?? '').replace(/^REGISTER\\s*/i, '');\nconst [name = 'Demo Farmer', district = 'Demo District', crop = 'maize'] = raw.split(',').map((part) => part.trim()).filter(Boolean);\nreturn [{ json: { ...data, registration_name: name, registration_district: district, registration_crop: crop } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "b8482a10-9f4f-41a1-b4b6-332079682094",
      "name": "Add Register Farmer",
      "type": "n8n-nodes-base.code",
      "position": [
        304,
        2320
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, demo_backend_note: 'Replace this demo node with your own Google Sheets, database, or CRM action.' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "c3a78ac7-3150-4f40-8bcb-f2740719118f",
      "name": "Log Registration Success",
      "type": "n8n-nodes-base.code",
      "position": [
        304,
        2512
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, demo_backend_note: 'Replace this demo node with your own Google Sheets, database, or CRM action.' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "dee269de-8a7e-4f62-9723-386da9677098",
      "name": "Log Registration Reply",
      "type": "n8n-nodes-base.code",
      "position": [
        304,
        2064
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, demo_backend_note: 'Replace this demo node with your own Google Sheets, database, or CRM action.' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "2c1691bd-7d0d-4b5c-8f3d-0fae9a9c1b4e",
      "name": "Lookup Existing Registration Phone",
      "type": "n8n-nodes-base.code",
      "position": [
        -880,
        2192
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, demo_backend_note: 'Replace this demo node with your own Google Sheets, database, or CRM action.' } }];"
      },
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "3957d95f-613e-41d2-8644-cf445ef26bc5",
      "name": "Already Registered",
      "type": "n8n-nodes-base.if",
      "position": [
        -592,
        2192
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "eaef4af1-e0c9-4aeb-bc16-30a179e9ffbb",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.farmer_id }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "2afbca57-bd02-4eb8-99f2-49a71581d489",
      "name": "Build Already Registered Reply",
      "type": "n8n-nodes-base.code",
      "position": [
        -368,
        2064
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, reply_text: \"This phone is already registered in the demo workflow.\", delivery_mode: 'Demo Preview - Not Sent' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "4462985e-588c-4900-af1c-016b7c2aebd2",
      "name": "Log Already Registered Reply",
      "type": "n8n-nodes-base.code",
      "position": [
        -144,
        2064
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, demo_backend_note: 'Replace this demo node with your own Google Sheets, database, or CRM action.' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "4e1702bc-1ddb-485e-b3f0-afe324aa6c20",
      "name": "Lookup Weather Zone For Registration",
      "type": "n8n-nodes-base.code",
      "position": [
        -368,
        2256
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, demo_backend_note: 'Replace this demo node with your own Google Sheets, database, or CRM action.' } }];"
      },
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "4ae6e308-7702-4ea2-bd1d-37d4550c523f",
      "name": "Merge Registration + Weather Zone",
      "type": "n8n-nodes-base.merge",
      "position": [
        -144,
        2368
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2
    },
    {
      "id": "b2448cd1-e823-4016-95a0-14b5648bda82",
      "name": "Prepare Registered Farmer Row",
      "type": "n8n-nodes-base.code",
      "position": [
        80,
        2368
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, registration_status: 'Demo record prepared - not saved' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "6e42ed03-0a42-4932-8e64-5f3ffc57949a",
      "name": "Log Planting Reply",
      "type": "n8n-nodes-base.code",
      "position": [
        304,
        1632
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, demo_backend_note: 'Replace this demo node with your own Google Sheets, database, or CRM action.' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "4ba3bf99-e4d3-4114-8dfe-f105bf5b071d",
      "name": "Build Registered Update Reply",
      "type": "n8n-nodes-base.code",
      "position": [
        -144,
        192
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, reply_text: \"Your details have been prepared in demo mode. Connect your own database to save them.\", delivery_mode: 'Demo Preview - Not Sent' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "0350a0f8-0288-49de-b71f-077f0dbdec07",
      "name": "Log Registered Update Reply",
      "type": "n8n-nodes-base.code",
      "position": [
        80,
        192
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, demo_backend_note: 'Replace this demo node with your own Google Sheets, database, or CRM action.' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "8187c115-e333-4ae4-8faf-adb434b5543e",
      "name": "AI Classify Unknown SMS",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        -944,
        1216
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-mini",
          "cachedResultName": "GPT-4.1-MINI"
        },
        "options": {},
        "responses": {
          "values": [
            {
              "content": "=You classify SMS messages from Kenyan farmers.\n\nReturn ONLY valid JSON. No markdown. No explanation.\n\nThe farmer may write in English, Swahili, Sheng, or simple mixed language.\nUnderstand common farming words:\n- mvua = rain\n- kunyesha = raining\n- mahindi = maize\n- mbegu = seeds\n- dawa = pesticide/chemical/treatment\n- trekta/tractor = tractor\n- pump = pump\n- sprayer = sprayer\n- moto = fire\n- moshi = smoke\n- kupanda = planting\n- vuna/kuvuna = harvest\n- kuvuna lini = when to harvest\n- shamba = farm\n\nAllowed intents:\n- weather_request: farmer asks about rain, weather, temperature, drought, or forecast\n- fire_alert: farmer asks about fire, smoke, burning, or fire risk\n- supplier_lookup: farmer asks where to buy seeds, fertilizer, seedlings, pesticide, chemicals, or crop inputs\n- equipment_lookup: farmer asks about tools, machines, sprayers, pumps, tractors, irrigation equipment, or equipment hire\n- planting_advice: farmer asks when/how to plant or prepare planting\n- harvest_advice: farmer asks when/how to harvest\n- registration: farmer wants to register or update profile\n- unknown: message does not match any allowed intent\n\nImportant:\nIf the message mentions sprayer, pump, tractor, irrigation, machine, tool, equipment, or hire, choose equipment_lookup, not supplier_lookup.\nIf the message mentions seeds, fertilizer, seedlings, agrovet inputs, pesticide, chemicals, or dawa, choose supplier_lookup.\nIf the message mentions mvua, kunyesha, rain, weather, drought, or forecast, choose weather_request.\nIf the message mentions moto, moshi, fire, smoke, or burning, choose fire_alert.\nIf the message mentions kupanda, plant, planting, or sowing, choose planting_advice.\nIf the message mentions vuna, kuvuna, harvest, or ready to harvest, choose harvest_advice.\n\nFarmer profile:\nName: {{$json.name}}\nCounty/District: {{$json.district}}\nMain crop: {{$json.main_crop}}\nLanguage preference: {{$json.preferred_language}}\n\nSMS message:\n{{$json.message_text}}\n\nReturn JSON in this exact shape:\n{\n  \"intent\": \"one_allowed_intent\",\n  \"crop\": \"crop name or empty string\",\n  \"location\": \"location name or empty string\",\n  \"language_detected\": \"English, Swahili, Sheng, Mixed, or Unknown\",\n  \"confidence\": 0.0,\n  \"reason\": \"short reason\"\n}"
            }
          ]
        },
        "builtInTools": {}
      },
      "typeVersion": 2.3
    },
    {
      "id": "04e2fb83-5fc5-4be6-92c6-6d3c5fc799a1",
      "name": "Parse AI Classification",
      "type": "n8n-nodes-base.code",
      "position": [
        -592,
        1216
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nconst text = data.output?.[0]?.content?.[0]?.text ?? data.ai_response ?? '';\nlet classified = {};\ntry { classified = JSON.parse(text); } catch { classified = { intent: 'unknown', confidence: 0, reason: 'Demo parser could not read AI JSON.' }; }\nreturn [{ json: { ...data, ai_intent: classified.intent ?? 'unknown', ai_confidence: classified.confidence ?? 0, ai_reason: classified.reason ?? '' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "9f3f437e-5d09-4447-8f74-e72e183cdbad",
      "name": "Route AI Intent",
      "type": "n8n-nodes-base.switch",
      "position": [
        -432,
        1152
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "weather_request",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "fa541f07-65fe-4f13-ae5d-4041594c0b2c",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.ai_intent }}",
                    "rightValue": "weather_request"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "fire_alert",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "e2b3b4c2-fdaa-48cc-b12c-c8a97a83ee2d",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.ai_intent }}",
                    "rightValue": "fire_alert"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "supplier_lookup",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "bab71301-7a8a-4d09-ad12-df7cc8e27933",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.ai_intent }}",
                    "rightValue": "supplier_lookup"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "equipment_lookup",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "4e71c534-18f3-4aba-8874-11fda41970d5",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.ai_intent }}",
                    "rightValue": "equipment_lookup"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "planting_advice",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "21fecb68-0ba4-49ca-ae87-38ce5afdbd40",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.ai_intent }}",
                    "rightValue": "planting_advice"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "harvest_advice",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "0aa106c5-71b5-47d2-8ad8-d18b7bf7233b",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.ai_intent }}",
                    "rightValue": "harvest_advice"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra",
          "renameFallbackOutput": "Unknown"
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "2a5937b3-ff02-4712-91bb-89908ef08c0a",
      "name": "Attach Farmer To Rain Weather",
      "type": "n8n-nodes-base.code",
      "position": [
        80,
        944
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn [{ json: { ...data, farmer_context: 'Demo farmer context attached to demo weather data' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "34efb0d6-114e-4ba1-8311-7d9ea2556e14",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -4128,
        -48
      ],
      "parameters": {
        "width": 1312,
        "height": 688,
        "content": "# AI Farmer SMS Assistant\n\nHow it works:\n\n1. Receive or simulate an incoming SMS.\n2. Normalize the phone number, message text, timestamp, and provider message ID.\n3. Look up the farmer profile.\n4. Route exact commands such as RAIN, FIRE, SEEDS, EQUIPMENT, PLANT, and HARVEST.\n5. Use AI only when the message does not match a known command.\n6. Prepare and log the reply before any live SMS sending.\n\n# Setup\n\n- [ ] Use the Webhook node's test URL to send an SMS-style payload while testing the workflow.\n- [ ] Replace \"Send SMS Reply\" with your SMS provider node or HTTP Request node. \n- [ ] Replace \"Lookup Farmer\", \"Lookup Seed Suppliers\", and \"Log SMS Send Result\", with your Google Sheets or database actions.\n- [ ] Add your OpenAI credential to \"AI Classify Unknown SMS\".\n\nThis is a template version. Review all credentials, sheet IDs, phone numbers, and live SMS settings before using it with real farmers. \n\n## Who is this for?\nDesigned for African smallholder-farmer and low-connectivity SMS contexts. It can be adapted for other countries, languages, crops, and local advice sources."
      },
      "typeVersion": 1
    },
    {
      "id": "bf99d928-1f56-4d00-b901-dff946e0ad46",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2560,
        1328
      ],
      "parameters": {
        "color": "#FFFFFF",
        "width": 880,
        "height": 464,
        "content": "# Incoming SMS\n\nThis section receives the farmer message and converts it into a clean structure.\n\nExpected fields include phone, message text, timestamp, provider message ID, and channel. Replace the demo or provider-specific fields with the format used by your own SMS provider."
      },
      "typeVersion": 1
    },
    {
      "id": "b07584b7-450a-4f58-b181-d2389dd215ff",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1968,
        2016
      ],
      "parameters": {
        "color": "#FFFFFF",
        "width": 2496,
        "height": 848,
        "content": "# Farmer Lookup and Registration\n\nThis section checks whether the sender already exists in the farmer database.\n\nRegistered farmers continue to the main routing logic. Unknown farmers receive a registration prompt or are processed through the registration branch."
      },
      "typeVersion": 1
    },
    {
      "id": "6175daf2-dada-4871-9e26-abb83b0c4e8a",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1648,
        -48
      ],
      "parameters": {
        "color": "#FFFFFF",
        "width": 1360,
        "height": 928,
        "content": "# Command Routing\n\nThis section routes simple SMS commands before using AI.\n\nExact commands such as RAIN, SEEDS, EQUIPMENT, PLANT MAIZE, HARVEST MAIZE, and REGISTER are routed to dedicated reply paths."
      },
      "typeVersion": 1
    },
    {
      "id": "eb17ab61-d0b6-43f1-b218-1d607bfc0b96",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -256,
        -48
      ],
      "parameters": {
        "color": "#FFFFFF",
        "width": 784,
        "height": 2032,
        "content": "# Reply Builders\n\nEach branch prepares a farmer-facing SMS reply.\n\nThe replies combine the farmer profile, crop, location, supplier data, weather data, or crop rules. It is best to keep replies short because SMS length affects cost and readability."
      },
      "typeVersion": 1
    },
    {
      "id": "b5e7bed2-e5b2-438b-91f2-be4fb58a955e",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1456,
        1008
      ],
      "parameters": {
        "color": "#FFFFFF",
        "width": 1168,
        "height": 512,
        "content": "# AI Fallback\n\nMessages that do not match an exact command can be classified with OpenAI. Add your own OpenAI credential and review the prompt and test local-language examples before production use.\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "0eb29fb8-0b6a-499d-8d15-8da83a210e51",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        560,
        736
      ],
      "parameters": {
        "color": "#F05C5C",
        "width": 1312,
        "height": 432,
        "content": "# Important: Review Before Live Use\n\nThis workflow can affect real SMS costs. \n\nBefore production use, replace all demo values, remove private IDs, configure your own credentials, and test delivery reports. Provider \u201csuccess\u201d usually means the SMS was accepted, not necessarily delivered."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {},
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "Normalize Incoming SMS",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SMS Opt-In?": {
      "main": [
        [
          {
            "node": "Test Phone Allowed?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Farmer Exists": {
      "main": [
        [
          {
            "node": "Merge SMS + Farmer",
            "type": "main",
            "index": 1
          }
        ],
        [
          {
            "node": "Is Registration Message?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Lookup Farmer": {
      "main": [
        [
          {
            "node": "Farmer Exists",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send SMS Reply": {
      "main": [
        [
          {
            "node": "Merge Reply + Send Result",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Route AI Intent": {
      "main": [
        [
          {
            "node": "Get Weather Forecast",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Fire Reply",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Lookup Seed Suppliers",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Lookup Equipment Suppliers",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Lookup Planting Rule",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Lookup Harvest Rule",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Unknown Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Fire Reply": {
      "main": [
        [
          {
            "node": "Log Fire Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Rain Reply": {
      "main": [
        [
          {
            "node": "SMS Opt-In?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route SMS Intent": {
      "main": [
        [
          {
            "node": "Get Weather Forecast",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Fire Reply",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Lookup Seed Suppliers",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Lookup Equipment Suppliers",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Registered Update Reply",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Lookup Planting Rule",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Lookup Harvest Rule",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "AI Classify Unknown SMS",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Seeds Reply": {
      "main": [
        [
          {
            "node": "Log Seeds Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Already Registered": {
      "main": [
        [
          {
            "node": "Build Already Registered Reply",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Lookup Weather Zone For Registration",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge SMS + Farmer": {
      "main": [
        [
          {
            "node": "Route SMS Intent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Registration": {
      "main": [
        [
          {
            "node": "Lookup Existing Registration Phone",
            "type": "main",
            "index": 0
          },
          {
            "node": "Merge Registration + Weather Zone",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Harvest Reply": {
      "main": [
        [
          {
            "node": "Log Harvest Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Unknown Reply": {
      "main": [
        [
          {
            "node": "Log Unknown Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Lookup Harvest Rule": {
      "main": [
        [
          {
            "node": "Build Harvest Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Test Phone Allowed?": {
      "main": [
        [
          {
            "node": "Merge Reply + Send Result",
            "type": "main",
            "index": 0
          },
          {
            "node": "Send SMS Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Planting Reply": {
      "main": [
        [
          {
            "node": "Log Planting Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Weather Forecast": {
      "main": [
        [
          {
            "node": "Attach Farmer To Rain Weather",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Lookup Planting Rule": {
      "main": [
        [
          {
            "node": "Build Planting Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Equipment Reply": {
      "main": [
        [
          {
            "node": "Log Equipment Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Lookup Seed Suppliers": {
      "main": [
        [
          {
            "node": "Build Seeds Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Incoming SMS": {
      "main": [
        [
          {
            "node": "Lookup Farmer",
            "type": "main",
            "index": 0
          },
          {
            "node": "Merge SMS + Farmer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Classify Unknown SMS": {
      "main": [
        [
          {
            "node": "Parse AI Classification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse AI Classification": {
      "main": [
        [
          {
            "node": "Route AI Intent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Registration Message?": {
      "main": [
        [
          {
            "node": "Parse Registration",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Registration Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Registration Prompt": {
      "main": [
        [
          {
            "node": "Log Registration Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Reply + Send Result": {
      "main": [
        [
          {
            "node": "Log SMS Send Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Lookup Equipment Suppliers": {
      "main": [
        [
          {
            "node": "Build Equipment Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Attach Farmer To Rain Weather": {
      "main": [
        [
          {
            "node": "Build Rain Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Registered Update Reply": {
      "main": [
        [
          {
            "node": "Log Registered Update Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Registered Farmer Row": {
      "main": [
        [
          {
            "node": "Add Register Farmer",
            "type": "main",
            "index": 0
          },
          {
            "node": "Log Registration Reply",
            "type": "main",
            "index": 0
          },
          {
            "node": "Log Registration Success",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Already Registered Reply": {
      "main": [
        [
          {
            "node": "Log Already Registered Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Registration + Weather Zone": {
      "main": [
        [
          {
            "node": "Prepare Registered Farmer Row",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Lookup Existing Registration Phone": {
      "main": [
        [
          {
            "node": "Already Registered",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Lookup Weather Zone For Registration": {
      "main": [
        [
          {
            "node": "Merge Registration + Weather Zone",
            "type": "main",
            "index": 1
          }
        ]
      ]
    }
  }
}