{
  "name": "Update rotate seedlist on HubSpot",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "update_seedlist_hubspot",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        480,
        272
      ],
      "id": "09411a20-ec4e-40a5-aa08-4ec8d612b97d",
      "name": "Webhook",
      "webhookId": "c7cff830-571c-4a45-a29f-ec511643f43c"
    },
    {
      "parameters": {
        "mode": "raw",
        "jsonOutput": "{\n  \"split_info\": [\n    {\n      \"split_id\": \"\",\n      \"hubspot_list_id\": \"\"\n    }\n  ]\n}",
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        704,
        272
      ],
      "id": "c15e8ead-b8a4-4fb7-9429-5b72ce4cd131",
      "name": "Set Workflow Global Variables"
    },
    {
      "parameters": {
        "jsCode": "const events = [$('Webhook').first().json.body];\n\nconst setupArr = $items('Set Workflow Global Variables').map(i => i.json);\nconst setup = setupArr[0].split_info;\n\nlet result = [];\n\nfor (const e of events) {\n  const affectedId = e.affected_id;\n  const action = e.action_key;\n\n  const info = setup.find(s => s.split_id === affectedId);\n  if (!info) continue;\n  if (action == \"seed_list_rotate\"){\n    result.push({\n      split_id: affectedId,\n      action_key: action,\n      hubspot_list_id: info.hubspot_list_id\n    });\n  }else{\n    result.push({\n      split_id: affectedId,\n      action_key: action,\n      hubspot_list_id: info.hubspot_list_id,\n      balanced: e.data.balanced_emails,\n      removed: e.data.removed_emails\n    });\n  }\n}\n\nreturn result.map(r => ({ json: r }));"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        928,
        272
      ],
      "id": "29590ff6-9453-451e-8b97-3a0393b7539e",
      "name": "Process Webhook Input Data",
      "alwaysOutputData": true
    },
    {
      "parameters": {
        "fieldToSplitOut": "results",
        "options": {}
      },
      "type": "n8n-nodes-base.splitOut",
      "typeVersion": 1,
      "position": [
        1376,
        176
      ],
      "id": "d077e8c2-eb2b-4794-a06d-83df54774172",
      "name": "Split Out"
    },
    {
      "parameters": {},
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3.2,
      "position": [
        2272,
        272
      ],
      "id": "24381938-efd1-4490-8ba2-ed859e3e0f79",
      "name": "Merge"
    },
    {
      "parameters": {
        "jsCode": "const contacts = $input.all().map(item => ({ id: item.json.recordId }));\nconst chunkSize = 100;\nconst chunks = [];\nfor (let i = 0; i < contacts.length; i += chunkSize) {\n  chunks.push(contacts.slice(i, i + chunkSize));\n}\nreturn chunks.map(contacts => ({ json: { contacts } }));"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1600,
        176
      ],
      "id": "9d69d07c-c1ae-4732-82da-04f820ed1910",
      "name": "Format body for request"
    },
    {
      "parameters": {
        "resource": "seedlist",
        "operation": "getSplitEmails",
        "splitId": "={{ $json.split_id }}",
        "returnAll": true
      },
      "type": "n8n-nodes-warmy-io.warmy",
      "typeVersion": 1,
      "position": [
        1824,
        368
      ],
      "id": "3bfaf9f8-16c3-47b2-a56c-d2210e64cb20",
      "name": "Get split emails",
      "credentials": {
        "warmyApi": {
          "id": "0RCYg41UzauUYZ6P",
          "name": "TEST ACC"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const hubspot_emails = $input.all()\n  .flatMap(item => item.json.results)\n  .map(contact => ({email: contact.properties.email, id: contact.id}));\nconst action_key = $('Process Webhook Input Data').first().json.action_key;\n\nif (action_key === 'seed_list_update'){\n  const balanced_emails = $('Process Webhook Input Data').first().json.balanced;\n  const removed = $('Process Webhook Input Data').first().json.removed;\n  return { json: { hubspot_emails, balanced_emails, removed } }; \n}\nreturn { json: { hubspot_emails } };"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2048,
        176
      ],
      "id": "97cb3bcc-7044-4910-bb96-77e2618757e3",
      "name": "Formate hubspot, balanced, removed"
    },
    {
      "parameters": {
        "jsCode": "const split_emails = $input.all().map(item => item.json.email);\nreturn {json: {split_emails}}"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2048,
        368
      ],
      "id": "2fa7f82f-2bf9-4fd7-b592-d9f5f83e2cbe",
      "name": "Format split emails"
    },
    {
      "parameters": {
        "jsCode": "const all = $input.all();\nconst pick = key => {\n  for (const it of all) {\n    const v = it.json?.[key];\n    if (v !== undefined) return v;\n  }\n  return undefined;\n};\n\nconst splitEmails    = pick('split_emails');\nconst balancedEmails = pick('balanced_emails');\nconst removed        = pick('removed')        || [];\nconst hubspotEmails  = pick('hubspot_emails') || [];\nconst listId         = $('Process Webhook Input Data').first().json.split_id;\n\nconst norm = e => (e || '').trim().toLowerCase();\n\nconst sourceEmails = (splitEmails ?? balancedEmails) || [];\nconst isFullSync   = splitEmails !== undefined;\n\nconst hubspotSet = new Set(hubspotEmails.map(c => norm(c.email)));\nconst splitSet   = new Set(sourceEmails.map(norm));\nconst removedSet = new Set(removed.map(norm));\n\nconst to_add = sourceEmails.filter(e => !hubspotSet.has(norm(e)));\n\nconst to_remove = hubspotEmails.filter(c => {\n  const e = norm(c.email);\n  return removedSet.has(e) || (isFullSync && !splitSet.has(e));\n});\n\nconst chunk = (arr, size = 100) => {\n  const out = [];\n  for (let i = 0; i < arr.length; i += size) out.push(arr.slice(i, i + size));\n  return out;\n};\n\nconst items = [];\n\nchunk(to_add).forEach((batch) => {\n  items.push({\n    json: {\n      list_id: listId,\n      operation: 'add',\n      emails: batch.map(email => ({ properties: { email } })),\n    }\n  });\n});\n\nchunk(to_remove).forEach((batch) => {\n  items.push({\n    json: {\n      list_id: listId,\n      operation: 'remove',\n      ids: batch.map(c => ({ id: c.id })),\n    }\n  });\n});\n\nreturn items;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2496,
        272
      ],
      "id": "aabf79ab-2d52-45d3-86c3-67daf75664eb",
      "name": "Create body for request"
    },
    {
      "parameters": {
        "url": "=https://api.hubapi.com/crm/lists/2026-03/{{ $json.hubspot_list_id }}/memberships",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "hubspotAppToken",
        "options": {
          "pagination": {
            "pagination": {
              "parameters": {
                "parameters": [
                  {
                    "name": "after",
                    "value": "={{ $response.body.paging.next.after }}"
                  }
                ]
              },
              "paginationCompleteWhen": "other",
              "completeExpression": "={{ $response.body.paging.next.after == null}}",
              "requestInterval": 5000
            }
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        1152,
        176
      ],
      "id": "23bed0c3-ac3f-4882-b479-f9ae7d2f4b08",
      "name": "HUBSPOT -- Get contacts from list",
      "credentials": {
        "hubspotAppToken": {
          "id": "TJ09jBeJHGRYUaHL",
          "name": "Test"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.hubapi.com/crm/objects/2026-03/0-1/batch/read",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "hubspotAppToken",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"properties\": [\"email\"],\n  \"inputs\": {{ JSON.stringify($json.contacts) }}\n}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        1824,
        176
      ],
      "id": "7ec21519-5980-47b0-bce2-84f6cefafbc8",
      "name": "HUBSPOT -- Get list emails",
      "credentials": {
        "hubspotAppToken": {
          "id": "TJ09jBeJHGRYUaHL",
          "name": "Test"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.hubapi.com/crm/objects/2026-03/0-1/batch/archive",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "hubspotAppToken",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"inputs\": {{JSON.stringify($json.ids)}}\n}",
        "options": {
          "batching": {
            "batch": {
              "batchSize": 1,
              "batchInterval": 5000
            }
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        2944,
        176
      ],
      "id": "b580f268-9856-4c34-93fb-c67d6eda8938",
      "name": "HUBSPOT -- Delete contacts",
      "credentials": {
        "hubspotAppToken": {
          "id": "TJ09jBeJHGRYUaHL",
          "name": "Test"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.hubapi.com/crm/objects/2026-03/0-1/batch/create",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "hubspotAppToken",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"inputs\": {{JSON.stringify($json.emails)}}\n}",
        "options": {
          "batching": {
            "batch": {
              "batchSize": 1,
              "batchInterval": 5000
            }
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        2944,
        368
      ],
      "id": "b3dd6b7a-8794-4711-a796-6e679d32a6df",
      "name": "HUBSPOT -- Create contacts",
      "credentials": {
        "hubspotAppToken": {
          "id": "TJ09jBeJHGRYUaHL",
          "name": "Test"
        }
      }
    },
    {
      "parameters": {
        "method": "PUT",
        "url": "=https://api.hubapi.com/crm/lists/2026-03/{{ $('Process Webhook Input Data').first().json.hubspot_list_id }}/memberships/add",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "hubspotAppToken",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify($json.results.map(item => Number(item.id))) }}",
        "options": {
          "batching": {
            "batch": {
              "batchSize": 1,
              "batchInterval": 5000
            }
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        3168,
        368
      ],
      "id": "8ebef60a-64e7-40af-9e65-9fc9db13f894",
      "name": "HUBSPOT -- Add contact to list",
      "credentials": {
        "hubspotAppToken": {
          "id": "TJ09jBeJHGRYUaHL",
          "name": "Test"
        }
      }
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.operation }}",
                    "rightValue": "remove",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "id": "62cd8b30-f770-4ff6-a032-3a03224a6142"
                  }
                ],
                "combinator": "and"
              }
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "2912aa2f-e494-4f1c-8ee1-ecc9b9967580",
                    "leftValue": "={{ $json.operation }}",
                    "rightValue": "add",
                    "operator": {
                      "type": "string",
                      "operation": "equals",
                      "name": "filter.operator.equals"
                    }
                  }
                ],
                "combinator": "and"
              }
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.4,
      "position": [
        2720,
        272
      ],
      "id": "a1c16682-af91-47ab-9fae-d232feaaf852",
      "name": "Add/delete"
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "4b50e2d8-fca4-44c6-a677-b152be2b9863",
                    "leftValue": "={{ $json.action_key }}",
                    "rightValue": "seed_list_rotate",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              }
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.4,
      "position": [
        1152,
        368
      ],
      "id": "1b336a6b-3c40-405a-9bb6-69a0b4f8f9a2",
      "name": "Update/Rotate"
    }
  ],
  "pinData": {},
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "Set Workflow Global Variables",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Workflow Global Variables": {
      "main": [
        [
          {
            "node": "Process Webhook Input Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process Webhook Input Data": {
      "main": [
        [
          {
            "node": "HUBSPOT -- Get contacts from list",
            "type": "main",
            "index": 0
          },
          {
            "node": "Update/Rotate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Out": {
      "main": [
        [
          {
            "node": "Format body for request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge": {
      "main": [
        [
          {
            "node": "Create body for request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format body for request": {
      "main": [
        [
          {
            "node": "HUBSPOT -- Get list emails",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get split emails": {
      "main": [
        [
          {
            "node": "Format split emails",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Formate hubspot, balanced, removed": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format split emails": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Create body for request": {
      "main": [
        [
          {
            "node": "Add/delete",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HUBSPOT -- Get contacts from list": {
      "main": [
        [
          {
            "node": "Split Out",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HUBSPOT -- Get list emails": {
      "main": [
        [
          {
            "node": "Formate hubspot, balanced, removed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HUBSPOT -- Create contacts": {
      "main": [
        [
          {
            "node": "HUBSPOT -- Add contact to list",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add/delete": {
      "main": [
        [
          {
            "node": "HUBSPOT -- Delete contacts",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "HUBSPOT -- Create contacts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update/Rotate": {
      "main": [
        [
          {
            "node": "Get split emails",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate",
    "availableInMCP": false
  },
  "versionId": "be8e2a52-9e9e-4ac7-9423-06c48d9ae29b",
  "meta": {
    "templateCredsSetupCompleted": true,
    "instanceId": "6f57e464250a9fd092024d89a5e7f85582364ce6c7ac3677734aa0fb1770e696"
  },
  "nodeGroups": [],
  "id": "boF0H6vbuJ8m0YQN",
  "tags": []
}