How to Build Housecall Pro Webhook Automations with n8n (Free Template)

How to Build Housecall Pro Webhook Automations with n8n (Free Template)

Field service businesses lose hours every week manually syncing Housecall Pro data to spreadsheets, CRMs, and notification systems. When a new job gets created, technicians get assigned, or a customer updates their information, that data needs to flow everywhere—instantly. This n8n workflow automates the entire process using Housecall Pro's webhook system, eliminating manual data entry and ensuring your team always has current information.

You'll learn how to capture Housecall Pro events in real-time, process the data through custom business logic, and route it to multiple destinations automatically. By the end, you'll have a production-ready automation template you can customize for your specific workflow needs.

The Problem: Manual Data Sync Kills Productivity

Field service companies using Housecall Pro face constant data synchronization challenges. Every new job, customer update, or schedule change requires manual updates across multiple systems.

Current challenges:

  • Technicians miss job details because information doesn't sync to their preferred tools
  • Sales teams work with outdated customer data from yesterday's exports
  • Managers spend 5-10 hours weekly copying data between Housecall Pro and Google Sheets
  • Pipeline stage changes don't trigger follow-up actions in CRMs or notification systems
  • Custom tags and notes get lost because they're buried in Housecall Pro's interface

Business impact:

  • Time spent: 10-15 hours per week on manual data entry
  • Delayed response times: 2-4 hour lag between job creation and team notification
  • Error rate: 15-20% of manual transfers contain incorrect or incomplete data
  • Revenue leakage: Missed follow-ups on jobs stuck in pipeline stages

The Solution Overview

This n8n workflow uses Housecall Pro's webhook system to capture events in real-time and automatically distribute data to your business tools. When Housecall Pro fires a webhook (new job created, customer updated, schedule changed), n8n receives it, processes the payload, and executes your custom logic—routing data to Google Sheets, sending Slack notifications, updating CRM records, or triggering follow-up sequences.

The workflow handles webhook authentication, payload parsing, field mapping, and error handling automatically. You configure it once, and it runs continuously without manual intervention.

What You'll Build

This automation captures Housecall Pro webhook events and processes them through a flexible routing system that adapts to your business needs.

Component Technology Purpose
Webhook Receiver n8n Webhook node Captures Housecall Pro events in real-time
Authentication HTTP Header validation Verifies webhook requests are from Housecall Pro
Data Processing Function nodes Extracts and transforms HCP payload data
Routing Logic Switch/IF nodes Directs events to appropriate destinations
Google Sheets Sync Google Sheets API Logs all events for reporting and analysis
Notification System Slack/Email nodes Alerts team members of critical events
CRM Integration HTTP Request nodes Updates customer records in external systems
Error Handling Error Trigger workflow Captures and logs failed executions

Key capabilities:

  • Processes unlimited webhook events from Housecall Pro
  • Handles multiple event types (jobs, customers, schedules, estimates)
  • Routes data based on custom business rules (tags, pipeline stages, job types)
  • Maintains audit trail in Google Sheets with timestamps
  • Sends conditional notifications based on event properties
  • Updates external CRMs with formatted customer data
  • Retries failed API calls automatically
  • Logs errors for troubleshooting

Prerequisites

Before starting, ensure you have:

  • n8n instance (cloud or self-hosted with public URL)
  • Housecall Pro account with API access enabled
  • Housecall Pro API key from Settings → Integrations → API
  • Google Sheets with write permissions for your service account
  • Slack workspace (if using Slack notifications)
  • Basic JavaScript knowledge for Function node customizations
  • Understanding of webhook concepts and HTTP requests

Step 1: Configure Housecall Pro Webhook Endpoint

Your n8n workflow needs a public URL to receive webhook events from Housecall Pro. This is where HCP will send data every time a relevant event occurs.

