DEV Community

Cover image for How to Export Xero Data to a Database
ilshaad
ilshaad

Posted on • Originally published at codelesssync.com

How to Export Xero Data to a Database

Compare 5 ways to export Xero data to a database: CSV report exports, the Xero API, Zapier, ETL platforms, and no-code sync. Honest pros, cons, and costs.

By Ilshaad Kheerdali ยท 20 July 2026


If you run your accounting on Xero, you've probably hit a wall trying to get the data out. There is no one-click "export everything" button. Contacts export from one screen, invoices from another, reports from a third, and every file is a static snapshot that's stale the moment you download it. The API works, but only after you register an app, wire up OAuth 2.0, and babysit tokens forever.

The frustrating part is that "export Xero data to a database" sounds like it should be simple. It isn't. Different methods exist for different needs, and most of them either go stale immediately, cost more than they should, or leave you maintaining a pipeline that quietly breaks at 3am.

This guide walks through the five practical ways to export Xero data into a real, queryable database: CSV exports, the Xero API directly, Zapier-style automation, enterprise ETL platforms, and no-code sync. Honest pros, honest cons, and what each one actually costs to run.

Why Exporting Xero Data Is Harder Than It Should Be

Xero holds the data you care about: contacts, invoices, payments, bank transactions, the whole accounting picture. But getting it out in a form you can actually use takes more work than most teams expect.

Built-in exports are per-screen snapshots. Xero lets you export contacts, invoices, and bills as CSV files, and reports as Excel, PDF, or Google Sheets, but each data type exports separately from its own screen. A complete picture of your accounts means running several exports, and every one is frozen in time the second you download it.

There's no bulk "export everything" endpoint. The Xero API is built for transactional access, not data extraction. Invoices page through 100 records at a time (up to 1,000 with the pageSize parameter), contacts are a separate set of calls, payments another. For a complete dataset you're making dozens of calls and stitching the responses together.

List calls hide the detail you actually need. Ask the API for a list of invoices and it returns trimmed summaries with no line items, to keep responses fast. Getting the full records means fetching them individually or paging with larger page sizes, so a single "get my invoices" is rarely one call.

Webhooks notify but don't deliver data. Xero webhooks only fire for four things (contacts, invoices, credit notes, and App Store subscriptions), and the payload carries just a reference to the record, not the record itself. You still call the API to fetch what changed, which means you're maintaining the polling layer regardless.

OAuth 2.0 is non-negotiable. Every Xero integration needs a registered app, a consent flow, and token management. Access tokens last 30 minutes, and the refresh token is single-use with a rolling 60-day life: every refresh returns a new refresh token and invalidates the old one. Store the wrong one and your export job silently stops working. (For the full breakdown of the integration burden, see Xero API vs Database Sync.)

The result is that "export Xero data to a database" gets solved one of five ways. Here they are.

5 Ways to Export Xero Data to a Database

Method 1: Manual CSV / Excel Exports from Xero

The simplest option. From inside Xero, export each data type from its own screen: Contacts โ†’ Export for your customer and supplier list, Business โ†’ Invoices โ†’ Export for invoices and bills, and the Reports section for the General Ledger, Trial Balance, and other reports (which export to Excel, PDF, or Google Sheets; notably, Xero's newer reports don't offer CSV).

Once you have a file, you import it into your database with a COPY statement or a one-off script:

COPY xero_invoices_export (invoice_number, contact_name, invoice_date, total, amount_due)
FROM '/path/to/xero-invoices.csv'
DELIMITER ','
CSV HEADER;
Enter fullscreen mode Exit fullscreen mode

Pros:

  • Free and built into Xero
  • No code, no API setup, no developer required
  • Useful for one-off analysis or sending to an accountant

Cons:

  • Stale the moment you click export; the file represents a single point in time
  • Manual every time. If you need fresh data weekly, you're running this every week
  • Each data type exports separately, so a full dataset means many separate exports from different screens
  • Column layouts differ between screens and reports, so your import scripts need per-file handling
  • No automation, no incremental updates, no joins with your application data

CSV exports are fine for a quarterly accountant handoff. They are not a database export strategy.

Method 2: Direct Xero API Integration

