• Home
BuildWithMatija
Get In Touch
  1. Home
  2. Blog
  3. Tools
  4. Automate Lead Qualification Fast with n8n & Pipedrive

Automate Lead Qualification Fast with n8n & Pipedrive

Step-by-step guide to build a webhook gateway, CRM creation, and email notification sub-flows using n8n and Pipedrive…

5th February 2026·Updated on:22nd February 2026·MŽMatija Žiberna·
Tools
Automate Lead Qualification Fast with n8n & Pipedrive

📚 Get Practical Development Guides

Join developers getting comprehensive guides, code examples, optimization tips, and time-saving prompts to accelerate their development workflow.

No spam. Unsubscribe anytime.

Related Posts:

  • •Active Tenant Scoping vs Access Control: A Practical Guide
  • •n8n vs Zapier 2026: Why Zapier Fails for Serious Projects
  • •Payload CMS Jobs Queue Explained: Tasks, Jobs & Queues

I was building a lead qualification system for a client project where the website chatbot and contact form needed to do more than collect data. Every inbound lead needed to arrive in Pipedrive fully structured — contact created, company linked, qualification fields populated, a follow-up activity assigned, and the sales team notified with a formatted summary. All of it before a human ever looked at the lead.

The manual version of this process was taking fifteen to twenty minutes per lead. Search the CRM for duplicates, create the contact, create the company, link them together, copy the qualification answers into custom fields, write a summary note, create a follow-up task, send an internal email. Multiply that by twenty leads a day and you have someone's entire morning consumed by data entry.

I built the automated version with three interconnected n8n workflows that handle the full pipeline: a CRM structuring sub-flow that builds complete Pipedrive records, an email notification sub-flow that dispatches internal alerts and visitor confirmations, and a main webhook gateway that receives inbound leads, prevents duplicates, and orchestrates the other two.

This guide walks through building all three workflows from scratch. By the end, you will have a production-ready system where every lead that hits your webhook arrives in Pipedrive fully qualified, linked, and actionable — with your sales team notified immediately.

What we are building

The system has three workflows that call each other. Understanding the architecture before building prevents confusion later.

Workflow 1: CRM Creation Sub-Flow. This is the foundation. It receives structured lead data and builds a complete Pipedrive record — Person, Organisation, Lead, Activity, structured Note, and custom qualification fields. It does not have its own trigger. Other workflows call it.

Workflow 2: Email Notification Sub-Flow. This is the messaging layer. It receives a payload with an event type and lead data, routes to the correct email template, sends an internal notification to the sales inbox, and optionally sends an acknowledgement to the visitor. Like Workflow 1, it is called by other workflows.

Workflow 3: Webhook Gateway. This is the public entry point. It receives POST requests from a chatbot or form, normalizes the data, checks for duplicate contacts in Pipedrive, and branches based on whether the lead is new or an update. For new leads, it calls Workflow 1 and Workflow 2. For updates, it modifies the existing record directly.

The reason for three separate workflows instead of one giant flow is maintainability. The CRM creation logic lives in one place. If you need to add a field to every new lead, you change it once. The email templates live in one place. If you add a new notification type, you add one Switch branch. The gateway stays clean because it only handles routing and deduplication.

This tutorial assumes you have a working n8n instance and a Pipedrive account with API access. If you need to set up n8n first, follow my guide on self-hosting n8n on a VPS with Docker. You will also need SMTP credentials for sending notification emails.

Preparing Pipedrive custom fields

Before building any workflows, you need custom fields in Pipedrive to store qualification data. Go to Pipedrive Settings, then Data Fields, and create the following custom fields on the Person entity:

  • contact_source (text or single option) — tracks where the lead originated
  • budget_readiness (text) — the lead's budget status
  • decision_authority (text) — whether they are the decision maker
  • project_type (text) — what kind of project they need
  • scope_scale (text) — the size and complexity of the project
  • project_timeline (text) — when they want to start