Set up the Webhook node:

  1. Add a Webhook node as your workflow's trigger
  2. Set HTTP Method to POST
  3. Set Path to /housecall-pro-webhook (or your preferred endpoint)
  4. Enable "Respond Immediately" to acknowledge receipt to HCP
  5. Set Response Code to 200
  6. Copy the Production URL (looks like https://your-n8n-instance.com/webhook/housecall-pro-webhook)

Node configuration:

{
  "httpMethod": "POST",
  "path": "housecall-pro-webhook",
  "responseMode": "onReceived",
  "responseCode": 200,
  "options": {
    "rawBody": true
  }
}

Register webhook in Housecall Pro:

  1. Log into Housecall Pro → Settings → Integrations → Webhooks
  2. Click "Add Webhook"
  3. Paste your n8n webhook URL
  4. Select events to monitor: job.created, job.updated, customer.created, customer.updated, schedule.updated
  5. Add your webhook secret for authentication (save this—you'll need it)
  6. Click "Save" and test the connection

Why this works:
Housecall Pro sends HTTP POST requests to your webhook URL whenever subscribed events occur. The rawBody option preserves the exact payload structure, which is critical for signature verification. Responding immediately (status 200) prevents HCP from marking your webhook as failed and retrying unnecessarily.

Step 2: Authenticate and Parse Webhook Payload

Housecall Pro includes a signature header to verify webhook authenticity. You must validate this before processing any data to prevent unauthorized requests from triggering your workflow.

Add Function node for signature verification:

// Extract signature from headers
const signature = $input.item.headers['x-housecallpro-signature'];
const secret = 'YOUR_WEBHOOK_SECRET'; // Store in n8n credentials
const payload = JSON.stringify($input.item.body);

// Verify signature using HMAC SHA256
const crypto = require('crypto');
const expectedSignature = crypto
  .createHmac('sha256', secret)
  .update(payload)
  .digest('hex');

if (signature !== expectedSignature) {
  throw new Error('Invalid webhook signature');
}

// Parse and return the event data
return {
  json: {
    eventType: $input.item.body.event,
    eventId: $input.item.body.id,
    timestamp: $input.item.body.created_at,
    data: $input.item.body.data
  }
};

Extract key fields with Set node:

  1. Add a Set node after signature verification
  2. Map Housecall Pro fields to standardized names:
    • job_id{{ $json.data.id }}
    • customer_name{{ $json.data.customer.first_name }} {{ $json.data.customer.last_name }}
    • job_type{{ $json.data.job_type }}
    • pipeline_stage{{ $json.data.lead_source }}
    • tags{{ $json.data.tags.join(', ') }}
    • scheduled_date{{ $json.data.scheduled_start }}
    • technician{{ $json.data.pro.name }}

Why this approach:
Signature verification prevents malicious actors from triggering your workflow with fake data. The Set node standardizes field names across different event types, making downstream processing consistent. This structure lets you handle job.created and job.updated events with the same logic.

Variables to customize:

  • secret: Your Housecall Pro webhook secret from Settings
  • Field mappings: Adjust based on which HCP fields you need
  • eventType filtering: Add conditions to process only specific events

Step 3: Route Events Based on Business Logic

Different Housecall Pro events require different actions. A new job might trigger a Slack notification, while a customer update might sync to your CRM. Use Switch nodes to route events intelligently.

Configure Switch node for event routing:

{
  "mode": "rules",
  "rules": [
    {
      "name": "New Job Created",
      "conditions": {
        "string": [
          {
            "value1": "={{ $json.eventType }}",
            "operation": "equals",
            "value2": "job.created"
          }
        ]
      }
    },
    {
      "name": "Job Updated",
      "conditions": {
        "string": [
          {
            "value1": "={{ $json.eventType }}",
            "operation": "equals",
            "value2": "job.updated"
          }
        ]
      }
    },
    {
      "name": "Customer Created/Updated",
      "conditions": {
        "string": [
          {
            "value1": "={{ $json.eventType }}",
            "operation": "contains",
            "value2": "customer"
          }
        ]
      }
    }
  ]
}

Add conditional logic for pipeline stages:

For jobs in specific pipeline stages, add a second Switch node:

// Function node to check pipeline stage and tags
const stage = $json.pipeline_stage;
const tags = $json.tags ? $json.tags.split(', ') : [];

return {
  json: {
    ...$json,
    isHighPriority: tags.includes('urgent') || tags.includes('vip'),
    requiresFollowup: stage === 'estimate_sent' || stage === 'needs_scheduling',
    notifyManager: $json.job_value > 5000
  }
};

Why this works:
Switch nodes create parallel processing paths without complex nested IF statements. Each route can have completely different logic—one path logs to Google Sheets, another sends Slack alerts, a third updates your CRM. The Function node adds computed fields based on your business rules, making downstream decisions cleaner.

Step 4: Sync Data to Google Sheets

Every webhook event should create an audit trail. Google Sheets provides a simple, accessible log that non-technical team members can review.

Configure Google Sheets node:

  1. Add Google Sheets node after your routing logic
  2. Set Operation to "Append Row"
  3. Select your spreadsheet and worksheet
  4. Map fields to columns:
Column Value Format
Timestamp {{ $now.toISO() }} ISO 8601
Event Type {{ $json.eventType }} Text
Job ID {{ $json.job_id }} Text
Customer Name {{ $json.customer_name }} Text
Job Type {{ $json.job_type }} Text
Pipeline Stage {{ $json.pipeline_stage }} Text
Tags {{ $json.tags }} Text
Scheduled Date {{ $json.scheduled_date }} Date
Technician {{ $json.technician }} Text
Job Value {{ $json.job_value }} Number

Add conditional columns for specific event types:

// Function node before Google Sheets
const baseData = { ...$json };

// Add event-specific fields
if ($json.eventType === 'job.created') {
  baseData.source = 'New Job';
  baseData.action_required = 'Assign Technician';
} else if ($json.eventType === 'job.updated') {
  baseData.source = 'Job Update';
  baseData.action_required = 'Review Changes';
}

return { json: baseData };

Why this approach:
Google Sheets creates a permanent, searchable record of every Housecall Pro event. Team members can filter by date, job type, or technician without accessing n8n. The ISO timestamp ensures proper sorting. Conditional columns let you track different data points for different event types without creating multiple spreadsheets.

Step 5: Send Conditional Notifications

High-priority events need immediate attention. Configure Slack or email notifications based on job value, tags, or pipeline stages.

Set up Slack notification node:

{
  "channel": "#field-ops",
  "text": "🚨 High Priority Job Created",
  "attachments": [
    {
      "color": "#FF0000",
      "fields": [
        {
          "title": "Customer",
          "value": "={{ $json.customer_name }}",
          "short": true
        },
        {
          "title": "Job Type",
          "value": "={{ $json.job_type }}",
          "short": true
        },
        {
          "title": "Value",
          "value": "$={{ $json.job_value }}",
          "short": true
        },
        {
          "title": "Scheduled",
          "value": "={{ $json.scheduled_date }}",
          "short": true
        },
        {
          "title": "Tags",
          "value": "={{ $json.tags }}",
          "short": false
        }
      ],
      "actions": [
        {
          "type": "button",
          "text": "View in HCP",
          "url": "https://pro.housecallpro.com/jobs/={{ $json.job_id }}"
        }
      ]
    }
  ]
}

Add IF node before notification:

// Only notify if conditions are met
const shouldNotify = 
  $json.isHighPriority || 
  $json.job_value > 5000 || 
  $json.tags.includes('urgent');

return shouldNotify ? [$json] : [];

Why this works:
Slack attachments create rich, actionable notifications with direct links to Housecall Pro. The IF node prevents notification fatigue by only alerting on truly important events. Color coding (red for urgent, yellow for follow-up needed) helps team members prioritize at a glance.

Workflow Architecture Overview

This workflow consists of 12 core nodes organized into 4 main sections:

  1. Webhook ingestion (Nodes 1-3): Receives HCP webhooks, validates signatures, extracts event data
  2. Routing logic (Nodes 4-6): Determines event type, applies business rules, calculates priority flags
  3. Data distribution (Nodes 7-10): Logs to Google Sheets, sends notifications, updates external systems
  4. Error handling (Nodes 11-12): Captures failures, logs errors, sends admin alerts

Execution flow:

  • Trigger: Housecall Pro webhook POST request
  • Average run time: 2-4 seconds per event
  • Key dependencies: Google Sheets API, Slack API, Housecall Pro webhook secret

Critical nodes:

  • Webhook Trigger: Must have public URL; HCP requires HTTPS in production
  • Function (Signature Verify): Prevents unauthorized webhook execution; uses crypto library
  • Switch (Event Router): Directs different event types to appropriate processing paths
  • Google Sheets (Audit Log): Creates permanent record; must have append permissions
  • IF (Notification Filter): Prevents alert fatigue; customize conditions for your team

The complete n8n workflow JSON template is available at the bottom of this article.

Key Configuration Details

Housecall Pro API Authentication

Required fields:

  • API Key: Found in HCP Settings → Integrations → API
  • Webhook Secret: Created when registering webhook endpoint
  • Base URL: https://api.housecallpro.com/v1

Common issues:

  • Using wrong API version → Results in 404 errors; always use /v1/ endpoints
  • Missing webhook secret → Signature validation fails; retrieve from HCP webhook settings
  • Rate limiting → HCP limits to 120 requests/minute; add retry logic with exponential backoff

Google Sheets Integration

Required setup:

  1. Create Google Cloud project
  2. Enable Google Sheets API
  3. Create service account
  4. Share spreadsheet with service account email
  5. Add service account credentials to n8n

Field mapping considerations:

  • Date fields: Convert HCP timestamps to readable format using {{ $json.scheduled_date.split('T')[0] }}
  • Currency: Format as number, not text: {{ parseFloat($json.job_value) }}
  • Arrays: Join tags with delimiter: {{ $json.tags.join(', ') }}

Slack Notification Setup

Authentication:

  • Create Slack app at api.slack.com/apps
  • Add chat:write and chat:write.public scopes
  • Install app to workspace
  • Copy Bot User OAuth Token to n8n credentials

Channel configuration:

  • Use channel ID, not name: #field-opsC01234ABCDE
  • Bot must be invited to private channels
  • Test with /invite @YourBotName in Slack

Testing & Validation

Test each component individually:

  1. Webhook reception: Use Housecall Pro's "Test Webhook" button to send sample payload
  2. Signature verification: Temporarily log the computed signature and compare to header value
  3. Data parsing: Add a "Stop and Error" node after Set node to inspect extracted fields
  4. Google Sheets: Verify row appears with correct data in all columns
  5. Notifications: Check Slack channel for formatted message with working HCP link

Common troubleshooting steps:

Issue Cause Solution
Webhook not receiving data Firewall blocking HCP IPs Whitelist HCP webhook IPs in n8n hosting
Signature validation fails Wrong secret or encoding Verify secret matches HCP settings; check rawBody enabled
Missing fields in Sheets Field path incorrect Use {{ $json }} to inspect full payload structure
Slack message fails Bot not in channel Invite bot with /invite @BotName
Duplicate rows in Sheets Webhook retry Add deduplication logic using event ID

Run test scenarios:

  1. Create test job in Housecall Pro with "urgent" tag
  2. Verify Google Sheets row appears within 5 seconds
  3. Confirm Slack notification sent to correct channel
  4. Update job to different pipeline stage
  5. Verify second row appears with updated data

Production Deployment Checklist

Area Requirement Why It Matters
Error Handling Add Error Trigger workflow with retry logic Prevents data loss when APIs are temporarily down
Monitoring Set up n8n webhook health checks every 5 minutes Detects failures within 5 minutes vs discovering days later
Credentials Store all API keys in n8n Credentials, not hardcoded Enables key rotation without editing workflow
Rate Limiting Add Wait node between API calls if processing >100 events/hour Prevents hitting Housecall Pro or Google API limits
Logging Enable workflow execution history for 30 days Allows debugging of historical issues
Documentation Add Sticky Notes in workflow explaining each section Reduces modification time by 2-4 hours for new team members
Backup Export workflow JSON weekly to version control Enables rollback if changes break production
Alerting Send admin notification on 3+ consecutive failures Ensures critical issues get immediate attention

Production-specific settings:

{
  "settings": {
    "executionTimeout": 300,
    "saveExecutionProgress": true,
    "saveDataErrorExecution": "all",
    "saveDataSuccessExecution": "all",
    "maxExecutionTime": 300
  }
}

Real-World Use Cases

Use Case 1: Multi-Location Service Company

  • Industry: HVAC with 5 locations
  • Scale: 200-300 jobs/day across all locations
  • Modifications needed: Add location-based routing to send notifications to regional Slack channels; filter Google Sheets by location code; route high-value jobs (>$10k) to regional managers

Use Case 2: Residential Plumbing with CRM Integration

  • Industry: Residential plumbing services
  • Scale: 50-75 jobs/day
  • Modifications needed: Add HTTP Request node to sync customer data to HubSpot CRM; map HCP pipeline stages to HubSpot deal stages; trigger email sequences based on job completion status

Use Case 3: Property Management Maintenance

  • Industry: Property management maintenance coordination
  • Scale: 100-150 work orders/day
  • Modifications needed: Add property address parsing to route jobs by building; integrate with property management software via API; send tenant notifications via email when technician is assigned

Use Case 4: Emergency Service Dispatch

  • Industry: Emergency restoration (water damage, fire damage)
  • Scale: 20-30 emergency calls/day
  • Modifications needed: Priority routing for "emergency" tagged jobs; SMS notifications to on-call technicians via Twilio; automatic escalation if job not acknowledged within 15 minutes

Use Case 5: Recurring Service Contracts

  • Industry: Pool maintenance and cleaning
  • Scale: 500+ recurring service appointments/month
  • Modifications needed: Filter for recurring jobs vs one-time; track service completion rates in separate Google Sheet; send customer satisfaction surveys via email after job completion

Customizing This Workflow

Alternative Integrations

Instead of Google Sheets:

  • Airtable: Better for complex relational data - swap Google Sheets node for Airtable node, map to base/table
  • PostgreSQL/Supabase: Best for high-volume operations (>1000 events/day) - replace with Postgres node, create table schema first
  • Microsoft Excel (OneDrive): Use if organization is Microsoft-centric - requires OneDrive node with similar field mapping

Instead of Slack:

  • Microsoft Teams: Use Teams node with webhook connector - requires channel webhook URL
  • Email: Add Send Email node for less urgent notifications - group multiple events into digest format
  • SMS via Twilio: For critical alerts requiring immediate response - add Twilio node with phone number routing

Workflow Extensions

Add automated follow-up sequences:

  • Add Schedule Trigger node to check pipeline stages daily
  • Query Housecall Pro API for jobs stuck in "estimate_sent" for >3 days
  • Send automated follow-up emails to customers
  • Nodes needed: +6 (Schedule, HTTP Request, IF, Function, Send Email, Google Sheets log)

Integrate with accounting software:

  • Capture job.completed events
  • Extract invoice data from HCP payload
  • Create invoice in QuickBooks or Xero via API
  • Nodes needed: +4 (Switch route, HTTP Request, Function for data mapping, Error handler)

Build customer portal notifications:

  • Add webhook to catch job status changes
  • Send formatted updates to customer portal database
  • Trigger push notifications via Firebase
  • Nodes needed: +5 (Filter for customer-facing events, HTTP Request to portal API, Function for formatting, Error handler, Audit log)

Scale to handle more data:

  • Replace single Google Sheets append with batch processing
  • Add Queue node to handle bursts of 100+ simultaneous webhooks
  • Implement Redis caching for frequently accessed HCP data
  • Performance improvement: 5x faster for >500 events/hour

Integration possibilities:

Add This To Get This Complexity
QuickBooks integration Automatic invoice creation from completed jobs Medium (6 nodes)
Twilio SMS Text alerts to technicians for urgent jobs Easy (3 nodes)
HubSpot CRM Bidirectional customer data sync Medium (8 nodes)
Power BI connector Executive dashboards with live HCP data Medium (5 nodes)
Calendly Auto-schedule follow-up calls for estimates Medium (7 nodes)
ServiceTitan Sync jobs between HCP and ServiceTitan Complex (12+ nodes)

Get Started Today

Ready to automate your Housecall Pro workflows?

  1. Download the template: Scroll to the bottom of this article to copy the n8n workflow JSON
  2. Import to n8n: Go to Workflows → Import from URL or File, paste the JSON
  3. Configure your services: Add your Housecall Pro API key, webhook secret, Google Sheets credentials, and Slack token
  4. Register webhook in HCP: Copy your n8n webhook URL to Housecall Pro Settings → Integrations → Webhooks
  5. Test with sample data: Use HCP's "Test Webhook" button to verify everything works before going live
  6. Deploy to production: Activate the workflow and monitor the first 10-20 events closely

Need help customizing this workflow for your specific field service business? Schedule an intro call with Atherial at https://atherial.ai/contact.


N8N Workflow Template JSON

{
  "name": "Housecall Pro Webhook Automation",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "housecall-pro-webhook",
        "responseMode": "onReceived",
        "options": {
          "rawBody": true
        }
      },
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [250, 300]
    },
    {
      "parameters": {
        "functionCode": "const signature = $input.item.headers['x-housecallpro-signature'];
const secret = 'YOUR_WEBHOOK_SECRET';
const payload = JSON.stringify($input.item.body);

const crypto = require('crypto');
const expectedSignature = crypto.createHmac('sha256', secret).update(payload).digest('hex');

if (signature !== expectedSignature) {
  throw new Error('Invalid webhook signature');
}

return {
  json: {
    eventType: $input.item.body.event,
    eventId: $input.item.body.id,
    timestamp: $input.item.body.created_at,
    data: $input.item.body.data
  }
};"
      },
      "name": "Verify Signature",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [450, 300]
    },
    {
      "parameters": {
        "values": {
          "string": [
            {"name": "job_id", "value": "={{ $json.data.id }}"},
            {"name": "customer_name", "value": "={{ $json.data.customer.first_name }} {{ $json.data.customer.last_name }}"},
            {"name": "job_type", "value": "={{ $json.data.job_type }}"},
            {"name": "pipeline_stage", "value": "={{ $json.data.lead_source }}"},
            {"name": "tags", "value": "={{ $json.data.tags.join(', ') }}"},
            {"name": "scheduled_date", "value": "={{ $json.data.scheduled_start }}"},
            {"name": "technician", "value": "={{ $json.data.pro.name }}"}
          ]
        }
      },
      "name": "Extract Fields",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [650, 300]
    }
  ],
  "connections": {
    "Webhook": {
      "main": [[{"node": "Verify Signature", "type": "main", "index": 0}]]
    },
    "Verify Signature": {
      "main": [[{"node": "Extract Fields", "type": "main", "index": 0}]]
    }
  }
}

