This workflow corresponds to n8n.io template #13928 — we link there as the canonical source.
This workflow follows the Google Sheets → HTTP Request 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 →
{
"meta": {
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "b2b02fc9-ea89-4d96-893f-f9e530876ea8",
"name": "\ud83d\udccb Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
-9264,
-336
],
"parameters": {
"width": 620,
"height": 584,
"content": "## \ud83c\udfac 360\u00b0 Product Video Generator\n\nTurn a single product photo into a cinematic 360\u00b0 video using Google Veo 3 \u2014 delivered straight to Telegram.\n\n## How it works\n1. User sends a product photo to your Telegram bot\n2. The workflow authenticates with Google Cloud using a Service Account stored in Google Sheets\n3. The image is sent to Vertex AI (Veo 3) with a 360\u00b0 orbit camera prompt\n4. The workflow polls every 2 minutes until the video is ready (up to 10 min)\n5. The finished video is sent back to the user in Telegram\n\n## Setup steps\n1. Create a Telegram bot via @BotFather and add the credentials in n8n\n2. Enable the **Vertex AI API** in your Google Cloud project and request Veo 3 preview access\n3. Create a Service Account with `roles/aiplatform.user` and download the JSON key\n4. Paste the key fields into your Google Sheet \u2014 columns needed: `client_email`, `private_key`, `project_id`, `scope`\n5. Update the **1. Get Service Account Details** node with your Sheet ID\n6. Connect your Google and Telegram credentials, then activate the workflow"
},
"typeVersion": 1
},
{
"id": "70a23ef7-b728-4388-b4e4-afe39ef8b657",
"name": "Group 1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-8528,
-208
],
"parameters": {
"color": 7,
"width": 428,
"height": 348,
"content": "## Receive & Validate\nListens for Telegram messages and checks that a photo was sent and is at least 480px. Rejects documents or text-only messages and replies with a clear error."
},
"typeVersion": 1
},
{
"id": "0cf4efdf-44ac-4673-a88c-cb25452ca036",
"name": "Group 2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-8064,
-176
],
"parameters": {
"color": 7,
"width": 840,
"height": 332,
"content": "## Google Cloud Auth\nReads Service Account credentials from Google Sheets, signs a JWT locally, and exchanges it for a short-lived OAuth access token. Runs fresh on every request."
},
"typeVersion": 1
},
{
"id": "db7f81ba-92c6-4677-a921-93e879d0771b",
"name": "Group 3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-7168,
-288
],
"parameters": {
"color": 7,
"width": 840,
"height": 480,
"content": "## Download & Convert\nDownloads the highest-resolution version of the photo from Telegram and converts it to Base64. Any conversion failure is caught and reported back to the user."
},
"typeVersion": 1
},
{
"id": "a8977c41-5e0f-4e02-91ce-3fef4a6ca60b",
"name": "Group 4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-6272,
-384
],
"parameters": {
"color": 7,
"width": 620,
"height": 508,
"content": "## Submit to Veo 3\nBuilds the API payload with a cinematic 360\u00b0 orbit prompt and submits a long-running job to Vertex AI Veo 3. Gets back an operation ID used for polling."
},
"typeVersion": 1
},
{
"id": "19948635-28b8-4c13-8ede-1a7bee91c42e",
"name": "Group 5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-5616,
-528
],
"parameters": {
"color": 7,
"width": 1108,
"height": 872,
"content": "## Poll for Result\nChecks every 2 minutes whether the video is ready. Times out after 40 attempts (~10 min) and notifies the user with a friendly error if generation takes too long."
},
"typeVersion": 1
},
{
"id": "be8ea122-84d1-4264-a646-be1010aa4bb2",
"name": "Group 6",
"type": "n8n-nodes-base.stickyNote",
"position": [
-4496,
-432
],
"parameters": {
"color": 7,
"width": 660,
"height": 276,
"content": "## Deliver Video\nConverts the Base64 video bytes to a file and sends it directly to the user in Telegram."
},
"typeVersion": 1
},
{
"id": "ee81c12f-2c54-441b-90a1-f5482c40b97e",
"name": "Wait 2 Minutes",
"type": "n8n-nodes-base.wait",
"position": [
-5552,
-240
],
"parameters": {
"unit": "minutes",
"amount": 2
},
"typeVersion": 1.1
},
{
"id": "99b5b684-d316-4c79-9f58-d190be2e85df",
"name": "Send Timeout Error",
"type": "n8n-nodes-base.telegram",
"position": [
-4784,
144
],
"parameters": {
"text": "=\u274c Video generation failed after {{ $json.poll_count }} attempts.\n\nPlease try again with a different image or contact support.",
"chatId": "={{ $json.chatId }}",
"additionalFields": {
"reply_to_message_id": "={{ $json.messageId }}"
}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.1
},
{
"id": "e545feb6-efa8-4bf0-9bf0-0bb5d3fae486",
"name": "Check Timeout",
"type": "n8n-nodes-base.if",
"position": [
-5184,
32
],
"parameters": {
"options": {},
"conditions": {
"string": [
{
"value1": "={{ $json.status }}",
"value2": "timeout"
}
]
}
},
"typeVersion": 2
},
{
"id": "7d7f7f2c-0e25-473b-bf87-7339957295d7",
"name": "Download Image",
"type": "n8n-nodes-base.telegram",
"position": [
-6896,
-160
],
"parameters": {
"fileId": "={{ $json.result.reply_to_message.photo[3].file_id }}",
"resource": "file",
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.1
},
{
"id": "83d5cd34-c7a8-454d-bea7-22854b9fea78",
"name": "Telegram Trigger",
"type": "n8n-nodes-base.telegramTrigger",
"position": [
-8480,
-48
],
"parameters": {
"updates": [
"message"
],
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "1ed72edc-642e-4d2b-a33a-39eac6401c2c",
"name": "2. Validate Input",
"type": "n8n-nodes-base.code",
"position": [
-8256,
-48
],
"parameters": {
"jsCode": "const inputData = $input.item.json;\nconst message = inputData.message;\nconst output = { ...inputData };\n\nif (!message) {\n output.error = true;\n output.errorMessage = '\u274c No message found.';\n return [{ json: output }];\n}\n\nif (!message.photo || !Array.isArray(message.photo) || message.photo.length === 0) {\n output.error = true;\n output.errorMessage = '\u274c No photo found. Please send an image of your product.';\n return [{ json: output }];\n}\n\nconst photo = message.photo[message.photo.length - 1];\nif (Math.min(photo.width, photo.height) < 480) {\n output.error = true;\n output.errorMessage = `\u274c Image too small (${photo.width}x${photo.height}).\\n\\nMinimum: 480px \u2014 Recommended: 1024x1024 or larger`;\n return [{ json: output }];\n}\n\noutput.chatId = message.chat?.id;\noutput.messageId = message.message_id;\noutput.caption = message.caption || '';\noutput.file_id = photo.file_id;\noutput.error = false;\n\nreturn [{ json: output }];"
},
"typeVersion": 2
},
{
"id": "1f36ad53-6c90-471e-b8a3-6686b96de5de",
"name": "Check Auth Token Valid",
"type": "n8n-nodes-base.if",
"position": [
-7344,
-48
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "9e617a27-7ee6-44ba-a7cb-02b3e5738b08",
"operator": {
"type": "boolean",
"operation": "false",
"singleValue": true
},
"leftValue": "={{ $json.access_token.isEmpty() }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2
},
{
"id": "3153c612-b11e-40ad-a24c-06b48b24f2eb",
"name": "Send Validation Error",
"type": "n8n-nodes-base.telegram",
"position": [
-7120,
32
],
"parameters": {
"text": "={{ $json.errorMessage }}",
"chatId": "={{ $json.chatId }}",
"additionalFields": {
"reply_to_message_id": "={{ $json.messageId }}"
}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.1
},
{
"id": "526add44-409e-41e6-b327-05c91a427708",
"name": "Send Processing Message",
"type": "n8n-nodes-base.telegram",
"position": [
-7120,
-160
],
"parameters": {
"text": "\ud83c\udfac Creating your 360\u00b0 product video...\n\n\u23f1\ufe0f This takes around 3\u20134 minutes\n\ud83d\udd04 Processing with Google Veo 3...",
"chatId": "={{ $json.chatId }}",
"additionalFields": {
"reply_to_message_id": "={{ $json.messageId }}"
}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.1
},
{
"id": "238d0cb6-789f-4cbd-b894-38525e8b18e8",
"name": "Convert Image to Base64",
"type": "n8n-nodes-base.code",
"position": [
-6672,
-160
],
"parameters": {
"jsCode": "const items = $input.all();\nconst results = [];\n\nfor (const item of items) {\n try {\n if (!item.binary || !item.binary.data) {\n throw new Error('No binary data found');\n }\n\n let imageBuffer;\n let mimeType = 'image/jpeg';\n\n if (item.binary.data.data) {\n imageBuffer = Buffer.from(item.binary.data.data, 'base64');\n mimeType = item.binary.data.mimeType || mimeType;\n } else if (Buffer.isBuffer(item.binary.data)) {\n imageBuffer = item.binary.data;\n mimeType = item.binary.mimeType || mimeType;\n } else if (typeof item.binary.data === 'string') {\n imageBuffer = Buffer.from(item.binary.data, 'base64');\n mimeType = item.binary.mimeType || mimeType;\n } else {\n const binaryKeys = Object.keys(item.binary).filter(k =>\n !['mimeType', 'fileType', 'fileName', 'fileExtension'].includes(k)\n );\n if (binaryKeys.length > 0) {\n const binaryData = item.binary[binaryKeys[0]];\n imageBuffer = Buffer.isBuffer(binaryData) ? binaryData\n : binaryData.data ? Buffer.from(binaryData.data)\n : Buffer.from(binaryData);\n mimeType = item.binary.mimeType || mimeType;\n } else {\n throw new Error('Could not locate binary data');\n }\n }\n\n if (!imageBuffer || imageBuffer.length === 0) throw new Error('Empty image buffer');\n\n results.push({\n json: {\n ...item.json,\n imageBase64: imageBuffer.toString('base64'),\n imageMimeType: mimeType,\n imageSize: imageBuffer.length,\n conversionStatus: 'success'\n }\n });\n\n } catch (error) {\n results.push({\n json: {\n ...item.json,\n error: true,\n conversionStatus: 'failed',\n conversionError: error.message\n }\n });\n }\n}\n\nreturn results;"
},
"typeVersion": 2
},
{
"id": "5696a1e9-ef12-4d7e-bc24-5cfcec661fec",
"name": "Conversion OK?",
"type": "n8n-nodes-base.if",
"position": [
-6448,
-160
],
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $json.conversionStatus }}",
"value2": "success"
}
]
}
},
"typeVersion": 1
},
{
"id": "f4ac9dea-d831-413b-9ecc-1181a8ee0185",
"name": "Send Conversion Error",
"type": "n8n-nodes-base.telegram",
"position": [
-6016,
-48
],
"parameters": {
"text": "=\u274c Failed to process your image: {{ $json.conversionError }}\n\nPlease try sending the photo again.",
"chatId": "={{ $json.chatId }}",
"additionalFields": {
"reply_to_message_id": "={{ $json.messageId }}"
}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.1
},
{
"id": "06685eae-cf1a-4469-84de-f2d06079121f",
"name": "5. Prepare Veo Request",
"type": "n8n-nodes-base.code",
"position": [
-6224,
-240
],
"parameters": {
"jsCode": "const item = $input.item.json;\n\nconst basePrompt = `Create a professional 360-degree product showcase video. The camera smoothly orbits the product in a full 360-degree rotation, maintaining consistent framing. Use studio lighting with a clean white background. The product stays centered throughout. Smooth, cinematic movement \u2014 no jitter or cuts.`;\n\nconst userCaption = item.caption || '';\nconst finalPrompt = userCaption.trim().length > 0\n ? basePrompt + ` Product context: ${userCaption.trim()}`\n : basePrompt;\n\nconst apiPayload = {\n instances: [{\n prompt: finalPrompt,\n image: {\n bytesBase64Encoded: item.imageBase64,\n mimeType: item.imageMimeType\n }\n }],\n parameters: {\n aspectRatio: '16:9',\n sampleCount: 1,\n durationSeconds: 8,\n personGeneration: 'allow_all',\n addWatermark: true,\n includeRaiReason: true,\n generateAudio: true\n }\n};\n\nreturn {\n api_payload: JSON.stringify(apiPayload),\n chatId: item.chatId,\n messageId: item.messageId,\n caption: item.caption\n};"
},
"typeVersion": 2
},
{
"id": "010b2b1c-fdde-454d-851d-e8d1aa5b7bfb",
"name": "6. Call Vertex AI Veo 3",
"type": "n8n-nodes-base.httpRequest",
"position": [
-6000,
-240
],
"parameters": {
"url": "=https://us-central1-aiplatform.googleapis.com/v1/projects/{{ $('3. Get Access Token').item.json.project_id }}/locations/us-central1/publishers/google/models/veo-3.0-generate-preview:predictLongRunning",
"method": "POST",
"options": {},
"jsonBody": "={{ $json.api_payload }}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "=Bearer {{ $('3. Get Access Token').item.json.access_token }}"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "1343ec01-9309-40c6-b287-df7d3af9941b",
"name": "Extract Operation Name",
"type": "n8n-nodes-base.code",
"position": [
-5776,
-240
],
"parameters": {
"jsCode": "const response = $input.item.json;\n\nif (response.name) {\n return [{\n json: {\n operation_name: response.name,\n status: 'polling',\n poll_count: 0,\n chatId: response.chatId,\n messageId: response.messageId,\n caption: response.caption\n }\n }];\n} else {\n return [{\n json: {\n ...response,\n error: 'No operation name returned from Vertex AI',\n status: 'failed'\n }\n }];\n}"
},
"typeVersion": 2
},
{
"id": "13ef8fde-d595-4fec-b48b-66e479cdd700",
"name": "Poll Video Status",
"type": "n8n-nodes-base.httpRequest",
"position": [
-5328,
-320
],
"parameters": {
"url": "=https://us-central1-aiplatform.googleapis.com/v1/projects/{{ $('3. Get Access Token').item.json.project_id }}/locations/us-central1/publishers/google/models/veo-3.0-generate-preview:fetchPredictOperation",
"method": "POST",
"options": {},
"jsonBody": "={\n \"operationName\": \"{{ $json.operation_name }}\"\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json"
},
"typeVersion": 4.2
},
{
"id": "041a8843-5462-4ff0-ae89-d7985463618a",
"name": "Is Video Ready?",
"type": "n8n-nodes-base.if",
"position": [
-5104,
-320
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "5b5ff11d-4bb6-4955-9d99-b1e9e27666ea",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.done }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2
},
{
"id": "4127d7d4-340d-4228-9ace-b287b6bb0526",
"name": "Convert Video to File",
"type": "n8n-nodes-base.convertToFile",
"position": [
-4880,
-416
],
"parameters": {
"options": {},
"operation": "toBinary",
"sourceProperty": "response.videos[0].bytesBase64Encoded"
},
"typeVersion": 1.1
},
{
"id": "82f5dcb0-62e4-43b7-9148-7bce5074361e",
"name": "Continue Polling",
"type": "n8n-nodes-base.code",
"position": [
-4880,
-224
],
"parameters": {
"jsCode": "const item = $input.item.json;\nconst pollCount = (item.poll_count || 0) + 1;\n\nif (pollCount > 40) {\n return {\n error: 'Video generation timeout',\n status: 'timeout',\n poll_count: pollCount,\n chatId: item.chatId,\n messageId: item.messageId\n };\n}\n\nreturn {\n operation_name: item.name || item.operation_name,\n poll_count: pollCount,\n status: 'polling',\n chatId: item.chatId,\n messageId: item.messageId,\n caption: item.caption\n};"
},
"typeVersion": 2
},
{
"id": "6b7f1886-adda-4211-a4ff-a0b16e4bb131",
"name": "Send Video to User",
"type": "n8n-nodes-base.telegram",
"position": [
-4224,
-320
],
"parameters": {
"chatId": "={{ $('Telegram Trigger').item.json.message.chat.id }}",
"operation": "sendVideo",
"binaryData": true,
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.1
},
{
"id": "8fb2a208-a649-4182-83d1-87d715e946a2",
"name": "2. Build JWT from Sheet",
"type": "n8n-nodes-base.code",
"position": [
-7792,
-48
],
"parameters": {
"jsCode": "const item = $input.item.json;\nconst crypto = require('crypto');\n\nconst SERVICE_ACCOUNT_EMAIL = item.client_email;\nconst PRIVATE_KEY = item.private_key.replace(/\\\\n/g, '\\n');\nconst PROJECT_ID = item.project_id;\nconst SCOPE = item.scope || 'https://www.googleapis.com/auth/cloud-platform';\nconst TOKEN_URI = 'https://oauth2.googleapis.com/token';\nconst now = Math.floor(Date.now() / 1000);\n\nfunction base64url(input) {\n const buf = Buffer.isBuffer(input) ? input : Buffer.from(JSON.stringify(input));\n return buf.toString('base64').replace(/=/g, '').replace(/\\+/g, '-').replace(/\\//g, '_');\n}\n\ntry {\n const header = base64url({ alg: 'RS256', typ: 'JWT' });\n const claims = base64url({ iss: SERVICE_ACCOUNT_EMAIL, scope: SCOPE, aud: TOKEN_URI, iat: now, exp: now + 3600 });\n const signingInput = `${header}.${claims}`;\n const sign = crypto.createSign('RSA-SHA256');\n sign.update(signingInput);\n sign.end();\n const signature = sign.sign(PRIVATE_KEY).toString('base64').replace(/=/g, '').replace(/\\+/g, '-').replace(/\\//g, '_');\n\n return [{ json: { ...item, jwt: `${signingInput}.${signature}`, project_id: PROJECT_ID, client_email: SERVICE_ACCOUNT_EMAIL, error: false } }];\n} catch (err) {\n return [{ json: { ...item, error: true, errorMessage: `\u274c JWT Build Failed: ${err.message}` } }];\n}"
},
"typeVersion": 2
},
{
"id": "faa1f906-1f3a-4b08-8fc1-fe117ea31a51",
"name": "3. Get Access Token",
"type": "n8n-nodes-base.httpRequest",
"position": [
-7568,
-48
],
"parameters": {
"url": "https://oauth2.googleapis.com/token",
"method": "POST",
"options": {},
"sendBody": true,
"contentType": "form-urlencoded",
"bodyParameters": {
"parameters": [
{
"name": "grant_type",
"value": "urn:ietf:params:oauth:grant-type:jwt-bearer"
},
{
"name": "assertion",
"value": "={{ $json.jwt }}"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "563b037e-91b8-4348-a994-abfa27fba9ec",
"name": "1. Get Service Account Details",
"type": "n8n-nodes-base.googleSheets",
"position": [
-8016,
-48
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID_HERE/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "YOUR_GOOGLE_SHEET_ID_HERE",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID_HERE/edit",
"cachedResultName": "Service Account Credentials"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
}
],
"connections": {
"Check Timeout": {
"main": [
[
{
"node": "Send Timeout Error",
"type": "main",
"index": 0
}
],
[
{
"node": "Wait 2 Minutes",
"type": "main",
"index": 0
}
]
]
},
"Conversion OK?": {
"main": [
[
{
"node": "5. Prepare Veo Request",
"type": "main",
"index": 0
}
],
[
{
"node": "Send Conversion Error",
"type": "main",
"index": 0
}
]
]
},
"Download Image": {
"main": [
[
{
"node": "Convert Image to Base64",
"type": "main",
"index": 0
}
]
]
},
"Wait 2 Minutes": {
"main": [
[
{
"node": "Poll Video Status",
"type": "main",
"index": 0
}
]
]
},
"Is Video Ready?": {
"main": [
[
{
"node": "Convert Video to File",
"type": "main",
"index": 0
}
],
[
{
"node": "Continue Polling",
"type": "main",
"index": 0
}
]
]
},
"Continue Polling": {
"main": [
[
{
"node": "Check Timeout",
"type": "main",
"index": 0
}
]
]
},
"Telegram Trigger": {
"main": [
[
{
"node": "2. Validate Input",
"type": "main",
"index": 0
}
]
]
},
"2. Validate Input": {
"main": [
[
{
"node": "1. Get Service Account Details",
"type": "main",
"index": 0
}
]
]
},
"Poll Video Status": {
"main": [
[
{
"node": "Is Video Ready?",
"type": "main",
"index": 0
}
]
]
},
"3. Get Access Token": {
"main": [
[
{
"node": "Check Auth Token Valid",
"type": "main",
"index": 0
}
]
]
},
"Convert Video to File": {
"main": [
[
{
"node": "Send Video to User",
"type": "main",
"index": 0
}
]
]
},
"5. Prepare Veo Request": {
"main": [
[
{
"node": "6. Call Vertex AI Veo 3",
"type": "main",
"index": 0
}
]
]
},
"Check Auth Token Valid": {
"main": [
[
{
"node": "Send Processing Message",
"type": "main",
"index": 0
}
],
[
{
"node": "Send Validation Error",
"type": "main",
"index": 0
}
]
]
},
"Extract Operation Name": {
"main": [
[
{
"node": "Wait 2 Minutes",
"type": "main",
"index": 0
}
]
]
},
"2. Build JWT from Sheet": {
"main": [
[
{
"node": "3. Get Access Token",
"type": "main",
"index": 0
}
]
]
},
"6. Call Vertex AI Veo 3": {
"main": [
[
{
"node": "Extract Operation Name",
"type": "main",
"index": 0
}
]
]
},
"Convert Image to Base64": {
"main": [
[
{
"node": "Conversion OK?",
"type": "main",
"index": 0
}
]
]
},
"Send Processing Message": {
"main": [
[
{
"node": "Download Image",
"type": "main",
"index": 0
}
]
]
},
"1. Get Service Account Details": {
"main": [
[
{
"node": "2. Build JWT from Sheet",
"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.
googleSheetsOAuth2ApitelegramApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Generate 360° product videos from a single photo using Google Veo 3 and Telegram
Source: https://n8n.io/workflows/13928/ — 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.
This workflow provides a complete solution for handling Telegram Stars payments, invoicing and refunds using n8n. It automates the process of sending invoices, managing pre-checkout approvals, recordi
clients kept booking meetings during my prayer times. i'd either miss a prayer or scramble to reschedule. the problem wasn't the clients — it was that my calendar had no blocked windows for salah. i n
02b — Article callback. Uses telegramTrigger, googleSheets, telegram, httpRequest. Event-driven trigger; 30 nodes.
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
Telegram-Command-Interface.N8N. Uses telegramTrigger, httpRequest, googleSheets, telegram. Event-driven trigger; 25 nodes.