Automated Dext to Xero Bill Processing & Enrichment (n8n)

Streamline financial document processing with advanced logic, multi-step approvals, and automated data enrichment using n8n.

Tools: DextXero

Platform: n8n

Short Answer

A robust n8n workflow that triggers when a document is ready in Dext, validates the data, filters for high-value approvals via Slack/Email, and creates a formatted Bill in Xero with the original receipt attached, ensuring 100% data integrity and audit compliance.

The Problem

Standard Dext-to-Xero native integrations lack conditional logic, such as routing high-value invoices for approval or mapping complex tracking categories based on supplier data. Additionally, businesses often need to archive documents to secondary storage or log them in audit trails before they reach the accounting software.

The Outcome

A robust n8n workflow that triggers when a document is ready in Dext, validates the data, filters for high-value approvals via Slack/Email, and creates a formatted Bill in Xero with the original receipt attached, ensuring 100% data integrity and audit compliance.

Step-by-Step Guide

1. **Setup Credentials**: In n8n, navigate to Credentials and add 'Dext API' (via Header Auth or OAuth2) and 'Xero OAuth2'. For self-hosted n8n, ensure your redirect URI is set in the Xero Developer Portal. 2. **Dext Trigger**: Use the 'Dext' node (or a Webhook node if using Dext's outbound webhooks). Set the event to 'Document Published' or poll the `/items` endpoint for items with `status: "ready"`. 3. **JSON Transformation**: Add a 'Set' or 'Edit Image' node to normalize the Dext output. Use expressions like `{{ $json.total_amount.toNumber() }}` to ensure numerical fields are not treated as strings. 4. **Duplicate Check**: Add a 'Xero' node with the action 'Get Many Bills'. Filter by the `reference` (Invoice Number). Use an 'If' node to check if the result length is 0 to prevent double-posting. 5. **Conditional Routing**: Add an 'If' node to check the invoice total. If total > 1000, route to a 'Wait for Webhook' or 'Slack' node for manual sign-off before proceeding. 6. **Create Contact**: Use the 'Xero' node with action 'Create/Update Contact'. Map the Dext `supplier_name` to Xero's `Name`. This ensures the bill creation doesn't fail due to a missing supplier. 7. **Map Chart of Accounts**: Use a 'Lookup' node (or a simple 'Switch' node) to map Dext Categories to Xero Account Codes (e.g., 'Travel' -> '400'). 8. **Create Bill**: Add the 'Xero' node for 'Create Purchase Invoice'. Map the Supplier ID from Step 6 and line items from Step 3. Set the 'Status' to 'AUTHORISED' or 'DRAFT' based on your preference. 9. **Attach Original File**: Use the 'HTTP Request' node to download the image URL provided by Dext, then use the 'Xero' node's 'Upload File' action to attach that binary data to the Bill ID created in Step 8. 10. **Error Handling**: Create an 'Error Trigger' workflow or use the 'On Error' settings on the Xero node to send a notification to a #dev-ops Slack channel if an API limit or 401 error occurs.

Data Mapping

| Source Field (Dext) | Transformation Expression | Destination Field (Xero) | Required | | :--- | :--- | :--- | :--- | | `supplier_name` | `{{ $json.contact_name }}` | Contact Name / ID | Yes | | `inv_ref` | `{{ $json.reference }}` | Invoice Number/Reference | Yes | | `date` | `{{ DateTime.fromISO($json.date).toISODate() }}` | Date | Yes | | `total_amount` | `{{ parseFloat($json.total) }}` | Line Amount | Yes | | `currency` | `{{ $json.currency || 'USD' }}` | Currency Code | Yes | | `category` | `{{ $node["Map"].json.xero_code }}` | Account Code | Yes | | `image_url` | `n8n Binary (via HTTP node)` | File Attachment | No |

Gotchas & Failure Modes

* **Rate Limiting**: Xero has a limit of 60 calls per minute. If processing bulk receipts, use the 'Split In Batches' node in n8n with a 1-second delay between items. * **Date Formats**: Dext may provide various date formats. Always use the `$now` or `DateTime` luxon library inside n8n expressions to format as `YYYY-MM-DD` for Xero. * **Rounding Differences**: n8n handles floating point numbers differently than Xero's accounting engine. Use `.toFixed(2)` in your expressions to prevent 'Total does not match sum of lines' errors. * **Token Expiry**: Xero OAuth tokens expire frequently. Ensure your n8n instance is configured with a persistent database (like PostgreSQL) to keep the refresh tokens valid in the background.

Verification Checklist

- [ ] **Execution History**: Trigger a test document in Dext and confirm the n8n execution log shows a green 'Success' status. - [ ] **Binary Check**: Verify that the receipt image appears in the 'Files' section of the specific Xero Bill, not just the general library. - [ ] **Account Mapping**: Confirm that the Dext category correctly mapped to the numeric Xero Account Code (e.g., 400, 200). - [ ] **Duplicate Prevention**: Re-run the same invoice through n8n and ensure the 'If' node correctly routes it to 'No Action' or updates the existing bill rather than creating a duplicate.

Ready to Automate?

Build this automation with n8n in minutes.