After creating each field, note down the custom field API key. Pipedrive assigns each custom field a hash-based key that looks something like a4b2c8d1e5f3a7b9. You will need these keys when configuring the workflow nodes that write to these fields.

To find custom field keys in Pipedrive, go to Settings, then Data Fields, click on a field, and look at the API key in the field details panel. Alternatively, call the Pipedrive API endpoint GET /v1/personFields to get all fields with their keys programmatically.

Workflow 1: CRM creation sub-flow

Create a new workflow in n8n and name it something clear like "SUB — Create Lead + Person + Organisation". This workflow will be called by the gateway, not triggered directly.

Step 1: Add the Execute Workflow Trigger

Start with the Execute Workflow Trigger node. This tells n8n that this workflow is a sub-flow, invoked by another workflow using the Execute Workflow node.

The trigger will receive structured JSON input with these fields:

{
  "firstName": "Jane",
  "lastName": "Smith",
  "email": "jane@example.com",
  "phone": "+1234567890",
  "company": "Acme Corp",
  "priority": "high",
  "contact_source": "website_chatbot",
  "status": "qualified",
  "message": "Looking for a CMS rebuild with AI search integration",
  "reasoning": "Clear budget, decision maker, timeline under 3 months",
  "recommendedAction": "Schedule discovery call this week",
  "budget_readiness": "Approved budget, 50-100k range",
  "project_type": "Website rebuild with AI layer",
  "project_timeline": "Q2 2026",
  "decision_authority": "CEO, final decision maker",
  "scope_scale": "Mid-size, 3 month engagement"
}

You do not need to configure anything on this node beyond placing it. The data structure is defined by whatever the calling workflow sends.

Step 2: Create the Person in Pipedrive

Add a Pipedrive node set to the "Create" operation on the "Person" resource.

Configure it as follows:

  • Name: Set this using an expression: {{ $json.firstName }} {{ $json.lastName }}
  • Email: {{ $json.email }}
  • Phone: {{ $json.phone }}
  • Additional Fields: Add your contact_source custom field key and map it to {{ $json.contact_source }}

This node outputs the newly created Person record, including the critical id field that every subsequent node needs.

Step 3: Attach a structured note

Add another Pipedrive node, this time set to "Create" on the "Note" resource.

The note content should be an HTML-formatted summary that gives sales reps instant context. Build it as an expression:

<h3>Lead Summary</h3>
<p><strong>Status:</strong> {{ $json.status }}</p>
<p><strong>Priority:</strong> {{ $json.priority }}</p>
<hr>
<h4>Contact</h4>
<p>{{ $json.firstName }} {{ $json.lastName }}<br>
{{ $json.email }}<br>
{{ $json.phone }}</p>
<hr>
<h4>Project Scope</h4>
<p>{{ $json.message }}</p>
<hr>
<h4>Why This Lead Matters</h4>
<p>{{ $json.reasoning }}</p>
<hr>
<h4>Qualification Details</h4>
<p><strong>Budget:</strong> {{ $json.budget_readiness }}<br>
<strong>Timeline:</strong> {{ $json.project_timeline }}<br>
<strong>Decision Authority:</strong> {{ $json.decision_authority }}<br>
<strong>Project Type:</strong> {{ $json.project_type }}<br>
<strong>Scope:</strong> {{ $json.scope_scale }}</p>
<hr>
<h4>Recommended Next Step</h4>
<p>{{ $json.recommendedAction }}</p>

Set the Person ID field to the output of the previous Create Person node: {{ $('Create Person').item.json.id }}

The purpose of this note is that a sales rep can open the contact and understand everything about the lead in thirty seconds without digging through raw form data.

Step 4: Create a follow-up activity

Add a Pipedrive node set to "Create" on the "Activity" resource.

  • Subject: New lead — {{ $json.firstName }} {{ $json.lastName }}
  • Type: call
  • Due Date: Use an expression for today's date: {{ $now.format('yyyy-MM-dd') }}
  • Person ID: {{ $('Create Person').item.json.id }}

