This workflow corresponds to n8n.io template #17769 — we link there as the canonical source.
This workflow follows the Informationextractor → OpenAI Chat 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": "pCnq7mPvN2eIs9Z3",
"meta": {
"builderVariant": "mcp",
"aiBuilderAssisted": true
},
"name": "Save business card contacts from Telegram photos to Google Contacts",
"tags": [],
"nodes": [
{
"id": "229ace2e-35c5-49b6-bed7-556c185930fb",
"name": "Get Business Card Message",
"type": "n8n-nodes-base.telegramTrigger",
"position": [
0,
112
],
"parameters": {
"updates": [
"message"
],
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.3
},
{
"id": "ae8cb876-2985-4c59-9d3c-76a684374a16",
"name": "Configuration",
"type": "n8n-nodes-base.set",
"position": [
224,
112
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "cfg-1",
"name": "authorized_user_ids",
"type": "string",
"value": "<__PLACEHOLDER_VALUE__Comma-separated Telegram user IDs allowed to use this bot, e.g. 123456789,987654321__>"
},
{
"id": "cfg-2",
"name": "trigger_caption",
"type": "string",
"value": "/business"
},
{
"id": "cfg-3",
"name": "ocr_model",
"type": "string",
"value": "mistral-ocr-latest"
},
{
"id": "cfg-4",
"name": "openai_model",
"type": "string",
"value": "gpt-5-mini"
},
{
"id": "cfg-5",
"name": "success_message",
"type": "string",
"value": "\u2705 Contact successfully added to Google Contacts"
},
{
"id": "cfg-6",
"name": "duplicate_message",
"type": "string",
"value": "\u2139\ufe0f A contact with this email already exists in Google Contacts \u2014 skipped to avoid duplicates"
},
{
"id": "cfg-7",
"name": "error_message",
"type": "string",
"value": "\u26a0\ufe0f There was a problem adding the contact to Google Contacts. Please check the extracted fields and try again"
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "4c920573-e848-44c4-9274-3cb6953e201f",
"name": "Validate Business Card Message",
"type": "n8n-nodes-base.if",
"position": [
448,
112
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "val-1",
"operator": {
"type": "object",
"operation": "exists"
},
"leftValue": "={{ $json.message.photo?.[0] }}",
"rightValue": ""
},
{
"id": "val-2",
"operator": {
"type": "string",
"operation": "startsWith"
},
"leftValue": "={{ $json.message.caption }}",
"rightValue": "={{ $('Configuration').item.json.trigger_caption }}"
}
]
}
},
"typeVersion": 2.3
},
{
"id": "d44c59fc-21a6-466d-8432-b4d5ae6c73c5",
"name": "Check Authorized User",
"type": "n8n-nodes-base.if",
"position": [
672,
112
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "auth-1",
"operator": {
"type": "boolean",
"operation": "true"
},
"leftValue": "={{ $('Configuration').item.json.authorized_user_ids.split(',').map(s => s.trim()).includes($json.message.from.id.toString()) }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.3
},
{
"id": "71d4c618-97b0-467c-823f-edc53a48428e",
"name": "Get Business Card Photo",
"type": "n8n-nodes-base.telegram",
"position": [
896,
112
],
"parameters": {
"fileId": "={{ $('Get Business Card Message').item.json.message.photo[$('Get Business Card Message').item.json.message.photo.length - 1].file_id }}",
"resource": "file",
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "53401d67-f83c-4e8e-9ddb-3d03e60a8500",
"name": "Extract Business Card Text",
"type": "n8n-nodes-base.mistralAi",
"position": [
1120,
112
],
"parameters": {
"model": "={{ $('Configuration').item.json.ocr_model }}",
"options": {},
"documentType": "image_url"
},
"typeVersion": 1
},
{
"id": "883be3e3-1fe6-43db-8d2a-d0bbcae8b4fc",
"name": "Extract Contact Fields",
"type": "@n8n/n8n-nodes-langchain.informationExtractor",
"position": [
1344,
112
],
"parameters": {
"text": "={{ $json.pages[0].markdown }}",
"options": {},
"attributes": {
"attributes": [
{
"name": "company_name",
"required": true,
"description": "Name of the company"
},
{
"name": "first_name",
"required": true,
"description": "First name"
},
{
"name": "last_name",
"required": true,
"description": "Last name"
},
{
"name": "role",
"required": true,
"description": "Business role or job title"
},
{
"name": "phone",
"required": true,
"description": "Phone number in international format for Google Contacts"
},
{
"name": "email",
"required": true,
"description": "Email address"
},
{
"name": "website",
"description": "Website URL if it exists"
},
{
"name": "street_address",
"description": "Street address only, for Google Contacts"
},
{
"name": "city",
"description": "City"
},
{
"name": "region",
"description": "Region or state, for Google Contacts"
},
{
"name": "country_code",
"description": "Country code, for Google Contacts"
},
{
"name": "postal_code",
"description": "Postal code"
}
]
}
},
"typeVersion": 1.2
},
{
"id": "1793bf00-ace8-4e61-9982-ee0bd07382df",
"name": "OpenAI Model - Extraction",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
1424,
336
],
"parameters": {
"model": {
"__rl": true,
"mode": "id",
"value": "={{ $('Configuration').item.json.openai_model }}"
},
"options": {},
"builtInTools": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.3
},
{
"id": "3d809c28-ec6d-4470-abd1-6bc1e7503323",
"name": "Check Duplicate Contact",
"type": "n8n-nodes-base.googleContacts",
"position": [
1696,
112
],
"parameters": {
"limit": 1,
"query": "={{ $json.output.email }}",
"useQuery": true,
"operation": "getAll"
},
"typeVersion": 1,
"alwaysOutputData": true
},
{
"id": "fbff5744-dad9-4bec-83ca-14c623fa55ca",
"name": "Is Duplicate Contact?",
"type": "n8n-nodes-base.if",
"position": [
1920,
112
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "dup-1",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json.resourceName }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.3
},
{
"id": "efd2d452-e001-4646-b881-fd899b3eb3fa",
"name": "Notify Duplicate Contact",
"type": "n8n-nodes-base.telegram",
"position": [
2144,
16
],
"parameters": {
"text": "={{ $('Configuration').item.json.duplicate_message }}",
"chatId": "={{ $('Get Business Card Message').item.json.message.from.id }}",
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "4202b1de-8f7c-4d69-861c-64b140ccae66",
"name": "Create Google Contact",
"type": "n8n-nodes-base.googleContacts",
"position": [
2144,
208
],
"parameters": {
"givenName": "={{ $('Extract Contact Fields').item.json.output.first_name }}",
"familyName": "={{ $('Extract Contact Fields').item.json.output.last_name }}",
"additionalFields": {
"phoneUi": {
"phoneValues": [
{
"type": "work",
"value": "={{ $('Extract Contact Fields').item.json.output.phone }}"
}
]
},
"emailsUi": {
"emailsValues": [
{
"type": "work",
"value": "={{ $('Extract Contact Fields').item.json.output.email }}"
}
]
},
"companyUi": {
"companyValues": [
{
"name": "={{ $('Extract Contact Fields').item.json.output.company_name }}",
"title": "={{ $('Extract Contact Fields').item.json.output.role }}",
"domain": "={{ $('Extract Contact Fields').item.json.output.email.split('@')[1] }}",
"current": true
}
]
},
"addressesUi": {
"addressesValues": {
"city": "={{ $('Extract Contact Fields').item.json.output.city }}",
"type": "work",
"region": "={{ $('Extract Contact Fields').item.json.output.region }}",
"postalCode": "={{ $('Extract Contact Fields').item.json.output.postal_code }}",
"countryCode": "={{ $('Extract Contact Fields').item.json.output.country_code }}",
"streetAddress": "={{ $('Extract Contact Fields').item.json.output.street_address }}"
}
}
}
},
"typeVersion": 1
},
{
"id": "f6fd7564-dce2-48cb-aecb-859cb77078fa",
"name": "Check Contact Created",
"type": "n8n-nodes-base.if",
"position": [
2368,
208
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "ok-1",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json.resourceName }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.3
},
{
"id": "4f620874-bddd-46ce-ae4f-4a8d2e415c46",
"name": "Notify Contact Added",
"type": "n8n-nodes-base.telegram",
"position": [
2592,
112
],
"parameters": {
"text": "={{ $('Configuration').item.json.success_message }} ({{ $('Extract Contact Fields').item.json.output.first_name }} {{ $('Extract Contact Fields').item.json.output.last_name }} - {{ $('Extract Contact Fields').item.json.output.company_name }})",
"chatId": "={{ $('Get Business Card Message').item.json.message.from.id }}",
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "90c5f06d-b440-421a-8583-d13f6c5d2914",
"name": "Notify Contact Error",
"type": "n8n-nodes-base.telegram",
"position": [
2592,
304
],
"parameters": {
"text": "={{ $('Configuration').item.json.error_message }}",
"chatId": "={{ $('Get Business Card Message').item.json.message.from.id }}",
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "fb6da88b-e610-46a2-bcdd-cb37463d8735",
"name": "Sticky Note 58edb1d0",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1088,
-736
],
"parameters": {
"color": 4,
"width": 780,
"height": 1736,
"content": "# Save business card contacts from Telegram photos to Google Contacts\n# \ud83d\udce5 [Open full documentation on Notion](https://automatisation.notion.site/Course-Save-business-card-contacts-from-Telegram-photos-to-Google-Contacts-39f3d6550fd9814aac7def269dee2bca)\n\n## How it works\nSend a photo of a business card to the Telegram bot with the caption `/business`. The workflow checks you are an authorized user, downloads the photo, runs OCR with the native Mistral AI node, and uses an OpenAI-powered Information Extractor to structure the fields (name, company, role, phone, email, website, address). It then checks Google Contacts for an existing contact with the same email to avoid duplicates, creates the contact if none is found, and replies on Telegram with a success, duplicate, or error message.\n\n## Setup\n1. Create a Telegram bot via @BotFather and connect its token as a Telegram credential.\n2. Create a Mistral Cloud API credential (get a key at https://console.mistral.ai).\n3. Connect an OpenAI credential.\n4. Connect a Google Contacts (Google OAuth2) credential with the Contacts scope.\n5. Open the Configuration node and fill in your authorized Telegram user ID(s).\n\n## Requirements\n- Telegram bot token\n- Mistral Cloud API key (OCR)\n- OpenAI API key\n- Google account with Contacts API access\n\n## Customization\n- Add more authorized user IDs (comma-separated) in Configuration.\n- Change `trigger_caption` if you prefer a different Telegram command.\n- Adjust the extracted fields in the Extract Contact Fields node for your region's address format.\n- Swap Google Contacts for a CRM by replacing the Create Google Contact node.\n\nNeed help customizing?\nContact me for consulting and support : [Linkedin](https://www.linkedin.com/in/doctor-firass/)\n\n# MY NEW YOUTUBE CHANNEL\n\ud83d\udc49 [Subscribe to my new YouTube channel](https://www.youtube.com/@DrFiras_AI). Here I'll share videos and Shorts with practical tutorials and FREE templates for n8n.\n\n[](https://www.youtube.com/@DrFiras_AI)"
},
"typeVersion": 1
},
{
"id": "a307e8bb-137f-4f02-a524-0aa2c8f9023a",
"name": "Sticky Note 2979bbb6",
"type": "n8n-nodes-base.stickyNote",
"position": [
-112,
-160
],
"parameters": {
"color": 7,
"width": 300,
"height": 200,
"content": "### Trigger & Configuration\nReceives the Telegram photo and centralizes every adjustable setting in one place."
},
"typeVersion": 1
},
{
"id": "3ccc2d0c-0502-4c89-847e-1e0aad490a58",
"name": "Sticky Note 362d0483",
"type": "n8n-nodes-base.stickyNote",
"position": [
208,
-160
],
"parameters": {
"color": 7,
"width": 300,
"height": 200,
"content": "### Validate & authorize\nChecks the message is a business card submission and that the sender is an authorized user."
},
"typeVersion": 1
},
{
"id": "b555cb78-dbce-415e-bd9a-7c9c5321e1f5",
"name": "Sticky Note 70b94138",
"type": "n8n-nodes-base.stickyNote",
"position": [
1344,
-160
],
"parameters": {
"color": 7,
"width": 300,
"height": 200,
"content": "### OCR & AI extraction\nDownloads the photo, extracts text with native Mistral OCR, then structures the fields with an OpenAI-powered Information Extractor."
},
"typeVersion": 1
},
{
"id": "def5124e-a79f-489d-8ba2-5322b8ecb212",
"name": "Sticky Note 7005d78c",
"type": "n8n-nodes-base.stickyNote",
"position": [
1696,
-160
],
"parameters": {
"color": 7,
"width": 300,
"height": 200,
"content": "### Duplicate check & save\nSearches Google Contacts by email first; creates the contact only if no match is found."
},
"typeVersion": 1
},
{
"id": "1256e484-2aac-45d5-9d86-2fdf5ae6febe",
"name": "Sticky Note 2c7a1471",
"type": "n8n-nodes-base.stickyNote",
"position": [
2496,
-160
],
"parameters": {
"color": 7,
"width": 300,
"height": 200,
"content": "### Confirmation\nReplies on Telegram with a success, duplicate, or error message."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"availableInMCP": true,
"executionOrder": "v1"
},
"versionId": "279b985a-ab0b-4678-8270-102d751106a3",
"nodeGroups": [],
"connections": {
"Configuration": {
"main": [
[
{
"node": "Validate Business Card Message",
"type": "main",
"index": 0
}
]
]
},
"Check Authorized User": {
"main": [
[
{
"node": "Get Business Card Photo",
"type": "main",
"index": 0
}
]
]
},
"Check Contact Created": {
"main": [
[
{
"node": "Notify Contact Added",
"type": "main",
"index": 0
}
],
[
{
"node": "Notify Contact Error",
"type": "main",
"index": 0
}
]
]
},
"Create Google Contact": {
"main": [
[
{
"node": "Check Contact Created",
"type": "main",
"index": 0
}
]
]
},
"Is Duplicate Contact?": {
"main": [
[
{
"node": "Notify Duplicate Contact",
"type": "main",
"index": 0
}
],
[
{
"node": "Create Google Contact",
"type": "main",
"index": 0
}
]
]
},
"Extract Contact Fields": {
"main": [
[
{
"node": "Check Duplicate Contact",
"type": "main",
"index": 0
}
]
]
},
"Check Duplicate Contact": {
"main": [
[
{
"node": "Is Duplicate Contact?",
"type": "main",
"index": 0
}
]
]
},
"Get Business Card Photo": {
"main": [
[
{
"node": "Extract Business Card Text",
"type": "main",
"index": 0
}
]
]
},
"Get Business Card Message": {
"main": [
[
{
"node": "Configuration",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Model - Extraction": {
"ai_languageModel": [
[
{
"node": "Extract Contact Fields",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Extract Business Card Text": {
"main": [
[
{
"node": "Extract Contact Fields",
"type": "main",
"index": 0
}
]
]
},
"Validate Business Card Message": {
"main": [
[
{
"node": "Check Authorized User",
"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.
openAiApitelegramApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow listens for Telegram messages containing a business card photo and the /business caption, uses Mistral OCR and OpenAI to extract contact details, checks Google Contacts for duplicates by email, then creates a new Google Contact and replies in Telegram with the…
Source: https://n8n.io/workflows/17769/ — 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 automates the process of scanning business cards received via Telegram and instantly saving the extracted contact information into Google Contacts. It combines OCR technology, AI-powered
Email Automation. Uses gmailTrigger, textClassifier, lmChatOpenAi, openAi. Event-driven trigger; 13 nodes.
Influencer 2.0. Uses formTrigger, form, informationExtractor, lmChatOpenAi. Event-driven trigger; 93 nodes.
Episode 18 Scary Stories TikTok final. Uses httpRequest, lmChatOpenAi, lmChatOllama, lmChatDeepSeek. Event-driven trigger; 83 nodes.
Gmailassistent. Uses gmailTrigger, telegram, dataTable, telegramTrigger. Event-driven trigger; 47 nodes.