Complete N8N Workflow Template

Copy the JSON below and import it into your N8N instance via Workflows → Import from File

{
  "name": "Housecall Pro Webhook Automation Builder",
  "nodes": [
    {
      "id": "webhook-trigger",
      "name": "Housecall Pro Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        250,
        300
      ],
      "parameters": {
        "path": "housecall-pro-webhook",
        "httpMethod": "POST",
        "responseData": "firstEntryJson",
        "responseMode": "responseNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "map-data",
      "name": "Map HCP Payload",
      "type": "n8n-nodes-base.set",
      "position": [
        450,
        300
      ],
      "parameters": {
        "mode": "manual",
        "assignments": [
          {
            "name": "eventType",
            "value": "={{ $json.event_type }}"
          },
          {
            "name": "customerId",
            "value": "={{ $json.customer?.id }}"
          },
          {
            "name": "customerName",
            "value": "={{ $json.customer?.name }}"
          },
          {
            "name": "customerEmail",
            "value": "={{ $json.customer?.email }}"
          },
          {
            "name": "customerPhone",
            "value": "={{ $json.customer?.phone }}"
          },
          {
            "name": "jobId",
            "value": "={{ $json.job?.id }}"
          },
          {
            "name": "jobTitle",
            "value": "={{ $json.job?.title }}"
          },
          {
            "name": "jobStatus",
            "value": "={{ $json.job?.status }}"
          },
          {
            "name": "jobAmount",
            "value": "={{ $json.job?.amount }}"
          },
          {
            "name": "jobScheduledDate",
            "value": "={{ $json.job?.scheduled_date }}"
          },
          {
            "name": "jobNotes",
            "value": "={{ $json.job?.notes }}"
          },
          {
            "name": "timestamp",
            "value": "={{ new Date().toISOString() }}"
          }
        ],
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "check-event-type",
      "name": "Check Event Type",
      "type": "n8n-nodes-base.if",
      "position": [
        650,
        300
      ],
      "parameters": {
        "conditions": {
          "rules": [
            {
              "value1": "={{ $json.eventType }}",
              "value2": "job.created",
              "operation": "equals"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "append-to-sheets",
      "name": "Append to Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "maxTries": 2,
      "position": [
        850,
        200
      ],
      "parameters": {
        "range": "A:L",
        "fieldsUi": {
          "fields": [
            {
              "fieldName": "timestamp",
              "fieldValue": "={{ $json.timestamp }}"
            },
            {
              "fieldName": "eventType",
              "fieldValue": "={{ $json.eventType }}"
            },
            {
              "fieldName": "customerId",
              "fieldValue": "={{ $json.customerId }}"
            },
            {
              "fieldName": "customerName",
              "fieldValue": "={{ $json.customerName }}"
            },
            {
              "fieldName": "customerEmail",
              "fieldValue": "={{ $json.customerEmail }}"
            },
            {
              "fieldName": "customerPhone",
              "fieldValue": "={{ $json.customerPhone }}"
            },
            {
              "fieldName": "jobId",
              "fieldValue": "={{ $json.jobId }}"
            },
            {
              "fieldName": "jobTitle",
              "fieldValue": "={{ $json.jobTitle }}"
            },
            {
              "fieldName": "jobStatus",
              "fieldValue": "={{ $json.jobStatus }}"
            },
            {
              "fieldName": "jobAmount",
              "fieldValue": "={{ $json.jobAmount }}"
            },
            {
              "fieldName": "jobScheduledDate",
              "fieldValue": "={{ $json.jobScheduledDate }}"
            },
            {
              "fieldName": "jobNotes",
              "fieldValue": "={{ $json.jobNotes }}"
            }
          ]
        },
        "resource": "sheet",
        "operation": "append",
        "sheetName": {
          "value": "Events",
          "cachedResultName": "Events"
        },
        "documentId": {
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID/edit",
          "cachedResultName": "HOUSECALL_PRO_SHEET"
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.7,
      "waitBetweenTries": 1000
    },
    {
      "id": "sync-to-ghl",
      "name": "Sync Contact to GHL",
      "type": "n8n-nodes-base.highLevel",
      "maxTries": 2,
      "position": [
        850,
        400
      ],
      "parameters": {
        "email": "={{ $json.customerEmail }}",
        "phone": "={{ $json.customerPhone }}",
        "lastName": "={{ $json.customerName ? $json.customerName.split(' ').slice(1).join(' ') : '' }}",
        "resource": "contact",
        "firstName": "={{ $json.customerName ? $json.customerName.split(' ')[0] : '' }}",
        "operation": "create or update",
        "customFields": {
          "values": [
            {
              "name": "housecallProJobId",
              "value": "={{ $json.jobId }}"
            },
            {
              "name": "housecallProJobStatus",
              "value": "={{ $json.jobStatus }}"
            }
          ]
        }
      },
      "retryOnFail": true,
      "typeVersion": 2,
      "waitBetweenTries": 1000
    },
    {
      "id": "sync-to-pipedrive",
      "name": "Sync to Pipedrive CRM",
      "type": "n8n-nodes-base.pipedrive",
      "maxTries": 2,
      "position": [
        850,
        550
      ],
      "parameters": {
        "name": "={{ $json.customerName }}",
        "email": [
          {
            "value": "={{ $json.customerEmail }}"
          }
        ],
        "phone": [
          {
            "value": "={{ $json.customerPhone }}"
          }
        ],
        "resource": "person",
        "operation": "create or update",
        "customFields": {
          "values": [
            {
              "key": "HCP_JobID",
              "value": "={{ $json.jobId }}"
            },
            {
              "key": "HCP_JobTitle",
              "value": "={{ $json.jobTitle }}"
            },
            {
              "key": "HCP_JobAmount",
              "value": "={{ $json.jobAmount }}"
            }
          ]
        }
      },
      "retryOnFail": true,
      "typeVersion": 1,
      "waitBetweenTries": 1000
    },
    {
      "id": "forward-to-custom-webhook",
      "name": "Forward to Custom Webhook",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        850,
        700
      ],
      "parameters": {
        "url": "={{ $json.customWebhookUrl }}",
        "method": "POST",
        "headers": {
          "Content-Type": "application/json",
          "X-Event-Type": "={{ $json.eventType }}"
        },
        "sendBody": true,
        "sendHeaders": true,
        "bodyParametersUi": {
          "parameter": [
            {
              "name": "eventType",
              "value": "={{ $json.eventType }}"
            },
            {
              "name": "customerId",
              "value": "={{ $json.customerId }}"
            },
            {
              "name": "jobId",
              "value": "={{ $json.jobId }}"
            },
            {
              "name": "status",
              "value": "{{ $json.jobStatus }}"
            },
            {
              "name": "timestamp",
              "value": "={{ $json.timestamp }}"
            }
          ]
        }
      },
      "typeVersion": 4.3,
      "continueOnFail": true
    },
    {
      "id": "build-success-response",
      "name": "Build Success Response",
      "type": "n8n-nodes-base.set",
      "position": [
        1050,
        300
      ],
      "parameters": {
        "mode": "manual",
        "assignments": [
          {
            "name": "status",
            "value": "success"
          },
          {
            "name": "message",
            "value": "Webhook processed successfully"
          },
          {
            "name": "eventType",
            "value": "={{ $json.eventType }}"
          },
          {
            "name": "customerId",
            "value": "={{ $json.customerId }}"
          },
          {
            "name": "jobId",
            "value": "={{ $json.jobId }}"
          },
          {
            "name": "processedAt",
            "value": "={{ new Date().toISOString() }}"
          }
        ]
      },
      "typeVersion": 3.4
    },
    {
      "id": "build-error-response",
      "name": "Build Error Response",
      "type": "n8n-nodes-base.set",
      "position": [
        1050,
        450
      ],
      "parameters": {
        "mode": "manual",
        "assignments": [
          {
            "name": "status",
            "value": "error"
          },
          {
            "name": "message",
            "value": "Error processing webhook"
          },
          {
            "name": "error",
            "value": "={{ $error ? $error.message : 'Unknown error' }}"
          }
        ]
      },
      "typeVersion": 3.4
    },
    {
      "id": "respond-to-webhook",
      "name": "Respond to Webhook",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1250,
        300
      ],
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json) }}"
      },
      "typeVersion": 1.4
    },
    {
      "id": "respond-with-error",
      "name": "Respond with Error",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1250,
        450
      ],
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json) }}"
      },
      "typeVersion": 1.4
    }
  ],
  "connections": {
    "Map HCP Payload": {
      "main": [
        [
          {
            "node": "Check Event Type",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Event Type": {
      "main": [
        [
          {
            "node": "Append to Google Sheets",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Error Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sync Contact to GHL": {
      "main": [
        [
          {
            "node": "Sync to Pipedrive CRM",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Error Response": {
      "main": [
        [
          {
            "node": "Respond with Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Housecall Pro Webhook": {
      "main": [
        [
          {
            "node": "Map HCP Payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sync to Pipedrive CRM": {
      "main": [
        [
          {
            "node": "Forward to Custom Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Success Response": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append to Google Sheets": {
      "main": [
        [
          {
            "node": "Sync Contact to GHL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Forward to Custom Webhook": {
      "main": [
        [
          {
            "node": "Build Success Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}