Short Answer
A fully automated pipeline where a closed deal in your CRM instantly verifies or creates a contact in Xero, generates a drafted sales invoice with line items, and notifies the team of success—all while maintaining a local execution log in n8n.
The Problem
Manual data entry between CRM systems and accounting software leads to invoicing delays, human error in tax calculations, and fragmented customer data. Business owners often lose hours re-typing 'Won' deal information into Xero, delaying cash flow.
The Outcome
A fully automated pipeline where a closed deal in your CRM instantly verifies or creates a contact in Xero, generates a drafted sales invoice with line items, and notifies the team of success—all while maintaining a local execution log in n8n.
Step-by-Step Guide
1. **Setup CRM Trigger**: Use the 'Webhook' node (for real-time) or the 'CRM' specific node (e.g., HubSpot, Pipedrive) to watch for 'Deal Updated' or 'Deal Won' events.
2. **Configure Xero Credentials**: In n8n, go to Credentials > New. Select 'Xero OAuth2 API'. Follow the OAuth flow to authorize n8n to access your Xero organization.
3. **Search for Existing Contact**: Add a 'Xero' node. Set Resource to 'Contact' and Operation to 'Get All'. Use a Filter parameter to search by the CRM's email: `{{ $json.email }}`.
4. **Logic Branching (IF Node)**: Add an 'IF' node to check if the previous step returned a Contact ID. Expression: `{{ $node["Xero"].json["ContactID"] }}` is not empty.
5. **Create/Update Contact**: Based on the IF node, add another Xero node. If false, use 'Create Contact'. If true, use 'Update Contact' to ensure the billing address is current.
6. **Format Line Items**: Use a 'Set' node or 'Code' node (JavaScript) to map CRM products into Xero's array format. Xero requires an array of objects containing `Description`, `Quantity`, `UnitAmount`, and `AccountCode`.
7. **Generate Invoice**: Add a Xero node. Set Resource to 'Invoice' and Operation to 'Create'. Map the Contact ID from Step 5 and the Line Items from Step 6. Set 'Status' to `DRAFT` for safety or `AUTHORISED` for automation.
8. **Data Transformation with Expressions**: Use n8n expressions like `{{ $now.format('YYYY-MM-DD') }}` for the invoice date and `{{ $json.total.toNumber() }}` to ensure numeric values.
9. **Error Handling**: Create a separate 'Error Trigger' workflow or use the 'On Error' settings on individual nodes to send a message to Slack or Email if an invoice fails (e.g., due to a missing Tax ID).
10. **Activate Workflow**: Save the workflow and toggle the 'Active' switch in the top right of the n8n UI.
Data Mapping
| CRM Field | Xero Field | Transformation / Expression | Required |
| :--- | :--- | :--- | :--- |
| `deal_name` | `Reference` | `{{ $json.deal_name }}` | No |
| `customer_email` | `Contact[EmailAddress]` | `{{ $json.email.toLowerCase() }}` | Yes |
| `close_date` | `Date` | `{{ $json.date_closed || $now }}` | Yes |
| `products[]` | `LineItems[]` | Use Code node to map Array | Yes |
| `currency` | `CurrencyCode` | `{{ $json.currency }} || 'USD'` | Yes |
| `n/a` | `AccountCode` | Fixed Value (e.g., '200' for Sales) | Yes |
Gotchas & Failure Modes
• **Rate Limiting**: Xero has a limit of 5,000 API calls per day and 60 requests per minute. Use the 'Wait' node or 'Split in Batches' if migrating large historical datasets.
• **Strict ISO Dates**: Xero will fail if the date is not a valid string (YYYY-MM-DD). Use n8n's `$now` or `DateTime` node to reformat CRM timestamps.
• **Contact Matching**: Matching by name can create duplicates if there is a typo. Always try to match by `ContactID` (if stored in CRM) or `EmailAddress` first.
• **Node Execution Limits**: If self-hosting on a small VPS, set `N8N_EXECUTIONS_DATA_SAVE_ON_SUCCESS` to `none` to prevent your database from filling up with large Xero payloads.
Verification Checklist
- [ ] **Credential Check**: The Xero node shows 'Connection successful'.
- [ ] **Dry Run**: Execute the workflow manually using a test Deal ID from the CRM.
- [ ] **Contact Search Logic**: Verify that if the contact already exists in Xero, a new one is NOT created.
- [ ] **Invoice Draft**: Check Xero > Business > Invoices > Draft to see if the data mapped correctly (Line Items, Tax, Reference).
- [ ] **Execution Log**: Check the n8n 'Executions' tab to ensure no '400 Bad Request' errors are hidden in the JSON output.
Ready to Automate?
Build this automation with n8n in minutes.