{
  "id": "a5rWRZm5oL0fXcSZ",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Business Card Scanner for Google Contacts",
  "tags": [],
  "nodes": [
    {
      "id": "bfd689dd-df28-4af9-b860-4dd418bbf606",
      "name": "Code",
      "type": "n8n-nodes-base.code",
      "position": [
        -1056,
        96
      ],
      "parameters": {
        "jsCode": "if ($input.first().json.message.from.id !== XXX) { // Replace with your Telegram user ID\n    return { unauthorized: true };\n} else {\n    // Return the original data when authorized\n    return $input.all();\n}\n"
      },
      "typeVersion": 2
    },
    {
      "id": "3a9afc73-48ca-4645-a747-697add2b50df",
      "name": "Get Message",
      "type": "n8n-nodes-base.telegramTrigger",
      "position": [
        -1376,
        96
      ],
      "parameters": {
        "updates": [
          "message"
        ],
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "fc12815d-bc7a-4381-811d-d0c63ab5d3bc",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1152,
        -32
      ],
      "parameters": {
        "color": 7,
        "width": 512,
        "height": 292,
        "content": "## STEP 1 - Telegram and switch\nCreate a Telegram Bot and set your Telegram ID in code Node. This workflow start if the caption starts with \"/business\" text"
      },
      "typeVersion": 1
    },
    {
      "id": "3b443fb6-a5f3-4fb3-a77c-8e7da9ea23cf",
      "name": "Get image file",
      "type": "n8n-nodes-base.telegram",
      "position": [
        -528,
        80
      ],
      "parameters": {
        "fileId": "={{ $json.message.photo[2].file_id }}",
        "resource": "file",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "065302f3-3c24-4664-bc72-d4776b46606b",
      "name": "Extract from File",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        -272,
        80
      ],
      "parameters": {
        "options": {},
        "operation": "binaryToPropery"
      },
      "typeVersion": 1.1
    },
    {
      "id": "63c307b4-0ea4-49ba-8b33-9cb29d18f9b5",
      "name": "Information Extractor",
      "type": "@n8n/n8n-nodes-langchain.informationExtractor",
      "position": [
        304,
        80
      ],
      "parameters": {
        "text": "={{ $json.pages[0].markdown }}",
        "options": {},
        "attributes": {
          "attributes": [
            {
              "name": "company_name",
              "required": true,
              "description": "Name about company"
            },
            {
              "name": "first_name",
              "required": true,
              "description": "First name"
            },
            {
              "name": "last_name",
              "required": true,
              "description": "Last name"
            },
            {
              "name": "role",
              "required": true,
              "description": "Business role"
            },
            {
              "name": "phone",
              "required": true,
              "description": "Phone number for Google Contacts format with international prefix"
            },
            {
              "name": "email",
              "required": true,
              "description": "Email address"
            },
            {
              "name": "website",
              "required": true,
              "description": "Website url if exist"
            },
            {
              "name": "street_address",
              "required": true,
              "description": "Only Strett Address for Google Contacts"
            },
            {
              "name": "city",
              "required": true,
              "description": "City"
            },
            {
              "name": "region",
              "required": true,
              "description": "Region for Google Contacts"
            },
            {
              "name": "country_code",
              "required": true,
              "description": "Country code for Google Contacts"
            },
            {
              "name": "postal_code",
              "required": true,
              "description": "Postal code"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "daf455db-71d1-4701-828d-bff833e20520",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        288,
        288
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-5.4-mini",
          "cachedResultName": "gpt-5.4-mini"
        },
        "options": {},
        "builtInTools": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "b7c1077d-c5f9-45f4-b6cb-e2f0b994a080",
      "name": "Create a contact",
      "type": "n8n-nodes-base.googleContacts",
      "position": [
        704,
        80
      ],
      "parameters": {
        "givenName": "={{ $json.output.first_name }}",
        "familyName": "={{ $json.output.last_name }}",
        "additionalFields": {
          "phoneUi": {
            "phoneValues": [
              {
                "type": "work",
                "value": "={{ $json.output.phone }}"
              }
            ]
          },
          "emailsUi": {
            "emailsValues": [
              {
                "type": "work",
                "value": "={{ $json.output.email }}"
              }
            ]
          },
          "companyUi": {
            "companyValues": [
              {
                "name": "={{ $json.output.company_name }}",
                "title": "={{ $json.output.role }}",
                "domain": "={{ $json.output.email.split('@')[1] }}",
                "current": true
              }
            ]
          },
          "addressesUi": {
            "addressesValues": {
              "city": "={{ $json.output.city }}",
              "type": "work",
              "region": "={{ $json.output.region }}",
              "postalCode": "={{ $json.output.postal_code }}",
              "countryCode": "={{ $json.output.country_code }}",
              "streetAddress": "={{ $json.output.street_address }}"
            }
          }
        }
      },
      "typeVersion": 1
    },
    {
      "id": "a1d5aea8-6d8b-4e6a-98fc-fa1a38d35669",
      "name": "Mistral OCR",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        48,
        80
      ],
      "parameters": {
        "url": "https://api.mistral.ai/v1/ocr",
        "method": "POST",
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        },
        "jsonBody": "={\n  \"model\": \"mistral-ocr-latest\",\n  \"document\": {\n    \"type\": \"image_url\",\n    \"image_url\": \"data:image/jpeg;base64,{{ $json.data }}\"\n  },\n  \"include_image_base64\": true\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth",
        "headerParameters": {
          "parameters": []
        }
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        },
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "4368d772-aa71-4408-8fe7-cd164163fa52",
      "name": "Success?",
      "type": "n8n-nodes-base.if",
      "position": [
        928,
        80
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "5a284c64-4097-4c38-8cb5-3e681097c443",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{$json.resourceName}}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "a79d3ed4-7cf5-4208-a0ff-cdb9f625bb0c",
      "name": "OK",
      "type": "n8n-nodes-base.telegram",
      "position": [
        1248,
        -16
      ],
      "parameters": {
        "text": "=Contact successfully added to Google Contacts",
        "chatId": "={{ $('Get Message').item.json.message.from.id }}",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "c664ce8f-36f9-4908-bf97-e06306fd1017",
      "name": "KO",
      "type": "n8n-nodes-base.telegram",
      "position": [
        1248,
        176
      ],
      "parameters": {
        "text": "=There was a problem adding the contact to Google Contacts",
        "chatId": "={{ $('Get Message').item.json.message.from.id }}",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "e26a5e21-fe4d-46f2-a149-a1e2798b318c",
      "name": "Validate message",
      "type": "n8n-nodes-base.if",
      "position": [
        -848,
        96
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "23708b60-bb27-42f6-9149-192e7684d218",
              "operator": {
                "type": "object",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.message.photo[0] }}",
              "rightValue": ""
            },
            {
              "id": "15d1861a-5c3e-475a-9368-5321d466328c",
              "operator": {
                "type": "string",
                "operation": "startsWith"
              },
              "leftValue": "={{ $('Get Message').item.json.message.caption }}",
              "rightValue": "=/business"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "c58144ee-0a0f-481d-9cf4-8928713031f1",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1152,
        -384
      ],
      "parameters": {
        "width": 1072,
        "height": 336,
        "content": "## AI-Powered Business Card Scanner for Google Contacts with Telegram\nThis 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 data extraction, and workflow automation to eliminate manual contact entry and reduce errors. \n\n### How it works\n\nThe workflow starts from a Telegram bot message, verifies the sender is authorized, and checks that the message includes a business card photo with the `/business` caption. It retrieves the best-quality image, uses Mistral OCR to extract text, then sends the text to an OpenAI-powered Information Extractor to structure contact fields such as name, company, role, phone, email, website, and address. The extracted data is saved as a new Google Contact, and Telegram returns either a success or error message.\n\n### Setup steps\n\nCreate a Telegram bot, add its API token to n8n, and replace the authorized user ID in the Code node. Add Mistral OCR credentials, configure OpenAI credentials with an available chat model, and set up Google OAuth2 access for Google Contacts. Activate the workflow, then test it by sending a business card photo to the bot with the `/business` caption.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "eb716118-fc28-493a-af96-9179ff71ec78",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -624,
        -32
      ],
      "parameters": {
        "color": 7,
        "width": 544,
        "height": 292,
        "content": "## STEP 2 - Get image\nGet business card image and covert it to base64 format"
      },
      "typeVersion": 1
    },
    {
      "id": "2b19a0c7-1c48-4ab8-80ce-6c7506935186",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -64,
        -32
      ],
      "parameters": {
        "color": 7,
        "width": 688,
        "height": 292,
        "content": "## STEP 3 - Info extraction\nThe image is sent to Mistral OCR (via HTTP Request) to extract text from the business card."
      },
      "typeVersion": 1
    },
    {
      "id": "781f65b3-b3f4-4603-bb34-9bde0fb5ab27",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        640,
        -32
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 288,
        "content": "## STEP 4 - Create Google Contact\nA Google Contacts node creates a new contact using the extracted data (addresses, company, emails, phone)"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "69db0971-0e88-4bc2-a5c3-bc2151f6d3a8",
  "connections": {
    "Code": {
      "main": [
        [
          {
            "node": "Validate message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Success?": {
      "main": [
        [
          {
            "node": "OK",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "KO",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Message": {
      "main": [
        [
          {
            "node": "Code",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mistral OCR": {
      "main": [
        [
          {
            "node": "Information Extractor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get image file": {
      "main": [
        [
          {
            "node": "Extract from File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create a contact": {
      "main": [
        [
          {
            "node": "Success?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate message": {
      "main": [
        [
          {
            "node": "Get image file",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract from File": {
      "main": [
        [
          {
            "node": "Mistral OCR",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Information Extractor",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Information Extractor": {
      "main": [
        [
          {
            "node": "Create a contact",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}