{
  "id": "JZ8C3IFRtHrntshw",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "CRM Contact Sync with Mailchimp and Pipedrive",
  "tags": [],
  "nodes": [
    {
      "id": "ad3a6351-b389-4c84-9821-c630039d67de",
      "name": "Incoming Contact Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        288,
        400
      ],
      "parameters": {
        "path": "crm-contact-sync",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 1
    },
    {
      "id": "5a7326b9-121d-4e12-99a0-63f67fb4e35e",
      "name": "Split Contacts",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        480,
        400
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "2920cb9e-f9f0-45aa-9682-ff14f89fec80",
      "name": "Fetch Contact Details (Source CRM)",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        688,
        400
      ],
      "parameters": {
        "url": "https://api.sourcecrm.com/contacts/{{$json.contactId}}",
        "options": {},
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "httpHeaderAuth"
      },
      "typeVersion": 4
    },
    {
      "id": "857756fa-ed62-4ed2-8f36-a063e3fd8a85",
      "name": "Normalize Contact Data",
      "type": "n8n-nodes-base.code",
      "position": [
        912,
        400
      ],
      "parameters": {
        "jsCode": "// normalise source CRM contact fields\nconst src = $input.item.json;\nreturn [{\n  json: {\n    contactId: src.id || src.vid || src.contactId || '',\n    email: src.email || src.properties?.email?.value || '',\n    firstName: src.firstName || src.properties?.firstname?.value || '',\n    lastName: src.lastName || src.properties?.lastname?.value || '',\n    phone: src.phone || src.properties?.phone?.value || '',\n    company: src.company || src.properties?.company?.value || '',\n    updatedAt: src.updatedAt || src.properties?.lastmodifieddate || new Date().toISOString()\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "d43aef50-dade-4eae-ac30-6df77bdd50b0",
      "name": "Search Person by Email",
      "type": "n8n-nodes-base.pipedrive",
      "position": [
        1088,
        288
      ],
      "parameters": {
        "term": "={{ $json.email }}",
        "resource": "person",
        "operation": "search",
        "returnAll": true,
        "additionalFields": {}
      },
      "typeVersion": 1
    },
    {
      "id": "3e8aa3da-b08e-4f14-a620-f8e2c47d5158",
      "name": "Combine Contact & Search",
      "type": "n8n-nodes-base.merge",
      "position": [
        1088,
        496
      ],
      "parameters": {
        "mode": "mergeByIndex",
        "options": {}
      },
      "typeVersion": 2
    },
    {
      "id": "76039f69-fd0c-46b8-8ca8-447b2c263733",
      "name": "Determine Existence & Prepare Data",
      "type": "n8n-nodes-base.code",
      "position": [
        1376,
        400
      ],
      "parameters": {
        "jsCode": "const item = $input.item.json;\nlet exists = false;\nlet personId = null;\nif (item.data && item.data.items && item.data.items.length > 0) {\n  exists = true;\n  personId = item.data.items[0].item.id;\n}\nreturn [{\n  json: {\n    ...item,\n    exists,\n    personId\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "88ae0120-b273-4211-b27f-c1eb64a7b236",
      "name": "Is Person Existing?",
      "type": "n8n-nodes-base.if",
      "position": [
        1600,
        400
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "boolean": [
            {
              "value1": "={{ $json.exists }}"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "8412367f-3c78-42ea-83a5-9582da1cdc0e",
      "name": "Create Person",
      "type": "n8n-nodes-base.pipedrive",
      "position": [
        1920,
        528
      ],
      "parameters": {
        "name": "={{ $json.firstName + ' ' + $json.lastName }}",
        "resource": "person",
        "additionalFields": {}
      },
      "typeVersion": 1
    },
    {
      "id": "6547b18d-f675-4890-ba35-6b3e257a63ba",
      "name": "Prepare New Notification",
      "type": "n8n-nodes-base.code",
      "position": [
        2112,
        528
      ],
      "parameters": {
        "jsCode": "const d = $input.item.json;\nreturn [{ json: { ...d, notificationType: 'new' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "1953300c-92df-4603-9aeb-e6947b7c3a93",
      "name": "Update Person",
      "type": "n8n-nodes-base.pipedrive",
      "position": [
        1920,
        336
      ],
      "parameters": {
        "personId": "={{ $json.personId }}",
        "resource": "person",
        "operation": "update",
        "updateFields": {}
      },
      "typeVersion": 1
    },
    {
      "id": "100ebfaa-0123-45e2-b32e-4a2f30eb1158",
      "name": "Prepare Updated Notification",
      "type": "n8n-nodes-base.code",
      "position": [
        2448,
        320
      ],
      "parameters": {
        "jsCode": "const d = $input.item.json;\nreturn [{ json: { ...d, notificationType: 'updated' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "e579c91d-09eb-429d-a0c0-a0e7ec9cc12f",
      "name": "Merge Notifications",
      "type": "n8n-nodes-base.merge",
      "position": [
        2640,
        496
      ],
      "parameters": {
        "mode": "mergeByIndex",
        "options": {}
      },
      "typeVersion": 2
    },
    {
      "id": "8ba16c91-af56-48e6-9296-f0c6acb69022",
      "name": "Build Mailchimp Payload",
      "type": "n8n-nodes-base.code",
      "position": [
        2896,
        432
      ],
      "parameters": {
        "jsCode": "const { email, firstName, lastName, notificationType } = $input.item.json;\nreturn [{\n  json: {\n    email,\n    firstName,\n    lastName,\n    tag: notificationType === 'new' ? 'New' : 'Updated'\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "5640ca3e-be77-47b6-a2b4-484db733a681",
      "name": "Send Sync Notification",
      "type": "n8n-nodes-base.mailchimp",
      "position": [
        3104,
        368
      ],
      "parameters": {
        "options": {},
        "mergeFieldsUi": {
          "mergeFieldsValues": [
            {},
            {}
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "b6afc1b9-0ee5-41f6-9b61-e615f9e587d7",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -624,
        32
      ],
      "parameters": {
        "width": 550,
        "height": 834,
        "content": "## How it works\nThis workflow keeps contact records aligned across your CRM stack whenever the source CRM fires a webhook. Each inbound contact ID is expanded into full profile data via the source-CRM REST API, normalised into a common schema, and compared against Pipedrive. If the person already exists we update only the changed fields; otherwise we create a new person. Every successful sync is mirrored to Mailchimp so marketing lists stay fresh, while any workflow error auto-routes to a separate Mailchimp list for the operations team.\n\n## Setup steps\n1. Create a webhook in your source CRM pointing to the URL generated by the **Incoming Contact Webhook** node.  \n2. Add your Source-CRM credentials to the **Fetch Contact Details** HTTP node.  \n3. Configure Pipedrive credentials for all Pipedrive nodes.  \n4. Enter your Mailchimp API credentials & List IDs in the Mailchimp nodes.  \n5. Adjust field mappings in the two *Prepare Notification* code nodes if you need extra data.  \n6. Activate the workflow and run a test contact from your CRM to verify end-to-end syncing."
      },
      "typeVersion": 1
    },
    {
      "id": "3c6bdf3a-bab1-4cf5-8bb4-ee3d8b129bda",
      "name": "Trigger & Source",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        272,
        48
      ],
      "parameters": {
        "color": 7,
        "width": 610,
        "height": 734,
        "content": "## Trigger & Source\n\nThis section ingests webhook events from any modern CRM (HubSpot, Salesforce, etc.) that can push contact notifications. The **Incoming Contact Webhook** node exposes a POST endpoint that receives one or many contact IDs. Because webhooks often batch multiple changes, we immediately fan-out the payload using **Split Contacts**, then enrich each ID with the complete contact profile through an authenticated **HTTP Request** call to your source CRM. The **Normalize Contact Data** code node flattens vendor-specific field names into a shared format (email, firstName, lastName, phone, company, updatedAt). Keeping a single canonical shape at this early stage makes the downstream logic vendor-agnostic and easy to extend to additional CRMs later."
      },
      "typeVersion": 1
    },
    {
      "id": "0fab0022-c26b-49ef-813e-a8256946e42b",
      "name": "Pipedrive Sync",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        896,
        64
      ],
      "parameters": {
        "color": 7,
        "width": 1394,
        "height": 718,
        "content": "## Pipedrive Sync\n\nNodes in this block handle the heavy lifting of matching incoming contacts against Pipedrive and writing changes. After normalisation we perform a **Search Person by Email** operation which returns zero or more potential matches. A quick **Merge** combines the search response with the source data so we can evaluate both in one place. The **Determine Existence & Prepare Data** code node extracts personId (when found) and flags whether we are in *create* or *update* mode. The **IF** node then routes the execution accordingly: new contacts go to **Create Person**, existing ones to **Update Person**. Field mappings are kept lean but you can enrich them with any custom fields Pipedrive supports."
      },
      "typeVersion": 1
    },
    {
      "id": "4481f4eb-66fa-47f6-ae78-9fdbf57ee80e",
      "name": "Notification & Error Handling",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2304,
        64
      ],
      "parameters": {
        "color": 7,
        "width": 1026,
        "height": 622,
        "content": "## Mailchimp Notification & Error Handling\n\nOnce Pipedrive confirms a successful create or update, the workflow prepares a concise payload for Mailchimp. Both success branches funnel into a **Merge Notifications** node, then a small code snippet decorates the payload with a contextual tag (*New* or *Updated*) before passing it to **Send Sync Notification**. This Mailchimp call performs an upsert operation so your marketing audience is always in lock-step with the CRM. An isolated **Error Trigger** path captures any failure in the entire workflow and fires a secondary Mailchimp call that sends an alert to your operations list. This keeps the alerting mechanism consistent and avoids scattering credentials across multiple services."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "403277de-94ba-4d15-a7b0-7d8799bcde63",
  "connections": {
    "Create Person": {
      "main": [
        [
          {
            "node": "Prepare New Notification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Person": {
      "main": [
        [
          {
            "node": "Prepare Updated Notification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Contacts": {
      "main": [
        [
          {
            "node": "Fetch Contact Details (Source CRM)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Person Existing?": {
      "main": [
        [
          {
            "node": "Update Person",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Create Person",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Notifications": {
      "main": [
        [
          {
            "node": "Build Mailchimp Payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Contact Data": {
      "main": [
        [
          {
            "node": "Search Person by Email",
            "type": "main",
            "index": 0
          },
          {
            "node": "Combine Contact & Search",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Person by Email": {
      "main": [
        [
          {
            "node": "Combine Contact & Search",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Send Sync Notification": {
      "main": [
        []
      ]
    },
    "Build Mailchimp Payload": {
      "main": [
        [
          {
            "node": "Send Sync Notification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Combine Contact & Search": {
      "main": [
        [
          {
            "node": "Determine Existence & Prepare Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Incoming Contact Webhook": {
      "main": [
        [
          {
            "node": "Split Contacts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare New Notification": {
      "main": [
        [
          {
            "node": "Merge Notifications",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Prepare Updated Notification": {
      "main": [
        [
          {
            "node": "Merge Notifications",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Determine Existence & Prepare Data": {
      "main": [
        [
          {
            "node": "Is Person Existing?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Contact Details (Source CRM)": {
      "main": [
        [
          {
            "node": "Normalize Contact Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}