FlowKit

Syncing a CRM (HubSpot or Pipedrive) with n8n: the complete guide

Published 21 July 2026 · 6 min read

HubSpot and Pipedrive's native integrations with your other tools tend to stop at the same wall: a simple trigger, a simple action, no conditional logic, no fine-grained deduplication, no way to combine several sources before writing to the CRM. The moment a requirement steps outside the standard case — syncing a CRM with a billing tool, enriching a contact before creating it, routing a deal based on precise business rules — n8n becomes the piece that fills the gap, without building a dedicated backend.

Why route through n8n instead of native integrations

Native integration marketplaces (the HubSpot App Marketplace, the Pipedrive Marketplace) handle generic cases well: syncing with Gmail, Slack, a standard form. They start feeling limiting once you need:

  • Conditional logic before writing (only create a deal if the lead clears a score threshold, route to a different pipeline based on source);
  • Combining multiple sources before touching the CRM (enrich a contact with Clearbit or LinkedIn data before creation);
  • Precise deduplication, beyond a simple exact-email match;
  • Logging or history of sync runs, useful for debugging or a later audit;
  • Bidirectional sync between two systems that don't natively talk to each other.

n8n becomes the orchestration layer: a central point that receives events, applies rules, and writes to the right systems in the right order — exactly the role it already plays in the AI-driven lead qualification pipeline, where scoring precedes routing into the CRM.

Authentication: API Key vs OAuth2, depending on the CRM

The authentication choice differs noticeably between the two CRMs.

Pipedrive HubSpot
Simplest option Personal API Token Private App Token
Setup effort Minutes, no consent screen Minutes, scopes chosen explicitly
When OAuth2 is needed Rarely, internal tokens cover most cases Multi-account apps, marketplace-published integrations
Token refresh N/A for API Token Automatic with n8n's OAuth2 node

Pipedrive stays simple: a personal API Token, generated in account settings, covers nearly every internal sync workflow. It's configured in n8n as a Pipedrive API credential, no OAuth consent screen involved.

HubSpot offers two paths:

  • A Private App Token: created from HubSpot's settings (Settings → Integrations → Private Apps), with scopes chosen precisely — crm.objects.contacts.write, crm.objects.deals.read, and so on. This is the simplest option for internal use within a single HubSpot account, with no third-party login screen.
  • OAuth2: needed if you're building an integration meant to serve multiple different HubSpot accounts (an app published on the marketplace, for instance), or if internal security policy requires it. n8n handles the HubSpot OAuth2 flow natively via its dedicated node, including automatic token refresh.

For an internal pipeline serving a single company — the most common case — a HubSpot Private App Token and a Pipedrive API Token cover the vast majority of needs, without the ongoing overhead of maintaining an OAuth2 flow.

Creating and updating contacts and deals

n8n ships dedicated HubSpot and Pipedrive nodes covering common operations (Create, Update, Get, Get Many, Search) without hand-writing HTTP requests. For anything the native node doesn't cover — a recent endpoint, a precise filter parameter — the HTTP Request node is the fallback, pointed directly at the CRM's REST API with the configured credential.

Example structure for creating or updating a HubSpot contact via HTTP Request:

POST https://api.hubapi.com/crm/v3/objects/contacts
{
  "properties": {
    "email": "{{ $json.email }}",
    "firstname": "{{ $json.firstName }}",
    "lastname": "{{ $json.lastName }}",
    "phone": "{{ $json.phone }}"
  }
}

On Pipedrive, creating a deal goes through the /deals endpoint, with the associated contact passed as person_id:

POST https://api.pipedrive.com/v1/deals
{
  "title": "{{ $json.dealTitle }}",
  "person_id": {{ $json.person_id }},
  "value": {{ $json.amount }},
  "currency": "EUR"
}

In both cases, a Set node upstream prepares the payload with the right field names before the call, which keeps the HTTP Request node readable and avoids scattering mapping logic across the URL or headers.

Deduplication: always search before you create

The most common failure mode of an automated CRM sync: creating a duplicate on every run because the workflow never checks whether the contact already exists. This isn't just a cosmetic problem: a now-classic study by Thomas Redman, published in Communications of the ACM in 1998, shows that poor data quality — duplicates, inconsistent fields, stale records — imposes real operational costs on the organization carrying them, by undermining the reliability of decisions made from that data (Redman, 1998, Communications of the ACM). A duplicate contact in HubSpot or Pipedrive is never harmless: every duplicate multiplies the risk of inconsistency between teams relying on that same record. The correct sequence has three steps:

  1. Search by email — the /crm/v3/objects/contacts/search endpoint on HubSpot (an EQ filter on the email property), or /persons/search?term=...&fields=email on Pipedrive.
  2. IF node — checks whether the search returned at least one match ({{ $json.total > 0 }} on HubSpot, {{ $json.data.items.length > 0 }} on Pipedrive).
  3. Update-or-Create branch — if a match exists, update the found record (PATCH with its ID); otherwise, create a new one.

