This workflow corresponds to n8n.io template #15238 — we link there as the canonical source.
This workflow follows the Gmail → Google Sheets 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 →
{
"id": "gDLUu13ouQw6hhsF",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Promo Code Expiry Alert System using Webhook, Google Sheets, Gmail & Slack",
"tags": [],
"nodes": [
{
"id": "8b5a7a7b-fec4-48c0-8dfc-75f2db56df2f",
"name": "Receive Promo Request",
"type": "n8n-nodes-base.webhook",
"position": [
-656,
-64
],
"parameters": {
"path": "27923033-a20e-4fc3-8bda-5308f6661a01",
"options": {},
"httpMethod": "POST"
},
"typeVersion": 2.1
},
{
"id": "868d15bc-d75e-45af-9657-6b1cc40bbdaf",
"name": "Normalize Promo Data",
"type": "n8n-nodes-base.set",
"position": [
-352,
-64
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "66113943-5c51-4825-acd6-f90fb1c2ad83",
"name": "body.code",
"type": "string",
"value": "={{ $json.body.code }}"
},
{
"id": "87925321-8d42-40ca-ae04-05d915598b4b",
"name": "body.discount_type",
"type": "string",
"value": "={{ $json.body.discount_type }}"
},
{
"id": "5141b5e6-1c1e-48d6-87c8-dbf7c53e8295",
"name": "body.value",
"type": "number",
"value": "={{ $json.body.value }}"
},
{
"id": "b7de7784-7564-440e-96ae-2d5f620c3573",
"name": "body.expiry",
"type": "string",
"value": "={{ $json.body.expiry }}"
},
{
"id": "d56b63af-b89d-40b1-8e7d-f574394dc4aa",
"name": "body.usage_limit",
"type": "number",
"value": "={{ $json.body.usage_limit }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "b744deba-370b-4cd4-a3c2-89011a66e427",
"name": "Expiry Is Valid",
"type": "n8n-nodes-base.if",
"position": [
64,
-64
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "1cba2ed6-e3c2-48da-bf85-cb0f47162a1e",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ new Date($json[\"body\"][\"expiry\"]) > new Date() }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "64f64cfa-5098-49ff-b8f7-f75a4874aeb8",
"name": "Send Promo Email",
"type": "n8n-nodes-base.gmail",
"position": [
288,
-80
],
"parameters": {
"sendTo": "user@example.com",
"message": "=<h2>\ud83c\udf89 New Promo Code Available!</h2> \n<p><b>Code:</b> {{ $('Expiry Is Valid').item.json.body.code }}</p> \n<p><b>Discount:</b> {{ $('Expiry Is Valid').item.json.body.value }}%</p> \n<p><b>Expiry:</b> {{ $('Expiry Is Valid').item.json.body.expiry }}</p>\n<p><b>Usage Limit:</b> {{ $('Expiry Is Valid').item.json.body.usage_limit }}</p>",
"options": {
"appendAttribution": false
},
"subject": "=\ud83c\udf89 New Promo Code: {{ $('Expiry Is Valid').item.json.body.code }}"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "57f812f3-3dc7-4d66-b62e-fc66f6da84f0",
"name": "Save Promo to Sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
528,
-80
],
"parameters": {
"columns": {
"value": {
"Code": "={{ $('Expiry Is Valid').item.json.body.code }}",
"Expiry": "={{ $('Expiry Is Valid').item.json.body.expiry }}",
"Discount": "={{ $('Expiry Is Valid').item.json.body.value }}",
"Usage Limit": "={{ $('Expiry Is Valid').item.json.body.usage_limit }}"
},
"schema": [
{
"id": "Code",
"type": "string",
"display": true,
"required": false,
"displayName": "Code",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Discount",
"type": "string",
"display": true,
"required": false,
"displayName": "Discount",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Expiry",
"type": "string",
"display": true,
"required": false,
"displayName": "Expiry",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Usage Limit",
"type": "string",
"display": true,
"required": false,
"displayName": "Usage Limit",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Created At",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Created At",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "",
"cachedResultName": ""
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1KiQqP-eWsyCKWZa1X07rV0eGhk93TXC30uS9POyNGZQ",
"cachedResultUrl": "",
"cachedResultName": ""
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "005324fd-512c-437f-94b6-f030888b69df",
"name": "Calculate Days Left",
"type": "n8n-nodes-base.set",
"position": [
944,
-80
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "f6d0bdf2-d8bf-4baa-bd81-c507db8df7e2",
"name": "daysLeft",
"type": "string",
"value": "={{ Math.ceil((new Date($json.Expiry) - new Date()) / (1000 * 60 * 60 * 24)) }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "085776b2-4a0a-49f4-84a3-629aac33ec4b",
"name": "Is Urgent (1 Day Left)",
"type": "n8n-nodes-base.if",
"position": [
1152,
-80
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "1755407a-ff14-4a9f-a7a7-e4e68dbfdfe8",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.daysLeft }}",
"rightValue": "1"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "088fdaed-8e99-4756-9735-1d3ca3f4e472",
"name": "Slack Urgent Alert",
"type": "n8n-nodes-base.slack",
"position": [
1872,
-368
],
"parameters": {
"text": "=\ud83d\udea8 URGENT: Promo Expiring Tomorrow! Code: {{ $('Save Promo to Sheet').item.json.Code }} Discount:{{ $('Save Promo to Sheet').item.json.Discount }}% Expiry: {{ $('Save Promo to Sheet').item.json.Expiry }} \u26a1 Only 1 day left!",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "C09S57E2JQ2",
"cachedResultName": "n8n"
},
"otherOptions": {}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.3
},
{
"id": "6b2e20f7-d4f6-4b9d-9a4b-71c190626df1",
"name": "Is Warning (2\u20133 Days Left)",
"type": "n8n-nodes-base.if",
"position": [
1728,
256
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "cdc81cf1-d994-45c3-a4b8-476685b62aeb",
"operator": {
"type": "boolean",
"operation": "equals"
},
"leftValue": "={{ $json.daysLeft > 1 && $json.daysLeft <= 3 }}",
"rightValue": true
}
]
}
},
"typeVersion": 2.2
},
{
"id": "ae3c3d89-517c-4c6e-8c29-c056d5a18ca1",
"name": "Slack Warning Alert",
"type": "n8n-nodes-base.slack",
"position": [
1984,
272
],
"parameters": {
"text": "=\u26a0\ufe0f Promo Expiring Soon Code:{{ $('Save Promo to Sheet').item.json.Code }} Discount:{{ $('Save Promo to Sheet').item.json.Discount }} % Expiry: {{ $('Save Promo to Sheet').item.json.Expiry }} \u23f3 Days Left: {{ $json.daysLeft }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "C09S57E2JQ2",
"cachedResultName": "n8n"
},
"otherOptions": {}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.3
},
{
"id": "279483cf-1853-49cc-81ff-f681e530c25d",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-704,
-240
],
"parameters": {
"color": 7,
"width": 624,
"height": 400,
"content": "## Promo Data Ingestion & Preparation\nThis section captures incoming promo data via webhook and standardizes the payload into a consistent structure. It ensures all required fields like code, discount, expiry and usage limits are properly formatted before moving forward in the workflow for validation and processing."
},
"typeVersion": 1
},
{
"id": "8aaa7edd-b206-4a07-85ba-a9ca8243b4c7",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
16,
-240
],
"parameters": {
"color": 7,
"width": 704,
"height": 400,
"content": "## Promo Validation & Storage\nThis section verifies whether the promo code is still valid based on its expiry date. If valid, it sends a notification email and stores the promo details in a Google Sheet, ensuring data persistence and enabling future tracking and analysis."
},
"typeVersion": 1
},
{
"id": "a4bfad6e-48d0-4208-8fed-76dd333839ab",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
816,
-240
],
"parameters": {
"color": 7,
"width": 656,
"height": 400,
"content": "## Expiry Analysis & Urgency Detection\nThis section calculates the number of days remaining until the promo expires. It then evaluates whether the promo is critically close to expiry, specifically identifying cases where only one day is left, triggering high-priority alert conditions."
},
"typeVersion": 1
},
{
"id": "5ed81672-7fb0-4ba0-ad63-a089ee2c1da6",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1616,
-512
],
"parameters": {
"color": 7,
"width": 688,
"height": 336,
"content": "## Urgent Alert Notification\nThis section handles high-priority alerts by sending an urgent Slack notification when a promo is about to expire within one day. It ensures immediate visibility to the team so they can take quick action before the offer becomes inactive."
},
"typeVersion": 1
},
{
"id": "9422e74b-fc0a-4150-b434-7b63ad3a96c3",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
1632,
96
],
"parameters": {
"color": 7,
"width": 688,
"height": 336,
"content": "## Warning Alert Notification\nThis section evaluates promos that are nearing expiry within two to three days. It sends a warning notification to Slack, helping teams stay informed in advance and take necessary actions before the promo reaches a critical expiration stage."
},
"typeVersion": 1
},
{
"id": "76828cef-1046-4305-9fbe-eb07ef81215f",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1488,
-912
],
"parameters": {
"width": 688,
"height": 704,
"content": "## How workflow workfs \n- The workflow begins when a webhook receives promo data from an external source such as a form, API or application.\n- Incoming data is transformed into a structured format to ensure consistency across all fields like code, discount, expiry and usage limit.\n- A validation check ensures that only non-expired promo codes are processed further in the workflow.\n- Once validated, a notification email is optionally sent and the promo details are stored in a Google Sheet for tracking and record-keeping.\n- The workflow then calculates the number of days remaining until the promo expires using the expiry date.\n- Based on the calculated value, it evaluates urgency conditions through decision nodes.\n- If only one day is left, an urgent Slack alert is triggered to notify the team immediately.\n- If the expiry is within two to three days, a warning Slack notification is sent to provide early awareness.\n- Promos outside these conditions are ignored, ensuring only relevant alerts are delivered.\n\n## Setup Steps\n- Create a new workflow in n8n and add a Webhook node configured to accept POST requests.\n- Add a Set node to normalize incoming data fields such as code, discount type, value, expiry and usage limit.\n- Configure an IF node to validate that the expiry date is greater than the current date.\n- Integrate Gmail (optional) to send email notifications for valid promo entries.\n- Add a Google Sheets node and connect your account to store promo data in a structured sheet.\n- Insert another Set node to calculate remaining days using a JavaScript expression.\n- Add decision nodes (IF) to check for urgency (1 day) and warning (2\u20133 days) conditions.\n- Connect Slack nodes and configure channels for urgent and warning alerts.\n- Test the workflow using sample webhook data and verify outputs in Slack and Google Sheets.\n- Activate the workflow to enable real-time automation and monitoring."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "937cfed7-34db-4bb3-bfae-ae5beae6ebcf",
"connections": {
"Expiry Is Valid": {
"main": [
[
{
"node": "Send Promo Email",
"type": "main",
"index": 0
}
]
]
},
"Send Promo Email": {
"main": [
[
{
"node": "Save Promo to Sheet",
"type": "main",
"index": 0
}
]
]
},
"Calculate Days Left": {
"main": [
[
{
"node": "Is Urgent (1 Day Left)",
"type": "main",
"index": 0
}
]
]
},
"Save Promo to Sheet": {
"main": [
[
{
"node": "Calculate Days Left",
"type": "main",
"index": 0
}
]
]
},
"Normalize Promo Data": {
"main": [
[
{
"node": "Expiry Is Valid",
"type": "main",
"index": 0
}
]
]
},
"Receive Promo Request": {
"main": [
[
{
"node": "Normalize Promo Data",
"type": "main",
"index": 0
}
]
]
},
"Is Urgent (1 Day Left)": {
"main": [
[
{
"node": "Slack Urgent Alert",
"type": "main",
"index": 0
}
],
[
{
"node": "Is Warning (2\u20133 Days Left)",
"type": "main",
"index": 0
}
]
]
},
"Is Warning (2\u20133 Days Left)": {
"main": [
[],
[
{
"node": "Slack Warning Alert",
"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.
gmailOAuth2googleSheetsOAuth2ApislackApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
> Webhook, Google Sheets, Gmail & Slack
Source: https://n8n.io/workflows/15238/ — 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.
Complete Calendly automation that handles confirmations, cancellations and reschedules in a single workflow. WHAT IT DOES:
Who is this for? This template is ideal for event organizers, conference managers, and community teams who need an automated participant management system. Perfect for workshops, conferences, meetups,
Automatically generate, validate, and deliver professional course completion certificates with zero manual work — from webhook request to PDF delivery in seconds.
Streamline and standardize your entire client onboarding process with a single end-to-end automation. 🚀📋 This workflow captures detailed client intake data via webhook, automatically creates a fully s
Human Approval AI Response. Uses httpRequest, slack, gmail, googleSheets. Webhook trigger; 20 nodes.