AutomationFlowsSlack & Telegram › Validate, Deduplicate, and Store Customers via API with Supabase, Slack,…

Validate, Deduplicate, and Store Customers via API with Supabase, Slack,…

Original n8n title: Validate, Deduplicate, and Store Customers via API with Supabase, Slack, Telegram, and Email

ByWeblineIndia @weblineindia on n8n.io

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 teams and customers informed through automated notifications.

Webhook trigger★★★★☆ complexity16 nodesSupabaseSlackTelegramGmail
Slack & Telegram Trigger: Webhook Nodes: 16 Complexity: ★★★★☆ Added:

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

This workflow follows the Gmail → Slack 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": "NofFLRbyZ07gRBlL",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "(Retail) Customer Cleanup API \u2192 Supabase and send Notification",
  "tags": [],
  "nodes": [
    {
      "id": "dc2de4d0-3e21-4179-90cf-1813a44e8014",
      "name": "Validate & Clean Data",
      "type": "n8n-nodes-base.code",
      "position": [
        -1872,
        800
      ],
      "parameters": {
        "jsCode": "const input = $json.body || {};\nconst errors = [];\n\n/* ------------------ Helpers ------------------ */\nconst trim = (v) => (v == null ? '' : String(v).trim());\n\nconst capitalize = (v) =>\n  trim(v)\n    .toLowerCase()\n    .replace(/\\b\\w/g, (c) => c.toUpperCase());\n\nconst isValidEmail = (email) =>\n  /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email);\n\nconst normalizePhone = (phone) => {\n  let v = trim(phone).replace(/[^0-9+]/g, '');\n\n  // Default India handling\n  if (v.length === 10) v = '+91' + v;\n\n  if (!v.startsWith('+')) return '';\n  if (v.length < 11 || v.length > 16) return '';\n\n  return v;\n};\n\nconst isValidName = (name) => /^[a-zA-Z\\s'-]+$/.test(name);\n\n/* ------------------ Cleaning ------------------ */\nconst firstName = capitalize(input.first_name);\nconst lastName = capitalize(input.last_name);\nconst email = trim(input.email).toLowerCase();\nconst phone = normalizePhone(input.phone);\n\n/* ------------------ Validation ------------------ */\n\n/* First Name */\nif (!firstName) {\n  errors.push({ field: 'first_name', message: 'First name is required' });\n} else if (!isValidName(firstName)) {\n  errors.push({ field: 'first_name', message: 'First name contains invalid characters' });\n} else if (firstName.length < 2) {\n  errors.push({ field: 'first_name', message: 'First name must be at least 2 characters long' });\n}\n\n/* Last Name */\nif (!lastName) {\n  errors.push({ field: 'last_name', message: 'Last name is required' });\n} else if (!isValidName(lastName)) {\n  errors.push({ field: 'last_name', message: 'Last name contains invalid characters' });\n} else if (lastName.length < 2) {\n  errors.push({ field: 'last_name', message: 'Last name must be at least 2 characters long' });\n}\n\n/* Email */\nif (!email) {\n  errors.push({ field: 'email', message: 'Email address is required' });\n} else if (!isValidEmail(email)) {\n  errors.push({ field: 'email', message: 'Email format is not valid' });\n} else if (email.length > 254) {\n  errors.push({ field: 'email', message: 'Email address is too long' });\n}\n\n/* Phone */\nif (!phone) {\n  errors.push({\n    field: 'phone',\n    message: 'Phone number is not valid or country code is missing'\n  });\n}\n\n/* ------------------ Final Response ------------------ */\nreturn [\n  {\n    json: {\n      valid: errors.length === 0,\n      errors,\n      data: {\n        first_name: firstName,\n        last_name: lastName,\n        email,\n        phone\n      }\n    }\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "1cbbb901-4ace-455d-a373-6ba97bd96d8f",
      "name": "Check Existing User",
      "type": "n8n-nodes-base.supabase",
      "position": [
        -1424,
        704
      ],
      "parameters": {
        "filters": {
          "conditions": [
            {
              "keyName": "email",
              "keyValue": "={{ $json.data.email }}",
              "condition": "eq"
            }
          ]
        },
        "tableId": "customers",
        "operation": "getAll"
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "bb13e6d0-6579-48f8-b61c-638d0f0a6a45",
      "name": "User Already Exists?",
      "type": "n8n-nodes-base.if",
      "position": [
        -1200,
        704
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "580b3c64-8b03-4be4-9ed5-1ef37514ba6a",
              "operator": {
                "type": "boolean",
                "operation": "empty",
                "singleValue": true
              },
              "leftValue": true,
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "c78819eb-dfed-4629-a167-ee4e38ca63f4",
      "name": "Create User",
      "type": "n8n-nodes-base.supabase",
      "position": [
        -976,
        608
      ],
      "parameters": {
        "tableId": "customers",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "first_name",
              "fieldValue": "={{ $('Is Validation Passed?').item.json.data.first_name }}"
            },
            {
              "fieldId": "last_name",
              "fieldValue": "={{ $('Is Validation Passed?').item.json.data.last_name }}"
            },
            {
              "fieldId": "email",
              "fieldValue": "={{ $('Is Validation Passed?').item.json.data.email }}"
            },
            {
              "fieldId": "phone",
              "fieldValue": "={{ $('Is Validation Passed?').item.json.data.phone }}"
            },
            {
              "fieldId": "valid",
              "fieldValue": "={{ $('Is Validation Passed?').item.json.valid }}"
            },
            {
              "fieldId": "error",
              "fieldValue": "={{ $('Is Validation Passed?').item.json.errors }}"
            }
          ]
        }
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "bd5804cf-c607-4a71-89ac-92884943054a",
      "name": "API User Exists",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        -528,
        800
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "9031719b-ad70-4b4f-9dcd-869688344396",
      "name": "API Validation Error",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        -528,
        992
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "41eaae3d-92df-4165-97cd-f2ebfe2485fc",
      "name": "Customer API1",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -2096,
        800
      ],
      "parameters": {
        "path": "customer/validate-and-store",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 1
    },
    {
      "id": "d4817e2b-5385-4933-8dd7-6a3917e42f90",
      "name": "API Success Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        -752,
        608
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "4f1f7efd-f1ce-46ca-97b1-27a2df853b97",
      "name": "Slack Notify",
      "type": "n8n-nodes-base.slack",
      "position": [
        -304,
        800
      ],
      "parameters": {
        "text": "={{ $json.valid ? 'Customer stored successfully' : 'Customer validation failed' }}",
        "user": {
          "__rl": true,
          "mode": "list",
          "value": "U09SEALBNAE",
          "cachedResultName": "n8n_demo"
        },
        "select": "user",
        "otherOptions": {}
      },
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "6f8c32e2-387b-4dde-a761-ed565c0cc6d4",
      "name": "Telegram Notify",
      "type": "n8n-nodes-base.telegram",
      "position": [
        -80,
        800
      ],
      "parameters": {
        "text": "={{ $json.valid ? 'Customer stored in Supabase' : 'Customer validation failed' }}",
        "chatId": "123456789",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "86cf5e69-b4c4-404e-868d-aee531dba0f3",
      "name": "Send Notifiaction to User",
      "type": "n8n-nodes-base.gmail",
      "position": [
        -528,
        608
      ],
      "parameters": {
        "sendTo": "",
        "message": "=Hello {{ $json.first_name }} {{ $json.last_name }},  Your customer profile has been successfully created.  Thank you.",
        "options": {},
        "subject": "Your account has been created",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "bef9b23b-e614-4c63-9c23-b5b3b0c8805b",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2240,
        528
      ],
      "parameters": {
        "color": 7,
        "width": 736,
        "height": 448,
        "content": "# API & Validation Layer \n\n## Description\n**This section receives customer data via an API call and performs centralized validation and cleanup. It standardizes names, emails and phone numbers, aggregates field-specific errors and decides whether the request can proceed further in the workflow.**"
      },
      "typeVersion": 1
    },
    {
      "id": "f094d656-640f-4dad-8287-367b435a2d26",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1472,
        368
      ],
      "parameters": {
        "color": 7,
        "width": 848,
        "height": 608,
        "content": "# Duplicate Check & Database Logic\n\n## Description\n**This section checks Supabase to determine whether a customer already exists based on email. It prevents duplicate records, routes existing users to an appropriate API response and ensures only new, valid customers are stored in the database.**"
      },
      "typeVersion": 1
    },
    {
      "id": "93a5eced-ca9c-4663-a314-d9f84437cea3",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -592,
        368
      ],
      "parameters": {
        "color": 7,
        "width": 720,
        "height": 768,
        "content": "# Notifications & API Responses \n\n## Description\n**This section handles final API responses and notifications. It sends success or failure responses back to the client and notifies internal teams via Slack and Telegram, while also emailing the customer when a new account is successfully created.**"
      },
      "typeVersion": 1
    },
    {
      "id": "343a5e2a-bf8d-4936-b92b-6afc95096b34",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2960,
        272
      ],
      "parameters": {
        "width": 688,
        "height": 688,
        "content": "## How It Works\n* The workflow starts when a client sends a **POST request** to the n8n webhook endpoint with customer details such as first name, last name, email and phone number. The webhook behaves like a synchronous API and waits for processing to complete before responding.\n* The **Validate & Clean Data** node normalizes and validates incoming data using JavaScript. It trims whitespace, capitalizes names, converts emails to lowercase and standardizes phone numbers with a country code.\n* Field-level validations are applied for required fields, correct formats and length rules. Only the fields that fail validation return clear, user-friendly error messages.\n* If validation fails, the workflow immediately returns a **400 API response** with detailed error messages and sends failure notifications to Slack and Telegram.\n* When validation passes, the workflow checks Supabase for an existing customer using the email address to prevent duplicate records.\n* If a duplicate user is found, the workflow stops processing, returns a **409 \u201cUser already exists\u201d response** and notifies internal teams.\n* If no existing user is found, a new customer record is created in Supabase. The workflow then returns a **201 success response**, sends internal success notifications and emails the customer confirming account creation.\n\n## Setup Steps\n* Create a **Supabase project** and ensure the `customers` table exists with required fields for customer data, validation status and error tracking.\n* Configure Supabase credentials in n8n using a service role key with read and write permissions.\n* Import the workflow JSON into n8n and verify all node connections.\n* Configure the **Webhook node** and copy the production webhook URL for API consumers.\n* Review and customize the JavaScript validation logic if additional rules or country-specific phone handling are required.\n* Set up Slack, Telegram and Gmail (or SMTP) credentials for notifications.\n* Test the workflow with Postman for invalid data, duplicate users and successful requests.\n* Activate the workflow and monitor executions to ensure stable production behavior."
      },
      "typeVersion": 1
    },
    {
      "id": "75ed8bdb-bff5-4138-9099-5d24213e9c0a",
      "name": "Is Validation Passed?",
      "type": "n8n-nodes-base.if",
      "position": [
        -1648,
        800
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "boolean": [
            {
              "value1": "={{$json.valid}}",
              "operation": "isTrue"
            }
          ]
        }
      },
      "typeVersion": 2
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "6616163d-9bca-4b78-890e-c4917fdb5c2e",
  "connections": {
    "Create User": {
      "main": [
        [
          {
            "node": "API Success Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack Notify": {
      "main": [
        [
          {
            "node": "Telegram Notify",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Customer API1": {
      "main": [
        [
          {
            "node": "Validate & Clean Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "API User Exists": {
      "main": [
        [
          {
            "node": "Slack Notify",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Existing User": {
      "main": [
        [
          {
            "node": "User Already Exists?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "API Success Response": {
      "main": [
        [
          {
            "node": "Send Notifiaction to User",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "API Validation Error": {
      "main": [
        [
          {
            "node": "Slack Notify",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "User Already Exists?": {
      "main": [
        [
          {
            "node": "API User Exists",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Create User",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Validation Passed?": {
      "main": [
        [
          {
            "node": "Check Existing User",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "API Validation Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate & Clean Data": {
      "main": [
        [
          {
            "node": "Is Validation Passed?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Notifiaction to User": {
      "main": [
        [
          {
            "node": "Slack Notify",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

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.

Pro

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

About this workflow

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 teams and customers informed through automated notifications.

Source: https://n8n.io/workflows/12366/ — 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

This workflow is an AI-powered style look transfer and quality control pipeline designed for VFX and editorial production. It transforms a new shot brief and a hero reference image into multiple style

HTTP Request, Slack, Gmail +3
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

This workflow is an AI-assisted clean plate and object removal pipeline built for modern VFX production environments. It transforms a single plate image and removal brief into multiple high-quality cl

HTTP Request, Google Drive, Slack +3
Slack & Telegram

This workflow is an AI-powered roto matte generation and first-pass compositing pipeline designed for VFX production. It transforms structured roto requests into multiple high-precision matte passes u

HTTP Request, Slack, Error Trigger +4
Slack & Telegram

This n8n workflow automates task creation and scheduled reminders for users via a Telegram bot, ensuring timely notifications across multiple channels like email and Slack. It streamlines task managem

Postgres, Email Send, Slack +1