This ensures every single lead generates a same-day action item. No lead sits untouched because someone forgot to check the pipeline.

Step 5: Create the Organisation

Add a Pipedrive node set to "Create" on the "Organization" resource.

  • Name: {{ $json.company || 'Unknown Company' }}

The fallback string prevents the node from failing when the company field is empty. Some leads — especially from chatbot interactions — might not provide a company name immediately.

Here is the critical configuration: set the node's On Error behavior to Continue (using regular output). Organisation creation can fail for various reasons — duplicate names, API limits, missing data — and you do not want the entire lead pipeline to stop because the company record could not be created. The Person and Lead are more important than the Organisation link.

Step 6: Associate the Person with the Organisation

Add a Pipedrive node set to "Update" on the "Person" resource.

  • Person ID: {{ $('Create Person').item.json.id }}
  • Organisation ID: {{ $('Create Organisation').item.json.id }}

This links the contact to their company inside Pipedrive. If the Organisation creation failed in the previous step but continued, this node will receive a null organisation ID and fail gracefully — which is the correct behavior.

Step 7: Create the Lead record

Add a Pipedrive node set to "Create" on the "Lead" resource.

  • Title: NEW LEAD — {{ $json.firstName }} {{ $json.lastName }} || {{ $json.company }}
  • Person ID: {{ $('Create Person').item.json.id }}
  • Organisation ID: {{ $('Create Organisation').item.json.id }}

The title format makes leads scannable in the Pipedrive pipeline view. Every lead follows the same naming convention, which matters when the volume starts growing.

Step 8: Update the lead source channel

Pipedrive's Lead resource has a channel property that tracks where the lead came from, but the native n8n Pipedrive node does not expose it. Use an HTTP Request node instead.

  • Method: PATCH
  • URL: https://api.pipedrive.com/v1/leads/{{ $('Create Lead').item.json.data.id }}
  • Authentication: Use your Pipedrive API token as a query parameter or header
  • Body (JSON):
{
  "channel": 57
}

Replace 57 with the channel ID that matches your lead source in Pipedrive. You can find channel IDs through the Pipedrive API documentation or by inspecting existing leads.

Using an HTTP Request node instead of the native Pipedrive node is a common pattern in n8n. When the built-in node does not expose a specific API field, drop down to a raw HTTP request. The Pipedrive REST API covers everything the node does not.

Step 9: Update qualification custom fields on the Person

Add a final HTTP Request node to update the Person record with all qualification data.

  • Method: PUT
  • URL: https://api.pipedrive.com/v1/persons/{{ $('Create Person').item.json.id }}
  • Body (JSON):
{
  "YOUR_BUDGET_FIELD_KEY": "{{ $json.budget_readiness }}",
  "YOUR_AUTHORITY_FIELD_KEY": "{{ $json.decision_authority }}",
  "YOUR_PROJECT_TYPE_FIELD_KEY": "{{ $json.project_type }}",
  "YOUR_SCOPE_FIELD_KEY": "{{ $json.scope_scale }}",
  "YOUR_TIMELINE_FIELD_KEY": "{{ $json.project_timeline }}"
}

Replace each YOUR_*_FIELD_KEY placeholder with the actual custom field keys you noted earlier from Pipedrive settings.

This is the step that makes qualification data structured and reportable inside your CRM. Instead of qualification answers being buried in a note or a raw JSON blob, they exist as proper fields you can filter, segment, and report on.

That completes Workflow 1. Save it. The full sequence is: create Person, attach Note, create Activity, create Organisation, link Person to Organisation, create Lead, set Lead channel, enrich Person with qualification fields. Nine steps that replace fifteen minutes of manual CRM data entry.

Workflow 2: Email notification sub-flow

Create a new workflow and name it "SUB — Email Notification". This workflow handles all internal sales notifications and visitor acknowledgement emails. Having it as a separate sub-flow means any workflow in your system can send notifications without duplicating email templates.

Step 1: Add the Execute Workflow Trigger

