Syncing Salesforce with n8n: OAuth2, SOQL, Bulk API and deduplication
Published 28 July 2026 · 5 min read
Salesforce's native Flow Builder handles automations that stay inside the org well — updating a field, sending a notification, assigning a task. It hits a wall the moment Salesforce needs to talk to an external system: cross-referencing data before a write, handling OAuth2 against a third-party API, or processing tens of thousands of records without blowing through the daily API call limit. n8n fills exactly that gap, with a native Salesforce node that covers most of it without writing a line of Apex.
Why n8n instead of Flow Builder or an iPaaS connector
Three situations push a Salesforce need toward n8n:
- Orchestrating multiple systems: enriching a Lead with an external API before creating it (see our guide on automatic lead enrichment), or syncing Salesforce with a tool that has no native Salesforce connector.
- High volumes: Flow Builder struggles with batch processing of thousands of records; the Bulk API is built precisely for that.
- Cost: classic iPaaS platforms (Zapier, Make) bill every Salesforce operation as a paid task, which gets expensive fast at volume — an arbitrage we cover in our n8n vs Make vs Zapier comparison.
An n8n pipeline becomes the central orchestration layer: it receives events (webhook, cron, another CRM), applies business logic, then reads from or writes to Salesforce at the right moment.
Authentication: setting up a Connected App
Unlike Pipedrive's simple API token, Salesforce requires OAuth2 for any third-party integration. Setup happens in two parts.
In Salesforce, under Setup → App Manager → New Connected App:
- Enable OAuth Settings.
- Set the Callback URL to your n8n instance:
https://your-instance.n8n.cloud/rest/oauth2-credential/callback. - Select the required OAuth scopes (
api,refresh_token,offline_accessat minimum). - Grab the generated Consumer Key and Consumer Secret.
In n8n, create a Salesforce OAuth2 API credential, paste those two values, then click Connect to run through the authorization flow. For a test account, flip the credential's environment toggle to "Sandbox": n8n then points to test.salesforce.com instead of login.salesforce.com, without touching your production org. We recommend this safeguard by default, in line with our advice on securing API credentials.
Querying Salesforce with SOQL
The Salesforce node exposes a "Get Many" operation with a custom-query mode using SOQL (Salesforce Object Query Language), close to SQL but adapted to Salesforce's relational model:
SELECT Id, Name, Email, LeadSource, CreatedDate
FROM Lead
WHERE IsConverted = false
AND CreatedDate = THIS_WEEK
SOQL can traverse relationships between objects directly in the query (SELECT Id, Account.Name FROM Contact), avoiding a second call to resolve a parent-child relationship. For dynamic filters (a sliding date range, a variable status), build the SOQL string in an upstream Set or Code node, then inject it into the query parameter — the same approach described in our article on JavaScript expressions in the Code node.
Creating, updating, and the central question of deduplication
The native Salesforce node offers Create, Update, Get, Get Many, Delete, and crucially Upsert for objects that support it (Lead, Contact, Account, custom objects). Upsert is the operation to reach for on any recurring sync.
Upsert relies on an External ID: a custom field (text type, marked "External ID" and "Unique" in its field definition) that carries the identifier from your source system — a form submission ID, another CRM's ID, or a Supabase row ID. Passing that External ID to the Upsert operation lets Salesforce create the record if it doesn't exist, or update the existing one, in a single request — no prior lookup, no risk of a duplicate from an imperfect name or email match.
That's a structural difference from HubSpot or Pipedrive, where deduplication typically relies on an email search before writing (see our guide on syncing HubSpot/Pipedrive): Salesforce delegates that logic to the server via the External ID, which is both faster and more reliable at scale.
That step's quality is not a cosmetic detail. A reference study, Reinartz, Krafft and Hoyer ("The Customer Relationship Management Process: Its Measurement and Impact on Performance," Journal of Marketing Research, 2004, see on Google Scholar), shows that it's the quality of the CRM process itself — including the reliability of the data it handles — that drives the impact of CRM on sales performance, more than simply owning the tool.
Scaling up: when to use Bulk API 2.0
The standard Salesforce node processes records one at a time over the classic REST API — fine up to a few hundred records per run. Beyond that, two problems show up: the workflow's execution time stretches out, and every call eats into your daily API call allocation (capped based on your Salesforce edition).
Bulk API 2.0 solves this: it processes operations (insert, update, upsert, delete) asynchronously, in batches that can hold tens of thousands of records in a single job. n8n reaches it through the Salesforce node's dedicated operation, or, for finer control over batching, through direct HTTP Request calls to the /services/data/vXX.X/jobs/ingest endpoints. The trade-off: results aren't immediate — the job runs in the background and its status is checked by polling, a pattern similar to the one described in our article on handling API retries and timeouts.
In practice, a nightly sync of your contact base into Salesforce (a few thousand rows) should go through Bulk API rather than a loop of individual creates — the gain in reliability and speed is significant.
Handling rate limits and errors
Salesforce enforces API call limits on a rolling 24-hour window, scaled to your edition and user license count. A pipeline that syncs continuously should:
- Batch writes instead of calling the API on every single event (batch every few minutes rather than in real time, when immediate freshness isn't critical);
- Watch response headers (
Sforce-Limit-Info) to anticipate the approaching ceiling, following the same principle documented in our guide on rate-limiting AI APIs; - Catch errors through a dedicated n8n Error Workflow rather than letting an execution fail silently — see our error-handling guide.
Logging the sync for audit purposes
For any organization under compliance requirements — tracing changes to a Lead or an AI-qualified Opportunity, for instance — it's worth logging every Salesforce operation to a dedicated Supabase table: which record was created or updated, when, and from what source data. That's exactly the pattern packaged in our Compliance & Audit Pack: a ready-made audit trail, adaptable to a Salesforce sync with a few mapping tweaks.
Wrapping up
Syncing Salesforce with n8n takes a bit more setup rigor than a HubSpot or Pipedrive connector — Connected App, OAuth2, External ID management — but gives you full control in return: SOQL for precise queries, native upsert for reliable deduplication, and a path to Bulk API 2.0 the moment volume demands it. Once that foundation is in place, Salesforce becomes just another system in your n8n orchestration, rather than a silo you have to update by hand.
FAQ
Frequently asked questions
Should I use n8n's native Salesforce node or the HTTP Request node?
Start with the native Salesforce node: it handles OAuth2 authentication and pagination, and covers Leads, Contacts, Opportunities, Accounts, Cases, Tasks and custom objects out of the box. Reach for HTTP Request only for a recent REST endpoint the node doesn't expose yet, or for fine-grained control over a composite SOQL query.
Do I need a Salesforce Developer Edition account to test?
Yes, it's the best option: it's free, gives you a full sandbox environment (Setup, App Manager, custom objects) and lets you test without touching a production org. Switch the n8n credential to sandbox mode while testing, then point it back to login.salesforce.com in production.
When should I switch to Bulk API 2.0 instead of the standard Salesforce node?
As soon as you're processing more than a few thousand records per run. Bulk API 2.0 processes insert/update/upsert/delete operations asynchronously in batches (tens of thousands of records per job) and consumes far less of your daily API call allocation than looping over individual REST calls.
How do I avoid creating duplicate Leads or Contacts on every sync?
The most reliable method is upsert by External ID: a custom unique field (holding your source system's own ID) marked as an External ID field in Salesforce lets the n8n node's Upsert operation create or update a record in a single call, with no prior lookup and no risk of a duplicate from an imperfect email match.
Bundle FlowKit Complet
€269