AutomationFlowsSlack & Telegram › Send Subscription Renewal Reminders via Telegram with Supabase

Send Subscription Renewal Reminders via Telegram with Supabase

Byvinci-king-01 @vinci-king-01 on n8n.io

This workflow tracks upcoming subscription expiry dates stored in Supabase and automatically sends personalized renewal-reminder messages to each customer via Telegram. It is designed to be triggered by an HTTP Webhook (manually or on a schedule) and ensures that customers are…

Webhook trigger★★★★☆ complexity19 nodesSupabaseTelegram
Slack & Telegram Trigger: Webhook Nodes: 19 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #13193 — we link there as the canonical source.

This workflow follows the Supabase → 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 →

Download .json
{
  "id": "JZ8C3IFRtHrntshw",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Subscription Renewal Reminder \u2013 Telegram & Supabase",
  "tags": [],
  "nodes": [
    {
      "id": "c27c9a31-87c7-45c4-91d6-f76c1f5e459f",
      "name": "Webhook Trigger",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -2032,
        -32
      ],
      "parameters": {
        "path": "subscription-renewal",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 1.1
    },
    {
      "id": "e4709aa5-1ee7-4c7a-8cd9-d27071ce208d",
      "name": "Extract API Key",
      "type": "n8n-nodes-base.set",
      "position": [
        -1840,
        -32
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3.4
    },
    {
      "id": "0c98d8f4-dc5b-4ef9-898e-0102d9e0df35",
      "name": "Authorized?",
      "type": "n8n-nodes-base.if",
      "position": [
        -1632,
        -32
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "string": [
            {
              "value1": "={{ $json.apiKey }}",
              "value2": "{{YOUR_SECRET_KEY}}",
              "operation": "equals"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "6b4ceea6-b888-4cfe-874d-0995182a6b20",
      "name": "Fetch Subscriptions",
      "type": "n8n-nodes-base.supabase",
      "position": [
        -1440,
        -32
      ],
      "parameters": {
        "operation": "list"
      },
      "typeVersion": 1
    },
    {
      "id": "f5638554-9802-49a5-9947-06ee14dec899",
      "name": "Calculate Days",
      "type": "n8n-nodes-base.code",
      "position": [
        -1232,
        -32
      ],
      "parameters": {
        "jsCode": "// Add daysToExpiry to every row\nconst now = new Date();\nreturn $input.all().map(item => {\n  const expiry = new Date(item.json.expiry_date);\n  const diff = Math.ceil((expiry - now) / (1000*60*60*24));\n  return {\n    json: {\n      ...item.json,\n      daysToExpiry: diff\n    }\n  };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "ef038b64-933a-48bc-97b7-dedfa0a2dab7",
      "name": "Expiring Soon?",
      "type": "n8n-nodes-base.if",
      "position": [
        -1040,
        -32
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "number": [
            {
              "value1": "={{ $json.daysToExpiry }}",
              "value2": 7,
              "operation": "smallerEqual"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "3136b9a3-68de-4fc3-af9f-fac13d69b8aa",
      "name": "Create Telegram Message",
      "type": "n8n-nodes-base.set",
      "position": [
        -832,
        -32
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3.4
    },
    {
      "id": "e52d93f6-d14c-42e6-ae9b-a332176a4fac",
      "name": "Send Telegram Reminder",
      "type": "n8n-nodes-base.telegram",
      "position": [
        -640,
        -32
      ],
      "parameters": {
        "text": "={{ $json.telegramMessage }}",
        "chatId": "={{ $json.chatId }}",
        "additionalFields": {}
      },
      "typeVersion": 1.2
    },
    {
      "id": "fdd0c495-c9b6-4d59-a79a-fb6dd99a84d7",
      "name": "Telegram Sent?",
      "type": "n8n-nodes-base.if",
      "position": [
        -432,
        -32
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "boolean": [
            {
              "value1": "={{ $json.ok === true }}",
              "operation": "isTrue"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "7317ad39-4685-472a-b56e-4d512882717f",
      "name": "Prepare Reminder Log",
      "type": "n8n-nodes-base.set",
      "position": [
        -240,
        -32
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3.4
    },
    {
      "id": "a37b7f6f-fcf2-47b7-bc7b-d24bb166ad7a",
      "name": "Insert Reminder Log",
      "type": "n8n-nodes-base.supabase",
      "position": [
        -32,
        -32
      ],
      "parameters": {
        "tableId": "renewal_reminders",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "customer_id",
              "fieldValue": "={{ $json.customer_id }}"
            },
            {
              "fieldId": "reminder_sent_at",
              "fieldValue": "={{ $json.reminder_sent_at }}"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "dbddf411-e753-470c-8160-9e49b49e3408",
      "name": "Compose Success Response",
      "type": "n8n-nodes-base.set",
      "position": [
        176,
        -32
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3.4
    },
    {
      "id": "f579f71e-d319-4661-9541-a41e01084ef6",
      "name": "Respond to Webhook",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        368,
        -32
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "049b1ab5-006e-4690-9265-bc56cf0c40b8",
      "name": "Compose Error Response",
      "type": "n8n-nodes-base.set",
      "position": [
        -432,
        176
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3.4
    },
    {
      "id": "945303cd-c6a3-4e57-a712-bb973f2d7940",
      "name": "Insert Error Log",
      "type": "n8n-nodes-base.supabase",
      "position": [
        -240,
        176
      ],
      "parameters": {
        "tableId": "workflow_errors",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "error_message",
              "fieldValue": "={{ $json.message }}"
            },
            {
              "fieldId": "error_detail",
              "fieldValue": "={{ $json.error_detail }}"
            },
            {
              "fieldId": "created_at",
              "fieldValue": "={{ new Date().toISOString() }}"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "29619ad1-576d-4a3e-9451-e3b0b89c9b61",
      "name": "\ud83d\udd14 Subscription Renewal Reminder \u2013 Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2736,
        -368
      ],
      "parameters": {
        "width": 550,
        "height": 738,
        "content": "## How it works\nThis workflow listens for an incoming webhook call to kick off a subscription-renewal check. After validating an API key, it queries a Supabase table that stores all active subscriptions. Each record is enriched with a calculated **daysToExpiry** value, then filtered so only customers whose plan expires in seven days or fewer proceed. For every imminent renewal, a friendly Telegram reminder is sent. Successful sends are logged back to Supabase while failures or unauthorized calls create an error entry. Finally, the workflow returns a concise JSON response to the original webhook request.\n\n## Setup steps\n1. Add your Supabase project URL and service role key to an **Supabase API** credential.\n2. Create two tables: `subscriptions` (with columns: customer_id, customer_name, telegram_chat_id, expiry_date) and `renewal_reminders`.\n3. Generate a Telegram bot and store its token in a **Telegram API** credential.\n4. Replace `{{YOUR_SECRET_KEY}}` in the *Authorized?* IF node with a secure value and pass it via an `x-api-key` header when calling the webhook.\n5. Deploy the workflow and copy the production webhook URL from the *Webhook Trigger* node.\n6. Schedule or call the webhook from your billing system on a daily basis.\n7. Monitor Supabase tables for reminder logs and review Telegram delivery results."
      },
      "typeVersion": 1
    },
    {
      "id": "99d33e26-9974-440c-82c7-1980a86208a1",
      "name": "\ud83d\udee1\ufe0f Trigger & Auth (Info)",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1984,
        -400
      ],
      "parameters": {
        "color": 7,
        "width": 610,
        "height": 702,
        "content": "## Trigger & Authentication\nThis block handles all incoming requests. The **Webhook Trigger** node exposes a public endpoint that external services can call. Immediately after triggering, the workflow extracts the `x-api-key` header so it can be validated. The **Authorized?** IF node compares the provided key with your secret. Unauthorized traffic is short-circuited, returning an error JSON and recording the event in the error-logging branch. Keeping authentication logic up front prevents unnecessary Supabase queries and secures the rest of the workflow.\n\nKey points:\n\u2022 Webhook response mode is set to *Response Node* so we can craft custom replies.\n\u2022 API key travels in headers, avoiding exposure in query strings.\n\u2022 All failed checks are directed to the error-handling lane for visibility."
      },
      "typeVersion": 1
    },
    {
      "id": "b44c28e9-84d1-4786-aa5d-92a1592c913a",
      "name": "\ud83d\udcca Processing (Info)",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1296,
        -368
      ],
      "parameters": {
        "color": 7,
        "width": 738,
        "height": 654,
        "content": "## Processing & Filtering\nOnce a request is authorized, the workflow pulls current subscription rows from Supabase. The **Calculate Days** code snippet computes the remaining time until each subscription\u2019s `expiry_date`. Next, the **Expiring Soon?** IF node isolates customers whose plans lapse within seven days. This logic keeps Telegram traffic efficient, ensuring only relevant users receive messages. Because n8n processes items individually, each record moves independently through the remainder of the flow, enabling fine-grained logging and error handling without complex loops."
      },
      "typeVersion": 1
    },
    {
      "id": "d60acb9e-730e-44d6-a347-f2e4761a0a59",
      "name": "\ud83d\udce8 Notification & Logging (Info)",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -496,
        -288
      ],
      "parameters": {
        "color": 7,
        "width": 1010,
        "height": 638,
        "content": "## Notifications & Logging\nFor every imminent renewal, a personalized message is assembled and dispatched via the **Send Telegram Reminder** node. Successful sends trigger a logging sequence that writes a confirmation row into `renewal_reminders`. If Telegram responds with an error (e.g., invalid chat ID), the alternative branch builds an error object and stores it in `workflow_errors`. Both success and failure paths conclude by assembling a human-readable JSON payload that the **Respond to Webhook** node returns to the caller, closing the loop with clear status feedback."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "5b7cced7-f575-4ed7-8cfe-ab88ae5a994d",
  "connections": {
    "Authorized?": {
      "main": [
        [
          {
            "node": "Fetch Subscriptions",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Compose Error Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculate Days": {
      "main": [
        [
          {
            "node": "Expiring Soon?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Expiring Soon?": {
      "main": [
        [
          {
            "node": "Create Telegram Message",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Compose Success Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Telegram Sent?": {
      "main": [
        [
          {
            "node": "Prepare Reminder Log",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Compose Error Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract API Key": {
      "main": [
        [
          {
            "node": "Authorized?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook Trigger": {
      "main": [
        [
          {
            "node": "Extract API Key",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Subscriptions": {
      "main": [
        [
          {
            "node": "Calculate Days",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Insert Reminder Log": {
      "main": [
        [
          {
            "node": "Compose Success Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Reminder Log": {
      "main": [
        [
          {
            "node": "Insert Reminder Log",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compose Error Response": {
      "main": [
        [
          {
            "node": "Insert Error Log",
            "type": "main",
            "index": 0
          },
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Telegram Reminder": {
      "main": [
        [
          {
            "node": "Telegram Sent?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Telegram Message": {
      "main": [
        [
          {
            "node": "Send Telegram Reminder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compose Success Response": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow tracks upcoming subscription expiry dates stored in Supabase and automatically sends personalized renewal-reminder messages to each customer via Telegram. It is designed to be triggered by an HTTP Webhook (manually or on a schedule) and ensures that customers are…

Source: https://n8n.io/workflows/13193/ — original creator credit. Request a take-down →

More Slack & Telegram workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Slack & Telegram

AIPA - BMF Work Logging. Uses telegram, telegramTrigger, supabase, httpRequest. Webhook trigger; 19 nodes.

Telegram, Telegram Trigger, Supabase +1
Slack & Telegram

This workflow provides an API-first solution to validate, clean, deduplicate and store customer data in Supabase. It ensures consistent customer records, prevents duplicates and keeps both internal te

Supabase, Slack, Telegram +1
Slack & Telegram

This workflow automatically captures Facebook Story replies, normalizes incoming webhook payloads, stores them in Supabase, assigns them to the correct regional support team based on UTC time, and sen

Telegram, Slack, Supabase
Slack & Telegram

qualiopi. Uses airtable, telegram, emailSend, httpRequest. Webhook trigger; 51 nodes.

Airtable, Telegram, Email Send +3
Slack & Telegram

PsyCardv2. Uses executeCommand, telegram, readBinaryFile, googleDrive. Webhook trigger; 41 nodes.

Execute Command, Telegram, Read Binary File +2