Same as Workflow 1, start with the Execute Workflow Trigger node. This sub-flow expects a payload with these common fields:

{
  "eventType": "sales_inquiry_notification",
  "firstName": "Jane",
  "lastName": "Smith",
  "email": "jane@example.com",
  "phone": "+1234567890",
  "company": "Acme Corp",
  "priority": "high",
  "category": "website_rebuild",
  "reasoning": "Clear budget and timeline, decision maker confirmed",
  "message": "Full project description here",
  "timestamp": "2026-02-15T10:30:00Z",
  "qualifier_1_key": "budget_readiness",
  "qualifier_1_label": "Budget Status",
  "qualifier_1_answer": "Approved, 50-100k range",
  "qualifier_2_key": "decision_authority",
  "qualifier_2_label": "Decision Authority",
  "qualifier_2_answer": "CEO, final decision maker",
  "qualifier_3_key": "project_timeline",
  "qualifier_3_label": "Timeline",
  "qualifier_3_answer": "Q2 2026"
}

The eventType field is the routing key. Everything else is template data.

Step 2: Route by event type

Add a Switch node that evaluates {{ $json.eventType }}.

Create three output branches:

  • Output 1: Value equals sales_inquiry_notification
  • Output 2: Value equals vendor_request
  • Output 3: Value equals form_submission

Each branch leads to a different email template node. This is where the sub-flow architecture pays off — adding a fourth notification type later means adding one Switch rule and one email node.

Step 3: Build the sales inquiry notification email

For the sales_inquiry_notification branch, add a Send Email node (using SMTP credentials).

  • From: no-reply@yourdomain.com
  • To: sales@yourdomain.com (your internal sales inbox)
  • Subject: Build this as an expression: NEW {{ $json.priority.toUpperCase() }} PRIORITY LEAD — {{ $json.company }}

For the HTML body, build a formatted template that sales can scan in seconds:

<div style="font-family: Arial, sans-serif; max-width: 600px;">
  <h2 style="color: #1a1a1a;">New Lead Received</h2>

  <table style="width: 100%; border-collapse: collapse;">
    <tr>
      <td style="padding: 8px; font-weight: bold;">Company</td>
      <td style="padding: 8px;">{{ $json.company }}</td>
    </tr>
    <tr>
      <td style="padding: 8px; font-weight: bold;">Contact</td>
      <td style="padding: 8px;">{{ $json.firstName }} {{ $json.lastName }}</td>
    </tr>
    <tr>
      <td style="padding: 8px; font-weight: bold;">Email</td>
      <td style="padding: 8px;">{{ $json.email }}</td>
    </tr>
    <tr>
      <td style="padding: 8px; font-weight: bold;">Phone</td>
      <td style="padding: 8px;">{{ $json.phone }}</td>
    </tr>
    <tr>
      <td style="padding: 8px; font-weight: bold;">Priority</td>
      <td style="padding: 8px;">{{ $json.priority }}</td>
    </tr>
    <tr>
      <td style="padding: 8px; font-weight: bold;">Category</td>
      <td style="padding: 8px;">{{ $json.category }}</td>
    </tr>
  </table>

  <h3 style="margin-top: 20px;">Why This Lead Matters</h3>
  <p>{{ $json.reasoning }}</p>

  <h3>Key Qualifications</h3>
  <table style="width: 100%; border-collapse: collapse;">
    <tr>
      <td style="padding: 8px; font-weight: bold;">{{ $json.qualifier_1_label }}</td>
      <td style="padding: 8px;">{{ $json.qualifier_1_answer }}</td>
    </tr>
    <tr>
      <td style="padding: 8px; font-weight: bold;">{{ $json.qualifier_2_label }}</td>
      <td style="padding: 8px;">{{ $json.qualifier_2_answer }}</td>
    </tr>
    <tr>
      <td style="padding: 8px; font-weight: bold;">{{ $json.qualifier_3_label }}</td>
      <td style="padding: 8px;">{{ $json.qualifier_3_answer }}</td>
    </tr>
  </table>

  <p style="color: #666; font-size: 12px; margin-top: 20px;">
    Received: {{ $json.timestamp }}
  </p>
