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
This n8n workflow allows users to generate AI-generated images by sending messages to a Telegram bot. Each request is logged in Google Sheets and limited by a daily quota per user. Image prompts are e