AutomationFlowsWeb Scraping › Phase 5 - Confirmation Call (vapi)

Phase 5 - Confirmation Call (vapi)

Phase 5 - Confirmation Call (Vapi). Uses httpRequest. Event-driven trigger; 8 nodes.

Event trigger★★★★☆ complexity8 nodesHTTP Request
Web Scraping Trigger: Event Nodes: 8 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 5 - Confirmation Call (Vapi)",
  "nodes": [
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "b86d5c8d-ee9c-4063-bfb9-b68a7fb0cbaf",
              "name": "supabaseUrl",
              "value": "https://YOUR_PROJECT_REF.supabase.co",
              "type": "string"
            },
            {
              "id": "3f5081fc-0cd7-4ba6-82df-997266bfb744",
              "name": "vapiAssistantId",
              "value": "YOUR_VAPI_ASSISTANT_ID",
              "type": "string"
            },
            {
              "id": "c6a778a8-dc49-4d0b-871e-0e9c3d1fdafb",
              "name": "vapiPhoneNumberId",
              "value": "YOUR_VAPI_PHONE_NUMBER_ID",
              "type": "string"
            },
            {
              "id": "015a2564-053c-444f-a3b4-d8eceb86bfa9",
              "name": "testNumber",
              "value": "+10000000000",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "40494942-3cdf-485f-96a9-e03f61f6cf83",
      "name": "Config",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        784,
        2304
      ]
    },
    {
      "parameters": {
        "method": "PATCH",
        "url": "={{ $('Config').item.json.supabaseUrl + '/rest/v1/meetings?id=eq.' + $json.meetingId }}",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "supabaseApi",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Prefer",
              "value": "return=minimal"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ { \"status\": \"confirmed\" } }}",
        "options": {}
      },
      "id": "9fa20730-a08d-4339-b3d6-815ca49fd0d2",
      "name": "Set Meeting Confirmed",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1952,
        2400
      ],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 2000,
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $('Config').item.json.supabaseUrl + '/rest/v1/calls' }}",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "supabaseApi",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Prefer",
              "value": "return=minimal"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ { \"contact_id\": $json.contactId, \"call_type\": \"confirmation\", \"outcome\": \"confirmed\", \"vapi_call_id\": $json.vapiCallId, \"transcript_summary\": \"Confirmation call placed to the test number via Vapi. (Outcome shown here is simulated; a live end-of-call webhook would write the real outcome + transcript.)\" } }}",
        "options": {}
      },
      "id": "d086e281-0a9b-45a2-87bf-dfc2854a16e3",
      "name": "Log Call",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1952,
        2192
      ],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 2000,
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const src = $('Build Call').all();\nfunction extractText(r) {\n  if (r == null) return '';\n  if (typeof r === 'string') return r;\n  if (Array.isArray(r.output)) {\n    let acc = '';\n    for (const msg of r.output) {\n      if (msg && Array.isArray(msg.content)) {\n        for (const c of msg.content) { if (c && typeof c.text === 'string') acc += c.text; }\n      } else if (typeof msg === 'string') { acc += msg; }\n      else if (msg && typeof msg.text === 'string') { acc += msg.text; }\n    }\n    if (acc) return acc;\n  }\n  if (typeof r.output_text === 'string') return r.output_text;\n  if (typeof r.output === 'string') return r.output;\n  if (typeof r.content === 'string') return r.content;\n  if (typeof r.text === 'string') return r.text;\n  if (r.message && typeof r.message.content === 'string') return r.message.content;\n  if (r.choices && r.choices[0] && r.choices[0].message && typeof r.choices[0].message.content === 'string') return r.choices[0].message.content;\n  if (Array.isArray(r.content)) return r.content.map(b => (b && b.text) ? b.text : '').join('');\n  return '';\n}\nconst out = [];\nfor (let i = 0; i < items.length; i++) {\n  const r = items[i].json || {};\n  const callId = r.id || (r.call && r.call.id) || '';\n  const c = (src[i] && src[i].json) ? src[i].json : {};\n  out.push({ json: { contactId: c.contactId, meetingId: c.meetingId, contactName: c.contactName, vapiCallId: callId } });\n}\nreturn out;\n"
      },
      "id": "e6efce3d-3bef-401d-a6c1-e6ab5ad4a9ae",
      "name": "Extract Call",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1712,
        2304
      ]
    },
    {
      "parameters": {
        "jsCode": "const cfg = $('Config').item.json;\nconst out = [];\nfor (const item of items) {\n  const m = item.json;\n  const c = Array.isArray(m.contacts) ? (m.contacts[0]||{}) : (m.contacts||{});\n  const s = c && (Array.isArray(c.schools) ? (c.schools[0]||{}) : (c.schools||{})) || {};\n  const when = m.scheduled_at ? new Date(m.scheduled_at).toUTCString() : 'your upcoming call';\n  const vapiBody = {\n    assistantId: cfg.vapiAssistantId,\n    phoneNumberId: cfg.vapiPhoneNumberId,\n    customer: { number: cfg.testNumber },\n    assistantOverrides: {\n      variableValues: {\n        contactName: c.name || 'there',\n        schoolName: s.name || 'your school',\n        meetingTime: when\n      }\n    }\n  };\n  out.push({ json: { contactId: m.contact_id, meetingId: m.id, contactName: c.name, vapiBody: vapiBody } });\n}\nreturn out;\n"
      },
      "id": "f55ce8bc-1b89-418d-8444-666bd85048d5",
      "name": "Build Call",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1232,
        2304
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.vapi.ai/call",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ $json.vapiBody }}",
        "options": {}
      },
      "id": "a8c39fe4-e884-451c-9d5e-01f9588379df",
      "name": "Trigger Vapi Call",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1472,
        2304
      ],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 2000,
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "url": "={{ $('Config').item.json.supabaseUrl + '/rest/v1/meetings?status=eq.booked&select=id,scheduled_at,contact_id,contacts(name,schools(name))' }}",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "supabaseApi",
        "options": {}
      },
      "id": "153c6449-bd48-402d-a2b2-1fcbb1415169",
      "name": "Get Booked Meetings",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1008,
        2304
      ],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 2000,
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {},
      "id": "b62958c0-1eaa-4a46-9666-aeb6689edef1",
      "name": "Manual Trigger",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        564,
        2304
      ]
    }
  ],
  "connections": {
    "Get Booked Meetings": {
      "main": [
        [
          {
            "node": "Build Call",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Call": {
      "main": [
        [
          {
            "node": "Trigger Vapi Call",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Trigger Vapi Call": {
      "main": [
        [
          {
            "node": "Extract Call",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Call": {
      "main": [
        [
          {
            "node": "Log Call",
            "type": "main",
            "index": 0
          },
          {
            "node": "Set Meeting Confirmed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Config": {
      "main": [
        [
          {
            "node": "Get Booked Meetings",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Manual Trigger": {
      "main": [
        [
          {
            "node": "Config",
            "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 5 - Confirmation Call (Vapi). Uses httpRequest. Event-driven trigger; 8 nodes.

Source: https://github.com/Tusharvijaypatil/LWL-Growth-Engine/blob/main/Workflows/phase6_confirmation_call.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 workflow listens for an “Approved” label on a Trello card, reads the AI draft bookkeeping JSON from card comments, and posts the corresponding transaction to Xero. It then adds a Xero deep link b

Trello Trigger, HTTP Request
Web Scraping

02_LLM_Pipeline v1.0. Uses executeWorkflowTrigger, httpRequest, seaTable. Event-driven trigger; 65 nodes.

Execute Workflow Trigger, HTTP Request, Sea Table
Web Scraping

This workflow allows you to import any workflow from a file or another n8n instance and map the credentials easily. A multi-form setup guides you through the entire process At the beginning you have t

Execute Command, Read Write File, HTTP Request +3
Web Scraping

[n8n] Advanced URL Parsing and Shortening Workflow - Switchy.io Integration. Uses splitInBatches, stickyNote, httpRequest, html. Event-driven trigger; 56 nodes.

HTTP Request, GitHub, Stop And Error +1
Web Scraping

[](https://youtu.be/c7yCZhmMjtI)

HTTP Request, GitHub, Stop And Error +1