</div>

This template renders cleanly in every major email client because it uses inline styles and basic HTML tables. No external CSS, no web fonts, no fancy layout that Gmail will strip.

Step 4: Build the other notification templates

For the vendor_request branch, add another Send Email node with a template tailored for partnership inquiries. The structure is similar but the fields differ — vendor requests typically include requestType, description, budget, and deadline instead of qualification answers.

For the form_submission branch, add a third Send Email node for generic contact form submissions. Simpler template, fewer qualification fields, but the same core structure of contact details plus message.

I will not reproduce every template line by line here because the pattern is identical — an HTML table with inline styles, customized field labels, and expression-based values. The important thing is that each event type gets its own template so sales can visually distinguish a hot lead notification from a vendor request at a glance.

Step 5: Check if visitor email exists

After all three notification branches, connect them to a single IF node.

The condition checks whether the visitor's email address is present:

  • Value 1: {{ $('When Executed by Another Workflow').item.json.email }}
  • Operation: is not empty

This gate prevents the workflow from trying to send an acknowledgement email when the email field is missing or blank. Chatbot interactions sometimes collect leads progressively — name and company first, email later. Without this check, the SMTP node would throw an error.

Step 6: Send visitor acknowledgement

On the true branch of the IF node, add a Send Email node.

  • From: noreply@yourdomain.com
  • To: {{ $('When Executed by Another Workflow').item.json.email }}
  • Subject: We have received your request
  • Body:
<div style="font-family: Arial, sans-serif; max-width: 600px;">
  <p>Hi {{ $('When Executed by Another Workflow').item.json.firstName }},</p>
  <p>Thank you for reaching out. We have received your inquiry
     and will follow up shortly.</p>
  <p>Best regards,<br>The Team</p>
</div>

This single acknowledgement node is shared across all three event types. No matter how the lead came in — chatbot, vendor form, contact form — the visitor gets the same confirmation. This is the advantage of converging all branches into one IF gate before the acknowledgement step.

Save Workflow 2. The complete structure is: trigger receives data, Switch routes by event type, three parallel email nodes send internal notifications, all branches converge into an IF check, and a single node sends the visitor confirmation if an email exists.

Workflow 3: The webhook gateway

This is the main workflow — the public entry point that receives lead data from your website and orchestrates everything else. Create a new workflow and name it "Lead Intake — Webhook Gateway".

Step 1: Set up the Webhook trigger

Add a Webhook node.

  • HTTP Method: POST
  • Path: Something descriptive like lead-intake

This gives you a URL like https://your-n8n-instance.com/webhook/lead-intake that your chatbot or form backend will POST to.

The webhook expects a JSON body with this structure:

{
  "firstName": "Jane",
  "lastName": "Smith",
  "email": "jane@example.com",
  "phone": "+1234567890",
  "company": "Acme Corp",
  "priority": "high",
  "status": "qualified",
  "category": "website_rebuild",
  "reasoning": "Clear budget and timeline confirmed",
  "recommendedAction": "Schedule discovery call",
  "actionType": "new_lead",
  "qualifierAnswers": [
    { "question": { "key": "budget_readiness" }, "answer": "Approved, 50-100k" },
    { "question": { "key": "decision_authority" }, "answer": "CEO" },
    { "question": { "key": "project_type" }, "answer": "Website rebuild" },
    { "question": { "key": "scope_scale" }, "answer": "Mid-size" },
    { "question": { "key": "project_timeline" }, "answer": "Q2 2026" }
  ]
}

The actionType field controls whether this is a new lead or an update to an existing one. The qualifierAnswers array is dynamic — it supports any number of questions with arbitrary keys.

In production, protect this webhook endpoint. Add a shared secret header (e.g., x-webhook-secret) and validate it in a Code node before processing any data. Without authentication, anyone who discovers the URL can inject fake leads into your CRM.

