This workflow follows the HTTP Request → OpenAI recipe pattern — see all workflows that pair these two integrations.
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 →
{
"name": "Cal.com Booking \u2192 Pre-Meeting Brief",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "calcom/booking",
"responseMode": "responseNode",
"options": {}
},
"id": "node-webhook",
"name": "Cal.com Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
220,
300
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={ {\"status\": \"ok\"} }",
"options": {}
},
"id": "node-respond",
"name": "Respond OK",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
420,
500
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "condition-booking-created",
"leftValue": "={{ $json.triggerEvent }}",
"rightValue": "BOOKING_CREATED",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "node-filter",
"name": "Filter BOOKING_CREATED",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
420,
300
]
},
{
"parameters": {
"jsCode": "// Normalize Cal.com booking payload into a flat object\nconst p = $input.first().json.payload;\n\nconst attendee = p.attendee || {};\nconst meta = attendee.metadata || {};\n\n// Split full name into first/last\nconst nameParts = (attendee.name || '').split(' ');\nconst firstName = nameParts[0] || '';\nconst lastName = nameParts.slice(1).join(' ');\n\nreturn [{\n json: {\n booking_uid: p.uid,\n event_title: p.title,\n start_time: p.startTime,\n end_time: p.endTime,\n time_zone: attendee.timeZone || 'UTC',\n attendee_name: attendee.name,\n attendee_first_name: firstName,\n attendee_last_name: lastName,\n attendee_email: attendee.email,\n company: meta.company || null,\n website: meta.website || null,\n notes: meta.notes || null,\n meeting_url: (p.conferenceData && p.conferenceData.url) || null,\n organizer_name: p.organizer?.name,\n organizer_email: p.organizer?.email\n }\n}];"
},
"id": "node-normalize",
"name": "Normalize Booking",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
640,
300
]
},
{
"parameters": {
"method": "POST",
"url": "https://services.leadconnectorhq.com/contacts/",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Version",
"value": "2021-07-28"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"firstName\": \"{{ $json.attendee_first_name }}\",\n \"lastName\": \"{{ $json.attendee_last_name }}\",\n \"email\": \"{{ $json.attendee_email }}\",\n \"companyName\": \"{{ $json.company }}\",\n \"locationId\": \"{{ $env.GHL_LOCATION_ID }}\",\n \"tags\": [\"cal-discovery\", \"new-lead\"],\n \"customFields\": [\n {\"key\": \"cal_booking_uid\", \"value\": \"{{ $json.booking_uid }}\"},\n {\"key\": \"cal_start_time\", \"value\": \"{{ $json.start_time }}\"},\n {\"key\": \"cal_meeting_url\", \"value\": \"{{ $json.meeting_url }}\"},\n {\"key\": \"cal_event_title\", \"value\": \"{{ $json.event_title }}\"}\n ]\n}",
"options": {
"response": {
"response": {
"fullResponse": true
}
}
}
},
"id": "node-ghl-upsert",
"name": "GHL \u2013 Upsert Contact",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
860,
300
],
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
},
"onError": "continueRegularOutput"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": false,
"leftValue": "",
"typeValidation": "loose"
},
"conditions": [
{
"id": "condition-not-freemail",
"leftValue": "={{ $('Normalize Booking').item.json.attendee_email }}",
"rightValue": "gmail.com|yahoo.com|hotmail.com|outlook.com|aol.com|icloud.com",
"operator": {
"type": "string",
"operation": "notRegex"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "node-freemail-check",
"name": "Is Business Email?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1080,
300
]
},
{
"parameters": {
"method": "GET",
"url": "https://api.peopledatalabs.com/v5/person/enrich",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "email",
"value": "={{ $('Normalize Booking').item.json.attendee_email }}"
},
{
"name": "min_likelihood",
"value": "6"
}
]
},
"options": {
"response": {
"response": {
"fullResponse": true
}
}
}
},
"id": "node-pdl-enrich",
"name": "PDL \u2013 Enrich",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1300,
200
],
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
},
"onError": "continueRegularOutput"
},
{
"parameters": {
"jsCode": "// Build context for AI brief by merging booking data with PDL enrichment\nconst booking = $('Normalize Booking').first().json;\n\nlet enrichment = {};\ntry {\n const pdlResponse = $('PDL \u2013 Enrich').first().json;\n if (pdlResponse && pdlResponse.status === 200) {\n enrichment = pdlResponse.data || pdlResponse;\n }\n} catch (e) {\n // PDL enrichment failed or was skipped \u2013 continue with booking data only\n enrichment = {};\n}\n\nreturn [{\n json: {\n attendee_name: booking.attendee_name,\n attendee_email: booking.attendee_email,\n company_name: booking.company || enrichment.job_company_name || 'Unknown',\n website: booking.website || enrichment.job_company_website || null,\n notes: booking.notes || null,\n company_employees: enrichment.job_company_size || 'n/a',\n company_industry: enrichment.job_company_industry || 'n/a',\n company_funding: enrichment.job_company_founded ? ('Founded ' + enrichment.job_company_founded) : 'n/a',\n job_title: enrichment.job_title || 'n/a',\n linkedin_url: enrichment.linkedin_url || null,\n start_time: booking.start_time,\n end_time: booking.end_time,\n time_zone: booking.time_zone,\n meeting_url: booking.meeting_url,\n booking_uid: booking.booking_uid,\n organizer_name: booking.organizer_name,\n organizer_email: booking.organizer_email\n }\n}];"
},
"id": "node-build-context",
"name": "Build Brief Context",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1520,
300
]
},
{
"parameters": {
"resource": "chat",
"model": "gpt-4.1-mini",
"messages": {
"values": [
{
"role": "system",
"content": "You are an assistant helping a consultant prepare for a 30-minute discovery call.\nSummarize the prospect and their company, list 3\u20135 talking points,\nand suggest 3 tailored questions for the call. Be concise and skimmable.\nUse markdown formatting for readability."
},
{
"role": "user",
"content": "=Prospect info:\n- Name: {{ $json.attendee_name }}\n- Email: {{ $json.attendee_email }}\n- Job title: {{ $json.job_title }}\n- LinkedIn: {{ $json.linkedin_url }}\n- Company: {{ $json.company_name }}\n- Website: {{ $json.website }}\n- Notes from booking form: {{ $json.notes }}\n\nEnrichment data:\n- Company employees: {{ $json.company_employees }}\n- Company industry: {{ $json.company_industry }}\n- Company founded: {{ $json.company_funding }}\n\nPlease:\n1) Provide a short company overview.\n2) Suggest 3\u20135 bullet-point talking points for the call.\n3) Propose 3 high-value discovery questions tailored to this prospect."
}
]
},
"options": {
"temperature": 0.7,
"maxTokens": 800
}
},
"id": "node-openai-brief",
"name": "OpenAI \u2013 Pre-Meeting Brief",
"type": "@n8n/n8n-nodes-langchain.openAi",
"typeVersion": 1.4,
"position": [
1740,
300
],
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"onError": "continueRegularOutput"
},
{
"parameters": {
"resource": "message",
"channel": {
"__rl": true,
"mode": "id",
"value": "={{ $env.SLACK_CHANNEL_ID_DISCOVERY }}"
},
"text": "=:new: *New Discovery Call Booked*\n\n*Prospect:* {{ $('Build Brief Context').item.json.attendee_name }} ({{ $('Build Brief Context').item.json.attendee_email }})\n*Role:* {{ $('Build Brief Context').item.json.job_title }}\n*Company:* {{ $('Build Brief Context').item.json.company_name }} \u2013 {{ $('Build Brief Context').item.json.company_industry }} \u2013 {{ $('Build Brief Context').item.json.company_employees }} employees\n*Time:* {{ $('Build Brief Context').item.json.start_time }} ({{ $('Build Brief Context').item.json.time_zone }})\n*Meeting Link:* {{ $('Build Brief Context').item.json.meeting_url }}\n\n*AI Pre-Meeting Brief:*\n{{ $json.message?.content || $json.content || $json.text || 'Brief generation failed \u2013 review manually.' }}",
"otherOptions": {}
},
"id": "node-slack-post",
"name": "Slack \u2013 Post Brief",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.2,
"position": [
1960,
300
],
"credentials": {
"slackApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "// No-op pass-through for free email addresses (skip PDL enrichment)\nconst booking = $('Normalize Booking').first().json;\nreturn [{ json: booking }];"
},
"id": "node-skip-pdl",
"name": "Skip PDL (Free Email)",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1300,
420
]
}
],
"connections": {
"Cal.com Webhook": {
"main": [
[
{
"node": "Filter BOOKING_CREATED",
"type": "main",
"index": 0
},
{
"node": "Respond OK",
"type": "main",
"index": 0
}
]
]
},
"Filter BOOKING_CREATED": {
"main": [
[
{
"node": "Normalize Booking",
"type": "main",
"index": 0
}
],
[]
]
},
"Normalize Booking": {
"main": [
[
{
"node": "GHL \u2013 Upsert Contact",
"type": "main",
"index": 0
}
]
]
},
"GHL \u2013 Upsert Contact": {
"main": [
[
{
"node": "Is Business Email?",
"type": "main",
"index": 0
}
]
]
},
"Is Business Email?": {
"main": [
[
{
"node": "PDL \u2013 Enrich",
"type": "main",
"index": 0
}
],
[
{
"node": "Skip PDL (Free Email)",
"type": "main",
"index": 0
}
]
]
},
"PDL \u2013 Enrich": {
"main": [
[
{
"node": "Build Brief Context",
"type": "main",
"index": 0
}
]
]
},
"Skip PDL (Free Email)": {
"main": [
[
{
"node": "Build Brief Context",
"type": "main",
"index": 0
}
]
]
},
"Build Brief Context": {
"main": [
[
{
"node": "OpenAI \u2013 Pre-Meeting Brief",
"type": "main",
"index": 0
}
]
]
},
"OpenAI \u2013 Pre-Meeting Brief": {
"main": [
[
{
"node": "Slack \u2013 Post Brief",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"staticData": null,
"tags": [
{
"name": "cal-pipeline",
"id": "tag-cal-pipeline"
},
{
"name": "production",
"id": "tag-production"
}
],
"triggerCount": 1
}
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.
httpHeaderAuthopenAiApislackApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Cal.com Booking → Pre-Meeting Brief. Uses httpRequest, openAi, slack. Webhook trigger; 11 nodes.
Source: https://github.com/albincikaj/cal-appointment-pipeline/blob/main/n8n-workflows/booking-pre-meeting-brief.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Venafi Presentation - Watch Video
Automatically detects missed Zoom demos booked via Calendly and triggers AI-powered follow-up sequences.
AI-Powered Fake Review Detection Workflow Using n8n & Airtable. Uses httpRequest, airtable, openAi, slack. Webhook trigger; 27 nodes.
This workflow automates the end-to-end process of scheduling technical or behavioral interviews. It captures interview data via Webhook, creates a Google Calendar event with an integrated Google Meet
This workflow automatically scores and categorizes new GoHighLevel contacts using AI (GPT-4), then tags and assigns them to the appropriate team member based on their score. Hot leads also trigger a S