If you need fresh data and you're comfortable writing code, you can pull directly from the Xero Accounting API and write the results into PostgreSQL yourself.

Here's a stripped-down example in TypeScript:

import { Pool } from 'pg';

const pool = new Pool({ connectionString: process.env.DATABASE_URL });

async function exportInvoices(accessToken: string, tenantId: string) {
  let page = 1;

  while (true) {
    const response = await fetch(
      `https://api.xero.com/api.xro/2.0/Invoices?page=${page}&pageSize=1000`,
      {
        headers: {
          Authorization: `Bearer ${accessToken}`,
          'Xero-tenant-id': tenantId,
          Accept: 'application/json',
        },
      },
    );

    const json = await response.json();
    const invoices = json.Invoices ?? [];

    for (const inv of invoices) {
      await pool.query(
        `INSERT INTO xero_invoices (xero_id, invoice_number, contact_name, type, status, total, amount_due, updated_at)
         VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
         ON CONFLICT (xero_id) DO UPDATE
         SET status = $5, total = $6, amount_due = $7, updated_at = $8`,
        [
          inv.InvoiceID,
          inv.InvoiceNumber,
          inv.Contact?.Name ?? null,
          inv.Type,
          inv.Status,
          inv.Total ?? 0,
          inv.AmountDue ?? 0,
          inv.UpdatedDateUTC,
        ],
      );
    }

    if (invoices.length < 1000) break;
    page += 1;
  }
}
Enter fullscreen mode Exit fullscreen mode

Pros:

  • Real, current data on demand
  • Full control over which data types you export and how they map to your schema
  • Free in tooling cost; you only pay for the infrastructure that runs it

Cons:

  • OAuth 2.0 setup: app registration, consent flow, redirect URI handling, and token storage
  • Access tokens expire every 30 minutes, and the single-use refresh token must be re-persisted on every refresh
  • One Xero login can cover several organisations, so you also enumerate tenants and send the right Xero-tenant-id header on every call
  • Rate limiting is on you: 60 calls per minute per organisation, 5 concurrent requests, plus a daily cap
  • Incremental sync via If-Modified-Since has blind spots (some changes never bump UpdatedDateUTC), so you still need periodic full reconciliation
  • Each new data type (contacts, payments, bank transactions, credit notes) is another query, another schema, another set of edge cases
  • Maintenance is forever. The build is the easy part

This is the right path if your needs are unusual or you have engineering time to spare. For most teams, the upkeep cost outweighs the benefit.

Method 3: Zapier, Make, or Generic Automation Platforms

If you want fresh data without writing code, automation platforms like Zapier and Make have pre-built Xero triggers. You can wire up "when an invoice is created in Xero, insert a row into Postgres" and it just works.

Pros:

  • No code required
  • Decent library of triggers: new invoice, new contact, new payment, and so on
  • Quick to set up for simple flows

Cons:

  • Per-task pricing scales fast. A growing business with thousands of monthly invoices can hit the higher tiers within a couple of months
  • No historical backfill; only future events trigger zaps. Your existing contacts and invoices stay outside the database unless you export them separately
  • Limited transformation logic. Anything more complex than a direct field mapping needs custom code steps, which take you back toward the territory of Method 2
  • Failures retry, but silently; debugging a stuck zap is painful
  • Vendor lock-in. Your "data export pipeline" lives inside a Zapier account, not in your codebase

Zapier-style platforms work for single-trigger flows. They're a poor fit for "I want a complete, current copy of my Xero data in Postgres."

Method 4: Enterprise ETL Platforms (Fivetran, Airbyte)

General-purpose ETL platforms have Xero connectors and will land your data in a warehouse or database on a schedule, alongside hundreds of other sources.

Pros:

  • Mature scheduling, monitoring, and retry infrastructure
  • Handles many sources beyond accounting, useful if you're already consolidating a large data stack
  • Managed OAuth and rate-limit handling

Cons:

  • Usage-based pricing (Fivetran bills by monthly active rows) is hard to predict and usually overkill for one accounting sync
  • Self-hosting Airbyte trades the subscription for your own infrastructure and upgrade maintenance
  • Built for data teams feeding warehouses, so setup assumes more data-engineering context than most small teams have
  • A heavyweight platform for what is, for most readers, a single-source job