Step 2: Normalize qualifier answers

The qualifierAnswers array is flexible for the frontend but inconvenient for CRM mapping. Add a Code node to flatten it into a simple key-value object.

// File: n8n Code Node — Map Qualifier Answers
const input = $input.first().json;
const answers = input.qualifierAnswers || [];

const results = {};

for (const qa of answers) {
  const key = qa.question?.key;
  if (key) {
    results[key] = qa.answer;
  }
}

return [{
  json: {
    ...input,
    ...results,
  }
}];

This takes the dynamic array and spreads each answer as a top-level field. After this node, the data has both the original qualifierAnswers array (for reference) and flat fields like budget_readiness, decision_authority, project_type, scope_scale, and project_timeline available as direct expressions.

The reason for this transformation is that every downstream node — Pipedrive fields, email templates, sub-flow inputs — needs to reference these values by key. Having them at the top level of the JSON object means you can write {{ $json.budget_readiness }} instead of looping through an array in every expression.

Step 3: Branch by action type

Add a Switch node that checks {{ $json.actionType }}.

  • Output 1: Value equals new_lead
  • Output 2: Value equals update_lead

These two branches handle fundamentally different operations. New leads go through the full creation pipeline. Updates modify an existing record without creating duplicates.

Path A: Handling new leads

Step 4A: Search for existing person by email

Before creating anything, check if this person already exists in Pipedrive. Add a Pipedrive node set to "Search" on the "Person" resource.

  • Term: {{ $json.email }}
  • Search by: email

This is duplicate prevention. If someone submits a form twice, or a chatbot conversation generates a lead that was already captured through a different channel, you do not want duplicate Person records in your CRM.

Step 5A: Branch on search results

Add an IF node that checks whether the search returned results.

  • Condition: {{ $('Search Person').item.json.data?.items?.length > 0 }}

If the person exists, you take the "already exists" path. If not, you take the "create new" path.

Step 6A (Person exists): Attach a note and create an activity

If the person already exists, you do not create a new record. Instead, you enrich the existing one.

Add a Pipedrive node to create a Note on the existing person. The HTML content follows the same structure as in Workflow 1 — status, contact details, project scope, reasoning, qualification answers, and recommended next step. The Person ID comes from the search result: {{ $('Search Person').item.json.data.items[0].item.id }}

Then add a Pipedrive node to create an Activity linked to the same Person ID with today's date and a "call" type.

This means repeat inquiries from the same person still generate actionable context in the CRM, just without creating duplicate contacts.

Step 7A (Person exists): Notify sales

After enriching the existing person, call Workflow 2 to send the notification. Add an Execute Workflow node.

Before calling it, you may need a second Code node to flatten the qualifier answers onto the root object again, this time including the qualifier labels for the email template:

// File: n8n Code Node — Prepare Email Payload
const input = $input.first().json;
const answers = input.qualifierAnswers || [];

const emailData = { ...input };

answers.forEach((qa, index) => {
  const num = index + 1;
  emailData[`qualifier_${num}_key`] = qa.question?.key || '';
  emailData[`qualifier_${num}_label`] = qa.question?.label || qa.question?.key || '';
  emailData[`qualifier_${num}_answer`] = qa.answer || '';
});

emailData.eventType = 'sales_inquiry_notification';

return [{ json: emailData }];

This prepares the data in the exact shape that Workflow 2 expects — flat qualifier fields with numbered keys (qualifier_1_label, qualifier_1_answer, etc.) and the eventType set.

Connect this Code node to an Execute Workflow node that calls your "SUB — Email Notification" workflow.

Step 8A (Person does not exist): Call the CRM sub-flow

If the search returned no results, the person is new. Add an Execute Workflow node that calls your "SUB — Create Lead + Person + Organisation" workflow (Workflow 1).

Pass the full flattened data object. Workflow 1 handles everything — Person creation, Organisation, Lead, Activity, Note, custom fields.