This search-before-create logic is the same pattern used to avoid duplicates in a Supabase contact table; see our n8n-Supabase connection guide for the database-side equivalent, useful when the CRM acts as a secondary source rather than the source of truth.

Bidirectional sync: CRM to tool, and tool to CRM

A genuinely bidirectional sync needs two separate n8n workflows, each triggered by its own source:

  • CRM → other tool: a HubSpot or Pipedrive Webhook (configured on the CRM side to notify n8n on contact.propertyChange or deal.updated) triggers a workflow that pushes the change into the third-party tool (billing, product database, support tool).
  • Other tool → CRM: the reverse, an event in the third-party tool (new order, resolved ticket) triggers a workflow that writes into the CRM via the dedicated node.

The classic risk with this setup: an infinite loop, where the update fired by workflow A retriggers the webhook feeding workflow B, which updates the CRM again, which retriggers A. The most reliable guard is comparing a timestamp or content hash before writing, and skipping the write if nothing actually changed — a simple IF node comparing updatedAt on the source and destination handles most cases. To harden the incoming webhook on the n8n side against unwanted calls, apply the same principles covered in our securing an n8n webhook article.

Handling CRM API rate limits

Both HubSpot and Pipedrive enforce throughput limits:

  • HubSpot: depending on plan, between 100 and 190 requests per 10 seconds for Private Apps, with an X-HubSpot-RateLimit-Remaining header returned on every response.
  • Pipedrive: a daily "budget" system per token, with X-RateLimit-Remaining and X-RateLimit-Reset headers indicating the remaining balance and reset time.

For a sync that processes a batch of contacts at once (an initial import, a full resync), a Loop Over Items node paired with a Wait node between batches prevents saturating these limits — the same mechanic detailed in our article on AI API rate limits in n8n, directly transferable to CRM APIs.

Mapping custom fields

Custom fields require explicit mapping, since their technical identifier often differs from the label shown in the UI:

  • HubSpot references custom properties by an internal name, visible under Settings → Properties → property name. That name is added directly into the request's properties object, alongside standard fields.
  • Pipedrive identifies custom fields by a hash (e.g. 5f3e2a1b4c9d8e7f...), retrievable once via the /dealFields or /personFields endpoint, then stored in a Set node or an environment variable to avoid re-fetching it on every run.

A Set node placed right before the create/update call centralizes this mapping: it translates the readable field names from your source (estimated_budget, industry) into the technical identifiers expected by the CRM, keeping the rest of the workflow readable and easy to maintain.

Wrapping up

Syncing a CRM with n8n instead of its native integration buys you three things standard integrations don't offer: conditional logic before writing, reliable deduplication through a systematic search-before-create, and a properly controlled bidirectional sync across multiple systems. The authentication piece (a HubSpot Private App Token, a Pipedrive API Token) takes a few minutes to set up; most of the real work happens afterward, in field mapping and rate-limit handling. If your CRM pipeline already relies on AI-driven scoring or qualification upstream, the Inbox AI Pack shows the same webhook + business logic + CRM write architecture, applied to triaging incoming emails.

FAQ

Frequently asked questions

Should I use n8n's native HubSpot/Pipedrive node or an HTTP Request node?

Start with the native node: it handles authentication and pagination for you and covers most cases (create, update, search a contact or a deal). Fall back to HTTP Request only for an endpoint the native node doesn't expose yet, or when you need fine control over search query parameters.

How do I avoid creating a duplicate on every sync run?

Always search by email before creating: a search call (the /crm/v3/objects/contacts/search endpoint on HubSpot, /persons/search on Pipedrive) runs ahead of creation, then an IF or Switch node decides between update and create depending on whether the search returns a match.

Is OAuth2 mandatory to connect to HubSpot or Pipedrive?

HubSpot recommends OAuth2 for third-party integrations but still accepts a Private App Token (an API-key-style credential) for internal use within a single account, which greatly simplifies n8n setup. Pipedrive works equally well with a classic API Token or OAuth2; the token alone covers nearly all sync workflows.

How do I handle custom fields (custom properties) in the mapping?

On HubSpot, custom properties are referenced by their internal name, visible in property settings, and added to the same properties object as standard fields. On Pipedrive, custom fields are identified by a long hash (e.g. 5f3e2a1b4c...) retrievable via the /dealFields or /personFields endpoint, mapped once and reused in a Set node.

Bundle FlowKit Complet

€269