This workflow follows the HTTP Request → Telegram 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 →
{
"name": "Non-Banale: Usage Notifications",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "usage-notify",
"options": {}
},
"id": "webhook-trigger",
"name": "Usage Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [
250,
300
]
},
{
"parameters": {
"jsCode": "// Get data from webhook body\nconst input = $input.first().json;\nconst data = input.body || input;\n\n// \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u044d\u043a\u0440\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f Markdown \u0441\u043f\u0435\u0446\u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432\nconst escapeMarkdown = (text) => {\n if (!text) return '';\n return String(text).replace(/_/g, '-').replace(/\\*/g, '').replace(/`/g, \"'\").replace(/\\[/g, '(').replace(/\\]/g, ')');\n};\n\nconst type = data.type || 'unknown';\nconst inviteCode = data.inviteCode || 'N/A';\nconst location = data.location || {};\nconst city = escapeMarkdown(location.city || 'unknown');\nconst country = escapeMarkdown(location.country || 'unknown');\nconst details = data.details || {};\nconst timestamp = data.timestamp ? new Date(data.timestamp).toLocaleString('ru-RU', { timeZone: 'Europe/Moscow' }) : 'N/A';\n\n// Emoji and title based on type\nlet emoji = '';\nlet title = '';\nlet extraInfo = '';\nlet isImportant = false;\n\nswitch (type) {\n case 'analyze':\n emoji = '\ud83d\udcf8';\n title = '\u0410\u043d\u0430\u043b\u0438\u0437 \u043e\u0431\u0440\u0430\u0437\u0430';\n extraInfo = `\u0412\u0435\u0440\u0434\u0438\u043a\u0442: ${escapeMarkdown(details.verdict) || 'N/A'}`;\n break;\n case 'trends_analyze':\n emoji = '\ud83d\udc57';\n title = '\u0410\u043d\u0430\u043b\u0438\u0437 \u0432\u0435\u0449\u0435\u0439';\n extraInfo = `\u0412\u0435\u0440\u0434\u0438\u043a\u0442: ${escapeMarkdown(details.verdict) || 'N/A'}`;\n break;\n case 'trends_chat':\n emoji = '\ud83d\udcac';\n title = '\u0427\u0430\u0442 \u043e \u0442\u0440\u0435\u043d\u0434\u0430\u0445';\n extraInfo = `\u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439: ${details.historyLength || 0}`;\n break;\n case 'new_user':\n emoji = '\ud83c\udd95';\n title = '\u041d\u043e\u0432\u044b\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c!';\n extraInfo = `\u041a\u043e\u0434: ${escapeMarkdown(details.codeName || inviteCode)} (${details.usedCount || '?'}/${details.maxUses || '?'})`;\n isImportant = true;\n break;\n case 'appeal':\n emoji = '\u2696\ufe0f';\n const appealType = details.appealType === 'item' ? '\u0432\u0435\u0449\u0438' : '\u043e\u0431\u0440\u0430\u0437\u0430';\n const appealDecision = escapeMarkdown(details.appealDecision || 'N/A');\n const decisionEmoji = appealDecision === '\u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u0435\u043d\u0430' ? '\u2705' : appealDecision.includes('\u0447\u0430\u0441\u0442\u0438\u0447\u043d\u043e') ? '\u26a0\ufe0f' : '\u274c';\n title = `\u0410\u043f\u0435\u043b\u043b\u044f\u0446\u0438\u044f ${appealType}`;\n extraInfo = `${decisionEmoji} ${appealDecision}`;\n if (details.originalVerdict && details.newVerdict && details.originalVerdict !== details.newVerdict) {\n extraInfo += `\\n\ud83d\udcca \u0412\u0435\u0440\u0434\u0438\u043a\u0442: ${escapeMarkdown(details.originalVerdict)} \u2192 ${escapeMarkdown(details.newVerdict)}`;\n }\n if (details.changes && details.changes.length > 0) {\n extraInfo += `\\n\ud83d\udd04 \u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f: ${details.changes.map(c => escapeMarkdown(c)).join(', ')}`;\n }\n isImportant = true;\n break;\n default:\n emoji = '\ud83d\udcca';\n title = '\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435';\n extraInfo = '';\n}\n\n// Get closing text (analysis summary)\nconst closing = escapeMarkdown(details.closing || '');\n\n// Build message\nlet message = `${emoji} *${title}*\\n\\n`;\nmessage += `\ud83d\udccd ${city}, ${country}\\n`;\nmessage += `\ud83c\udfab \u041a\u043e\u0434: \\`${inviteCode}\\`\\n`;\nif (extraInfo) {\n message += `\u2139\ufe0f ${extraInfo}\\n`;\n}\nif (closing) {\n message += `\\n\ud83d\udcac ${closing}\\n`;\n}\nmessage += `\\n\ud83d\udd50 ${timestamp}`;\n\nreturn [{ json: { message, type, isNewUser: type === 'new_user', isImportant } }];"
},
"id": "format-message",
"name": "Format Message",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
450,
300
]
},
{
"parameters": {
"method": "GET",
"url": "={{$vars.SUPABASE_URL}}/rest/v1/admin_subscribers",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "apikey",
"value": "={{$vars.SUPABASE_SERVICE_KEY}}"
},
{
"name": "Authorization",
"value": "=Bearer {{$vars.SUPABASE_SERVICE_KEY}}"
}
]
},
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "is_active",
"value": "eq.true"
},
{
"name": "select",
"value": "telegram_chat_id"
}
]
},
"options": {}
},
"id": "get-subscribers",
"name": "\u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u043e\u0432",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
650,
300
]
},
{
"parameters": {
"jsCode": "// n8n HTTP Request \u0440\u0430\u0437\u0431\u0438\u0432\u0430\u0435\u0442 \u043c\u0430\u0441\u0441\u0438\u0432 \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 items\nconst subscriberItems = $input.all();\nconst messageData = $('Format Message').first().json;\n\n// \u0415\u0441\u043b\u0438 \u043d\u0435\u0442 \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u043e\u0432 - \u0432\u044b\u0445\u043e\u0434\u0438\u043c\nif (!subscriberItems || subscriberItems.length === 0 || !subscriberItems[0].json.telegram_chat_id) {\n return [];\n}\n\n// Create an item for each subscriber\nreturn subscriberItems.map(item => ({\n json: {\n chatId: item.json.telegram_chat_id,\n message: messageData.message,\n isImportant: messageData.isImportant\n }\n}));"
},
"id": "split-subscribers",
"name": "\u0420\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u043f\u043e \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u0430\u043c",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
850,
300
]
},
{
"parameters": {
"chatId": "={{ $json.chatId }}",
"text": "={{ $json.message }}",
"additionalFields": {
"parse_mode": "Markdown",
"disable_notification": "={{ !$json.isImportant }}"
}
},
"id": "telegram-send",
"name": "Send to Telegram",
"type": "n8n-nodes-base.telegram",
"typeVersion": 1,
"position": [
1050,
300
],
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
}
}
],
"connections": {
"Usage Webhook": {
"main": [
[
{
"node": "Format Message",
"type": "main",
"index": 0
}
]
]
},
"Format Message": {
"main": [
[
{
"node": "\u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u043e\u0432",
"type": "main",
"index": 0
}
]
]
},
"\u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u043e\u0432": {
"main": [
[
{
"node": "\u0420\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u043f\u043e \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u0430\u043c",
"type": "main",
"index": 0
}
]
]
},
"\u0420\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u043f\u043e \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u0430\u043c": {
"main": [
[
{
"node": "Send to Telegram",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"staticData": null,
"tags": [
"Non-Banale",
"Notifications",
"Usage"
]
}
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.
telegramApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Non-Banale: Usage Notifications. Uses httpRequest, telegram. Webhook trigger; 5 nodes.
Source: https://github.com/KirillTrubitsyn/Non-Banale/blob/52be985e34efa7734a07e30c8895b77cec991ff3/n8n-workflows/usage-notification.json — 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.
qualiopi. Uses airtable, telegram, emailSend, httpRequest. Webhook trigger; 51 nodes.
PsyCardv2. Uses executeCommand, telegram, readBinaryFile, googleDrive. Webhook trigger; 41 nodes.
[](https://www.linkedin.com/in/mosaab-yassir-lafrimi/)[](https://t.me/joevenner)
How it works • Webhook triggers from content creation system in Airtable • Downloads media (images/videos) from Airtable URLs • Uploads media to Postiz cloud storage • Schedules or publishes content a
I wanted to avoid the rush at end of month to log expenses. I tried existing expense apps but found them either too expensive for what they offer, or frustrating with inconsistent extraction results.