This workflow corresponds to n8n.io template #15719 — 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": "GE4ttRmIwrgfsKRj",
"name": "mercadopago-bulk-payment-links-template",
"tags": [],
"nodes": [
{
"id": "1a244fc0-a7cd-459d-9a87-e7f709f1887d",
"name": "About this template",
"type": "n8n-nodes-base.stickyNote",
"position": [
-464,
432
],
"parameters": {
"color": 4,
"width": 3200,
"height": 780,
"content": "## Who is this for\n\nBusinesses and freelancers using MercadoPago who need to send payment links to many customers at once \u2014 courses, subscriptions, invoices, or any product billed individually.\n\n## How it works\n\nReads a Google Sheet row by row, generates a unique MercadoPago Checkout Link for each row, writes the link back to the sheet, then delivers it through the channel the customer prefers: **Email** (Gmail), **WhatsApp Business**, or **Telegram**. A single batch can mix delivery methods \u2014 each row picks its own channel.\n\n## How to set up\n\n1. **Create a Google Sheet** with the required columns (see the *Step 1* note below).\n2. Open the **Read Sheet** node and select your document and sheet.\n3. Connect your **MercadoPago API** credential on the *Create Payment Link* node.\n4. Connect your **Google Sheets OAuth** credential on all three Sheets nodes.\n5. Choose your delivery channel(s), connect credentials, and **disable the branches you don't use** (right-click \u2192 Disable).\n6. Click **Execute Workflow**. Re-runs are safe \u2014 rows with an existing link are skipped automatically.\n\n## Requirements\n\n- MercadoPago account with a valid Access Token \u2192 [Get yours here](https://www.mercadopago.com.ar/developers/es/docs/credentials)\n- Google account with Sheets access\n- At least one of: Gmail / WhatsApp Business Cloud / Telegram bot\n\n## How to customize\n\n- Replace **Gmail** with the *Send Email (SMTP)* node for custom mail servers.\n- Replace the **Manual Trigger** with a **Schedule Trigger** to run automatically on a cron.\n- Add an **Error Trigger** branch to get notified on failures.\n\n---\n\n> \u26a0\ufe0f **Community node notice:** This template uses `@mercadopago/n8n-nodes-mercadopago` and works on **self-hosted n8n only**. It will not run on n8n Cloud unless the node is installed by your instance admin."
},
"typeVersion": 1
},
{
"id": "39fa508f-0660-4e1a-8c0a-5f0929ab5e59",
"name": "Step 1 \u2014 Google Sheet",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1136,
1264
],
"parameters": {
"width": 1092,
"height": 436,
"content": "## Step 1 \u2014 Prepare your Google Sheet\n\nCreate a new sheet and paste these headers into **row 1**:\n\n```\ncustomer_name | customer_email | customer_phone | customer_telegram_chat_id | product_id | product_title | product_description | quantity | unit_price | currency_id | external_reference | channel\n```\n\nLeave these output columns blank \u2014 the workflow fills them:\n\n```\npayment_link | preference_id | link_created_at | status | sent_at | channel_used\n```\n\n**Required per row:** `product_title`, `quantity` (\u2265 1), `unit_price` (> 0), a unique `external_reference` (max 64 chars), `channel` (`email` / `whatsapp` / `telegram`), and the contact field matching the channel.\n\nThen open **Read Sheet** and select your document and sheet tab."
},
"typeVersion": 1
},
{
"id": "45eaddc6-4fe4-4f75-9dbe-735b35fb0930",
"name": "Step 2 \u2014 Generate link",
"type": "n8n-nodes-base.stickyNote",
"position": [
32,
1280
],
"parameters": {
"width": 728,
"height": 236,
"content": "## Step 2 \u2014 Generate and save the payment link\n\nFor each row that doesn't yet have a `payment_link`, the **Create Payment Link** node calls MercadoPago's Checkout Preferences API and returns a unique `init_point` URL.\n\nThe link is immediately written back to the sheet before delivery \u2014 so even if the notification fails, the link is always persisted and can be resent manually."
},
"typeVersion": 1
},
{
"id": "1b0cf5db-88a3-4580-9968-549d553f2240",
"name": "Step 3 \u2014 Route and deliver",
"type": "n8n-nodes-base.stickyNote",
"position": [
864,
1264
],
"parameters": {
"width": 1380,
"height": 280,
"content": "## Step 3 \u2014 Deliver to the customer\n\nThe **Route by channel** node reads the `channel` column of each row and forwards it to the correct branch:\n\n- `email` \u2192 Gmail sends an HTML email with the payment link\n- `whatsapp` \u2192 WhatsApp Business Cloud sends a text message\n- `telegram` \u2192 Telegram bot sends a message\n\nAfter delivery, the sheet is updated with `status = sent`, `sent_at`, and `channel_used`.\n\n**Disable branches you don't need** \u2014 right-click any node \u2192 Disable."
},
"typeVersion": 1
},
{
"id": "d8390986-da6a-4d8a-9423-b202fd9da9c8",
"name": "Schedule \u2014 optional",
"type": "n8n-nodes-base.stickyNote",
"position": [
-464,
1952
],
"parameters": {
"width": 400,
"height": 268,
"content": "## \u23f1 Optional \u2014 Schedule automatic runs\n\n1. Delete the **Manual Trigger** node.\n2. Add a **Schedule Trigger** in its place and connect it to **Read Sheet**.\n3. Set the interval (e.g. every hour, every morning).\n\nThe *Skip already processed* filter ensures re-runs never regenerate existing links."
},
"typeVersion": 1
},
{
"id": "82e8cfa4-83ef-4dd9-b3a2-af0ca9b0aff5",
"name": "When clicking 'Execute Workflow'",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-464,
1760
],
"parameters": {},
"typeVersion": 1
},
{
"id": "081224c1-0c00-4327-b55b-40b7edd1ea84",
"name": "Read Sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
-224,
1760
],
"parameters": {
"sheetName": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": "Select your Google Sheet"
}
},
"typeVersion": 4.5
},
{
"id": "0acb70da-43da-47fc-897f-8caf355cde69",
"name": "Skip already processed",
"type": "n8n-nodes-base.if",
"position": [
16,
1760
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "cond-link-empty",
"operator": {
"type": "string",
"operation": "empty",
"singleValue": true
},
"leftValue": "={{ $json.payment_link }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "8f0ec4e8-45cd-4a46-b942-594e675f378b",
"name": "Create Payment Link",
"type": "@mercadopago/n8n-nodes-mercadopago.mercadoPago",
"position": [
256,
1760
],
"parameters": {
"items": {
"itemsValues": [
{
"id": "={{ $json.product_id }}",
"title": "={{ $json.product_title }}",
"quantity": "={{ Number($json.quantity) }}",
"unit_price": "={{ Number($json.unit_price) }}",
"currency_id": "={{ $json.currency_id }}",
"description": "={{ $json.product_description }}"
}
]
},
"additionalFields": {
"external_reference": "={{ $json.external_reference }}"
}
},
"typeVersion": 1
},
{
"id": "103b739e-ddc8-4f0d-bdf7-886cf2cfecdd",
"name": "Update Sheet \u2014 Link",
"type": "n8n-nodes-base.googleSheets",
"position": [
496,
1760
],
"parameters": {
"columns": {
"value": {
"payment_link": "={{ $json.init_point }}",
"preference_id": "={{ $json.id }}",
"link_created_at": "={{ $now.toISO() }}",
"external_reference": "={{ $('Skip already processed').item.json.external_reference }}"
},
"schema": [],
"mappingMode": "defineBelow",
"matchingColumns": [
"external_reference"
]
},
"options": {},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "id",
"value": "={{ $('Read Sheet').params.sheetName.value }}"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Read Sheet').params.documentId.value }}"
}
},
"typeVersion": 4.5
},
{
"id": "9c32bb30-32c3-4ab2-8435-443b57ee399a",
"name": "Route by channel",
"type": "n8n-nodes-base.switch",
"position": [
736,
1760
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "email",
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": false,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "rule-email",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $('Skip already processed').item.json.channel }}",
"rightValue": "email"
}
]
},
"renameOutput": true
},
{
"outputKey": "whatsapp",
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": false,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "rule-whatsapp",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $('Skip already processed').item.json.channel }}",
"rightValue": "whatsapp"
}
]
},
"renameOutput": true
},
{
"outputKey": "telegram",
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": false,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "rule-telegram",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $('Skip already processed').item.json.channel }}",
"rightValue": "telegram"
}
]
},
"renameOutput": true
}
]
},
"options": {}
},
"typeVersion": 3.2
},
{
"id": "8a96199d-b702-4412-9dcf-49a87c0fb77a",
"name": "Email \u2014 setup",
"type": "n8n-nodes-base.stickyNote",
"position": [
1488,
1568
],
"parameters": {
"width": 660,
"height": 240,
"content": "## \ud83d\udce7 Email \u2014 setup\n\n1. In n8n go to **Credentials \u2192 New \u2192 Gmail OAuth2 API** and follow the OAuth flow.\n2. Assign the credential to the **Send Email** node.\n3. Make sure each row has `customer_email` filled and `channel = email`.\n\nTo use SMTP instead, replace the Gmail node with **Send Email (SMTP)** and configure host / port / user / password."
},
"typeVersion": 1
},
{
"id": "90af133f-5f08-4f6c-8862-41328f0fb9a6",
"name": "Send Email",
"type": "n8n-nodes-base.gmail",
"position": [
976,
1632
],
"parameters": {
"sendTo": "={{ $('Skip already processed').item.json.customer_email }}",
"message": "=<p>Hi <b>{{ $('Skip already processed').item.json.customer_name }}</b>,</p>\n<p>Your secure payment link for <b>{{ $('Skip already processed').item.json.product_title }}</b> is ready:</p>\n<p><a href=\"{{ $('Update Sheet \u2014 Link').item.json.payment_link }}\">Pay now with MercadoPago \u2192</a></p>\n<p>Amount: <b>{{ $('Skip already processed').item.json.currency_id }} {{ $('Skip already processed').item.json.unit_price }}</b><br>Reference: {{ $('Skip already processed').item.json.external_reference }}</p>\n<p>Thank you!</p>",
"options": {},
"subject": "=Your payment link \u2014 {{ $('Skip already processed').item.json.product_title }}"
},
"typeVersion": 2.1
},
{
"id": "a3b8df88-d6e3-4e9d-987d-7df7fd5dba72",
"name": "WhatsApp \u2014 setup",
"type": "n8n-nodes-base.stickyNote",
"position": [
1488,
1856
],
"parameters": {
"width": 660,
"height": 280,
"content": "## \ud83d\udcf1 WhatsApp \u2014 setup\n\n1. Create a Meta Business app and get your **permanent access token** and **business account ID**: [Meta for Developers guide](https://developers.facebook.com/docs/whatsapp/cloud-api/get-started)\n2. In n8n go to **Credentials \u2192 New \u2192 WhatsApp Business Cloud API** and paste both values.\n3. Assign the credential to **Send WhatsApp** and select your phone number from the dropdown.\n4. In sandbox: add the recipient to your test numbers. In production: make sure a 24h customer window is open or use an approved template.\n\nRows must have `customer_phone` as digits only with country code \u2014 no `+` prefix (e.g. `5491123456789`)."
},
"typeVersion": 1
},
{
"id": "a90c4b8c-02fe-435d-b6ee-55d48b1e5f7c",
"name": "Send WhatsApp",
"type": "n8n-nodes-base.whatsApp",
"position": [
976,
2032
],
"parameters": {
"textBody": "=Hi {{ $('Skip already processed').item.json.customer_name }}, your payment link for {{ $('Skip already processed').item.json.product_title }}:\n\n{{ $('Update Sheet \u2014 Link').item.json.payment_link }}\n\nAmount: {{ $('Skip already processed').item.json.currency_id }} {{ $('Skip already processed').item.json.unit_price }}\nRef: {{ $('Skip already processed').item.json.external_reference }}",
"operation": "send",
"phoneNumberId": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultName": "Select your phone number"
},
"additionalFields": {
"previewUrl": true
},
"recipientPhoneNumber": "={{ $('Skip already processed').item.json.customer_phone.replace(/^\\+/, '') }}"
},
"typeVersion": 1
},
{
"id": "a8714432-f9d8-431d-a004-bbf3c4353d75",
"name": "Telegram \u2014 setup",
"type": "n8n-nodes-base.stickyNote",
"position": [
1488,
2304
],
"parameters": {
"width": 660,
"height": 260,
"content": "## \ud83d\udce8 Telegram \u2014 setup\n\n1. Open Telegram and talk to **@BotFather** \u2192 `/newbot` \u2192 copy the bot token.\n2. In n8n go to **Credentials \u2192 New \u2192 Telegram API** and paste the token.\n3. Each customer must **send `/start`** to your bot at least once before they can receive messages.\n4. Use **@userinfobot** to get each customer's numeric `chat_id`.\n5. Fill the `customer_telegram_chat_id` column in your sheet.\n\nRows must have `customer_telegram_chat_id` filled and `channel = telegram`."
},
"typeVersion": 1
},
{
"id": "d4bcc843-3295-4dc4-8918-d215c70d11e5",
"name": "Send Telegram",
"type": "n8n-nodes-base.telegram",
"position": [
976,
2432
],
"parameters": {
"text": "=Hi {{ $('Skip already processed').item.json.customer_name }}, your payment link for {{ $('Skip already processed').item.json.product_title }}:\n\n{{ $('Update Sheet \u2014 Link').item.json.payment_link }}\n\nAmount: {{ $('Skip already processed').item.json.currency_id }} {{ $('Skip already processed').item.json.unit_price }}\nRef: {{ $('Skip already processed').item.json.external_reference }}",
"chatId": "={{ $('Skip already processed').item.json.customer_telegram_chat_id }}",
"additionalFields": {}
},
"typeVersion": 1.2
},
{
"id": "efa6ac59-9810-4fc5-8aba-61807b47c4b6",
"name": "Mark Sent \u2014 Email",
"type": "n8n-nodes-base.googleSheets",
"position": [
1216,
1632
],
"parameters": {
"columns": {
"value": {
"status": "sent",
"sent_at": "={{ $now.toISO() }}",
"channel_used": "email",
"external_reference": "={{ $('Skip already processed').item.json.external_reference }}"
},
"schema": [],
"mappingMode": "defineBelow",
"matchingColumns": [
"external_reference"
]
},
"options": {},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "id",
"value": "={{ $('Read Sheet').params.sheetName.value }}"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Read Sheet').params.documentId.value }}"
}
},
"typeVersion": 4.5
},
{
"id": "894daaef-99f0-42d5-b91d-f7a6a0750519",
"name": "Mark Sent \u2014 WhatsApp",
"type": "n8n-nodes-base.googleSheets",
"position": [
1216,
2032
],
"parameters": {
"columns": {
"value": {
"status": "sent",
"sent_at": "={{ $now.toISO() }}",
"channel_used": "whatsapp",
"external_reference": "={{ $('Skip already processed').item.json.external_reference }}"
},
"schema": [],
"mappingMode": "defineBelow",
"matchingColumns": [
"external_reference"
]
},
"options": {},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "id",
"value": "={{ $('Read Sheet').params.sheetName.value }}"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Read Sheet').params.documentId.value }}"
}
},
"typeVersion": 4.5
},
{
"id": "57279ec9-bed5-447c-838c-addcc5d2b797",
"name": "Mark Sent \u2014 Telegram",
"type": "n8n-nodes-base.googleSheets",
"position": [
1216,
2432
],
"parameters": {
"columns": {
"value": {
"status": "sent",
"sent_at": "={{ $now.toISO() }}",
"channel_used": "telegram",
"external_reference": "={{ $('Skip already processed').item.json.external_reference }}"
},
"schema": [],
"mappingMode": "defineBelow",
"matchingColumns": [
"external_reference"
]
},
"options": {},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "id",
"value": "={{ $('Read Sheet').params.sheetName.value }}"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Read Sheet').params.documentId.value }}"
}
},
"typeVersion": 4.5
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "24522ecf-218b-4862-be52-9aa8d39ce28f",
"connections": {
"Read Sheet": {
"main": [
[
{
"node": "Skip already processed",
"type": "main",
"index": 0
}
]
]
},
"Send Email": {
"main": [
[
{
"node": "Mark Sent \u2014 Email",
"type": "main",
"index": 0
}
]
]
},
"Send Telegram": {
"main": [
[
{
"node": "Mark Sent \u2014 Telegram",
"type": "main",
"index": 0
}
]
]
},
"Send WhatsApp": {
"main": [
[
{
"node": "Mark Sent \u2014 WhatsApp",
"type": "main",
"index": 0
}
]
]
},
"Route by channel": {
"main": [
[
{
"node": "Send Email",
"type": "main",
"index": 0
}
],
[
{
"node": "Send WhatsApp",
"type": "main",
"index": 0
}
],
[
{
"node": "Send Telegram",
"type": "main",
"index": 0
}
]
]
},
"Create Payment Link": {
"main": [
[
{
"node": "Update Sheet \u2014 Link",
"type": "main",
"index": 0
}
]
]
},
"Update Sheet \u2014 Link": {
"main": [
[
{
"node": "Route by channel",
"type": "main",
"index": 0
}
]
]
},
"Skip already processed": {
"main": [
[
{
"node": "Create Payment Link",
"type": "main",
"index": 0
}
]
]
},
"When clicking 'Execute Workflow'": {
"main": [
[
{
"node": "Read Sheet",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
HOW IT WORKS
Source: https://n8n.io/workflows/15719/ — 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.
Automates LinkedIn job searches across multiple countries and categories, filters results with AI, stores data in Google Sheets, and sends weekly Telegram notifications. Perfect for professionals seek
Get notified when a customer completes a Stripe checkout — including all products they purchased in a single checkout session.
Error Monitoring!. Uses errorTrigger, gmail, whatsApp, slack. Event-driven trigger; 8 nodes.
The aim of the YouTube Video Summarizer Workflow is to automate the process of summarizing or extracting transcripts from YouTube videos with the help of Gemini AI, while optionally storing results an
Deal-Finder. Uses executeWorkflowTrigger, googleSheets, perplexity, httpRequest. Event-driven trigger; 49 nodes.