Xero Accounting¶
Overview¶
The Xero Accounting task integrates BaseCloud CRM with Xero (cloud accounting platform), enabling OAuth-authenticated contact and invoice management across multiple organizations with automatic token refresh.
Key Features:
- 8 Actions: create, update, get and list contacts and invoices
- Multi-Tenant Support: Manage multiple Xero organizations
- Auto Token Refresh: Automatic OAuth token renewal
- Tracking Categories: Two-level project/department tracking
- Contact Auto-Create: Automatic contact creation in invoices
- Global Coverage: 180+ countries, 160+ currencies
- Pagination: Handle large datasets efficiently
- Advanced Filtering: OData-style where clauses
Use Cases:
- Multi-organization invoicing from single CRM
- Automated contact synchronization
- Project-based billing with tracking
- Invoice status monitoring and reconciliation
- Bulk reads that fetch every page automatically
Prerequisites¶
1. Xero Account¶
An active Xero subscription, and a Xero user who may manage contacts and invoices in the organisation(s) to use. No Xero developer app is needed — BaseCloud connects with its own.
2. BaseCloud App Connection¶
- Go to Settings → App Connections and add a Xero connection
- Sign in to Xero and allow access
- On the task, pick the connection, then the Organisation (Tenant) it works in
One connection can reach every organisation the Xero user allowed; each task works in the one it names. BaseCloud renews the connection's access with Xero by itself.
3. Tracking Categories (Optional)¶
Xero Tracking Setup:
- Log into Xero Settings Tracking Categories
- Create categories (e.g., "Department", "Project")
- Add options (e.g., Department: Sales, Marketing, Support)
- Note exact option names for use in invoices
![]()
Two categories maximum, because that is Xero's limit — but each can hold any number of options. Categories group invoice line items for reporting and reconciliation, so the names here are what a task writes into when it sets a tracking value.
Outputs¶
Reference fields as {{task_<ID>_<field>}}.
| Field | Type | Notes |
|---|---|---|
xero |
string | Xero's response — contact or invoice data, depending on the action. Present only on some actions. |
Always emitted¶
| Field | Type | Notes |
|---|---|---|
run |
boolean | Whether the task succeeded. |
run_text |
string | What happened, including the reason on failure. |
Fields marked as action-dependent may be absent
This task does several different things depending on its action setting, and only the fields relevant to that action are emitted. Check a real run in the OUTPUT panel before referencing one downstream.
Configuration¶
Builder fields¶
The Field column is the label as it appears in the task builder; Key is the name the value is stored under and referenced by.
| Field | Key | Type | Default | Notes |
|---|---|---|---|---|
| Xero Account | app_connection_id |
app-connection | – | |
| Organisation (Tenant) | tenant_id |
select | – | |
| Action | xero_action |
select | – | Options: Create Contact · Update Contact · Get Contact · Get Contacts · Create Invoice · Update Invoice · Get Invoice · Get Invoices |
| Contact ID | Contact ID |
text | – | Only shown when xero_action is update_contact, get_contact |
| Contact Name | Contact Name |
text | – | Only shown when xero_action is create_contact, update_contact, get_contact, create_invoice |
| Account Number | Account Number |
text | – | Only shown when xero_action is create_contact, update_contact, get_contact |
| First Name | First Name |
text | – | Only shown when xero_action is create_contact, update_contact |
| Last Name | Last Name |
text | – | Only shown when xero_action is create_contact, update_contact |
| Email Address | Email Address |
text | – | Only shown when xero_action is create_contact, update_contact |
| Tax Number | Tax Number |
text | – | Only shown when xero_action is create_contact, update_contact |
| Bank Account Details | Bank Account Details |
text | – | Only shown when xero_action is create_contact, update_contact |
| Where Filter | Where Filter |
text | – | Only shown when xero_action is get_contacts |
| Where Filter | Where Filter |
text | – | Only shown when xero_action is get_invoices |
| Order By | Order By |
select | – | Options: Default order · Name (A to Z) · Name (Z to A) · Recently updated first · Oldest updated first · Email address · Account number. Only shown when xero_action is get_contacts |
| Order By | Order By |
select | – | Options: Default order · Newest invoice date first · Oldest invoice date first · Due soonest first · Due latest first · Invoice number · Highest total first · Highest amount due first · Recently updated first. Only shown when xero_action is get_invoices |
| Include Archived | Include Archived |
select | false |
Options: No · Yes. Only shown when xero_action is get_contacts |
| Invoice ID | Invoice ID |
text | – | Only shown when xero_action is update_invoice, get_invoice |
| Invoice Number | Invoice Number |
text | – | Only shown when xero_action is create_invoice, get_invoice |
| Invoice Date | Date |
text | – | Only shown when xero_action is create_invoice, update_invoice |
| Due Date | Due Date |
text | – | Only shown when xero_action is create_invoice, update_invoice |
| Reference | Reference |
text | – | Only shown when xero_action is create_invoice, update_invoice |
| Status | Status |
select | – | Options: Draft · Submitted · Authorised · Voided. Only shown when xero_action is create_invoice, update_invoice |
| Statuses Filter | Statuses |
select | – | Options: Draft · Submitted · Authorised · Paid · Voided · Deleted. Only shown when xero_action is get_invoices |
| Contact IDs Filter | Contact IDs |
text | – | Only shown when xero_action is get_invoices |
| Tax Type | line_items_tax_type |
select | – | Options: Exclusive · Inclusive · No Tax. Only shown when xero_action is create_invoice, update_invoice |
| Item Code(s) | Item Code |
text | – | Only shown when xero_action is create_invoice, update_invoice |
| Description(s) | Description |
text | – | Only shown when xero_action is create_invoice, update_invoice |
| Quantity(ies) | Quantity |
text | – | Only shown when xero_action is create_invoice, update_invoice |
| Unit Price(s) | Unit Price |
text | – | Only shown when xero_action is create_invoice, update_invoice |
| Discount %(s) | Discount % |
text | – | Only shown when xero_action is create_invoice, update_invoice |
| Account Code(s) | Account Code |
text | – | Only shown when xero_action is create_invoice, update_invoice |
| Tracking Category 1 | Tracking Category 1 Value |
text | – | Only shown when xero_action is create_invoice, update_invoice |
| Tracking Category 2 | Tracking Category 2 Value |
text | – | Only shown when xero_action is create_invoice, update_invoice |
Actions¶
Every action uses the Xero Account and Organisation (Tenant) chosen above. The settings each action reads are the ones the builder shows for it; anything else is ignored. A task with no account, no organisation or no action fails at once, and so does an action missing a setting it requires.
What the action returns is the xero output. Its fields are referenced with an underscore, for example
{{task_<ID>_xero_contact_id}} for the contact_id inside xero.
Create Contact¶
Creates a contact. Contact Name is required; Account Number, First Name, Last Name, Email Address, Tax Number and Bank Account Details are optional.
If Xero already has a contact with that name or account number, the task does not fail: it returns the existing contact, and its message says so. It never updates that contact — use Update Contact for that.
xero holds status, contact_id, contact_name, account_number, first_name, last_name, email_address
and message.
Update Contact¶
Updates the contact given by Contact ID (required, Xero's contact ID). Only the fields that hold a value are sent, so an empty field is left as it is in Xero, not cleared.
Get Contact¶
Finds one contact by Contact ID, Account Number or Contact Name (an exact name match) — one of them is
required. xero.contact is Xero's contact record. Finding none is not a failure: the task completes with "No contact
found." and found false.
Get Contacts¶
Lists contacts, reading every page Xero returns. Where Filter takes a Xero where clause (for example
Name.Contains("Acme")), Order By a sort from the list, and Include Archived whether archived contacts are
included. xero.contacts is the list and xero.pagination says how many were read and whether the list was cut short
because it was too large to keep in full.
Create Invoice¶
Creates an invoice for Contact Name. The contact is found by name, or created if Xero has none. Required: Contact
Name, Invoice Date and Due Date (both DD/MM/YYYY HH:mm), Status (Draft, Submitted, Authorised or
Voided) and Tax Type (Exclusive, Inclusive or No Tax). Invoice Number and Reference are optional; an
Invoice Number Xero already has fails the task.
Line items are written as lists separated by |, one entry per line: Item Code(s), Description(s),
Quantity(ies), Unit Price(s), and optionally Discount %(s), Account Code(s) and the two Tracking
Category values. The number of descriptions decides the number of lines, so keep every list the same length. A
tracking value must be an option of that Xero tracking category.
Xero has one description per line. To send the details shown under an item in BaseCloud as well, map
item_description_with_details into Description(s) instead of item_description: it carries each description
with its details on the lines below it.
xero holds status, message, invoice_id, invoice_number, invoice_status, invoice_total,
invoice_sub_total, invoice_total_tax, invoice_total_discount and contact_id.
Get Invoice¶
Finds one invoice by Invoice ID or Invoice Number — one is required. xero.invoice is Xero's invoice record.
Get Invoices¶
Lists invoices, reading every page. Where Filter takes a Xero where clause, Order By a sort from the list,
Statuses Filter limits it to some statuses, and Contact IDs Filter (Xero contact IDs, comma-separated) to some
contacts. xero.invoices is the list and xero.pagination as for Get Contacts.
Update Invoice¶
Updates the invoice given by Invoice ID (required): any of Reference, Status, Invoice Date and Due Date that hold a
value, and — when line items are given — its lines, in the same | format as Create Invoice. Given lines replace the
invoice's lines; they are not added to them. Xero decides which changes an invoice's status allows (a paid invoice, for
example, cannot be edited).
Real-World Examples¶
Create a Xero invoice from a won deal¶
CRM Trigger (status changed to "Won")
└─ Match to Client look the client up
└─ Xero create the invoice
Keep a Xero contact in step with the CRM¶
Store the Xero contact ID on the client record so the update targets the right contact rather than creating a duplicate.
Confirm to the customer once the invoice exists¶
Troubleshooting¶
Connection expired¶
Cause: Xero no longer accepts the connection — it was revoked, or its tokens lapsed.
Solution: BaseCloud refreshes tokens on its own; when that is no longer possible, reconnect Xero in App Connections.
Create Contact returned a contact that already existed¶
Cause: Xero already had a contact with that name or account number.
Solution: This is expected — the task returns the existing contact (its message says so) and does not change it.
Use {{task_31001_xero_contact_id}} either way, and Update Contact to change it.
Tracking Category Not Found¶
Cause: A tracking value must match one of the category's options exactly (case included). A value that matches none is left off the line silently — the invoice is still created, untracked.
Solutions:
- Copy the option name exactly as Xero shows it
- Leave a line's value empty (or
null) to leave that line untracked on purpose
Invoice Number Already Exists¶
Cause: Xero already has an invoice with that number; the task fails with "Invoice number … already exists."
Solutions:
- Leave Invoice Number empty to let Xero number it
- Or check first with Get Invoice by that number
Line Items Calculation Wrong¶
Cause: Tax type mismatch with line_items_tax_type
Solutions:
- Exclusive: Unit prices don't include tax tax added on top
- Inclusive: Unit prices include tax tax extracted from price
- Verify which format your prices use
Not All Records Returned¶
Cause: Get Contacts and Get Invoices read every page, but stop at about 12 MB of results so the output can still be saved. {{task_31001_xero_pagination.truncated}} is true when that happens.
Solution: Narrow the list with a Where Filter, Statuses or Contact IDs.
Wrong organisation¶
Cause: The task's Organisation (Tenant) is not the Xero organisation you meant — one Xero account can hold several.
Solution: Pick the organisation in the task; the list shows every organisation the connected Xero account can reach. Use a separate task (or connection) per organisation.
Best Practices¶
OAuth Management¶
- Tokens: BaseCloud keeps and refreshes the connection's tokens itself
- Reconnection: if Xero ends the connection (revoked, or unused for too long), reconnect it in App Connections
Contact Management¶
- Auto-Create in Invoices: create_invoice auto-creates missing contacts
- Unique Account Numbers: Use CRM client IDs:
C{{client_id}} - Sync Strategy: Decide on sync direction (CRMXero, XeroCRM, bi-directional)
- Duplicate Prevention: Use get_contact before create_contact
Invoice Creation¶
- Status Workflow:
- DRAFT: For review/approval workflows
- AUTHORISED: For immediate dispatch
-
Never set to PAID manually (Xero manages)
-
Tracking Categories:
- Always use both levels for detailed reporting
- Standardize category values across CRM
-
Validate values exist before invoice creation
-
Line Items:
- Use meaningful item codes
- Consistent account codes (200=Sales, 400=Sales Discounts)
- Calculate totals in CRM for validation
Performance¶
- Pagination: Automatic for get_contacts and get_invoices — every page is read
- Filters: Use where clauses to reduce data transfer
- Caching: Cache tenant IDs and tracking categories
- Rate Limits: Xero has rate limits - add delays in bulk operations
Error Handling¶
- Why it failed:
{{task_31001_run_text}}carries Xero's message - Retries: a Xero rate limit is retried later on its own; a missing or wrong setting fails at once, as retrying cannot fix it
FAQ¶
Q: Can I use Xero with multiple organizations simultaneously?
A: Yes — each task picks its organisation in Organisation (Tenant).
Q: How do I get my tenant ID?
A: You don't need it: the task's Organisation (Tenant) list shows the organisations by name once the Xero account is connected.
Q: Can I update invoice line items after creation?
A: Yes, with update_invoice. Note: Replaces all existing line items (not additive).
Q: What happens if I create invoice with existing invoice number?
A: The task fails, saying the number already exists. Leave Invoice Number blank to let Xero number it.
Q: How do I handle refunds or credit notes?
A: Create separate credit note in Xero (not currently supported via task). Use Xero UI or request feature addition.
Q: Can I attach files to invoices?
A: Not via task action. Use Xero API directly or Xero UI for attachments.
Q: How long do access tokens last?
A: Access tokens: 30 minutes, Refresh tokens: 90 days. Auto-refresh handled by task.
Q: Can I get invoice PDFs?
A: Not directly. Xero generates PDFs separately. Use Xero API or UI to download.
Q: What's the rate limit?
A: Xero: 60 requests per minute per tenant. Add delays in bulk operations.
Q: How do I query tracking category reports?
A: Use get_invoices with where filter or query Xero Reports API separately.
Q: Can I create quotes instead of invoices?
A: Xero separates quotes from invoices. This task handles invoices only.
Q: How do I handle multiple currencies?
A: Xero supports 160+ currencies per contact. Specify currency when creating invoices.
Q: Can I mark invoices as paid from CRM?
A: No - Xero manages payment status based on payment entry. Use Xero UI or payment API.
Q: What if contact auto-create fails?
A: Task returns error. Create contact manually first with create_contact action.
Related Tasks¶
- BaseCloud Accounting - Internal alternative
- Sage - Alternative accounting integration
- Email - Send invoice notifications
- Loop - Process multiple contacts/invoices
- If Statement - Handle sync logic
- Timer Trigger - Schedule sync/monitoring
Technical Details¶
- Type ID: 31
- Function:
taskXero()in automationService.js - Service: xeroService.js
- Library: xero-node (XeroClient)
- Authentication: OAuth 2.0 with auto token refresh
- Outputs:
{{task_<ID>_xero_<field>}}, the ID being the task's own - Pagination: Automatic, 1,000 results per request
- Rate limits: a rate-limited call is retried later on its own