After Workflow 1 completes, add another Execute Workflow node to call Workflow 2 for the notification email. The data preparation is identical to Step 7A.

Path B: Handling lead updates

The update path is simpler. When actionType is update_lead, the chatbot or form is sending additional information about an existing lead — perhaps they answered more qualification questions in a follow-up conversation.

Step 4B: Search for the person by email

Same as Step 4A — search Pipedrive for the person by email.

Step 5B: Update the person record

If the person exists, add a Pipedrive node set to "Update" on the "Person" resource.

Update whatever fields have changed. Typically this means the qualification custom fields:

  • Person ID: From search results
  • Custom Fields: Map the flattened qualifier values to their Pipedrive field keys

If the person does not exist (which should be rare on an update action), you can either fall through to the new lead creation path or log the anomaly and skip processing.

The update path is particularly useful when lead qualification happens progressively. A chatbot might capture name and company in the first interaction, then budget and timeline in a follow-up. Each interaction sends an update_lead action that enriches the existing CRM record without creating duplicates.

Connecting the workflows

To wire the Execute Workflow nodes, you need the workflow IDs of your two sub-flows. In n8n, open each sub-flow, look at the URL — the number at the end is the workflow ID. Enter that ID in the Execute Workflow node's "Workflow" field.

Make sure both sub-flows are active. If a sub-flow is inactive, the Execute Workflow node will fail.

Testing the complete pipeline

Test the system by sending a POST request to your webhook URL. You can use the n8n Webhook test mode or send a request with curl:

curl -X POST https://your-n8n-instance.com/webhook/lead-intake \
  -H "Content-Type: application/json" \
  -d '{
    "firstName": "Jane",
    "lastName": "Smith",
    "email": "jane@example.com",
    "phone": "+1234567890",
    "company": "Acme Corp",
    "priority": "high",
    "status": "qualified",
    "category": "website_rebuild",
    "actionType": "new_lead",
    "reasoning": "Clear budget, decision maker, short timeline",
    "recommendedAction": "Schedule discovery call this week",
    "qualifierAnswers": [
      { "question": { "key": "budget_readiness" }, "answer": "Approved, 50-100k" },
      { "question": { "key": "decision_authority" }, "answer": "CEO, final decision maker" },
      { "question": { "key": "project_type" }, "answer": "Website rebuild with AI" },
      { "question": { "key": "scope_scale" }, "answer": "Mid-size, 3 months" },
      { "question": { "key": "project_timeline" }, "answer": "Q2 2026" }
    ]
  }'

After execution, verify in Pipedrive that you see a new Person with the correct name, email, and phone. Check that an Organisation named "Acme Corp" exists and is linked to the Person. Confirm the Lead record exists with the correct title format. Open the Person and verify the structured Note is attached and readable. Check that a call Activity is assigned for today. Inspect the Person's custom fields and confirm all five qualification values are populated. Finally, check your sales inbox for the notification email.

Send the same request again with the same email. This time, the gateway should detect the duplicate, skip the creation sub-flow, and instead attach a new Note and Activity to the existing Person.

Then send an update:

curl -X POST https://your-n8n-instance.com/webhook/lead-intake \
  -H "Content-Type: application/json" \
  -d '{
    "email": "jane@example.com",
    "actionType": "update_lead",
    "qualifierAnswers": [
      { "question": { "key": "project_timeline" }, "answer": "Moved to Q1 2026" }
    ]
  }'

Verify that the Person's project_timeline custom field updates without creating new records.

What you have at the end

After building these three workflows, your system handles the full lead lifecycle automatically.

Every lead that hits the webhook gets normalized, deduplicated, and routed. New leads arrive in Pipedrive as fully structured records with Person, Organisation, Lead, Activity, and Note all linked together, plus structured qualification data in custom fields that are filterable and reportable. Returning leads get enriched with new context instead of creating duplicates. Your sales team gets a formatted email notification the moment a lead arrives, with enough context to decide on a next step without opening the CRM first. And visitors get an immediate acknowledgement that their inquiry was received.

