AutomationFlowsSlack & Telegram › Create a Virtual Outfit Try-on Telegram Bot with Async Polling and Google Sheets

Create a Virtual Outfit Try-on Telegram Bot with Async Polling and Google Sheets

ByAppStoneLab Technologies LLP @appstonelab on n8n.io

Try on any outfit virtually - right inside Telegram. A user sends a person photo, then a garment photo (captioned ), and the bot replies with an AI-generated try-on result image using a dedicated Virtual Try-On API. No app. No frontend. Just a Telegram chat. Fashion e-commerce…

Event trigger★★★★★ complexity37 nodesTelegram TriggerTelegramGoogle SheetsHTTP Request
Slack & Telegram Trigger: Event Nodes: 37 Complexity: ★★★★★ Added:
Create a Virtual Outfit Try-on Telegram Bot with Async Polling and Google Sheets — n8n workflow card showing Telegram Trigger, Telegram, Google Sheets integration

This workflow corresponds to n8n.io template #14006 — 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 →

Download .json
{
  "id": "bxMDNbmaW6ygo8Rb",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Virtual Apparel Try-On Telegram Bot",
  "tags": [],
  "nodes": [
    {
      "id": "0ede88b5-b324-40f3-b0f2-3d38d02f14d9",
      "name": "Telegram Trigger",
      "type": "n8n-nodes-base.telegramTrigger",
      "position": [
        -416,
        2128
      ],
      "parameters": {
        "updates": [
          "message"
        ],
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "967cc6cb-ce35-4b6e-9da1-ce97bd9a7c87",
      "name": "Extract Message Info",
      "type": "n8n-nodes-base.set",
      "position": [
        -192,
        2128
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "e1",
              "name": "chatId",
              "type": "string",
              "value": "={{ $json.message.chat.id }}"
            },
            {
              "id": "e2",
              "name": "caption",
              "type": "string",
              "value": "={{ ($json.message.caption ?? '').toLowerCase().trim() }}"
            },
            {
              "id": "e3",
              "name": "hasPhoto",
              "type": "boolean",
              "value": "={{ $json.message.photo !== undefined }}"
            },
            {
              "id": "e4",
              "name": "fileId",
              "type": "string",
              "value": "={{ $json.message.photo ? $json.message.photo[$json.message.photo.length - 1].file_id : '' }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "ef066042-e44f-4d8b-aab8-813cef499e5c",
      "name": "\u2699\ufe0f Config",
      "type": "n8n-nodes-base.set",
      "position": [
        32,
        2128
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "c1",
              "name": "botToken",
              "type": "string",
              "value": "{TELEGRAM_BOT_TOKEN}"
            },
            {
              "id": "c2",
              "name": "tryonApiKey",
              "type": "string",
              "value": "{TRYON_API_KEY}"
            },
            {
              "id": "c3",
              "name": "tryonApiBase",
              "type": "string",
              "value": "https://tryon-api.com"
            },
            {
              "id": "c4",
              "name": "sheetId",
              "type": "string",
              "value": "{GOOGLE_SHEET_ID}"
            },
            {
              "id": "c5",
              "name": "chatId",
              "type": "string",
              "value": "={{ $('Extract Message Info').item.json.chatId }}"
            },
            {
              "id": "c6",
              "name": "fileId",
              "type": "string",
              "value": "={{ $('Extract Message Info').item.json.fileId }}"
            },
            {
              "id": "c7",
              "name": "caption",
              "type": "string",
              "value": "={{ $('Extract Message Info').item.json.caption }}"
            },
            {
              "id": "c8",
              "name": "hasPhoto",
              "type": "boolean",
              "value": "={{ $('Extract Message Info').item.json.hasPhoto }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "ca083aaa-154d-484f-a721-1094765a7178",
      "name": "Has Photo?",
      "type": "n8n-nodes-base.if",
      "position": [
        256,
        2128
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "hp1",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.hasPhoto }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "81f8f152-96ab-4d51-a1e3-e5660753d1c6",
      "name": "Send Welcome Message",
      "type": "n8n-nodes-base.telegram",
      "position": [
        480,
        2224
      ],
      "parameters": {
        "text": "\ud83d\udc4b Welcome to Virtual Try-On Bot!\n\n1\ufe0f\u20e3 Send a *person photo* \u2014 full body, no caption\n2\ufe0f\u20e3 Then send the *garment photo* with caption `garment`\n\nI'll generate the try-on result! \ud83d\udc57\u2728",
        "chatId": "={{ $('\u2699\ufe0f Config').item.json.chatId }}",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "2024a886-5e99-4c3e-b09e-2a7b61047388",
      "name": "Is Garment Photo?",
      "type": "n8n-nodes-base.if",
      "position": [
        480,
        2032
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "ig1",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.caption }}",
              "rightValue": "garment"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "1f2bcd45-87fc-46fb-9466-4f6c2f002dd8",
      "name": "Save Person to Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        704,
        1936
      ],
      "parameters": {
        "columns": {
          "value": {
            "chat_id": "={{ $('\u2699\ufe0f Config').item.json.chatId }}",
            "person_file_id": "={{ $('\u2699\ufe0f Config').item.json.fileId }}"
          },
          "schema": [
            {
              "id": "chat_id",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "chat_id",
              "defaultMatch": true,
              "canBeUsedToMatch": true
            },
            {
              "id": "person_file_id",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "person_file_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "chat_id"
          ]
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "tryon-state"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('\u2699\ufe0f Config').item.json.sheetId }}"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "5eac99d6-4dcb-4351-8ad3-6cf8e9eaa099",
      "name": "Ask for Garment Photo",
      "type": "n8n-nodes-base.telegram",
      "position": [
        928,
        1936
      ],
      "parameters": {
        "text": "\u2705 Person photo saved!\n\nNow send your *garment photo* with caption `garment` \ud83d\udc55",
        "chatId": "={{ $('\u2699\ufe0f Config').item.json.chatId }}",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "6c3211b9-78d2-4f98-8026-0e6c18e06fc5",
      "name": "Lookup Person from Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        704,
        2128
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "={{ $json.chatId }}",
              "lookupColumn": "chat_id"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1wsCSDxhnTnIcyDxAYd16haxLHfRaZnB2ZXIPTGEesZs/edit#gid=0",
          "cachedResultName": "tryon-state"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('\u2699\ufe0f Config').item.json.sheetId }}"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "b0a6bad7-019c-4ab2-933f-17a9b74c5f86",
      "name": "Has Person Saved?",
      "type": "n8n-nodes-base.if",
      "position": [
        928,
        2128
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "hp2",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.person_file_id }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "66b0aa3c-269d-4fad-a698-15e02080430e",
      "name": "Ask for Person First",
      "type": "n8n-nodes-base.telegram",
      "position": [
        1152,
        2224
      ],
      "parameters": {
        "text": "\u26a0\ufe0f Please send your *person photo* first (full body, no caption needed), then send the garment photo with caption `garment`.",
        "chatId": "={{ $('\u2699\ufe0f Config').item.json.chatId }}",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "fba2ab05-ea3e-45b1-aa94-f721bbc7315f",
      "name": "Collect IDs",
      "type": "n8n-nodes-base.set",
      "position": [
        1152,
        2032
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "ci1",
              "name": "chatId",
              "type": "string",
              "value": "={{ $('\u2699\ufe0f Config').item.json.chatId }}"
            },
            {
              "id": "ci2",
              "name": "personFileId",
              "type": "string",
              "value": "={{ $json.person_file_id }}"
            },
            {
              "id": "ci3",
              "name": "garmentFileId",
              "type": "string",
              "value": "={{ $('\u2699\ufe0f Config').item.json.fileId }}"
            },
            {
              "id": "ci4",
              "name": "rowNumber",
              "type": "number",
              "value": "={{ $json.row_number }}"
            },
            {
              "id": "ci5",
              "name": "botToken",
              "type": "string",
              "value": "={{ $('\u2699\ufe0f Config').item.json.botToken }}"
            },
            {
              "id": "ci6",
              "name": "tryonApiKey",
              "type": "string",
              "value": "={{ $('\u2699\ufe0f Config').item.json.tryonApiKey }}"
            },
            {
              "id": "ci7",
              "name": "tryonApiBase",
              "type": "string",
              "value": "={{ $('\u2699\ufe0f Config').item.json.tryonApiBase }}"
            },
            {
              "id": "ci8",
              "name": "sheetId",
              "type": "string",
              "value": "={{ $('\u2699\ufe0f Config').item.json.sheetId }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "c0fff2e6-7cd1-4d00-8b35-3eb1d5a434ae",
      "name": "Send Processing Message",
      "type": "n8n-nodes-base.telegram",
      "position": [
        1376,
        2032
      ],
      "parameters": {
        "text": "\ud83d\udd04 Processing your virtual try-on...\n\nThis usually takes 15\u201360 seconds. Please wait! \u23f3",
        "chatId": "={{ $json.chatId }}",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "3041396b-99d2-4999-a979-a6aceb3990cf",
      "name": "Get Person File Path",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1600,
        2032
      ],
      "parameters": {
        "url": "=https://api.telegram.org/bot{{ $('Collect IDs').item.json.botToken }}/getFile",
        "options": {},
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "file_id",
              "value": "={{ $('Collect IDs').item.json.personFileId }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "5f51611e-5e17-46b2-b64b-5f3808f22e47",
      "name": "Set Person Download URL",
      "type": "n8n-nodes-base.set",
      "position": [
        1824,
        2032
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "pu1",
              "name": "personDownloadUrl",
              "type": "string",
              "value": "=https://api.telegram.org/file/bot{{ $('Collect IDs').item.json.botToken }}/{{ $json.result.file_path }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "cfb00dcf-fd84-4448-89ff-219339443e46",
      "name": "Get Garment File Path",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2048,
        2032
      ],
      "parameters": {
        "url": "=https://api.telegram.org/bot{{ $('Collect IDs').item.json.botToken }}/getFile",
        "options": {},
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "file_id",
              "value": "={{ $('Collect IDs').item.json.garmentFileId }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "f4096aba-fb45-47f4-b02b-c1a0ba2d5620",
      "name": "Set Garment Download URL",
      "type": "n8n-nodes-base.set",
      "position": [
        2272,
        2032
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "gu1",
              "name": "garmentDownloadUrl",
              "type": "string",
              "value": "=https://api.telegram.org/file/bot{{ $('Collect IDs').item.json.botToken }}/{{ $json.result.file_path }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "f8cd2136-e962-4408-84ee-b5b701c4410d",
      "name": "Download Person Image",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2496,
        2032
      ],
      "parameters": {
        "url": "={{ $('Set Person Download URL').item.json.personDownloadUrl }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file",
              "outputPropertyName": "person_image"
            }
          }
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "354a10f6-9cdd-453e-ab96-e63b0d2ef7c8",
      "name": "Download Garment Image",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2720,
        2032
      ],
      "parameters": {
        "url": "={{ $('Set Garment Download URL').item.json.garmentDownloadUrl }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file",
              "outputPropertyName": "garment_image"
            }
          }
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "eb8542fb-91a8-462c-b191-c2e01fa905e7",
      "name": "Submit Try-On Job",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2944,
        2032
      ],
      "parameters": {
        "url": "={{ $('Collect IDs').item.json.tryonApiBase }}/api/v1/tryon",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "contentType": "multipart-form-data",
        "sendHeaders": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "person_images",
              "parameterType": "formBinaryData",
              "inputDataFieldName": "person_image"
            },
            {
              "name": "garment_images",
              "parameterType": "formBinaryData",
              "inputDataFieldName": "garment_image"
            },
            {
              "name": "fast_mode",
              "value": "false"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "=Bearer {{ $('Collect IDs').item.json.tryonApiKey }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "0d24662f-aa0c-46f6-b3b3-35bc774f7811",
      "name": "Extract Job ID",
      "type": "n8n-nodes-base.set",
      "position": [
        3168,
        2032
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "ji1",
              "name": "jobId",
              "type": "string",
              "value": "={{ $json.jobId }}"
            },
            {
              "id": "ji2",
              "name": "statusUrl",
              "type": "string",
              "value": "={{ $json.statusUrl }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "b3afa4b4-4b7d-4df8-8af3-92a973cbc1f8",
      "name": "Wait 15 Seconds",
      "type": "n8n-nodes-base.wait",
      "position": [
        3392,
        2032
      ],
      "parameters": {
        "amount": 15
      },
      "typeVersion": 1.1
    },
    {
      "id": "f90cce7f-857e-4260-ae86-81efd01f9d7e",
      "name": "Check Job Status",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        3616,
        1904
      ],
      "parameters": {
        "url": "={{ $('Collect IDs').item.json.tryonApiBase }}/api/v1/tryon/status/{{ $('Submit Try-On Job').item.json.jobId }}",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "=Bearer {{ $('Collect IDs').item.json.tryonApiKey }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "1b0f1b09-a081-424a-98a3-d689cc6fd71a",
      "name": "Merge State",
      "type": "n8n-nodes-base.set",
      "position": [
        3840,
        1904
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "ms1",
              "name": "status",
              "type": "string",
              "value": "={{ $json.status }}"
            },
            {
              "id": "ms2",
              "name": "imageUrl",
              "type": "string",
              "value": "={{ $json.imageUrl }}"
            },
            {
              "id": "ms3",
              "name": "jobId",
              "type": "string",
              "value": "={{ $json.jobId }}"
            },
            {
              "id": "ms4",
              "name": "errorMessage",
              "type": "string",
              "value": "={{ $json.error ?? '' }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "6a7c9814-d81a-4106-b75b-8b56f4415409",
      "name": "Is Job Complete?",
      "type": "n8n-nodes-base.if",
      "position": [
        4064,
        1904
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "jc1",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.status }}",
              "rightValue": "completed"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "52b6967f-8093-4a97-b8d3-c801a6146ba9",
      "name": "Is Job Failed?",
      "type": "n8n-nodes-base.if",
      "position": [
        4288,
        2128
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "jf1",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.status }}",
              "rightValue": "failed"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "bb7c6f29-0712-4300-ab39-5bb342b52f9f",
      "name": "Send Result Photo",
      "type": "n8n-nodes-base.telegram",
      "position": [
        4512,
        1840
      ],
      "parameters": {
        "chatId": "={{ $('Collect IDs').item.json.chatId }}",
        "operation": "sendPhoto",
        "binaryData": true,
        "additionalFields": {
          "caption": "\u2705 Here's your virtual try-on result! \ud83c\udf89\n\nSend a new person photo to try another outfit! \ud83d\udc57"
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "2bf9864a-9db8-4f40-8928-6ddb4f395239",
      "name": "Delete Row from Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        4752,
        1840
      ],
      "parameters": {
        "operation": "delete",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "tryon-state"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Collect IDs').item.json.sheetId }}"
        },
        "startIndex": "={{ $('Collect IDs').item.json.rowNumber }}"
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "c6a72a21-b298-4e46-8fdf-ae7a9f36844e",
      "name": "Send Error Message",
      "type": "n8n-nodes-base.telegram",
      "position": [
        4512,
        2128
      ],
      "parameters": {
        "text": "\u274c Sorry, the try-on failed. Please try again with clearer photos!\n\n\u2022 Person photo: full body visible, good lighting\n\u2022 Garment photo: clear view of the item \ud83d\udcf8",
        "chatId": "={{ $('Collect IDs').item.json.chatId }}",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "d7b6dbe0-b0ed-45b2-b1df-dea70af43b84",
      "name": "HTTP Request",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        4288,
        1840
      ],
      "parameters": {
        "url": "={{ $json.imageUrl }}",
        "options": {}
      },
      "typeVersion": 4.4
    },
    {
      "id": "10b68de2-086f-44c4-a7ef-8520f54bb553",
      "name": "Sticky Note - Config",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -64,
        1808
      ],
      "parameters": {
        "color": 3,
        "width": 284,
        "height": 482,
        "content": "## \u2699\ufe0f Config \u2014 Edit This First\n\nSet these 2 values before activating:\n\n* `botToken` - Your Telegram bot token from @BotFather\n* `sheetId` - ID from your Google Sheets URL\n\nAll other nodes reference values from here \u2014 you only need to change things in one place."
      },
      "typeVersion": 1
    },
    {
      "id": "bff60fff-9cf5-47be-babe-b7acf67ea595",
      "name": "Sticky Note - State Management1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        368,
        1616
      ],
      "parameters": {
        "color": 5,
        "width": 688,
        "height": 292,
        "content": "## \ud83d\udccb State Management via Google Sheets\n\n**The problem:** Each Telegram message triggers a separate workflow execution with no shared memory.\n\n**The fix:** Google Sheets acts as a bridge.\n\n- **Save Person to Sheet** \u2192 writes `chat_id` + `person_file_id` when user sends person photo\n- **Lookup Person from Sheet** \u2192 reads that row back when garment photo arrives\n- **Has Person Saved?** \u2192 if no row found, tells user to send person photo first\n\n> The `chat_id` is the unique key \u2014 it never changes for a given user/bot conversation."
      },
      "typeVersion": 1
    },
    {
      "id": "8bca4062-f765-4e5b-a36f-7c97d97c4e12",
      "name": "Sticky Note - Collect IDs1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1152,
        1760
      ],
      "parameters": {
        "color": 6,
        "width": 456,
        "height": 230,
        "content": "## \ud83d\udcc1 Collect IDs\n\nCarries all required data forward into the rest of the workflow:\n- `chatId` \u2014 who to reply to\n- `personFileId` \u2014 Telegram file ID of person photo\n- `garmentFileId` \u2014 Telegram file ID of garment photo\n- `rowNumber` \u2014 sheet row to delete after job completes\n- `botToken`, `tryonApiKey`, `tryonApiBase`, `sheetId` \u2014 configs\n\n> Needed because after Lookup node, the Config node is no longer in the direct chain."
      },
      "typeVersion": 1
    },
    {
      "id": "971a0a2c-acef-448f-8ed5-8adbe810f6c8",
      "name": "Sticky Note - File URL Resolution1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2048,
        1760
      ],
      "parameters": {
        "color": 6,
        "width": 792,
        "height": 226,
        "content": "## \ud83d\udd17 Telegram File URL Resolution\n\nTelegram does **not** give you a direct download URL in the message. It only gives a `file_id`.\n\nTo get the actual image you must:\n1. Call `getFile?file_id=...` \u2192 returns a `file_path`\n2. Build download URL: `api.telegram.org/file/bot{TOKEN}/{file_path}`\n\nThis 4-node sequence does this for **both** person and garment images before passing them to the Try-On API."
      },
      "typeVersion": 1
    },
    {
      "id": "97a0e691-7408-40dd-ad9a-bf058cc45fda",
      "name": "Sticky Note - Polling Loop1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3536,
        2048
      ],
      "parameters": {
        "color": 7,
        "width": 668,
        "height": 252,
        "content": "## \u23f1\ufe0f Polling Loop\n\nThe Try-On API is **asynchronous** \u2014 submitting a job returns a `jobId`, not the result immediately.\n\nThis loop:\n1. Waits 15 seconds\n2. Calls the status endpoint with the `jobId`\n3. Checks if status is `completed` \u2192 send result\n4. Checks if status is `failed` \u2192 send error\n5. Otherwise loops back to Wait\n\n**Typical wait time:** 15\u201360 seconds total"
      },
      "typeVersion": 1
    },
    {
      "id": "c794ec17-2a15-4624-b401-80edc061c511",
      "name": "Sticky Note - Download Result1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4240,
        1600
      ],
      "parameters": {
        "color": 2,
        "width": 436,
        "height": 222,
        "content": "## \u2b07\ufe0f Download Result Image\n\nThe Try-On API returns an `imageUrl` (a signed URL). Telegram's `sendPhoto` with a URL can fail if the URL expires or requires auth headers.\n\nThis node downloads the image as a binary file first, then **Send Result Photo** sends it as a proper file upload \u2014 more reliable."
      },
      "typeVersion": 1
    },
    {
      "id": "33934043-0a35-4283-8917-9e8fd4a06a92",
      "name": "Sticky Note - Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1536,
        1792
      ],
      "parameters": {
        "color": 4,
        "width": 1068,
        "height": 580,
        "content": "# \ud83d\udc57 Virtual Try-On Telegram Bot\n\n## What this workflow does\nThis bot lets users virtually try on clothing via Telegram. A user sends a **person photo**, then a **garment photo** (with caption `garment`), and the bot replies with an AI-generated try-on result image.\n\n## How it works\n1. **Message comes in** \u2192 checks if it contains a photo\n2. **Person photo** (no caption) \u2192 saved to Google Sheets as state\n3. **Garment photo** (caption: `garment`) \u2192 looks up saved person photo from Sheets, resolves both Telegram file URLs, downloads both images, submits to Try-On API\n4. **Polling loop** \u2192 checks job status every 15s until `completed` or `failed`\n5. **Result** \u2192 downloads the result image and sends it back to the user in Telegram\n\n## Setup checklist\n- [ ] Set your **Telegram Bot Token** in \u2699\ufe0f Config node\n- [ ] Set your **Google Sheet ID** in \u2699\ufe0f Config node\n- [ ] Confirm Google Sheet has tab named `tryon-state` with headers `chat_id` and `person_file_id`\n- [ ] Assign Telegram credential to all Telegram nodes\n- [ ] Assign Google Sheets credential to all Google Sheets nodes\n- [ ] **Activate** the workflow (Telegram Trigger only works when active)"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "9fede48e-ca46-4fc0-88ce-5af539c8e6d9",
  "connections": {
    "Has Photo?": {
      "main": [
        [
          {
            "node": "Is Garment Photo?",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send Welcome Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Collect IDs": {
      "main": [
        [
          {
            "node": "Send Processing Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge State": {
      "main": [
        [
          {
            "node": "Is Job Complete?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request": {
      "main": [
        [
          {
            "node": "Send Result Photo",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u2699\ufe0f Config": {
      "main": [
        [
          {
            "node": "Has Photo?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Job ID": {
      "main": [
        [
          {
            "node": "Wait 15 Seconds",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Job Failed?": {
      "main": [
        [
          {
            "node": "Send Error Message",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait 15 Seconds",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait 15 Seconds": {
      "main": [
        [
          {
            "node": "Check Job Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Job Status": {
      "main": [
        [
          {
            "node": "Merge State",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Job Complete?": {
      "main": [
        [
          {
            "node": "HTTP Request",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Is Job Failed?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Telegram Trigger": {
      "main": [
        [
          {
            "node": "Extract Message Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has Person Saved?": {
      "main": [
        [
          {
            "node": "Collect IDs",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Ask for Person First",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Garment Photo?": {
      "main": [
        [
          {
            "node": "Lookup Person from Sheet",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Save Person to Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Result Photo": {
      "main": [
        [
          {
            "node": "Delete Row from Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Submit Try-On Job": {
      "main": [
        [
          {
            "node": "Extract Job ID",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Message Info": {
      "main": [
        [
          {
            "node": "\u2699\ufe0f Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Person File Path": {
      "main": [
        [
          {
            "node": "Set Person Download URL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save Person to Sheet": {
      "main": [
        [
          {
            "node": "Ask for Garment Photo",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Person Image": {
      "main": [
        [
          {
            "node": "Download Garment Image",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Garment File Path": {
      "main": [
        [
          {
            "node": "Set Garment Download URL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Garment Image": {
      "main": [
        [
          {
            "node": "Submit Try-On Job",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Processing Message": {
      "main": [
        [
          {
            "node": "Get Person File Path",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Person Download URL": {
      "main": [
        [
          {
            "node": "Get Garment File Path",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Lookup Person from Sheet": {
      "main": [
        [
          {
            "node": "Has Person Saved?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Garment Download URL": {
      "main": [
        [
          {
            "node": "Download Person Image",
            "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

Try on any outfit virtually - right inside Telegram. A user sends a person photo, then a garment photo (captioned ), and the bot replies with an AI-generated try-on result image using a dedicated Virtual Try-On API. No app. No frontend. Just a Telegram chat. Fashion e-commerce…

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

TGBot. Uses telegram, googleSheets, telegramTrigger, httpRequest. Event-driven trigger; 30 nodes.

Telegram, Google Sheets, Telegram Trigger +1
Slack & Telegram

This n8n workflow enables Telegram users to interact with multiple AI models dynamically using #model_id commands. It also supports a /models command to list all available models. Each user has a dail

Telegram Trigger, Google Sheets, Telegram +2
Slack & Telegram

Send any URL to your Telegram bot and get an AI summary instantly.

Telegram Trigger, HTTP Request, Chain Llm +4
Slack & Telegram

A robust n8n workflow designed to enhance Telegram bot functionality for user management and broadcasting. It facilitates automatic support ticket creation, efficient user data storage in Redis, and a

HTTP Request, Redis, Telegram +1
Slack & Telegram

Transform your digital payment business with a fully-featured Telegram bot that handles everything from product listings to transaction processing. Perfect for entrepreneurs looking to automate their

Telegram Trigger, Telegram, HTTP Request