Pipedrive Integration
Sync your Pipedrive CRM contacts and companies with Propstreet automatically.
Overview
| Feature | Support |
|---|---|
| Market | Global (Nordic-wide) |
| Sync Direction | Bidirectional |
| Real-time Updates | Yes (customer-managed sync) |
| Contacts | ✅ Full support |
| Companies | ✅ Full support |
| Projects | ✅ Full support (v1.2.0) |
| Prospects | ✅ Full support (v1.2.0) |
| Properties | ⚠️ API available (v1.3.0) |
Data Mapping
Contact Fields
| Pipedrive | Propstreet | Notes |
|---|---|---|
| Name | First/Last Name | Parsed from single name field |
| Primary email synced | ||
| Phone | Phone | Primary phone synced |
| Organization | Connection | Links contact to company |
| Job Title | Job Title | Synced to company connection |
| Labels | Tags | Mapped as tags |
| Notes | Notes | Via Notes API |
| Custom: Strategy | Strategy | Investment focus (custom field) |
Note: Pipedrive supports multiple emails and phones per person. We sync the primary value to Propstreet's single-value fields.
Company Fields
| Pipedrive | Propstreet | Notes |
|---|---|---|
| Name | Name | |
| Address (country) | Country Code | ISO 2-letter code |
| Custom: Org Number | External Reference | For Nordic deduplication |
| Custom: Domain | Domain | For company matching |
How Sync Works
Pipedrive → Propstreet
You control the sync through your own integration layer:
- Configure Pipedrive Webhooks v2 to send events to your middleware (e.g., Zapier, Make, Azure Logic Apps, n8n, or custom service)
- Your middleware transforms and pushes data to Propstreet via our API
- Records are matched using email or company domain and created/updated in Propstreet
Pipedrive Webhooks v2 provide near real-time delivery with retry logic—any 2XX response counts as successful delivery.
Propstreet → Pipedrive
When you update a contact in Propstreet, you have two options:
Option A: Webhooks (Recommended)
- Register a Propstreet webhook for
contact.*andcompany.*events - Propstreet pushes changes to your endpoint in real-time
- Your middleware transforms and pushes to Pipedrive
Option B: Polling
- Your integration layer polls the Propstreet API for changes (using
updated_since) - Changes are transformed and pushed to Pipedrive via their API
- Your Pipedrive records stay in sync
Propstreet recommends polling every 5–15 minutes for delta sync.
Duplicate Handling
We use smart matching to prevent duplicates:
- Contacts: Matched by email address first, then Pipedrive person ID via
externalRefs - Companies: Matched by domain, then organization number (if configured)
Store Pipedrive IDs in Propstreet's externalRefs array and Propstreet IDs in Pipedrive custom fields for reliable bidirectional sync.
Field Considerations
Multiple Emails and Phones
Pipedrive supports multiple emails and phone numbers per person. Propstreet syncs the primary value only; additional values remain in Pipedrive but are not synced.
Job Title and Organization
Pipedrive stores persons with an organization association. In Propstreet, job title is part of the company connection. When syncing:
- The person's organization maps to a company connection in Propstreet
- Job title (if stored as custom field or note) maps to the connection's job title field
Notes vs Strategy
Pipedrive has a notes feature for activity logging. For commercial real estate investors:
- Investment criteria ("Looking for office buildings, €10M+") → sync to Propstreet's
strategyfield via a custom Pipedrive field - Activity logs ("Called Jan 15, discussed pipeline") → sync to Propstreet's Notes API
Create a custom Pipedrive field investor_strategy to separate investment focus from activity notes.
Website and Domain
Pipedrive organizations don't have a native website field. For company matching:
- Create a custom field
domainin Pipedrive to store the company's web domain - Use this for deduplication alongside organization number
Organization Number (Nordic)
Pipedrive doesn't have a built-in organization number field. For Nordic markets, create a custom field in Pipedrive to store:
- Norway: Organisasjonsnummer
- Sweden: Organisationsnummer
- Denmark: CVR-nummer
- Finland: Y-tunnus
This enables accurate company matching via Propstreet's externalRefs field.
Setup Requirements
To build a Pipedrive integration, you'll need:
- Pipedrive Account - Any plan; Advanced or higher recommended for more API tokens
- Propstreet API Credentials - Generate in your account settings
- Integration Layer - Middleware to handle webhooks and API calls (Zapier, Make, Azure Logic Apps, n8n, or custom)
- Pipedrive Custom Fields - Create fields for:
propstreet_contact_id,propstreet_company_id,investor_strategy,domain, and optionallyorg_number
Getting Started
- Generate Propstreet API credentials in your account settings (requires login)
- Review the Propstreet API documentation for endpoints and data models
- Set up your integration layer to sync data between Pipedrive and Propstreet
- Create custom fields in Pipedrive for Propstreet IDs and investor strategy
- Configure Pipedrive Webhooks v2 for person and organization events
- Test with a small dataset before full rollout
You're responsible for building and maintaining the integration.
Frequently Asked Questions
Which Pipedrive plans support the integration?
The integration works with all Pipedrive plans. However, API token budgets vary by plan—Advanced and higher tiers provide more daily API tokens.
How does Pipedrive rate limiting work?
Pipedrive uses token-based rate limiting with daily budgets (30,000 base tokens × plan multiplier × seats) and burst limits (10 requests per 2 seconds for Search API). Design your integration to:
- Use webhooks instead of polling where possible
- Avoid heavy Search API usage—use stable IDs and a mapping database instead
- Implement exponential backoff on 429 responses
How often does data sync?
Sync frequency depends on how you configure your integration layer:
- Real-time: Use Pipedrive Webhooks v2 to trigger immediate syncs
- Scheduled: Poll Propstreet API every 5–15 minutes (using
updated_since) - Manual: Trigger syncs on-demand
What happens to data if I stop syncing?
Your data remains in both systems. No data is deleted. Use externalRefs to maintain record linkage if you resume syncing later.
Can I choose which contacts to sync?
Yes. Your integration layer controls which records to sync. Common filtering approaches:
- Pipedrive filters or custom fields
- Labels (e.g., only sync persons with "Investor" label)
- Organization associations
How should I handle merge conflicts?
Design your integration layer to handle conflicts. Common approaches:
- Last write wins: Compare
updatedUtc(Propstreet) andupdate_time(Pipedrive) to determine the most recent change - Source of truth: Designate one system as authoritative for specific fields (e.g., CRM for identity, Propstreet for investment strategy)
- Manual review: Flag conflicts for human review
Propstreet supports ETags for optimistic concurrency—use If-Match headers to prevent lost updates.
Projects & Prospects (v1.2.0)
Sync real estate deals between Pipedrive Deals and Propstreet Projects. Track investor prospects through your pipeline with bidirectional classification sync.
Deal to Project Mapping
| Pipedrive Deal | Propstreet Project | Notes |
|---|---|---|
| id | externalRefs | namespace: "pipedrive" |
| title | name | Direct mapping |
| stage_id | status | Map to pipeline stages (see below) |
| pipeline_id | — | Use to filter which deals to sync |
| status (open/won/lost) | status | won/lost → closed/deleted |
| (custom) is_portfolio | isPortfolio | Create custom field |
| (custom) property_count | propertyCount | Create custom field |
| add_time | createdUtc | Read-only in Propstreet |
| update_time | updatedUtc | For delta sync |
Deal Participants to Prospect Mapping
| Pipedrive | Propstreet Prospect | Notes |
|---|---|---|
| person_id (primary) | contactId | Primary contact becomes prospect |
| Participant person_id | contactId | Each participant → prospect |
| org_id | companyId | Alternative for company-level |
| (custom) classification | classification | Track via custom field |
Note: Pipedrive webhooks v2 do not trigger on participant changes. Poll the participants endpoint every 5-15 minutes to sync prospect additions/removals.
Stage Mapping
Propstreet uses three separate fields for project state. Map Pipedrive deal stages to the appropriate combination:
| Pipedrive Stage (example) | status |
classification |
teaser.stage |
Notes |
|---|---|---|---|---|
| Lead In | open | draft | — | Initial deal setup |
| Property Added | open | draft | — | Property details added |
| Teaser Drafting | open | active | published | Marketing preparation |
| Investor Outreach | open | active | communicated | Active outreach |
| Due Diligence | open | active | communicated | Deep investor engagement |
| Closing | open | active | communicated | Final negotiations |
| Won | closed | — | — | Deal completed |
| Lost | deleted | — | — | Deal fell through |
status: Lifecycle state (open,closed,deleted) — read-only, set by systemclassification: Work stage (draft,active,inactive) — settable via APIteaser.stage: Teaser progress (property_added,drafting,published,verified,communicated) — read-only, set by system
Custom Fields to Create in Pipedrive
Create these custom fields for reliable bidirectional sync:
| Field Name | Field Type | Purpose |
|---|---|---|
propstreet_project_id |
Text | Propstreet Project ID |
is_portfolio |
Single option (Yes/No) | Portfolio deal flag |
property_count |
Number | Number of properties |
property_type |
Multiple options | Office, Retail, etc. |
Sync Architecture
Pipedrive → Propstreet (using Webhooks v2):
- Subscribe to deal events via Webhooks v2
- Transform and push to Propstreet Projects API
- Store Propstreet IDs in custom fields
- Poll participants endpoint for prospect sync
// Handle Pipedrive webhook v2
async function handlePipedriveWebhook(payload) {
const { meta, data } = payload;
if (meta.action === "added" && meta.object === "deal") {
const project = await propstreet.post("/api/v1/projects", {
name: data.title,
externalRefs: [{ namespace: "pipedrive", id: String(data.id) }],
});
// Store Propstreet ID in Pipedrive
await pipedrive.put(`/v1/deals/${data.id}`, {
propstreet_project_id: project.id,
});
}
}
Propstreet → Pipedrive (using Webhooks):
- Register webhooks for
project.*andprospect.*events - Look up Pipedrive Deal ID from
externalRefs - Update Pipedrive via REST API
// Handle Propstreet webhook
async function handlePropstreetWebhook(payload) {
const pipedriveId = payload.data.externalRefs?.find(
(ref) => ref.namespace === "pipedrive"
)?.id;
if (payload.event === "project.updated" && pipedriveId) {
await pipedrive.put(`/v1/deals/${pipedriveId}`, {
title: payload.data.name,
});
}
}
Webhook Events
Subscribe to these Propstreet events for deal sync:
| Event | Description | Pipedrive Action |
|---|---|---|
| project.created | New project created | Create Deal |
| project.updated | Project fields modified | Update Deal |
| project.deleted | Project soft-deleted | Mark as Lost |
| prospect.created | Investor added to prospect list | Add Deal Participant |
| prospect.updated | Classification changed | Update custom field |
| prospect.deleted | Investor deleted from prospect list | Remove Deal Participant |
Pipedrive Webhooks v2 Setup
curl -X POST "https://{company}.pipedrive.com/v1/webhooks" \
-H "x-api-token: $PIPEDRIVE_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"subscription_url": "https://your-middleware.com/pipedrive/webhooks",
"event_action": "*",
"event_object": "deal",
"version": "2.0"
}'
Example: Create Project with Pipedrive Reference
curl -X POST "https://app.propstreet.com/api/v1/projects" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Stockholm Office Building",
"isPortfolio": false,
"externalRefs": [{ "namespace": "pipedrive", "id": "12345" }]
}'
Example: Lookup Project by Pipedrive ID
curl "https://app.propstreet.com/api/v1/projects/external/pipedrive/12345" \
-H "Authorization: Bearer $TOKEN"
Participant Sync (Polling Required)
Since Pipedrive webhooks don't fire on participant changes, poll periodically:
// Poll every 5-15 minutes
async function syncParticipants(pipedriveProjectMapping) {
for (const [dealId, projectId] of pipedriveProjectMapping) {
const participants = await pipedrive.get(
`/v1/deals/${dealId}/participants`
);
const prospects = await propstreet.get(
`/api/v1/projects/${projectId}/prospects`
);
// Find new participants to add as prospects
const existingContactIds = new Set(prospects.data.map((p) => p.contactId));
const newParticipants = participants.data.filter(
(p) => !existingContactIds.has(lookupPropstreetContactId(p.person_id))
);
if (newParticipants.length > 0) {
await propstreet.post(`/api/v1/projects/${projectId}/prospects:batch`, {
prospects: newParticipants.map((p) => ({
contactId: lookupPropstreetContactId(p.person_id),
externalRefs: [{ namespace: "pipedrive", id: String(p.id) }],
})),
});
}
}
}
Batch Operations
Propstreet supports adding up to 100 prospects in a single request:
POST /api/v1/projects/{id}/prospects:batch
{
"prospects": [
{ "contactId": "123", "externalRefs": [{ "namespace": "pipedrive", "id": "456" }] },
{ "contactId": "124", "externalRefs": [{ "namespace": "pipedrive", "id": "457" }] }
]
}