NetSuite to Salesforce Lead-to-Cash Sync (n8n)
Automate the transition from Back-Office Finance to Front-Office Sales using n8n's robust node-based architecture.
Tools: NetSuite → Salesforce
Platform: n8n
Short Answer
A bi-directional flow where Salesforce Accounts are automatically updated with NetSuite financial data, and sales reps receive real-time notifications of payment issues or inventory changes directly in the CRM.
The Problem
Sales teams often lack visibility into back-office financial status, leading to manual data entry errors and 'blind' selling to credit-blocked customers. This integration bridges the gap between NetSuite ERP and Salesforce CRM by synchronizing customer health and transaction data.
The Outcome
A bi-directional flow where Salesforce Accounts are automatically updated with NetSuite financial data, and sales reps receive real-time notifications of payment issues or inventory changes directly in the CRM.
Step-by-Step Guide
1. **Establish Credentials**: In n8n, go to 'Credentials' and setup **NetSuite Restlet API** (Token-Based Authentication/OAuth 1.0) and **Salesforce OAuth2**. Ensure Salesforce 'Consumer Key' and 'Consumer Secret' are configured in a Connected App.
2. **Configure NetSuite Trigger**: Use an n8n **Webhook Node** as the entry point. In NetSuite, create a 'User Event Script' or 'Scheduled Script' to POST data to the n8n webhook URL whenever a record matches your criteria.
3. **Handle Data Structure**: Add an **Edit Fields Node** (formerly Set) to extract $node['Webhook'].json["body"] and normalize the NetSuite nested JSON structure.
4. **Verify Record Presence**: Add a **Salesforce Node** set to 'Search' for an existing Account using the NetSuite `Internal ID` as the `External ID` in Salesforce to prevent duplicates.
5. **Branching Logic (IF Node)**: Use an **If Node** to check if a match was found. This determines whether you call the 'Create' or 'Update' action.
6. **Map Financial Data**: Use n8n **Expressions** to transform NetSuite currency formats to Salesforce decimal fields. Example: `{{$json.balance.toString().replace(/[^0-9.]/g, '')}}`.
7. **Salesforce Upsert**: Configure the **Salesforce Node** (Action: Upsert) using the custom `NetSuite_ID__c` field as the lookup key to ensure data integrity without duplicate accounts.
8. **Implement Error Handling**: Create a separate 'Error Workflow' and link it in the original workflow's **Settings > Error Workflow** to catch API rate limits or field validation errors.
9. **Wait/Delay (Optional)**: If processing large batches of NetSuite Inventory, use the **Wait Node** or **Split In Batches Node** (set to 50 records) to avoid Salesforce API concurrency limits.
Data Mapping
| NetSuite Field | Salesforce Field | n8n Transformation Expression | Required? |
| :--- | :--- | :--- | :--- |
| Internal ID | NetSuite_ID__c (Ext ID) | `{{ $json.id }}` | Yes |
| Company Name | Name | `{{ $json.companyname }}` | Yes |
| Balance | AnnualRevenue | `{{ parseFloat($json.balance) }}` | No |
| Is Inactive | IsActive__c | `{{ $json.isinactive === 'F' ? true : false }}` | No |
| Terms | Account_Status__c | `{{ $json.terms.name }}` | No |
| Email | PersonEmail / Email | `{{ $json.email.toLowerCase() }}` | Yes |
Gotchas & Failure Modes
• **NetSuite Complexity**: NetSuite returns sublists (e.g., addressbook) as nested objects; use n8n's **Item Lists Node** to flatten these if you need to update multiple Salesforce Contacts.
• **API Limits**: Salesforce has strict 'Concurrent Request' limits. If syncing >1000 records, use the **Split In Batches** node with a batch size of 50.
• **Type Conversion**: NetSuite numbers often arrive as strings in webhooks. Always use `parseFloat()` or `.toNumber()` in n8n expressions before sending to Salesforce numeric fields.
• **TBA Expiry**: NetSuite Token-Based Auth tokens can expire or be revoked if the user's role permissions change. Ensure the NetSuite Service Account has 'Web Services Only' enabled.
Verification Checklist
- [ ] Trigger the NetSuite Webhook manually using a 'Preview' transaction.
- [ ] Check n8n **Execution Log** to Ensure JSON structure matches Expected Salesforce input.
- [ ] Verify globally unique `NetSuite_ID__c` field exists in Salesforce.
- [ ] Test matching logic: Ensure an existing Salesforce account is updated rather than a new one created.
- [ ] Trigger an intentional error (e.g., missing name) to verify the **Error Trigger** workflow initiates.
Ready to Automate?
Build this automation with n8n in minutes.