If you already run a Fivetran or Airbyte stack, adding Xero to it is reasonable. Adopting one just to export your accounting data is like buying a truck to deliver one parcel.

Method 5: A Purpose-Built No-Code Sync (Codeless Sync)

Codeless Sync was built for exactly this problem: getting API data into a PostgreSQL database without code, without ETL infrastructure, and without per-row pricing.

How it works:

  1. Connect your PostgreSQL database via connection string (Supabase, Neon, AWS RDS, Railway, Heroku, or self-hosted)
  2. Authorize Xero with one click; the OAuth consent, token storage, and refresh are handled for you
  3. Pick which data to export (contacts, invoices, payments, accounts, bank transactions, credit notes, items, purchase orders, journals, or organisation details)
  4. The destination table is auto-created with the right schema and indexes
  5. The first export runs immediately. Schedule recurring syncs, or trigger them manually

Pros:

  • No code, no OAuth plumbing, no token refresh maintenance
  • Historical backfill plus ongoing incremental updates in one workflow
  • Works with any PostgreSQL host
  • Free tier for small projects, flat predictable pricing as you scale
  • Setup takes about 5 minutes

Cons:

  • Batch-based, not real-time (though incremental syncs run as often as every minute on paid plans)
  • Currently focused on Stripe, QuickBooks, Xero, and Paddle; not a general-purpose ETL tool

This is the recommended path if your goal is a current, queryable copy of your Xero data in your own database, with the lowest possible maintenance burden.

Comparison: Which Export Method Fits Your Use Case?

Method Setup time Keeps data current? Best for Cost
CSV / Excel exports Minutes No; single snapshot per screen One-off accountant handoffs Free
Direct Xero API Days to weeks Yes, if you maintain the polling Bespoke integrations with engineering capacity Infrastructure only, plus dev time
Zapier / Make Hours Partial; future events only, no backfill Single-trigger flows for small volumes Tiered, scales with task volume
Fivetran / Airbyte Hours to days Yes; scheduled connector runs Data teams already running a multi-source stack Usage-priced or self-hosted infra
Codeless Sync ~5 minutes Yes; backfill plus scheduled incremental Developers and small teams who want it to just work Free tier, then flat plans

The split is roughly: free options give you stale per-screen files, the API gives you fresh data at the cost of forever-maintenance, automation platforms work until your volume grows, enterprise ETL works if you already own the stack, and a purpose-built sync sits in the middle: fresh data, low maintenance, predictable cost.

What You Can Do Once Xero Data Is in PostgreSQL

The whole point of exporting Xero data into a database is what becomes possible afterwards. With the data in Postgres, you have full SQL access to everything, and you can join it with your application's own tables.

Monthly sales revenue with month-over-month growth:

WITH monthly_revenue AS (
  SELECT
    DATE_TRUNC('month', invoice_date) AS month,
    SUM(total) AS revenue,
    COUNT(*) AS invoice_count
  FROM xero_invoices
  WHERE type = 'ACCREC'          -- sales invoices, not supplier bills
    AND status = 'PAID'
  GROUP BY 1
)
SELECT
  month,
  revenue,
  invoice_count,
  ROUND(
    100.0 * (revenue - LAG(revenue) OVER (ORDER BY month))
    / NULLIF(LAG(revenue) OVER (ORDER BY month), 0),
    1
  ) AS mom_growth_pct
FROM monthly_revenue
ORDER BY month DESC
LIMIT 12;
Enter fullscreen mode Exit fullscreen mode

Outstanding receivables by contact:

SELECT
  contact_name,
  SUM(amount_due) AS outstanding_balance,
  COUNT(*) AS unpaid_invoices,
  MIN(due_date) AS oldest_due_date
FROM xero_invoices
WHERE type = 'ACCREC'
  AND amount_due > 0
  AND status IN ('AUTHORISED', 'SUBMITTED')
GROUP BY contact_name
ORDER BY outstanding_balance DESC;
Enter fullscreen mode Exit fullscreen mode

Net position: what you're owed vs what you owe:

