AutomationFlowsWeb Scraping › Phase 4 - Calendly Booking Webhook

Phase 4 - Calendly Booking Webhook

Phase 4 - Calendly Booking Webhook. Uses httpRequest. Webhook trigger; 7 nodes.

Webhook trigger★★★★☆ complexity7 nodesHTTP Request
Web Scraping Trigger: Webhook Nodes: 7 Complexity: ★★★★☆ Added:

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "name": "Phase 4 - Calendly Booking Webhook",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "calendly-booking",
        "options": {
          "allowedOrigins": "*"
        }
      },
      "id": "efe9e664-a759-47bf-97e9-560fa2764322",
      "name": "Calendly Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        864,
        1888
      ]
    },
    {
      "parameters": {
        "url": "={{ $('Config').item.json.supabaseUrl + '/rest/v1/contacts?select=id&limit=1&email=eq.' + encodeURIComponent($json.inviteeEmail) }}",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "supabaseApi",
        "options": {}
      },
      "id": "79075cdc-7482-4f54-bd82-f884693c8404",
      "name": "Find Contact",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1536,
        1888
      ],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 2000,
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "0b7be3dd-0bd1-48bd-aa02-4bc05cd5e74d",
              "name": "supabaseUrl",
              "value": "https://YOUR_PROJECT_REF.supabase.co",
              "type": "string"
            }
          ]
        },
        "includeOtherFields": true,
        "options": {}
      },
      "id": "5a518cfc-2d1b-45be-8398-304e34bfc433",
      "name": "Config",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1088,
        1872
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $('Config').item.json.supabaseUrl + '/rest/v1/meetings' }}",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "supabaseApi",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Prefer",
              "value": "return=minimal"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ { \"contact_id\": $json.contactId, \"scheduled_at\": $json.scheduledAt, \"phone_captured\": $json.phone, \"calendly_event_id\": $json.calendlyEventId, \"status\": \"booked\" } }}",
        "options": {}
      },
      "id": "5be4c04b-4e36-4bec-97c3-5cf8132f4932",
      "name": "Create Meeting Row",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1984,
        1984
      ],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 2000,
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const raw = items[0].json;\nlet env = (raw.body != null) ? raw.body : raw;\nif (typeof env === 'string') { try { env = JSON.parse(env); } catch (e) {} }\nconst p = (env && env.payload) ? env.payload : (env || {});\n\nconst email = p.email || (p.invitee && p.invitee.email) || '';\nconst name  = p.name  || (p.invitee && p.invitee.name)  || '';\n\nlet phone = '';\nconst qa = p.questions_and_answers || (p.invitee && p.invitee.questions_and_answers) || [];\nfor (const q of qa) {\n  const label = ((q.question || '') + '').toLowerCase();\n  if (label.includes('phone') || label.includes('reach') || label.includes('contact number') || label.includes('mobile')) {\n    phone = q.answer || ''; break;\n  }\n}\nif (!phone) phone = p.text_reminder_number || p.phone || '';\n\nconst se = p.scheduled_event || p.event || {};\nconst scheduledAt = se.start_time || p.start_time || null;\n\nlet eventId = '';\nconst uri = (se && se.uri) || p.event || p.uri || '';\nif (uri && typeof uri === 'string') {\n  const parts = uri.split('/').filter(Boolean);\n  eventId = parts[parts.length - 1] || '';\n}\n\nreturn [{ json: { inviteeEmail: email, inviteeName: name, phone: phone, scheduledAt: scheduledAt, calendlyEventId: eventId } }];"
      },
      "id": "056760c8-5505-4335-bbb1-a7592923df55",
      "name": "Parse Booking",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1312,
        1888
      ]
    },
    {
      "parameters": {
        "method": "PATCH",
        "url": "={{ $('Config').item.json.supabaseUrl + '/rest/v1/contacts?id=eq.' + $json.contactId }}",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "supabaseApi",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Prefer",
              "value": "return=minimal"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ { \"phone\": $json.phone, \"outreach_status\": \"meeting_booked\" } }}",
        "options": {}
      },
      "id": "7d3ceaa7-eda3-4780-803f-e9cb7d47b3b1",
      "name": "Set Meeting Booked",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1984,
        1776
      ],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 2000,
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const booking = $('Parse Booking').first().json;\nlet contactId = null;\nfor (const it of items) {\n  const j = it.json;\n  if (j && j.id) { contactId = j.id; break; }\n  if (Array.isArray(j) && j[0] && j[0].id) { contactId = j[0].id; break; }\n}\nif (!contactId) { return []; }   // no matching contact -> stop gracefully\nreturn [{ json: {\n  contactId: contactId,\n  phone: booking.phone || null,\n  scheduledAt: booking.scheduledAt || null,\n  calendlyEventId: booking.calendlyEventId || null\n}}];\n"
      },
      "id": "29b43675-60ad-4eed-9843-f94de2f02703",
      "name": "Merge Booking + Contact",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1744,
        1888
      ]
    }
  ],
  "connections": {
    "Calendly Webhook": {
      "main": [
        [
          {
            "node": "Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Booking": {
      "main": [
        [
          {
            "node": "Find Contact",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Find Contact": {
      "main": [
        [
          {
            "node": "Merge Booking + Contact",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Booking + Contact": {
      "main": [
        [
          {
            "node": "Set Meeting Booked",
            "type": "main",
            "index": 0
          },
          {
            "node": "Create Meeting Row",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Config": {
      "main": [
        [
          {
            "node": "Parse Booking",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Phase 4 - Calendly Booking Webhook. Uses httpRequest. Webhook trigger; 7 nodes.

Source: https://github.com/Tusharvijaypatil/LWL-Growth-Engine/blob/main/Workflows/phase5_calendly_webhook.json — original creator credit. Request a take-down →

More Web Scraping workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Web Scraping

This n8n template provides enterprise-level version control for your workflows using GitHub integration. Stop losing hours to broken workflows and manual exports – get proper commit history, visual di

n8n, Execute Workflow Trigger, HTTP Request +1
Web Scraping

This flow creates dummy files for every item added in your *Arrs (Radarr/Sonarr) with the tag .

HTTP Request, Ssh
Web Scraping

eek-Go v2 (Batch-Then-Review). Uses httpRequest. Webhook trigger; 75 nodes.

HTTP Request
Web Scraping

This workflow receives webhook requests from a content calendar and uses the X API v2 to publish text posts, threads, image/video posts, and polls, as well as delete existing posts and run a credentia

HTTP Request
Web Scraping

This workflow acts as a central API gateway for all technical indicator agents in the Binance Spot Market Quant AI system. It listens for incoming webhook requests and dynamically routes them to the c

HTTP Request