Watch our latest video available on Youtube.
Tutorials/Tutorial

Creating Invoices in Xero with Airtable

Xero is excellent accounting software but its built-in invoice editor wasn't designed for teams that manage line items collaboratively, generate dozens of similar invoices, or pull billable work from across projects. The fix is to build the invoice in Airtable — where the data already lives — and push the finished invoice to Xero with one button. This guide walks through the full workflow: base structure, Make scenario, edge cases, and the moves that keep accounting clean.

Intermediate18 min readMay 21, 2026

Xero is excellent accounting software. The invoice editor inside Xero is fine. But for teams that build invoices from project data, with multiple line items per invoice, with reviews and approvals before sending, working directly in Xero starts to feel like the wrong place. The data lives in Airtable — projects, hours, deliverables, retainer fees — and bouncing back to Xero to type it all in is repetitive at best and error-prone at worst.

The workflow this guide describes is one we've built for agencies, photography studios, and consultancies. The team assembles invoices in Airtable, where the source data already is. Finance reviews and approves them in Airtable. Then a single click pushes the invoice to Xero via Make, where it becomes the official record of account.

What We're Building

End state:

  • An Airtable base with Clients, Invoices, and Line Items tables
  • A way for project managers to assemble draft invoices using project data
  • A review and approval step for finance
  • A Make scenario that, on approval, creates the invoice in Xero with all line items, contact, tax codes, and currency
  • The Xero invoice URL written back to the Airtable record so anyone can click through
  • A clean status flow so no invoice gets sent twice

The split of responsibilities is the point. Airtable handles assembly and approval. Xero handles accounting.

The Airtable Schema

Three tables form the core.

Clients

  • Name (primary)
  • Xero Contact ID (single-line text — captured from Xero)
  • Email (for invoice send-to)
  • Currency (single-select: USD / GBP / EUR / etc.)
  • Default Tax Code (single-select, matching your Xero codes)

Invoices

  • Invoice Number (primary, formula INV- + autonumber)
  • Client (linked record → Clients)
  • Issue Date
  • Due Date
  • Status (single-select: Draft / Ready to Send / Sent / Paid / Void)
  • Total (rollup of Line Items Amount)
  • Xero Invoice ID (single-line text, populated by Make)
  • Xero Invoice URL (URL, populated by Make)
  • Notes

Line Items

  • Description (primary)
  • Invoice (linked record → Invoices)
  • Quantity (number)
  • Unit Price (currency)
  • Amount (formula: {Quantity} * {Unit Price})
  • Tax Code (single-select, matching Xero codes)
  • Account Code (single-line text, optional — Xero account code if you want explicit chart-of-accounts assignment)

The relationship is one-to-many: one Invoice has many Line Items. For more on this pattern, see our linked records guide.

The Invoice Total field is a rollup of the Line Item Amount, summed. As the team adds or edits line items, the invoice total updates automatically.

Capturing Xero Contact IDs

Xero invoices need to be linked to a Xero Contact. The Contact must already exist in Xero — the Make scenario won't auto-create one (you could add that, but we usually keep contact creation manual to avoid duplicate clients).

For each Airtable Client, you need the corresponding Xero Contact ID stored on the record. Two ways to capture it:

  1. Manual. Open Xero, find the contact, copy the ID from the URL or the contact's API response. Paste into Airtable. Fine for small client lists.
  2. Bulk import. Export contacts from Xero, match by name or email to your Airtable Clients, paste the IDs in.
  3. Lookup at send time. Have the Make scenario search Xero contacts by email and grab the ID dynamically. Adds complexity but avoids the prep step.

We default to manual capture because it forces an explicit "this client exists in Xero" check that's hard to fake.

Building an Invoice in Airtable

The workflow for the team:

  1. Create the Invoice record. Pick a client. The Currency and Default Tax Code from the client auto-populate.
  2. Add line items. Open the Invoice record, click into the linked Line Items field, and create new line items inline. Each gets a description, quantity, unit price, and tax code.
  3. Review the rollup. The Invoice's Total field updates as line items are added.
  4. Set status to Ready to Send. The act of changing status to "Ready to Send" triggers the Make scenario.

For agencies, the line items often come from project data. A useful enhancement: build a button on the Invoice record that runs a script to pull unbilled time entries or deliverables from the linked project and create line items automatically. The PM reviews and adjusts, then approves.

The Make Scenario

This is the orchestration layer. The scenario watches for invoices ready to send, reads them and their line items, and creates the Xero invoice.

Trigger: Watch Records

Configure as:

  • Module: Airtable → Watch Records
  • Base: your base
  • Table: Invoices
  • View: a dedicated view called Ready for Xero filtered to Status = Ready to Send
  • Trigger field: Last Modified Time

The dedicated view means as soon as the scenario flips status to Sent, the record falls out of the view and the scenario won't see it again.

Step 2: Fetch Line Items

Module: Airtable → Search Records on the Line Items table.

Filter formula — match against the trigger record's Airtable record ID, not the primary field text:

RECORD_ID({Invoice}) = '{{1.Airtable record ID}}'

