{
  "id": "fM5PRDQlmoaAlnBm",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "AI Agent Rate Limiter",
  "tags": [
    {
      "id": "2GEineegHgFbbJ26",
      "name": "AI",
      "createdAt": "2025-08-04T12:39:26.962Z",
      "updatedAt": "2025-08-04T12:39:26.962Z"
    },
    {
      "id": "ewcMZyQBnLVMPImC",
      "name": "AI Agent",
      "createdAt": "2025-08-04T12:39:26.852Z",
      "updatedAt": "2025-08-04T12:39:26.852Z"
    }
  ],
  "nodes": [
    {
      "id": "6d351c55-6aad-4031-8456-0ea676d390b9",
      "name": "Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -880,
        464
      ],
      "parameters": {
        "text": "={{ $('Telegram').item.json.message.text }}",
        "options": {
          "systemMessage": "=You are a knowledgeable and helpful AI assistant designed to provide accurate, thoughtful, and actionable responses. Your role is to:\n\nCORE PRINCIPLES:\n- Provide clear, accurate information based on your knowledge\n- Admit uncertainty when you don't know something\n- Ask clarifying questions when requests are ambiguous\n- Prioritize user safety and well-being in all responses\n- Maintain a professional yet friendly tone\n\nRESPONSE GUIDELINES:\n- Structure longer responses with clear headings or bullet points\n- Provide step-by-step instructions for complex tasks\n- Include relevant examples when helpful\n- Suggest follow-up actions or resources when appropriate\n- Keep responses concise but comprehensive\n\nLIMITATIONS AWARENESS:\n- Acknowledge when tasks require real-time information you cannot access\n- Explain if requests fall outside your capabilities\n- Recommend human experts or specialized tools when appropriate\n\nRemember: Users have limited messages per session, so make each response valuable and complete. Focus on giving thorough, actionable help that addresses their needs efficiently."
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.7
    },
    {
      "id": "eb0afcd5-fcdb-4718-99e9-47fb932a7ae4",
      "name": "Code",
      "type": "n8n-nodes-base.code",
      "position": [
        -1456,
        432
      ],
      "parameters": {
        "jsCode": "// Get the data from the lookup result\nconst currentRow = $input.first().json;\n\n// Get current message count from column B (if it doesn't exist, start at 0)\nconst currentCount = $input.first().json['Message Counter'] || 0;\n\n// Add 1 to the count\nconst newCount = parseInt(currentCount) + 1;\n\n// Return the data we need for the next step\nreturn {\n  json: {\n    session_id: currentRow.A,\n    message_count: newCount,\n    row_number: currentRow.__rowNum\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "334982a1-5681-4718-ac94-51d1ffe80bd4",
      "name": "Append or update row in sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -1792,
        432
      ],
      "parameters": {
        "columns": {
          "value": {
            " ID": "={{ $json.message.chat.id }}"
          },
          "schema": [
            {
              "id": " ID",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": " ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Message Counter",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Message Counter",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            " ID"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY/edit?usp=drivesdk",
          "cachedResultName": "Message Counter"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "94d0cedf-8dc7-4f6a-905f-b8312a060f2b",
      "name": "Get row(s) in sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -1616,
        432
      ],
      "parameters": {
        "options": {
          "dataLocationOnSheet": {
            "values": {
              "range": "A:Z",
              "rangeDefinition": "specifyRangeA1"
            }
          }
        },
        "filtersUI": {
          "values": [
            {
              "lookupValue": "={{ $('Telegram').item.json.message.chat.id }}",
              "lookupColumn": " ID"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY/edit?usp=drivesdk",
          "cachedResultName": "Message Counter"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "35755fa3-22db-4457-a54e-6b35cc3d0b8a",
      "name": "Append or update row in sheet1",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -1280,
        432
      ],
      "parameters": {
        "columns": {
          "value": {
            " ID": "={{ $('Telegram').item.json.message.chat.id }}",
            "Message Counter": "={{ $json.message_count }}"
          },
          "schema": [
            {
              "id": " ID",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": " ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Message Counter",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Message Counter",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            " ID"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY/edit?usp=drivesdk",
          "cachedResultName": "Message Counter"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "012468ea-8550-40c1-a66c-10de42cc97f0",
      "name": "Azure",
      "type": "@n8n/n8n-nodes-langchain.lmChatAzureOpenAi",
      "position": [
        -880,
        640
      ],
      "parameters": {
        "model": "gpt-4.1-2",
        "options": {}
      },
      "credentials": {
        "azureOpenAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "2374ffee-2bbc-4d99-9b01-cd8c44510e43",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -1504,
        896
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "7c7712f0-3fce-4be9-a5ab-e3266e7c8d78",
      "name": "Get row(s) in sheet1",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -1504,
        1040
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY/edit?usp=drivesdk",
          "cachedResultName": "Message Counter"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "b33dba91-644e-4a8e-b92e-24858e290561",
      "name": "Update row in sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -1504,
        1200
      ],
      "parameters": {
        "columns": {
          "value": {
            " ID": "={{ $json[' ID'] }}",
            "Message Counter": "0"
          },
          "schema": [
            {
              "id": " ID",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": " ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Message Counter",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Message Counter",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            " ID"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY/edit?usp=drivesdk",
          "cachedResultName": "Message Counter"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "0a292f78-fd84-4b0f-9880-c0d84049a93f",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2032,
        832
      ],
      "parameters": {
        "color": 3,
        "width": 720,
        "height": 528,
        "content": "## \ud83d\udd04 Automatic Reset System (Separate Workflow Branch)\n\n### Reset Schedule Options:\n- **Current:** Every 1 minute (for testing)\n- **Hourly:** Change to `0 * * * *`\n- **Daily:** Change to `0 0 * * *` (midnight)\n- **Weekly:** Change to `0 0 * * 0` (Sunday)\n- **Custom:** Any cron expression\n\n### Reset Process:\n1. **Schedule Trigger** fires at set intervals\n2. **Get all user records** from Google Sheets\n3. **Bulk reset all counters** to 0\n4. **Users can interact again** after reset\n\n### Configuration Tips:\n- **Testing:** Use minutes for quick testing\n- **Production:** Use hourly/daily for real deployment\n- **High Traffic:** Consider shorter intervals\n- **Cost Control:** Use longer intervals\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "0533d580-8ce6-43b4-86a1-5f399b254829",
      "name": "Switch",
      "type": "n8n-nodes-base.switch",
      "position": [
        -1104,
        416
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "e34ecf3a-c51e-4cb3-9014-bfba185797f9",
                    "operator": {
                      "type": "number",
                      "operation": "gt"
                    },
                    "leftValue": "={{ $json['Message Counter'] }}",
                    "rightValue": 3
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "c0a45d11-2dc9-4022-838d-677e77096020",
                    "operator": {
                      "type": "number",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json['Message Counter'] }}",
                    "rightValue": 3
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "e6dc0f88-a9b6-417b-917e-904ebbbeff2c",
                    "operator": {
                      "type": "number",
                      "operation": "lt"
                    },
                    "leftValue": "={{ $json['Message Counter'] }}",
                    "rightValue": 3
                  }
                ]
              }
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.2
    },
    {
      "id": "04b0a71c-ac0f-4781-a836-513fbc8658d5",
      "name": "No Operation",
      "type": "n8n-nodes-base.noOp",
      "position": [
        -576,
        208
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "7287f221-93fa-4ffe-96d4-e173b73a0554",
      "name": "Limit Message",
      "type": "n8n-nodes-base.telegram",
      "position": [
        -576,
        352
      ],
      "parameters": {
        "text": "=Daily limit exceeded \ud83d\udeab. Try again later \u23f3.  ",
        "chatId": "={{ $('Telegram').item.json.message.chat.id }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "a5c77b19-ee2f-46d0-afb8-bd37269611e8",
      "name": "Agent Answer",
      "type": "n8n-nodes-base.telegram",
      "position": [
        -576,
        512
      ],
      "parameters": {
        "text": "={{ $json.output }}",
        "chatId": "={{ $('Telegram').item.json.message.chat.id }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "9f24f7b1-2971-4142-a5c7-99e6fbda7e17",
      "name": "Telegram",
      "type": "n8n-nodes-base.telegramTrigger",
      "position": [
        -1968,
        432
      ],
      "parameters": {
        "updates": [
          "message"
        ],
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "f6ca6972-3c8e-4f05-b215-955786367b52",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2736,
        -128
      ],
      "parameters": {
        "color": 5,
        "width": 656,
        "height": 912,
        "content": "## \ud83e\udd16 AI Agent Rate Limiter\n\n### What does this workflow do?\nThis template solves a critical production problem: **controlling AI agent usage to prevent abuse and manage costs** when deploying chatbots publicly.\n\n### Key Features:\n- **Per-user message limits** (default: 3 messages)\n- **Automatic counter resets** (configurable intervals)\n- **User-friendly limit notifications**\n- **Google Sheets tracking system**\n\n### Perfect for:\n- Customer service bots with quotas\n- Demo/trial AI assistants\n- Educational chatbots with daily limits\n- Cost-controlled production deployments\n\n### Quick Start:\n1. Set up your Telegram bot\n2. Create Google Sheets for tracking\n3. Configure your AI model \n4. Adjust message limits in Switch node\n5. Set reset schedule frequency\n6. Deploy and monitor usage!\n\n## \ud83d\udee0\ufe0f Easy Customization\n\n### Google Sheets Setup:\n1. Create new spreadsheet\n2. Add headers: \"ID\" (Column A), \"Message Counter\" (Column B)\n3. **Switch Node:** Modify conditions (3 \u2192 your limit)\n4. **All Routes:** Update comparison values\n5. **Schedule Trigger:** Change interval settings\n6. **Custom Limit Messages:** Edit Telegram nodes\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "a674ef45-ee99-4625-ab47-789a0b2dc32c",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2032,
        -128
      ],
      "parameters": {
        "color": 4,
        "width": 1680,
        "height": 912,
        "content": "## \ud83d\udcca Smart Message Tracking\n\n### How it works:\n1. **User sends message** \u2192 Telegram Trigger\n2. **Create/Update user record** in Google Sheets\n3. **Lookup current count** for this user\n4. **Increment counter** by 1\n5. **Check against limits** using Switch node\n\n### Google Sheets Structure:\n- **Column A:** User ID (Telegram chat.id)\n- **Column B:** Message Counter (current count)\n\n### Switch Logic:\n- **Route 1:** > 3 messages \u2192 Block (No Operation)\n- **Route 2:** = 3 messages \u2192 Send limit warning\n- **Route 3:** < 3 messages \u2192 Allow AI response\n\n**Tip:** Easily change the limit by modifying the Switch node conditions!"
      },
      "typeVersion": 1
    },
    {
      "id": "fae65b4d-9afa-432f-95f9-719d578eff33",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -944,
        -128
      ],
      "parameters": {
        "width": 592,
        "height": 912,
        "content": "## \ud83d\udcac User-Friendly Responses\n\n### Three Response Types:\n\n**1. Normal AI Response**\n- When user is within limits\n- Full AI capabilities active\n- Conversation memory maintained\n\n**2. Limit Warning Message**\n- \"You've hit the limit, try after!\"\n- Sent when exactly at limit\n- Customizable message text\n\n**3. Silent Block**\n- No response when over limit\n- Prevents spam/abuse\n- User must wait for reset\n"
      },
      "typeVersion": 1
    },
    {
      "id": "d90f5c67-c8a2-43df-bbd9-d727788c59b9",
      "name": "Memory",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "position": [
        -784,
        640
      ],
      "parameters": {
        "sessionKey": "={{ $('Telegram').item.json.message.chat.id }}",
        "sessionIdType": "customKey"
      },
      "typeVersion": 1.3
    }
  ],
  "active": true,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "d84fb1e2-3d76-4eb6-b175-a8c6dab6daeb",
  "connections": {
    "Code": {
      "main": [
        [
          {
            "node": "Append or update row in sheet1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Agent": {
      "main": [
        [
          {
            "node": "Agent Answer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Azure": {
      "ai_languageModel": [
        [
          {
            "node": "Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Memory": {
      "ai_memory": [
        [
          {
            "node": "Agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Switch": {
      "main": [
        [
          {
            "node": "No Operation",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Limit Message",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Telegram": {
      "main": [
        [
          {
            "node": "Append or update row in sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Get row(s) in sheet1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get row(s) in sheet": {
      "main": [
        [
          {
            "node": "Code",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get row(s) in sheet1": {
      "main": [
        [
          {
            "node": "Update row in sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append or update row in sheet": {
      "main": [
        [
          {
            "node": "Get row(s) in sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append or update row in sheet1": {
      "main": [
        [
          {
            "node": "Switch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}