{
  "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[![The AI Doctor](https://www.dr-firas.com/the-ai-doctor.png)](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
          }
        ]
      ]
    }
  }
}