{
  "name": "REVOPS-LI-005 | 05 | HubSpot duplicate property setup",
  "nodes": [
    {
      "parameters": {},
      "id": "a74dc6e2-1f82-49e7-bf91-29ba778afb00",
      "name": "Setup Duplicate Properties",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "return [{\"objectType\":\"contacts\",\"property\":{\"name\":\"revops_duplicate_status\",\"label\":\"RevOps Duplicate Status\",\"type\":\"enumeration\",\"fieldType\":\"select\",\"options\":[{\"label\":\"DUPLICATE_CONFIRMED\",\"value\":\"DUPLICATE_CONFIRMED\",\"displayOrder\":0,\"hidden\":false},{\"label\":\"DUPLICATE_REVIEW_REQUIRED\",\"value\":\"DUPLICATE_REVIEW_REQUIRED\",\"displayOrder\":1,\"hidden\":false},{\"label\":\"POSSIBLE_DUPLICATE\",\"value\":\"POSSIBLE_DUPLICATE\",\"displayOrder\":2,\"hidden\":false},{\"label\":\"DUPLICATE_WEAK_MATCH\",\"value\":\"DUPLICATE_WEAK_MATCH\",\"displayOrder\":3,\"hidden\":false},{\"label\":\"NO_DUPLICATE_FOUND\",\"value\":\"NO_DUPLICATE_FOUND\",\"displayOrder\":4,\"hidden\":false},{\"label\":\"MERGE_APPROVAL_PENDING\",\"value\":\"MERGE_APPROVAL_PENDING\",\"displayOrder\":5,\"hidden\":false},{\"label\":\"MERGE_APPROVED\",\"value\":\"MERGE_APPROVED\",\"displayOrder\":6,\"hidden\":false},{\"label\":\"MERGE_REJECTED\",\"value\":\"MERGE_REJECTED\",\"displayOrder\":7,\"hidden\":false},{\"label\":\"MERGE_COMPLETED\",\"value\":\"MERGE_COMPLETED\",\"displayOrder\":8,\"hidden\":false},{\"label\":\"MERGE_FAILED\",\"value\":\"MERGE_FAILED\",\"displayOrder\":9,\"hidden\":false},{\"label\":\"DUPLICATE_ARCHIVED\",\"value\":\"DUPLICATE_ARCHIVED\",\"displayOrder\":10,\"hidden\":false}],\"groupName\":\"contactinformation\",\"description\":\"REVOPS-LI-005 duplicate governance\"}},{\"objectType\":\"contacts\",\"property\":{\"name\":\"revops_duplicate_score\",\"label\":\"RevOps Duplicate Score\",\"type\":\"number\",\"fieldType\":\"number\",\"groupName\":\"contactinformation\",\"description\":\"REVOPS-LI-005 duplicate governance\"}},{\"objectType\":\"contacts\",\"property\":{\"name\":\"revops_duplicate_match_type\",\"label\":\"RevOps Duplicate Match Type\",\"type\":\"string\",\"fieldType\":\"text\",\"groupName\":\"contactinformation\",\"description\":\"REVOPS-LI-005 duplicate governance\"}},{\"objectType\":\"contacts\",\"property\":{\"name\":\"revops_recommended_master_id\",\"label\":\"RevOps Recommended Master ID\",\"type\":\"string\",\"fieldType\":\"text\",\"groupName\":\"contactinformation\",\"description\":\"REVOPS-LI-005 duplicate governance\"}},{\"objectType\":\"contacts\",\"property\":{\"name\":\"revops_merge_candidate_id\",\"label\":\"RevOps Merge Candidate ID\",\"type\":\"string\",\"fieldType\":\"text\",\"groupName\":\"contactinformation\",\"description\":\"REVOPS-LI-005 duplicate governance\"}},{\"objectType\":\"contacts\",\"property\":{\"name\":\"revops_merge_completed_at\",\"label\":\"RevOps Merge Completed At\",\"type\":\"datetime\",\"fieldType\":\"date\",\"groupName\":\"contactinformation\",\"description\":\"REVOPS-LI-005 duplicate governance\"}},{\"objectType\":\"contacts\",\"property\":{\"name\":\"revops_merged_record_ids\",\"label\":\"RevOps Merged Record IDs\",\"type\":\"string\",\"fieldType\":\"textarea\",\"groupName\":\"contactinformation\",\"description\":\"REVOPS-LI-005 duplicate governance\"}},{\"objectType\":\"companies\",\"property\":{\"name\":\"revops_duplicate_status\",\"label\":\"RevOps Duplicate Status\",\"type\":\"enumeration\",\"fieldType\":\"select\",\"options\":[{\"label\":\"DUPLICATE_CONFIRMED\",\"value\":\"DUPLICATE_CONFIRMED\",\"displayOrder\":0,\"hidden\":false},{\"label\":\"DUPLICATE_REVIEW_REQUIRED\",\"value\":\"DUPLICATE_REVIEW_REQUIRED\",\"displayOrder\":1,\"hidden\":false},{\"label\":\"POSSIBLE_DUPLICATE\",\"value\":\"POSSIBLE_DUPLICATE\",\"displayOrder\":2,\"hidden\":false},{\"label\":\"DUPLICATE_WEAK_MATCH\",\"value\":\"DUPLICATE_WEAK_MATCH\",\"displayOrder\":3,\"hidden\":false},{\"label\":\"NO_DUPLICATE_FOUND\",\"value\":\"NO_DUPLICATE_FOUND\",\"displayOrder\":4,\"hidden\":false},{\"label\":\"MERGE_APPROVAL_PENDING\",\"value\":\"MERGE_APPROVAL_PENDING\",\"displayOrder\":5,\"hidden\":false},{\"label\":\"MERGE_APPROVED\",\"value\":\"MERGE_APPROVED\",\"displayOrder\":6,\"hidden\":false},{\"label\":\"MERGE_REJECTED\",\"value\":\"MERGE_REJECTED\",\"displayOrder\":7,\"hidden\":false},{\"label\":\"MERGE_COMPLETED\",\"value\":\"MERGE_COMPLETED\",\"displayOrder\":8,\"hidden\":false},{\"label\":\"MERGE_FAILED\",\"value\":\"MERGE_FAILED\",\"displayOrder\":9,\"hidden\":false},{\"label\":\"DUPLICATE_ARCHIVED\",\"value\":\"DUPLICATE_ARCHIVED\",\"displayOrder\":10,\"hidden\":false}],\"groupName\":\"companyinformation\",\"description\":\"REVOPS-LI-005 duplicate governance\"}},{\"objectType\":\"companies\",\"property\":{\"name\":\"revops_duplicate_score\",\"label\":\"RevOps Duplicate Score\",\"type\":\"number\",\"fieldType\":\"number\",\"groupName\":\"companyinformation\",\"description\":\"REVOPS-LI-005 duplicate governance\"}},{\"objectType\":\"companies\",\"property\":{\"name\":\"revops_duplicate_match_type\",\"label\":\"RevOps Duplicate Match Type\",\"type\":\"string\",\"fieldType\":\"text\",\"groupName\":\"companyinformation\",\"description\":\"REVOPS-LI-005 duplicate governance\"}},{\"objectType\":\"companies\",\"property\":{\"name\":\"revops_recommended_master_id\",\"label\":\"RevOps Recommended Master ID\",\"type\":\"string\",\"fieldType\":\"text\",\"groupName\":\"companyinformation\",\"description\":\"REVOPS-LI-005 duplicate governance\"}},{\"objectType\":\"companies\",\"property\":{\"name\":\"revops_merge_candidate_id\",\"label\":\"RevOps Merge Candidate ID\",\"type\":\"string\",\"fieldType\":\"text\",\"groupName\":\"companyinformation\",\"description\":\"REVOPS-LI-005 duplicate governance\"}},{\"objectType\":\"companies\",\"property\":{\"name\":\"revops_merge_completed_at\",\"label\":\"RevOps Merge Completed At\",\"type\":\"datetime\",\"fieldType\":\"date\",\"groupName\":\"companyinformation\",\"description\":\"REVOPS-LI-005 duplicate governance\"}},{\"objectType\":\"companies\",\"property\":{\"name\":\"revops_merged_record_ids\",\"label\":\"RevOps Merged Record IDs\",\"type\":\"string\",\"fieldType\":\"textarea\",\"groupName\":\"companyinformation\",\"description\":\"REVOPS-LI-005 duplicate governance\"}},{\"objectType\":\"contacts\",\"property\":{\"name\":\"revops_do_not_contact\",\"label\":\"RevOps Do Not Contact\",\"type\":\"bool\",\"fieldType\":\"booleancheckbox\",\"groupName\":\"contactinformation\",\"description\":\"Merge safety control\",\"options\":[{\"label\":\"true\",\"value\":\"true\",\"displayOrder\":0,\"hidden\":false},{\"label\":\"false\",\"value\":\"false\",\"displayOrder\":1,\"hidden\":false}]}},{\"objectType\":\"contacts\",\"property\":{\"name\":\"revops_sequence_enrolled\",\"label\":\"RevOps Sequence Enrolled\",\"type\":\"bool\",\"fieldType\":\"booleancheckbox\",\"groupName\":\"contactinformation\",\"description\":\"Merge safety control\",\"options\":[{\"label\":\"true\",\"value\":\"true\",\"displayOrder\":0,\"hidden\":false},{\"label\":\"false\",\"value\":\"false\",\"displayOrder\":1,\"hidden\":false}]}},{\"objectType\":\"contacts\",\"property\":{\"name\":\"revops_linkedin_profile_url\",\"label\":\"RevOps LinkedIn Profile URL\",\"type\":\"string\",\"fieldType\":\"text\",\"groupName\":\"contactinformation\",\"description\":\"Optional duplicate signal\"}},{\"objectType\":\"companies\",\"property\":{\"name\":\"revops_company_linkedin_url\",\"label\":\"RevOps Company LinkedIn URL\",\"type\":\"string\",\"fieldType\":\"text\",\"groupName\":\"companyinformation\",\"description\":\"Optional duplicate signal\"}}].map(x=>({json:x}));"
      },
      "id": "68362bf1-a219-48c0-9135-43e38084d39e",
      "name": "Property Definitions",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        270,
        0
      ]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "={{ 'https://api.hubapi.com/crm/v3/properties/'+$json.objectType+'/'+$json.property.name }}",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "options": {
          "timeout": 30000,
          "response": {
            "response": {
              "fullResponse": true,
              "neverError": true,
              "responseFormat": "json"
            }
          }
        }
      },
      "id": "0249e3c7-7af4-47dd-bb25-fe9807005c83",
      "name": "Read Existing Property",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        540,
        0
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "REPLACE_HUBSPOT_CREDENTIAL",
          "name": "ATTRIBUTION HubSpot"
        }
      }
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const defs=$('Property Definitions').all();return $input.all().map((item,i)=>{const d=defs[i].json,r=item.json;if(![200,404].includes(r.statusCode))throw new Error('Property lookup failed: '+d.property.name);if(r.statusCode===200&&(r.body.type!==d.property.type||r.body.fieldType!==d.property.fieldType))throw new Error('Incompatible existing property: '+d.property.name);return {json:{...d,missing:r.statusCode===404},pairedItem:{item:i}}});"
      },
      "id": "f9b2f1dc-0d42-454c-b2ba-d68ec9cbc62c",
      "name": "Validate Definition",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        810,
        0
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "b756fa93-dcca-4299-911c-73fa6053e744",
              "leftValue": "={{ $json.missing === true }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "5d64ba46-2e46-4a7e-a929-d0c31095cff6",
      "name": "Property Missing?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1080,
        0
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ 'https://api.hubapi.com/crm/v3/properties/'+$json.objectType }}",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "contentType": "json",
        "specifyBody": "json",
        "jsonBody": "={{ $json.property }}",
        "options": {
          "timeout": 30000
        }
      },
      "id": "8899fb85-3456-428d-b5e8-6072573cdbc3",
      "name": "Create Missing Property",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1350,
        0
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "REPLACE_HUBSPOT_CREDENTIAL",
          "name": "ATTRIBUTION HubSpot"
        }
      }
    },
    {
      "parameters": {
        "content": "## Optional HubSpot governance fields\nCreates missing custom fields for contacts and companies and refuses incompatible existing types.\nDetection and approval state remains authoritative in PostgreSQL. The merge executor does not depend on these fields.",
        "width": 700,
        "height": 220
      },
      "id": "7152e9a4-52b3-4b24-8c6e-34675f83329b",
      "name": "Workflow Guide",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        0,
        -270
      ]
    }
  ],
  "connections": {
    "Setup Duplicate Properties": {
      "main": [
        [
          {
            "node": "Property Definitions",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Property Definitions": {
      "main": [
        [
          {
            "node": "Read Existing Property",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Existing Property": {
      "main": [
        [
          {
            "node": "Validate Definition",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Definition": {
      "main": [
        [
          {
            "node": "Property Missing?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Property Missing?": {
      "main": [
        [
          {
            "node": "Create Missing Property",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "timezone": "Asia/Tbilisi",
    "saveExecutionProgress": true
  },
  "active": false,
  "pinData": {},
  "tags": []
}
