How to Connect Excel to Xero with Power Query

"Connect Excel to Xero" sounds like it should be a single setting. It isn't. Xero has no native Excel connector, and Excel has no Xero data source in the Get Data menu, so every working setup is one of three routes: you export and let Power Query clean up, you call the Xero API yourself, or you point Excel at a database that something else keeps in sync with Xero (the approach Flow takes).

This guide walks each route end to end, with the M code, and is honest about where two of them stop working. If you want the wider comparison including non-Power-Query options, start with getting Xero data into Excel.

First, the constraint that shapes everything

Xero's API uses OAuth 2.0. Access tokens are short-lived, refresh tokens rotate, and every request needs both an Authorization: Bearer header and an xero-tenant-id header naming the organisation you want.

Power Query has no way to complete that OAuth flow. Excel's built-in web connector offers Anonymous, Basic, Windows, Organizational account and API-key authentication — none of which is Xero's flow — and Excel cannot load the custom connectors (.mez files) that Power BI Desktop can. So there is no version of this where Excel signs into Xero and keeps itself signed in.

That single fact is why the three routes below exist, and why most practices end up on the first or the third.

Route 1: Export from Xero, clean with Power Query

The zero-cost route. Xero produces the report, Power Query does everything after that: strip the report furniture, set types, reshape into a tidy table, and replay those steps on every refresh.

  1. Accounting → Reports, run your report, then Export → Excel.
  2. Save it to a fixed path with a stable filename.
  3. In your reporting workbook: Data → Get Data → From File → From Excel Workbook, then Transform Data.
  4. Clean up in the editor, and load.
let
    Source = Excel.Workbook(File.Contents("C:\Reports\Xero\TB-current.xlsx"), null, true),
    Sheet = Source{[Item = "Sheet1", Kind = "Sheet"]}[Data],
    Headers = Table.PromoteHeaders(Table.Skip(Sheet, 4), [PromoteAllScalars = true]),
    Rows = Table.SelectRows(Headers, each [Account] <> null),
    Typed = Table.TransformColumnTypes(Rows, {{"Debit", type number}, {"Credit", type number}})
in
    Typed

Overwrite the file next month, hit Data → Refresh All, and the whole transformation replays. Point the same pattern at a folder of monthly exports and you have a rolling multi-month history — the full walkthrough is in Xero trial balance in Excel with Power Query.

Where it stops: the export is manual, so "refreshable" only means "refreshable once someone has exported again". Historic months are frozen as files, so a back-dated journal into March never reaches your March figures unless you remember to re-export March. Per organisation, per month, that is a standing diary entry.

Route 2: Call the Xero API directly from Power Query

You can query Xero's API from M. What you cannot do is keep it working unattended.

Get an access token (Xero's OAuth playground or your own app registration), find your tenant ID, and write:

let
    Token    = "PASTE_ACCESS_TOKEN_HERE",
    TenantId = "PASTE_TENANT_ID_HERE",
    Response = Web.Contents(
        "https://api.xero.com/api.xro/2.0/Reports/TrialBalance",
        [
            Headers = [
                #"Authorization"  = "Bearer " & Token,
                #"xero-tenant-id" = TenantId,
                #"Accept"         = "application/json"
            ]
        ]
    ),
    Json    = Json.Document(Response),
    Reports = Json[Reports],
    Rows    = Reports{0}[Rows]
in
    Rows

That returns real data, and the response is deeply nested — Xero's report JSON is rows containing rows, so expect a fair amount of Table.ExpandRecordColumn work before it looks like a table.

Where it stops, and it stops hard:

Route 2 is genuinely useful for a one-off pull or for proving what an endpoint returns. Treat anything beyond that as building an integration, and build it outside Excel.

Route 3: Point Power Query at a synced database

The third route moves the OAuth problem somewhere it belongs: a service holds the Xero connection, refreshes its own tokens, and writes the data into a SQL database on a schedule. Excel then connects to a plain SQL data source — something it has supported natively for years.

  1. Data → Get Data → From Database → From SQL Server Database.
  2. Enter server and database.
  3. Choose Database authentication and enter your read-only credentials.
  4. Pick a view in the Navigator, then load or transform.
let
    Source = Sql.Database("your-server.database.windows.net", "your-database"),
    TB     = Source{[Schema = "dbo", Item = "TrialBalance"]}[Data],
    Recent = Table.SelectRows(TB, each [SnapshotDate] >= #date(2025, 8, 31))
in
    Recent

Three things change materially:

The trade-off is honest: you are depending on a service to keep the sync running, and on it handling back-dated journals by re-verifying historic months rather than writing each month once and never looking again. That is the specific thing worth asking any provider about, because it is the failure mode that silently produces wrong comparatives.

Choosing between them

Pitfalls worth designing around

Where Flow fits

Flow is Route 3 as a service: it connects to your Xero organisations, syncs trial balance snapshots, invoices, credit notes and the chart of accounts into an Azure SQL database daily, and re-verifies historic months so back-dated journals land in the right period. You get read-only credentials scoped to your own organisations and an Excel Power Query template, so the connection above is already written for you.

Plans start at £20/month for up to 5 organisations with 2 years of trial balance history; Plus (£40/month) covers 30 organisations with configurable 1–5 year history and real-time refresh, and Premium (£60/month) adds tracking category breakdowns across up to 60 organisations. There is a 14-day free trial, no credit card required.