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.
This workflow captures new leads via webhook, enriches and scores them with Apollo and Google Gemini, logs everything in Google Sheets, and automates outreach, reply handling, follow-ups, meeting prep
Venafi Presentation - Watch Video
Automatically detects missed Zoom demos booked via Calendly and triggers AI-powered follow-up sequences.
This workflow accepts invoice documents via webhook, validates and de-duplicates them, extracts invoice data from PDFs with OpenAI, and either posts approved invoices to an ERP via HTTP or routes exce
AI-Powered Fake Review Detection Workflow Using n8n & Airtable. Uses httpRequest, airtable, openAi, slack. Webhook trigger; 27 nodes.