Xero to Wave Migration Guide (2026): Methods, Mapping & Limits
A technical guide to migrating financial data from Xero to Wave, covering API constraints, CSV formatting pitfalls, data model mismatches, and step-by-step execution.
Planning a migration?
Get a free 30-min call with our engineers. We'll review your setup and map out a custom migration plan — no obligation.
Schedule a free call- 1,500+ migrations completed
- Zero downtime guaranteed
- Transparent, fixed pricing
- Project success responsibility
- Post-migration support included
Migrating from Xero to Wave is a structural compression of your accounting data. You're moving from a multi-entity platform with tracking categories, purchase orders, multi-currency support, and a 1,000+ app ecosystem into an SMB-focused tool built for simplicity and zero-cost core accounting.
Done right, it eliminates significant subscription overhead. Done wrong, you lose historical reporting granularity, orphan transactions, or stall mid-migration when you hit formatting errors that Wave's CSV importer silently rejects.
This guide covers the real architectural mismatches, API constraints on both sides, object-by-object field mapping, a direct comparison of every viable migration method, and a step-by-step execution plan. For a broader accounting migration framework, see our Accounting Data Migration Checklist: The 10-Point Plan.
Why Companies Migrate from Xero to Wave
The most common driver is cost. Xero's subscription plans — Early ($15/mo, capped at 20 invoices), Growing ($42/mo), and Established ($78/mo) — add up for small businesses that don't use advanced features like project tracking, multi-currency, or inventory management. Wave's core accounting is free, with no transaction limits and no user caps. Wave's revenue model relies on optional paid services: payroll processing and payment processing at standard card rates.
The typical migration scenarios:
- Freelancers and solopreneurs outgrowing the value of Xero's feature set relative to its price.
- Micro-businesses that never used tracking categories, purchase orders, or Xero's app marketplace.
- Cost-conscious startups consolidating to a simpler stack after their initial growth phase.
- Accountants managing multiple clients where some clients' needs are better served by a zero-cost tool.
Wave is not a drop-in replacement for Xero. Wave is only available to US and Canadian businesses, and the business currency is locked at setup to USD or CAD. If you rely on purchase orders, multi-currency transactions, inventory tracking, or tracking categories, Wave cannot replicate these. Evaluate the feature gap before committing.
The Data Model Gap: Xero vs. Wave
The most important thing to understand before touching any data is the structural mismatch between these two platforms. This is not a 1:1 copy — it's a lossy compression. You must decide what to flatten, what to split, and what to leave behind.
Xero's data model is relatively rich for an SMB accounting tool. Contacts are unified — a single contact record can function as both a customer and a supplier, and can hold up to five contact persons. Xero supports tracking categories (up to two) for dimensional reporting, purchase orders, quotes, credit notes, manual journals, bank rules, repeating invoices, fixed assets, and a deep chart of accounts with custom account codes. (developer.xero.com)
Wave's data model is deliberately simpler. Customers and Vendors are separate entities with no shared record. There are no purchase orders, no tracking categories, no fixed asset register, and no custom objects. Wave supports invoices, estimates, bills, transactions, products/services, a chart of accounts, and journal entries.
Core Object Mapping
| Xero Object | Wave Equivalent | Notes |
|---|---|---|
| Contacts (Customer) | Customers | Direct map; split by IsCustomer flag |
| Contacts (Supplier) | Vendors | Must split Xero's unified contact; dual-role contacts become two records |
| Invoices (AR) | Invoices | Line items, tax, status map cleanly |
| Bills (AP) | Bills | UI supports bills; public API write coverage for bills is limited |
| Credit Notes | No direct equivalent | Must record as journal entries or negative invoices |
| Purchase Orders | Not supported | Data lost; archive as PDF |
| Tracking Categories | Not supported | Flatten into account names, descriptions, or external archive |
| Quotes | Estimates | Similar structure; status mapping needed |
| Manual Journals | Journal Transactions | Map directly |
| Bank Transactions | Transactions | Import per-account via CSV |
| Fixed Assets | Not supported | Record as manual journal entries for depreciation |
| Products/Services | Products/Services | Wave links each to one income or expense account |
| Chart of Accounts | Chart of Accounts | Wave uses preset account types; custom codes differ |
| Repeating Invoices | Recurring Invoices (Pro) | Only available on Wave's Pro plan |
| Inventory Items | Products + manual value tracking | Wave tracks inventory by monetary value, not unit quantities |
Migration Methods Compared
Method 1: Native CSV Export & Import (DIY)
Complexity: Low–Medium · Best for: Small businesses with < 2 years of history and < 500 transactions/year
This is the most common approach and costs nothing beyond your time. But it is significantly more manual than most guides suggest.
How Xero Export Works
Xero does not offer a single "export all" button. You must export data from individual areas separately — contacts, invoices, bills, bank transactions, chart of accounts, and reports each require separate exports in CSV or PDF format. Invoice and bill CSV exports top out at 500 records per batch. (central.xero.com)
The typical export sequence:
- Chart of Accounts: Accounting → Advanced → Chart of Accounts → Export
- Contacts: Contacts → Export (CSV)
- Invoices: Business → Sales Overview → select invoices → Export
- Bills: Business → Purchases Overview → select bills → Export
- Bank Transactions: Reports → Account Transactions → filter by account → Export CSV
- Trial Balance: Reports → Trial Balance → Export CSV (for validation)
How Wave Import Works
Wave's CSV import is strict. The transaction upload only recognizes three columns: date, description, and amount. Special characters like #, &, * can cause failures. Each file must be uploaded to one account at a time, and the currency in the file must match the target payment account's currency.
Wave's CSV import has a practical row limit. Community reports indicate files with more than 100 rows tend to fail silently. Break large exports into batches of 50–100 rows per file. Always use ISO date format (YYYY-MM-DD) or MM/DD/YYYY. Wave also requires dot (.) decimal separators — files using commas for decimals (common in European exports) will fail to import entirely.
For customer imports, Wave requires at least one of: Company Name, First Name, or Last Name. You can use Wave's CSV template or the Wave Connect Google Sheets add-on for a more guided import experience. Wave Connect supports customers, products, invoices, transactions, and journal entries — but be aware that Wave Connect assumes consecutive rows belong to one invoice until the customer changes or you insert a blank row. Failure to account for this silently merges line items across invoices. (support.waveapps.com)
| Pros | Cons |
|---|---|
| Free, no tools required | Extremely time-consuming for large datasets |
| Full control over data | No relationship preservation (invoices won't auto-link to customers) |
| No API keys or developer setup | Wave's CSV parser is fragile; formatting errors cause silent failures |
| Works for simple migrations | Cannot migrate payment history, credit notes, or tracking categories |
For a deeper analysis of CSV-based migrations at scale, see Using CSVs for SaaS Data Migrations: Pros and Cons.
Method 2: API-Based Migration (Xero REST → Wave GraphQL)
Complexity: High · Best for: Engineering teams migrating > 2 years of historical data programmatically
This approach extracts data from Xero's REST API and writes it into Wave's GraphQL API. It preserves more relational integrity than CSV but requires development effort and careful handling of rate limits on both sides.
Xero API Constraints
Xero enforces strict rate limits per tenant per app:
- Minute limit: 60 API calls per 60-second rolling window
- Daily limit: 5,000 API calls per 24-hour rolling period
- Concurrent limit: 5 API calls in progress simultaneously
- Payload size: Max 3.5 MB per POST request
- Pagination: 100 records per page on supported endpoints (invoices, contacts, bank transactions, manual journals)
Exceeding any limit returns HTTP 429 with a Retry-After header.
As of March 2, 2026, Xero introduced tiered API pricing with data egress charges. The new model charges $2.40 AUD per extra gigabyte of data downloaded from its APIs. Inefficient, polling-heavy extractions are now directly expensive. Use If-Modified-Since headers, request only the fields you need, and batch where possible.
Wave API Constraints
Wave exposes a single GraphQL endpoint at https://gql.waveapps.com/graphql/public, authenticated via OAuth 2.0 Bearer tokens. Key constraints:
- Rate limits are not officially published in Wave's developer documentation, and no rate-limit headers or retry-after signals are documented. You must implement defensive backoff.
- OAuth scope: Users can only grant API access to businesses with an active Pro or Wave Advisor subscription. Free-tier Wave accounts cannot use OAuth-based API integrations.
- Write surface gaps: In the published schema, vendor and bill query types exist, but documented
vendorCreateandbillCreatemutations are not clearly present. ThemoneyTransactionCreatepath is marked BETA. Plan for hybrid API + Wave Connect loading where the public API doesn't cover your needs. (developer.waveapps.com) - GraphQL schema changes can happen without versioned URL changes, creating a risk of silent breaking changes.
| Pros | Cons |
|---|---|
| Preserves relational links (customer → invoice) | Requires Pro Plan subscription on Wave for API access |
| Automatable and repeatable | Xero's 2026 egress pricing makes extraction expensive |
| Handles large volumes with pagination | Wave's unpublished rate limits force defensive coding |
| Can transform data in-flight | High development effort (40–80 hours for a production-grade script) |
Method 3: Middleware Platforms (Zapier / Make)
Complexity: Low · Best for: Ongoing sync of new records, NOT historical migration
Zapier offers a pre-built Wave ↔ Xero integration with triggers like "New Customer" and actions like "Create Sales Invoice." Make (formerly Integromat) offers similar capabilities. Wave requires Pro or Wave Advisors for partner integrations and Make connections. (zapier.com)
The critical limitation: middleware platforms are trigger-based. They act on new events. They cannot backfill years of historical invoices, bank transactions, or journal entries. Zapier does not provide a "sync all existing records" function.
If you need to sync new invoices going forward while running both platforms in parallel during a transition period, Zapier works. If you need to move 3 years of historical data, it does not.
| Pros | Cons |
|---|---|
| No-code setup | Cannot migrate historical data |
| Good for parallel-run transition period | Zapier is a premium app (paid plan required) |
| Handles new records well | Limited error handling and no batch retry |
| Quick to configure | No field-level transformation for complex mappings |
Method 4: Managed Migration Service
Complexity: Low (for you) · Best for: Businesses with multi-year history, complex charts of accounts, or no engineering bandwidth
Dedicated migration services handle the extraction, transformation, and loading end-to-end. They typically use API-level access on both sides, handle rate limit throttling automatically, and reconcile trial balances pre- and post-migration.
This is the right choice when:
- You have 3+ years of transactional history
- Your Xero org uses tracking categories that need to be mapped into Wave's account structure
- You need to split Xero's unified contacts into Wave's separate Customer and Vendor lists without losing invoice associations
- You don't have 40–80 hours of engineering time to invest
- Financial integrity is non-negotiable (you need automated trial balance reconciliation)
Migration Method Comparison
| Criteria | CSV Export/Import | API-Based (Custom) | Zapier / Make | Managed Service |
|---|---|---|---|---|
| Cost | Free | Dev time + Xero egress | $20–100/mo | Fixed project fee |
| Historical data | Yes (manual) | Yes (automated) | No | Yes |
| Relationships preserved | No | Yes | Partial | Yes |
| Engineering effort | Low | High (40–80 hrs) | Low | None |
| Scalability | Poor (100-row limit per file) | Good | Poor | Good |
| Xero API egress cost | None | Yes ($2.40 AUD/GB) | Yes | Managed by provider |
| Wave Pro Plan required | No | Yes (for API) | Yes (for triggers) | Depends on method |
| Risk of data loss | High | Medium | Low (new data only) | Low |
| Best for | < 500 txns, 1 year | Custom needs, dev team | Forward sync only | Multi-year, hands-off |
Scenario Recommendations
- Freelancer, < 1 year of data: CSV export/import. Do it yourself in an afternoon.
- Small business, 2–5 years, no dev team: Managed migration service. The cost of getting it wrong exceeds the service fee.
- Business running both platforms during transition: Zapier for forward sync of new invoices and customers.
- Company with engineering resources and complex requirements: Custom API-based ETL pipeline, likely hybrid with Wave Connect for unsupported API paths.
Step-by-Step Xero to Wave Migration Process
Phase 1: Pre-Migration Audit
- Export Xero Trial Balance — This is your source of truth. Export as of your chosen cutover date.
- Inventory all Xero objects — Count contacts, invoices, bills, credit notes, manual journals, bank accounts, tracking categories.
- Identify what Wave cannot accept — Purchase orders, fixed assets, tracking categories, credit notes (as a distinct object), multi-currency transactions.
- Clean your data — Merge duplicate contacts in Xero before migration. Remove test invoices, voided transactions, and unused accounts.
- Map your Chart of Accounts — Wave uses preset account types (Asset, Liability, Equity, Income, Expense). Map every Xero account code to a Wave equivalent. Wave uses account names rather than numeric codes.
- Define your scope — Decide if you are migrating all historical data or just open AR/AP and trial balances for the current fiscal year. Financial migrations should almost always use a "Big Bang" cutover executed at month-end to ensure clean reconciliation.
For a complete pre-migration checklist, see 7 Costly Mistakes to Avoid When Migrating Financial Data.
Phase 2: Extract from Xero
Export each data type separately:
- Chart of Accounts → CSV (extract this first — it establishes the foundational IDs for all subsequent transactions)
- Contacts → CSV (flag each as Customer, Supplier, or Both)
- Invoices → CSV or API (include line items, tax, status)
- Bills → CSV or API
- Bank Transactions → Export per account, per date range
- Manual Journals → API only (the Journals endpoint is read-only; use ManualJournals for writable entries)
- Trial Balance, P&L, Balance Sheet → CSV (for reconciliation)
Xero's Journals API endpoint requires the Advanced tier under the 2026 pricing model and needs a security assessment. For most one-time migrations, exporting reports as CSV is more practical than paying for Advanced API access.
Phase 3: Transform
This is where most migrations fail. The transformation layer must handle:
- Contact splitting: Any Xero contact flagged as both Customer and Supplier must be duplicated — one record in Wave's Customer list, one in Wave's Vendor list. Check the
IsCustomerandIsSupplierboolean flags on the Contact object. If both are true, append a suffix (e.g., "- Vendor") to the vendor name to prevent naming collisions. - Account code remapping: Wave uses its own internal account numbering. Xero's account codes (e.g.,
200 – Sales) must be mapped to Wave's equivalent by type. Xero's broadTypevalues need translation to Wave's specificAccountSubtypeenum (e.g., Xero'sDIRECTCOSTSbecomes Wave'sCostOfGoodsSold). - Decimal formatting: Wave requires dot (
.) decimal separators. Files using commas fail. - Date formatting: Use
YYYY-MM-DDorMM/DD/YYYY. Other formats cause silent errors. - Currency isolation: If you had multi-currency transactions in Xero, each currency must be exported and imported separately. Wave does not support multi-currency natively.
- Tracking category flattening: Append the category value to the account name or transaction description.
- Tax rate pre-creation: Wave requires tax rates to be pre-created in the system before they can be applied to invoice payloads. Map by jurisdiction and rate, not just text label.
- Special character removal: Strip
#,&,*from CSV files before upload.
Phase 4: Load into Wave
Load in dependency order:
- Chart of Accounts — Either manually or via the API
accountCreatemutation. - Sales Taxes — Create all tax rates before importing invoices.
- Customers — Use Wave's CSV import or Wave Connect.
- Vendors — Separate upload. The public API may not expose a documented
vendorCreatemutation; use CSV or Wave Connect. - Products/Services — Map each to one income or expense account.
- Bank Transactions — Upload per account. Keep files under 100 rows each.
- Invoices — Via API (
invoiceCreatemutation) or re-enter manually for small volumes. EnsurecustomerIdmatches the newly generated Wave ID. - Bills — Plan for manual or Wave Connect import if API write coverage is limited.
- Journal Entries — For opening balances, credit note equivalents, and data that doesn't fit Wave's standard import.
Below is a GraphQL mutation for creating a customer in Wave:
mutation CreateCustomer($input: CustomerCreateInput!) {
customerCreate(input: $input) {
didSucceed
inputErrors {
code
message
path
}
customer {
id
name
email
}
}
}And a Python script for extracting contacts from Xero and creating customers in Wave:
import requests
import time
# --- Xero: Extract contacts ---
XERO_BASE = "https://api.xero.com/api.xro/2.0"
xero_headers = {
"Authorization": f"Bearer {XERO_ACCESS_TOKEN}",
"Xero-Tenant-Id": XERO_TENANT_ID,
"Accept": "application/json"
}
def get_xero_contacts(page=1):
resp = requests.get(
f"{XERO_BASE}/Contacts?page={page}&where=IsCustomer==true",
headers=xero_headers
)
if resp.status_code == 429:
wait = int(resp.headers.get("Retry-After", 60))
time.sleep(wait)
return get_xero_contacts(page)
resp.raise_for_status()
return resp.json()["Contacts"]
# --- Wave: Create customer via GraphQL ---
WAVE_GQL = "https://gql.waveapps.com/graphql/public"
wave_headers = {
"Authorization": f"Bearer {WAVE_ACCESS_TOKEN}",
"Content-Type": "application/json"
}
def create_wave_customer(business_id, name, email):
query = """
mutation ($input: CustomerCreateInput!) {
customerCreate(input: $input) {
didSucceed
inputErrors { path message }
customer { id name }
}
}
"""
variables = {
"input": {
"businessId": business_id,
"name": name,
"email": email
}
}
resp = requests.post(
WAVE_GQL,
json={"query": query, "variables": variables},
headers=wave_headers
)
result = resp.json()
if result.get("errors"):
raise Exception(f"Wave API error: {result['errors']}")
return result["data"]["customerCreate"]Build idempotency around external IDs and log every source ID, target ID, payload hash, and response. Never map by contact name alone — Xero explicitly warns against relying on contact name uniqueness. (developer.xero.com)
Phase 5: Validate
Never assume a 200 OK response means the financial data is accurate.
- Compare Trial Balances — Export Wave's Trial Balance and compare line-by-line against Xero's export from Phase 1. The debits and credits must match to the penny.
- Record count check — Total customers, vendors, invoices, and transactions should match expected counts.
- Spot-check 10% of transactions — Verify amounts, dates, and account categorization. Focus on complex invoices (multi-line, multi-tax) to ensure tax rates and totals calculated correctly.
- Test invoice workflow — Send a test invoice in Wave to confirm payment processing and email templates work.
- Verify bank connections — Do not connect Wave's bank feed until after imports are complete.
Do not connect Wave's bank feed until after all CSV and Wave Connect imports are complete. Connecting a bank feed before imports are done creates duplicate transactions that require manual cleanup.
Field-Level Data Mapping Reference
| Xero Field | Wave Field | Transform Required |
|---|---|---|
| Contact.Name | Customer.Name / Vendor.Name | Split by IsCustomer/IsSupplier flag |
| Contact.EmailAddress | Customer.Email / Vendor.Email | Direct map |
| Contact.Phones [0].PhoneNumber | Customer.Phone | Flatten phone array |
| Contact.Addresses [0] | Customer.Address | Map Street, City, Province, Country, PostalCode |
| ContactID | External mapping table | Never map by name only |
| Invoice.InvoiceNumber | Invoice.InvoiceNumber | Direct map |
| Invoice.Date | Invoice.InvoiceDate | Format: YYYY-MM-DD |
| Invoice.DueDate | Invoice.DueDate | Format: YYYY-MM-DD |
| Invoice.LineItems [].Description | InvoiceLineItem.Description | Direct map |
| Invoice.LineItems [].UnitAmount | InvoiceLineItem.UnitPrice | Ensure dot decimal separator |
| Invoice.LineItems [].Quantity | InvoiceLineItem.Quantity | Direct map |
| Invoice.LineItems [].AccountCode | InvoiceLineItem.Product | Map to Wave product/account |
| Invoice.LineItems [].TaxType | InvoiceLineItem.SalesTax | Map by jurisdiction + rate, not text label alone |
| Account.Code | Account (by name/type) | Wave uses names, not codes; map by account type |
| Account.Type | Account.Type | Map: REVENUE→Income, EXPENSE→Expense, DIRECTCOSTS→CostOfGoodsSold |
| BankTransaction.Date | Transaction.Date | Format: YYYY-MM-DD |
| BankTransaction.Total | Transaction.Amount | Ensure dot decimal; single amount column |
| BankTransaction.Reference | Transaction.Description | Direct map |
| ManualJournal.Narration | JournalTransaction.Description | Direct map |
| ManualJournal.JournalLines [].AccountCode | JournalLine.Account | Map by account name |
| TaxType / tax rate | salesTaxId | Map by jurisdiction + rate |
| Tracking category values | memo, notes, or external table | No first-class Wave equivalent |
Edge Cases and Failure Modes
Credit notes — Wave has no dedicated credit note object. Record these as negative journal entries or negative-amount transactions. This breaks the audit trail if your accountant expects a distinct credit note register.
Multi-currency — Wave does not handle multi-currency natively. If your Xero org processed transactions in multiple currencies, each must be manually converted. Historical exchange rate accuracy is lost, and fractional cent discrepancies on historical invoices are common.
Tracking categories — Xero allows up to two tracking categories (e.g., Department, Location) on every transaction. Wave has no equivalent. The only workaround is encoding tracking category values into account names or transaction descriptions, which degrades reporting capability.
Attachments — Xero allows file attachments on invoices, bills, and contacts. Wave supports receipt scanning but does not provide a bulk import mechanism for attachments. Export attachments locally and store them in a secure drive.
Repeating invoices and bank rules — Xero's automation rules (bank rules, repeating invoices, repeating bills) do not export. They must be rebuilt manually in Wave, and Wave's automation options are significantly more limited.
Credit card statement sign flipping — When importing CSV files to a credit card (liability) account in Wave, withdrawals and deposits can be reversed. Community workarounds involve flipping the sign in Excel before upload.
Duplicate contacts — Duplicates happen when teams key on contact name even though Xero explicitly warns not to rely on contact name uniqueness. Store a durable ID map keyed on ContactID, not name. (developer.xero.com)
Wave Connect invoice grouping — Wave Connect assumes consecutive rows belong to one invoice until the customer changes or you insert a blank row. Failure to account for this silently merges line items across invoices. (support.waveapps.com)
Customer imports are irreversible — Wave warns that customer imports cannot be undone once submitted. Run a test import on a dummy Wave business first.
Historical journal entries — Migrating raw journal entries is highly prone to error. It is often safer to migrate monthly trial balances rather than every individual historical journal entry.
Wave Limitations to Accept Before Migrating
Be honest with your finance team about what will not migrate. Wave is a simplified platform by design.
- No purchase orders — Wave cannot create or track POs
- No inventory management — Wave does not track unit quantities or calculate COGS automatically
- No multi-currency — All transactions must be in a single currency (USD or CAD)
- No tracking categories / dimensional reporting — No equivalent to Xero's department or project tags
- No fixed asset register — Depreciation must be tracked manually via journal entries
- No custom objects or fields — Wave's schema is fixed
- Limited integrations — Wave connects natively with Shopify, PayPal, Etsy, and Zapier, compared to Xero's 1,000+ app marketplace
- US and Canada only — Wave is not available outside these markets
- API rate limits unpublished — Defensive coding required; no official documentation on thresholds
- API write surface incomplete — Vendor and bill write mutations are not clearly documented in the public schema
Post-Migration Tasks
- Connect bank feeds — Re-authenticate bank feeds in Wave. Be extremely careful with the "import start date" to avoid duplicating transactions you just migrated. Wave's docs specifically advise turning off auto-imports if switching to manual uploads or Wave Connect. (support.waveapps.com)
- Lock Xero — Set a lock date in Xero to prevent team members from adding new data to the old system. Keep Xero active for 30–90 days post-cutover as a read-only reference.
- Rebuild automations — Recreate bank rules, recurring invoices, and payment reminders in Wave. If you used Zapier to send Xero invoices to a CRM, update those workflows to point to Wave.
- Train your team — Wave's UI differs from Xero's. The transaction categorization workflow is account-based rather than rule-based.
- Set up receipt scanning — If you used Hubdoc with Xero, transition to Wave's built-in receipt scanning (Pro Plan) or a third-party tool.
- Monitor for 30 days — Watch for miscategorized transactions, missing records, or bank feed duplicates.
- Document every mapping decision — Future you (or your accountant) will need to understand why tracking categories were flattened into specific accounts.
Best Practices Checklist
- Back up everything — Export Xero's full Trial Balance, P&L, Balance Sheet, and all transaction reports before touching anything
- Run a test migration first — Wave allows multiple "Businesses" under one account. Use a separate business profile to test your import process with a subset of data
- Validate incrementally — Don't import everything at once. Validate Chart of Accounts first, then customers/vendors, then transactions
- Use ISO date formats —
YYYY-MM-DDprevents the most common CSV import error - Strip special characters — Remove
#,&,*from CSV files before upload - Keep batch sizes under 100 rows — Wave's CSV importer is more reliable with smaller files
- Don't connect bank feeds until imports are done — Prevents duplicate transactions
- Implement exponential backoff — If building in-house, handle both Xero's 429 responses and Wave's undocumented limits gracefully
- Reconcile Trial Balances — The single most important validation step. If the numbers don't match, stop and investigate
When a Managed Migration Service Makes Sense
Build in-house when:
- Your data is simple (< 1 year, < 500 transactions, no tracking categories)
- You have engineering bandwidth to spare
- You're comfortable with data loss on non-essential objects
Use a managed service when:
- You have multi-year transactional history that must be preserved
- Financial integrity is auditable (you need trial balance reconciliation)
- You don't have 40–80 hours of engineering time to invest
- Your Xero org uses tracking categories, multi-currency, or complex contact structures
- The hidden cost of getting it wrong — broken reports, missing transactions, accountant rework — exceeds the service fee
At ClonePartner, the complexity we handle isn't the data volume — it's the structural translation. Splitting Xero's unified contacts into Wave's bifurcated Customer/Vendor model while preserving invoice associations. Flattening tracking categories into account structures without losing reporting fidelity. Using hybrid API + Wave Connect execution when Wave's write surface is incomplete. Automating trial balance reconciliation across both platforms. That's the work that separates a migration that's "done" from one that's correct.
We bypass Xero's manual export limitations and optimize extraction to avoid the 2026 API data egress overage charges. For more on our approach, see How We Run Migrations at ClonePartner.
Making the Call
Xero to Wave is a viable migration for businesses genuinely downsizing their accounting complexity. The subscription savings are real. But this is a lossy migration — you will lose purchase orders, tracking categories, multi-currency history, and some automation capabilities. If those features matter to your business, this isn't the right move.
If they don't, and your priority is a simple, free accounting tool that handles invoicing, expense tracking, and basic reporting well, Wave delivers. Just make sure the migration itself doesn't become the expensive part. A clean migration preserves financial integrity. A sloppy one creates months of accountant rework that costs more than the Xero subscription you were trying to eliminate.
Frequently Asked Questions
- Can I export all my data from Xero at once?
- No. Xero does not offer a single 'export all' button. You must export contacts, invoices, bills, bank transactions, chart of accounts, and reports separately as CSV or PDF files. Invoice and bill CSV exports are capped at 500 records per batch.
- Does Wave have an API for importing data?
- Yes. Wave exposes a GraphQL API at gql.waveapps.com/graphql/public with mutations for creating customers, invoices, and accounts. However, OAuth-based API access requires the business to have an active Wave Pro or Wave Advisor subscription. Vendor and bill write mutations are not clearly documented in the public schema.
- What Xero data does not migrate to Wave?
- Wave does not support purchase orders, tracking categories, multi-currency transactions, fixed assets, or credit notes as distinct objects. These must be archived separately, flattened into journal entries, or accepted as data loss.
- Can Zapier migrate historical data from Xero to Wave?
- No. Zapier is trigger-based and only acts on new events. It cannot backfill years of historical transactions, contacts, or journal entries. It is only useful for forward sync during a parallel-run transition period, not for migration.
- Why do CSV imports fail in Wave?
- Wave's CSV import is strict about formatting. It requires dot (.) decimal separators, ISO or MM/DD/YYYY date formats, and no special characters like #, &, or *. Files over 100 rows tend to fail silently. Each file must match the target account's currency.