Salesforce Lead-to-Cash Automation: Sync Opportunity to Xero Invoice (n8n)

Streamline financial operations by automatically generating Xero invoices from Salesforce Closed-Won opportunities using n8n's visual workflow engine.

Tools: SalesforceXero

Platform: n8n

Short Answer

A fully automated workflow in n8n that triggers when an Opportunity is 'Closed-Won'. It automatically syncs customer data, maps complex product line items to Xero, and creates a draft invoice, reducing administrative overhead by 95%.

The Problem

Manual data entry between Salesforce and Xero creates a bottleneck in the 'Lead-to-Cash' cycle. Finance teams often waste hours re-keying Opportunity Line Items into Xero, leading to human errors, delayed billing, and inconsistent customer records across the organization.

The Outcome

A fully automated workflow in n8n that triggers when an Opportunity is 'Closed-Won'. It automatically syncs customer data, maps complex product line items to Xero, and creates a draft invoice, reducing administrative overhead by 95%.

Step-by-Step Guide

1. **Establish Credentials**: In n8n, go to 'Credentials' and set up 'Salesforce OAuth2' and 'Xero OAuth2' using your Developer App Client IDs/Secrets. 2. **Salesforce Trigger Node**: Add a 'Salesforce Trigger' node. Set the Resource to 'Opportunity' and Event to 'Updated'. 3. **Filter Logic (IF Node)**: Add an 'IF' node to check if `{{ $json.StageName }}` equals `Closed Won`. This prevents the workflow from running on every stage change. 4. **Fetch Account Data**: Add a Salesforce node to 'Get' the 'Account' using the `AccountId` from the trigger. This ensures you have the correct billing address and email. 5. **Sync Contact to Xero**: Add a Xero node. Use the 'Get/Create Contact' action. Map the Name and Email from the Salesforce Account node. Use the contact's email as the unique identifier to prevent duplicates. 6. **Retrieve Line Items**: Salesforce stores product details in 'OpportunityLineItem'. Add a Salesforce node to 'Find' records where the `OpportunityId` matches your trigger ID. 7. **Transform Line Items**: Use an 'Edit Image' or 'Set' node with an n8n Expression to map the Salesforce array to the Xero structure. You will need to map `Quantity`, `UnitPrice`, and `PricebookEntry.Product2.ProductCode` to Xero's `LineItems` array. 8. **Create Xero Invoice**: Add a Xero node with the 'Create Invoice' action. Set the status to `DRAFT` (safest for finance review). Map the `ContactID` from Step 5 and the `LineItems` array from Step 7. 9. **Update Salesforce**: Add a final Salesforce 'Update' node to write the Xero Invoice Number back to a custom field in Salesforce for easy cross-referencing. 10. **Error Log**: Toggle 'On Error' in node settings or add an 'Error Trigger' node to send a Slack/Email alert if the Xero API rejects the data (e.g., due to a missing Product Code).

Data Mapping

| Salesforce Field | Xero Field | Transformation / Expression | | :--- | :--- | :--- | | Account.Name | Contact Name | `{{ $node["SF_Account"].json.Name }}` | | Account.BillingStreet | Address Line 1 | `{{ $node["SF_Account"].json.BillingStreet }}` | | Opportunity.CloseDate | Date | `{{ $json.CloseDate }}` (Standard YYYY-MM-DD) | | Amount | Total | (Handled via Line Items sum) | | OpportunityLineItem.Quantity | Quantity | `{{ $json.Quantity }}` | | OpportunityLineItem.ListPrice | UnitAmount | `{{ $json.ListPrice }}` | | Product2.ProductCode | ItemCode | `{{ $json.ProductCode ?? 'DEFAULT' }}` |

Gotchas & Failure Modes

• **Rate Limiting**: Xero has a limit of 60 requests per minute. If bulk-updating Salesforce, use the n8n 'Wait' node or 'Split in Batches' node (set to 50 records) to avoid API lockout. • **Data Arrays**: Salesforce 'OpportunityLineItems' returns an array. Ensure you use the n8n 'Execute Once' setting if your Xero node expects a single object, or iterate through them properly. • **Product Codes**: Xero requires an 'ItemCode' if you want to track inventory. Ensure every Product in Salesforce has a matching Code in Xero, otherwise, the invoice creation will fail. • **Currency Mismatch**: If you operate in multi-currency, ensure the Salesforce ISO code matches the Xero Currency code exactly.

Verification Checklist

- [ ] **Trigger Test**: Change a Salesforce Opportunity to 'Closed-Won' and verify the n8n Execution log triggers. - [ ] **Contact Lookup**: Confirm the workflow doesn't create a second Xero Contact if the person already exists (Search-then-Update logic). - [ ] **Line Item Accuracy**: Check that an invoice with 3+ items in Salesforce generates exactly 3 line items in Xero with correct totals. - [ ] **OAuth Refresh**: Ensure the n8n Salesforce app has 'Refresh Token' scope enabled to prevent workflow failure after 2 hours. - [ ] **Data Loophole**: Verify that the workflow ignores Opportunities with a $0 total if your business logic requires it.

Ready to Automate?

Build this automation with n8n in minutes.