The {{1.Airtable record ID}} token comes from the trigger module (the Watch Records output exposes the triggering record's ID alongside its fields). RECORD_ID() evaluated on the linked-record field returns the linked record's ID, so this is a deterministic ID-to-ID join.

Avoid the more obvious-looking {Invoice} = '{{1.Invoice Number}}'. That filter compares the linked field's primary-value rendering against the invoice number string, which silently breaks if you ever change the Invoice Number primary formula, end up with two invoices that produce the same primary value, or have line items whose invoice link was set before the primary value stabilized. Using record IDs eliminates all of those edge cases.

Step 3: Iterator

Module: Iterator pointing at the records array from Search Records.

After this, the scenario runs once per line item. We use this to build an array of line item objects for the Xero call, which is the next step.

Step 4: Array Aggregator

Module: Array aggregator that collects the iterated line items back into a single array.

Configure the target structure to match Xero's line item shape:

{
  "Description": "{{LineItem Description}}",
  "Quantity": "{{LineItem Quantity}}",
  "UnitAmount": "{{LineItem Unit Price}}",
  "TaxType": "{{LineItem Tax Code}}",
  "AccountCode": "{{LineItem Account Code}}"
}

Set the aggregator's "Source Module" to the Iterator. After this module, you have a single bundle with a LineItems array containing all the items for this invoice.

Step 5: Lookup Client Details

Module: Airtable → Get a Record on the Clients table, by the linked client ID from the original invoice. We need the Xero Contact ID, currency, and email.

Step 6: Create Invoice in Xero

Module: Xero → Create an Invoice.

Map the fields:

  • Type: ACCREC (sales invoice — this is the standard for invoices to clients)
  • Contact: Xero Contact ID from the client
  • Date: Issue Date from the invoice
  • DueDate: Due Date from the invoice
  • InvoiceNumber: Invoice Number from Airtable
  • CurrencyCode: Currency from the client
  • LineItems: the aggregated array from step 4
  • Status: AUTHORISED (or DRAFT if you want a manual review in Xero before sending)

For Xero's full invoice schema, see the Xero API Invoices documentation.

Step 7: Update Airtable Invoice

Module: Airtable → Update Record on the Invoices table.

Fields to set:

  • Xero Invoice ID: the ID returned by Xero in step 6
  • Xero Invoice URL: construct as https://go.xero.com/organisationlogin/default.aspx?shortcode=YOUR_CODE&redirecturl=/AccountsReceivable/Edit.aspx?InvoiceID= + the Xero invoice ID
  • Status: Sent

The status change removes the invoice from the trigger view so it won't be processed again.

Step 8: Notify Finance

Optional but useful. Module: Slack → Create a Message in the #finance channel: "Invoice INV-0042 for $4,500 created in Xero" with a link to the Xero URL.

Edge Cases You Need to Handle

A few situations that come up in production.

Missing Xero Contact ID

If the client's Xero Contact ID is blank, the scenario fails when it tries to create the invoice. Add a Filter before the Create Invoice step that blocks the scenario from continuing if the Xero Contact ID is missing, and route the blocked records to an error notification.

Better: add a validation step in Airtable (a formula field on Clients that flags missing Xero IDs) and a view that surfaces them, so the data is fixed before any invoice goes out.

Zero-Quantity Line Items

A line item with quantity 0 will pass through your Airtable Total rollup but get rejected by Xero. Add an Airtable filter on Line Items to your Iterator's source: only line items where Quantity > 0 get included.

Tax Code Mismatch

Xero rejects unknown tax codes. Maintain the Tax Code single-select options in Airtable as an exact mirror of your Xero tax codes. Periodically export your Xero rates and reconcile.

Currency Mismatch

If a client's invoice is in EUR but the client record's currency is USD, Xero won't push the invoice. Validate currency consistency before triggering the scenario — either with a formula field that flags mismatches, or by setting the line item currency from the invoice (not from the line item directly).

Duplicate Pushes

The view-based trigger pattern (Ready to Send → Sent) eliminates most duplicates, but if someone manually flips a Sent invoice back to Ready to Send, the scenario will re-push and create a second Xero invoice. Add a filter that checks Xero Invoice ID is empty before the Create Invoice step.

For more on error handling and these defensive patterns, see our Make automation guide.

Approval Flow Variant

The base setup pushes invoices the moment status is set to Ready to Send. For teams that want a finance approval step:

  1. PM sets status to Ready to Review.
  2. Finance opens the invoice in an Interface Designer approval screen, reviews line items.
  3. Finance clicks Approve, which sets status to Ready to Send.
  4. The Make scenario fires.

This adds a checkpoint without complicating the underlying flow.

Reconciling Paid Status Back to Airtable

The reverse direction — Xero updates back to Airtable — is also worth setting up so you can see invoice status in Airtable without opening Xero.

A second Make scenario:

  • Trigger: Xero → Watch Invoices (every hour)
  • Filter: only invoices recently updated and Status = PAID
  • Find the matching Airtable record by Xero Invoice ID
  • Update the Airtable Status to Paid and write the Paid Date

Now Airtable shows real-time payment status, which feeds into rollups on the Client record (Total Paid This Year, Outstanding Balance) and dashboards in Interface Designer.

For a complete agency receivables setup using this pattern, watch this space — we'll publish a dedicated tutorial on it next.

Why Not Just Use Xero's Own Invoice Editor?

Fair question. Use Xero's editor when:

  • Your invoice volume is low (a few per month)
  • Line items don't come from project data
  • Finance creates invoices end-to-end without input from project teams
  • You're a single person or two-person operation

Switch to the Airtable + Make pattern when:

  • Multiple people contribute to building an invoice
  • Invoices pull from project data (hours, deliverables)
  • You need an approval step between draft and sent
  • You generate dozens of similar invoices each month
  • You want client-level dashboards combining project data and billing

The setup time of the integrated workflow pays back within 2-3 months for most agencies and small studios.

Where to Go Next

For the broader picture of automating finance workflows on Airtable, see our business process automation examples guide. For the orchestration layer details, our Make automation guide covers the iterator/aggregator pattern used here in more depth.

For Xero API documentation, the Xero Developer site is the canonical reference and is worth bookmarking before you build.

Frequently Asked Questions

Common questions about this tutorial.

Ready to Transform Your Business Operations?

Join 100+ companies that have automated their way to success. Get started today and see the difference.