{
  "name": "REVOPS-L1-001 | 03 | HubSpot property setup",
  "nodes": [
    {
      "parameters": {},
      "id": "e4d16bcc-9280-4ef8-b273-c6d4f3f69d86",
      "name": "Create Missing Properties",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "return [\n  {\n    \"name\": \"revops_email_validation\",\n    \"label\": \"RevOps Email Validation\",\n    \"type\": \"enumeration\",\n    \"fieldType\": \"select\",\n    \"groupName\": \"contactinformation\",\n    \"description\": \"REVOPS-L1-001 lead routing and response automation\",\n    \"options\": [\n      {\n        \"label\": \"Email: Validated\",\n        \"value\": \"validated\",\n        \"displayOrder\": 0,\n        \"hidden\": false\n      },\n      {\n        \"label\": \"Email: Failed\",\n        \"value\": \"failed\",\n        \"displayOrder\": 1,\n        \"hidden\": false\n      },\n      {\n        \"label\": \"Email: Risky\",\n        \"value\": \"risky\",\n        \"displayOrder\": 2,\n        \"hidden\": false\n      },\n      {\n        \"label\": \"Email: Review\",\n        \"value\": \"review\",\n        \"displayOrder\": 3,\n        \"hidden\": false\n      }\n    ]\n  },\n  {\n    \"name\": \"revops_lead_priority\",\n    \"label\": \"RevOps Lead Priority\",\n    \"type\": \"enumeration\",\n    \"fieldType\": \"select\",\n    \"groupName\": \"contactinformation\",\n    \"description\": \"REVOPS-L1-001 lead routing and response automation\",\n    \"options\": [\n      {\n        \"label\": \"Lead: Hot\",\n        \"value\": \"hot\",\n        \"displayOrder\": 0,\n        \"hidden\": false\n      },\n      {\n        \"label\": \"Lead: Warm\",\n        \"value\": \"warm\",\n        \"displayOrder\": 1,\n        \"hidden\": false\n      },\n      {\n        \"label\": \"Lead: Cold\",\n        \"value\": \"cold\",\n        \"displayOrder\": 2,\n        \"hidden\": false\n      },\n      {\n        \"label\": \"Lead: Review\",\n        \"value\": \"review\",\n        \"displayOrder\": 3,\n        \"hidden\": false\n      }\n    ]\n  },\n  {\n    \"name\": \"revops_response_status\",\n    \"label\": \"RevOps Response Status\",\n    \"type\": \"enumeration\",\n    \"fieldType\": \"select\",\n    \"groupName\": \"contactinformation\",\n    \"description\": \"REVOPS-L1-001 lead routing and response automation\",\n    \"options\": [\n      {\n        \"label\": \"Pending\",\n        \"value\": \"pending\",\n        \"displayOrder\": 0,\n        \"hidden\": false\n      },\n      {\n        \"label\": \"Draft Only\",\n        \"value\": \"draft\",\n        \"displayOrder\": 1,\n        \"hidden\": false\n      },\n      {\n        \"label\": \"Human Review\",\n        \"value\": \"review\",\n        \"displayOrder\": 2,\n        \"hidden\": false\n      },\n      {\n        \"label\": \"Email Blocked\",\n        \"value\": \"blocked\",\n        \"displayOrder\": 3,\n        \"hidden\": false\n      },\n      {\n        \"label\": \"Suppressed\",\n        \"value\": \"suppressed\",\n        \"displayOrder\": 4,\n        \"hidden\": false\n      },\n      {\n        \"label\": \"Email Sent\",\n        \"value\": \"email_sent\",\n        \"displayOrder\": 5,\n        \"hidden\": false\n      },\n      {\n        \"label\": \"CRM Log Pending\",\n        \"value\": \"log_pending\",\n        \"displayOrder\": 6,\n        \"hidden\": false\n      }\n    ]\n  },\n  {\n    \"name\": \"revops_lead_score\",\n    \"label\": \"RevOps Lead Score\",\n    \"type\": \"number\",\n    \"fieldType\": \"number\",\n    \"groupName\": \"contactinformation\",\n    \"description\": \"REVOPS-L1-001 lead routing and response automation\"\n  },\n  {\n    \"name\": \"revops_score_reason\",\n    \"label\": \"RevOps Score Reason\",\n    \"type\": \"string\",\n    \"fieldType\": \"textarea\",\n    \"groupName\": \"contactinformation\",\n    \"description\": \"REVOPS-L1-001 lead routing and response automation\"\n  },\n  {\n    \"name\": \"revops_do_not_contact\",\n    \"label\": \"RevOps Do Not Contact\",\n    \"type\": \"bool\",\n    \"fieldType\": \"booleancheckbox\",\n    \"groupName\": \"contactinformation\",\n    \"description\": \"REVOPS-L1-001 lead routing and response automation\",\n    \"options\": [\n      {\n        \"label\": \"Yes\",\n        \"value\": \"true\",\n        \"displayOrder\": 0,\n        \"hidden\": false\n      },\n      {\n        \"label\": \"No\",\n        \"value\": \"false\",\n        \"displayOrder\": 1,\n        \"hidden\": false\n      }\n    ]\n  },\n  {\n    \"name\": \"revops_last_submission_id\",\n    \"label\": \"RevOps Last Submission ID\",\n    \"type\": \"string\",\n    \"fieldType\": \"text\",\n    \"groupName\": \"contactinformation\",\n    \"description\": \"REVOPS-L1-001 lead routing and response automation\"\n  },\n  {\n    \"name\": \"revops_draft_subject\",\n    \"label\": \"RevOps Draft Subject\",\n    \"type\": \"string\",\n    \"fieldType\": \"text\",\n    \"groupName\": \"contactinformation\",\n    \"description\": \"REVOPS-L1-001 lead routing and response automation\"\n  },\n  {\n    \"name\": \"revops_draft_body\",\n    \"label\": \"RevOps Draft Body\",\n    \"type\": \"string\",\n    \"fieldType\": \"textarea\",\n    \"groupName\": \"contactinformation\",\n    \"description\": \"REVOPS-L1-001 lead routing and response automation\"\n  },\n  {\n    \"name\": \"revops_last_provider_email_id\",\n    \"label\": \"RevOps Last Provider Email ID\",\n    \"type\": \"string\",\n    \"fieldType\": \"text\",\n    \"groupName\": \"contactinformation\",\n    \"description\": \"REVOPS-L1-001 lead routing and response automation\"\n  },\n  {\n    \"name\": \"revops_last_email_sent_at\",\n    \"label\": \"RevOps Last Email Sent At\",\n    \"type\": \"datetime\",\n    \"fieldType\": \"date\",\n    \"groupName\": \"contactinformation\",\n    \"description\": \"REVOPS-L1-001 lead routing and response automation\"\n  }\n].map(property=>({json:{property}}));"
      },
      "id": "2779c869-2086-468e-8c3a-4a8c22149f93",
      "name": "Property Definitions",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        260,
        0
      ]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "={{ 'https://api.hubapi.com/crm/v3/properties/contacts/' + $json.property.name }}",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "options": {
          "timeout": 30000,
          "response": {
            "response": {
              "fullResponse": true,
              "neverError": true,
              "responseFormat": "json"
            }
          }
        }
      },
      "id": "eef0be2f-8163-463b-8840-b68133fb98d1",
      "name": "Read Property",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        520,
        0
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "REPLACE_HUBSPOT_CREDENTIAL",
          "name": "REVOPS HubSpot"
        }
      }
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const results = $input.all();\nreturn results.map((item,i)=>{\n  const expected = $('Property Definitions').all()[i].json.property;\n  const r = item.json;\n  if (![200,404].includes(r.statusCode)) throw new Error(expected.name + ': HTTP ' + r.statusCode);\n  if (r.statusCode === 200) {\n    if (r.body.type !== expected.type || r.body.fieldType !== expected.fieldType) throw new Error('Existing property has incompatible type: ' + expected.name);\n    for (const option of expected.options || []) if (!(r.body.options || []).some(o=>o.value === option.value)) throw new Error('Existing property missing option ' + option.value + ': ' + expected.name);\n  }\n  return {json:{property:expected,create:r.statusCode === 404},pairedItem:{item:i}};\n});"
      },
      "id": "3590b6e4-1a9f-4317-b2b6-34ec2fa494c0",
      "name": "Inspect Property",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        780,
        0
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "762627e6-a9b4-4273-903b-1a5cd15adaaa",
              "leftValue": "={{ $json.create === true }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "32032126-e37f-4621-afaf-ce03afb29c97",
      "name": "Property Missing?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1040,
        0
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.hubapi.com/crm/v3/properties/contacts",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ $json.property }}",
        "options": {
          "timeout": 30000
        }
      },
      "id": "72dc321f-fac0-4e05-af65-114e7d7a9861",
      "name": "Create Property",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1300,
        0
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "REPLACE_HUBSPOT_CREDENTIAL",
          "name": "REVOPS HubSpot"
        }
      }
    },
    {
      "parameters": {
        "content": "## 03 — One-time HubSpot setup\nCreates only missing custom contact properties. Existing definitions are checked for compatible types/options.\nUse a HubSpot credential with contact schema read/write scopes.\nRe-running is safe; incompatible properties fail for review.\nEach HTTP item retains its expected property definition.",
        "width": 650,
        "height": 220
      },
      "id": "b4cd6645-6e7b-4ffa-a6eb-4588c7adfbc1",
      "name": "Guide 6",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        0,
        -260
      ]
    }
  ],
  "connections": {
    "Create Missing Properties": {
      "main": [
        [
          {
            "node": "Property Definitions",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Property Definitions": {
      "main": [
        [
          {
            "node": "Read Property",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Property": {
      "main": [
        [
          {
            "node": "Inspect Property",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Inspect Property": {
      "main": [
        [
          {
            "node": "Property Missing?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Property Missing?": {
      "main": [
        [
          {
            "node": "Create Property",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "timezone": "UTC",
    "saveManualExecutions": true,
    "saveExecutionProgress": true
  },
  "active": false,
  "pinData": {},
  "tags": []
}