SELECT
  type,                                     -- ACCREC = sales invoices, ACCPAY = bills
  COUNT(*) FILTER (WHERE amount_due > 0) AS open_invoices,
  SUM(amount_due) AS outstanding
FROM xero_invoices
WHERE status IN ('AUTHORISED', 'SUBMITTED')
GROUP BY type;
Enter fullscreen mode Exit fullscreen mode

This is what a real export gets you. Not a folder of per-screen CSV files, but a queryable dataset that lives next to your application data, ready for dashboards, alerts, or any analysis you want to run.

Step-by-Step: Export Xero to Postgres with Codeless Sync

If Method 5 looks like the right fit, the setup itself takes about five minutes:

  1. Create a Codeless Sync account. The free tier covers small projects without a credit card.
  2. Add your PostgreSQL database. Paste your connection string. Codeless Sync tests the connection before saving.
  3. Open the configuration wizard and choose Xero as the source. Pick the data type you want first; contacts is a good starting point because it's easy to verify.
  4. Click Connect to Xero and authorize through Xero's standard consent screen, then pick which organisation to sync. The OAuth flow, token storage, and refresh loop are handled automatically.
  5. Auto-create the destination table. Codeless Sync builds the schema for you, with the right column types and indexes. If you'd rather review the SQL first, copy the template and run it manually.
  6. Run the first export. The full backfill pulls every matching record. For most organisations this takes seconds to a couple of minutes.
  7. Schedule recurring exports (every minute, hourly, or daily depending on your plan), or trigger them manually from the dashboard.

When the run finishes, your Xero data is in your Postgres database. Repeat the wizard for invoices, payments, or any other data type you need. Each one becomes its own table, each one stays current.

For a deeper walkthrough including the full Xero setup flow, see the step-by-step Xero-to-PostgreSQL sync guide.

Frequently Asked Questions

Can I export Xero data without using the API?

Yes. The no-API option is to export each data type from its own screen inside Xero (contacts, invoices, bills) or export reports as Excel, PDF, or Google Sheets. This works for one-off analysis but produces static files that are stale the moment they're downloaded, and a complete dataset means several separate exports. For ongoing access, every other method eventually involves the Xero API in some form; the question is whether you build that integration yourself or use a tool that handles it for you. A no-code sync like Codeless Sync uses the API behind the scenes so you don't have to.

Does Xero have a full backup or bulk export option?

Not in the way developers usually mean it. There's no single button or API endpoint that returns all of your data at once. Xero's own guidance is to export each data type separately: contacts from the Contacts screen, invoices and bills from the Business menu, and the General Ledger and other reports from the Reports section. This is the main reason most teams reach for a sync tool; a complete, current copy of your data in one place is exactly what those tools do.

What's the best way to export Xero data to PostgreSQL?

It depends on how often the data needs to refresh and how much engineering time you can spare. For a one-time export, per-screen CSV files plus a COPY statement is fastest. For a current, queryable copy of your Xero data with minimal maintenance, a no-code sync tool is the lowest-effort path. Building directly against the Xero API gives you the most control but the highest ongoing maintenance cost: 30-minute access tokens, single-use refresh tokens, tenant routing, and rate limits are all yours to manage.

How often should I export Xero data?

It depends on what you're using the data for. For monthly accounting reviews, daily syncs are plenty. For internal dashboards or cash-flow monitoring, hourly updates feel close to live. For event-driven workflows (like flagging overdue invoices to your ops team), you'll want incremental syncs running at least every 5-15 minutes. Codeless Sync supports schedules from every minute up to daily, depending on plan tier.

Will exporting Xero data affect my API rate limits?

Xero enforces 60 calls per minute per connected organisation, with 5 concurrent requests and a daily cap on top. A well-designed export tool stays well under that; incremental syncs typically only fetch records that changed since the last run, so the request count is small. If you're building a custom integration, you'll need to implement your own backoff and retry logic to stay under the limits. Sync tools handle this for you.


Need a current, queryable copy of your Xero data without writing a pipeline? Codeless Sync has a free tier, no credit card required. For the build-vs-buy decision in more depth, see Xero API vs Database Sync.


Related:

Top comments (0)