
A developer posted this on the WordPress support forums:
"I connected Contact Form 7 to Pipedrive. Web form data is going into Pipedrive under Contacts view but I want it in the Lead view. How do I fix this?"
The plugin author's reply: "The menu says 'Create New Contact' so it adds contacts. That's what it does."
Technically correct. Not very helpful.
The real issue isn't a plugin setting it's a Pipedrive data model misunderstanding that catches almost every developer building their first CF7-to-Pipedrive integration. Contacts, Leads, and Deals are three separate objects in Pipedrive, and they live in completely different parts of the CRM. Hitting the wrong API endpoint lands your data in the wrong place.
This post explains the difference, maps each to the correct API endpoint, and shows how to send CF7 submissions directly into Deals (or Leads) instead of just Contacts.
Pipedrive's Three-Object Data Model
This is the part no integration tutorial explains upfront:
| Object | What it is | Where it lives in Pipedrive UI | API Endpoint |
|---|---|---|---|
| Person (Contact) | A CRM contact record — name, email, phone | People tab | POST /v1/persons |
| Lead | A lightweight pre-qualified prospect not yet a deal | Leads Inbox | POST /v1/leads |
| Deal | An active sales opportunity in a pipeline stage | Deals / Pipeline view | POST /v1/deals |
Most CF7 integration plugins including the free tier of the one in this forum thread only call POST /v1/persons. That creates a Person record (Contact view). It does not create a Lead or a Deal.
If your sales team works from the Deals pipeline or the Leads Inbox, form submissions going only to Contacts are invisible to them in their daily workflow.
What You Actually Want: Deal vs Lead
Before picking an endpoint, decide which Pipedrive object fits your workflow:
Use POST /v1/deals if:
- You want submissions to appear in a pipeline with stages (e.g., New → Qualified → Proposal → Closed)
- Your sales team works from the Kanban or list pipeline view
- You need to assign pipeline stage, owner, and expected close date
Use POST /v1/leads if:
- You want a lightweight inbox for unqualified enquiries before they become deals
- You don't need pipeline stage assignment yet
- You want to triage first, convert to Deal later
Both require a Person to be created first you link the Deal or Lead to the Person via person_id.
The Correct API Sequence
Step 1 - Create a Person (always first)
POST https://api.pipedrive.com/v1/persons
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
{
"name": "Jane Smith",
"email": [{ "value": "jane@example.com", "primary": true }],
"phone": [{ "value": "+11234567890", "primary": true }]
}
Response gives you a person_id use it in the next call.
Step 2a - Create a Deal (pipeline view)
POST https://api.pipedrive.com/v1/deals
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
{
"title": "Website Enquiry - Jane Smith",
"person_id": 123,
"pipeline_id": 1,
"stage_id": 1,
"status": "open"
}
Step 2b - Create a Lead (leads inbox)
POST https://api.pipedrive.com/v1/leads
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
{
"title": "Website Enquiry - Jane Smith",
"person_id": 123
}
The Lead endpoint is simpler - no pipeline or stage needed. It lands in the Leads Inbox for your team to triage.
Full CF7 Implementation (Deals Flow)
add_action('wpcf7_before_send_mail', 'cf7_to_pipedrive_deal');
function cf7_to_pipedrive_deal($contact_form) {
if ((int) $contact_form->id() !== YOUR_FORM_ID) return;
$submission = WPCF7_Submission::get_instance();
if (!$submission) return;
$data = $submission->get_posted_data();
$token = defined('PIPEDRIVE_API_TOKEN') ? PIPEDRIVE_API_TOKEN : '';
$base = 'https://api.pipedrive.com/v1';
$headers = [
'Authorization' => 'Bearer ' . $token,
'Content-Type' => 'application/json',
];
// 1. Create Person
$person_res = wp_remote_post("$base/persons", [
'headers' => $headers,
'body' => wp_json_encode([
'name' => sanitize_text_field($data['your-name'] ?? ''),
'email' => [['value' => sanitize_email($data['your-email'] ?? ''), 'primary' => true]],
'phone' => [['value' => sanitize_text_field($data['your-phone'] ?? ''), 'primary' => true]],
]),
'timeout' => 15,
]);
$person = json_decode(wp_remote_retrieve_body($person_res), true);
$person_id = $person['data']['id'] ?? null;
if (!$person_id) return;
// 2. Create Deal linked to Person
wp_remote_post("$base/deals", [
'headers' => $headers,
'body' => wp_json_encode([
'title' => 'Enquiry - ' . sanitize_text_field($data['your-name'] ?? ''),
'person_id' => $person_id,
'pipeline_id' => 1, // get your IDs from GET /v1/pipelines
'stage_id' => 1, // get your IDs from GET /v1/stages
'status' => 'open',
]),
'timeout' => 15,
]);
}
To use the Leads Inbox instead, replace the second wp_remote_post call:
// 2. Create Lead linked to Person (lands in Leads Inbox)
wp_remote_post("$base/leads", [
'headers' => $headers,
'body' => wp_json_encode([
'title' => 'Enquiry - ' . sanitize_text_field($data['your-name'] ?? ''),
'person_id' => $person_id,
]),
'timeout' => 15,
]);
No-Code Option: Contact Form to API Plugin
If you'd rather configure this from a UI than deploy PHP, Contact Form to API lets you point directly at any Pipedrive endpoint — /persons, /deals, or /leads — set the Authorization header, and map CF7 fields to JSON keys. No code, no deployment, token updates happen in the dashboard.
Quick Lookup: Get Your Pipeline and Stage IDs
You need integer IDs for pipeline_id and stage_id. Grab them with a quick GET:
# Get pipeline IDs
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://api.pipedrive.com/v1/pipelines"
# Get stage IDs for pipeline 1
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://api.pipedrive.com/v1/stages?pipeline_id=1"
The id field in each response object is what you pass into your Deal payload.
--
Top comments (0)