The manual version of this process took fifteen minutes per lead. The automated version takes under three seconds.

The sub-flow architecture means the system is modular. When you need to add a new qualification field, you update the custom field mapping in one place. When you add a new lead source — a second chatbot, a partner referral form, a different landing page — you point it at the same webhook and everything downstream works the same way.

If you want to understand how this lead pipeline connects to a broader CMS-driven automation system where content changes, document processing, and AI workflows all run through the same architecture, I covered that in How Payload CMS and n8n Turn a Website Into an Operational System. And for the background on why self-hosted n8n is a better foundation for this kind of work than Zapier, read my n8n vs Zapier comparison.

Let me know in the comments if you have questions, and subscribe for more practical development guides.

Thanks, Matija

📄View markdown version
0

Frequently Asked Questions

Comments

Leave a Comment

Your email will not be published

Stay updated! Get our weekly digest with the latest learnings on NextJS, React, AI, and web development tips delivered straight to your inbox.

10-2000 characters

• Comments are automatically approved and will appear immediately

• Your name and email will be saved for future comments

• Be respectful and constructive in your feedback

• No spam, self-promotion, or off-topic content

Matija Žiberna
Matija Žiberna
Full-stack developer, co-founder

I'm Matija Žiberna, a self-taught full-stack developer and co-founder passionate about building products, writing clean code, and figuring out how to turn ideas into businesses. I write about web development with Next.js, lessons from entrepreneurship, and the journey of learning by doing. My goal is to provide value through code—whether it's through tools, content, or real-world software.

You might be interested in

Active Tenant Scoping vs Access Control: A Practical Guide
Active Tenant Scoping vs Access Control: A Practical Guide

8th March 2026

n8n vs Zapier 2026: Why Zapier Fails for Serious Projects
n8n vs Zapier 2026: Why Zapier Fails for Serious Projects

16th February 2026

Payload CMS Jobs Queue Explained: Tasks, Jobs & Queues
Payload CMS Jobs Queue Explained: Tasks, Jobs & Queues

14th February 2026

Table of Contents

  • What we are building
  • Preparing Pipedrive custom fields
  • Workflow 1: CRM creation sub-flow
  • Step 1: Add the Execute Workflow Trigger
  • Step 2: Create the Person in Pipedrive
  • Step 3: Attach a structured note
  • Step 4: Create a follow-up activity
  • Step 5: Create the Organisation
  • Step 6: Associate the Person with the Organisation
  • Step 7: Create the Lead record
  • Step 8: Update the lead source channel
  • Step 9: Update qualification custom fields on the Person
  • Workflow 2: Email notification sub-flow
  • Step 1: Add the Execute Workflow Trigger
  • Step 2: Route by event type
  • Step 3: Build the sales inquiry notification email
  • Step 4: Build the other notification templates
  • Step 5: Check if visitor email exists
  • Step 6: Send visitor acknowledgement
  • Workflow 3: The webhook gateway
  • Step 1: Set up the Webhook trigger
  • Step 2: Normalize qualifier answers
  • Step 3: Branch by action type
  • Path A: Handling new leads
  • Path B: Handling lead updates
  • Connecting the workflows
  • Testing the complete pipeline
  • What you have at the end
On this page:
  • What we are building
  • Preparing Pipedrive custom fields
  • Workflow 1: CRM creation sub-flow
  • Workflow 2: Email notification sub-flow
  • Workflow 3: The webhook gateway
Build With Matija Logo

Build with Matija

Matija Žiberna

I turn scattered business knowledge into one usable system. End-to-end system architecture, AI integration, and development.

Quick Links

Payload CMS Websites
  • Bespoke AI Applications
  • Projects
  • How I Work
  • Blog
  • Get in Touch

    Have a project in mind? Let's discuss how we can help your business grow.

    Contact me →
    © 2026BuildWithMatija•Principal-led system architecture•All rights reserved