Xero Journal API Limitations: How to Filter Voided and Reversal Entries [2025 Guide]

Introduction

When working with accounting software like Xero, transparency and accuracy in financial reporting are paramount.

However, Xero’s Journal API presents certain limitations when dealing with updates to transactions, especially when multiple journal entries are created for the same source transaction.

These limitations, while ensuring accurate records, can present challenges for API developers looking to integrate or work with Xero’s general ledger data.

We’ve previously explored similar challenges with Xero’s invoice synchronization.

In this article, we’ll explore the limitations developers face with Xero’s Journal API, offer a deep dive into the underlying reasons for the multiple journal entries, and provide practical solutions to make it easier to manage this data.

The Problem: Duplicate Journal Entries

While consulting a SaaS client who is aiming to develop a Real-Time AI reporting, analysis & forecasting solution that works with multiple Accounting and ERP software.

The client’s objective is to get the entire general ledger, chart of accounts, and generate the AI-driven insights from Xero, and drill down to the transactions history.

The problem occurred when Xero’s journal API returned duplicate transactions which included voided, deleted, and reversal of the original journal.

Duplicate !! Really?

How is it even possible?

It doesn’t make any sense that the Xero journal report will send duplicate entries.

Let’s understand if they are duplicates or something else.

Ideally Xero journal API should be returning only records which are actively present in Xero.

Not the deleted one or the modified transaction’s reversal journal entries.

Journal endpoint and deleted or voided filter- Xero forum discussion

(Source: Developer Xero Forum)

Why does Xero Journal API show voided and deleted journals?

Xero’s approach to journal entries ensures that every transaction is auditable and traceable.

However, when a transaction, such as an invoice or payment, is updated, Xero doesn’t simply modify the original journal entry.

Instead, it reverses the original journal and creates a new journal reflecting the updated transaction details.

Kelly, a 7-year-old user from Xero Central, summed it up quite simply when she explained the workflow:

“In Xero, journals are created for every transaction. If a transaction is then edited, deleted, or recoded, a journal is created to reverse the original transaction with a new journal created showing the revisions.”

Kelly, from Xero Central give ans to miki

(Source: Xero Forum)

For example, if you enter a sales invoice and then edit it, you will see the following entries in the Journal report:

Xero Journal Report showing accounting entries for Demo Company (Global) between 1 May 2025 and 31 May 2025. All entries are posted by Chintan Prajapati.
  1. The original journal from when the invoice was first entered.
  2. A reversal of the previous journal.
  3. A new journal for the updated transaction.

Kelly’s explanation highlights the key idea, Xero ensures that each change to a transaction creates a complete history, preserving transparency and auditability.

Key Takeaway: Xero’s system is designed for complete auditability, not just current state reporting

The Challenge for XERO API Developers

It is a very common use case where building a tool for Accountants and Financial Advisors to analyze the underlying data within Xero and displaying to them only records that are currently present within the system.

Xero Journal API endpoint officially doesn’t have any way to filter out the voided or deleted or modified transactions journal entries.

While Xero’s approach ensures the integrity of financial records, but it creates several challenges for Xero developers working with the Xero API.

Multiple Journals for a Single Source Transaction

As seen in the screenshot below, multiple journal entries are created for a single source transaction (e.g., an invoice which got modified by amending delivery charge from $10 to $20).

Although this redundancy is necessary for tracking transaction audit and history management, but it can become problematic for database storage, efficient querying and Data analysis.

Journal Report showing entries and reversals for Basket Case (ID 532 & 531) in May 2025, posted by Chintan Prajapati.

Check the above screenshot of an invoice, which got modified.

Journal Report showing original, reversal, and updated invoice entries for Bayside Club in May 2025

Invoice modification in Xero created a reversal journal entry for the original invoice and created a new journal entry with updated amounts.

XML-style data structure showing Journal Numbers 566, 567, and 568, each linked with the same SourceID and reference 'GB1-White'.

For better viewing, I copied the JSON output from Xero’s API explorer to the JSON viewer and highlighted the source ID and journal numbers.

The screenshot shows multiple journal entries with the same SourceID, illustrating the redundancy in the data created by the reversal and updated transactions i.e. invoice.

Here’s the key problem in Xero Journal API

  • How would you identify which journals to keep and which ones to delete from the database?

The possible solution is

  • Xero Developers need to store all these journal entries (including reversals) in their databases.

But it will create another problem

  • The database can quickly become cluttered with unnecessary data, leading to performance issues, especially when the number of journal entries increases over time.
  • Even though the net effect of the journals is correct (the total debits and credits balance out), the large volume of journal entries for a single source transaction can complicate financial reconciliation and reporting.

Xero developers must

  • Track and store every journal entry (original, reversal, and updated).
  • Reconciling multiple journal entries for the same transaction, which is cumbersome and error-prone without the right tools.
  • Optimize storage and performance to handle this added complexity.

Key Takeaway: Without proper filtering, Xero’s journal data creates database inefficiency and analytical complexity.

Solution: How to Efficiently Filter Deleted and Voided Journals in XERO

Now that we understand the challenge, let’s look at practical solutions for developers who need to work with Xero Journal API and filter out unwanted journal entries efficiently.

To filter out reversal Xero journal API entries for the same source transaction, one effective solution is to use an intermediary table. Here’s how you can do it:

Step 1: Storing Journals in an Intermediary Table.

Create an intermediary table where all journal entries (original, reversal, and updated) are stored temporarily.

Create an intermediary table where all journal entries

Each journal entry contains two important identifiers:

  • SourceType
  • SourceID

This way, all related journals can be grouped together by their SourceID.

Step 2: Grouping Based on SourceID

Once journals are in the intermediary table, you can easily group them by SourceID to track all changes made to a single transaction.

Step 3: Moving the Last Xero Journal to the Final Table

After identifying the most recent Xero journal (reflecting the updated transaction), move it to the final table, leaving the reversal and original journals in the intermediary table for auditing purposes.

The above approach will not solve the entire problem, because what if the most recent journal is deleted or voided one?

Complete Solution: Cross-reference with Transaction Tables

You need to pull following data from the individual API end points store them in database table.

Then cross-reference data from these key transactional tables:

Mapping SourceType to Transaction Tables

We will map SourceType to their respective transactional tables as follows:

SourceTypeTarget TableTransaction Type
ACCPAYInvoicesAccounts Payable
ACCPAYCREDITCreditNotesAP Credit Note
ACCPAYPAYMENTPaymentsAP Payment
ACCRECInvoicesAccounts Receivable
ACCRECCREDITCreditNotesAR Credit Note
ACCRECPAYMENTPaymentsAR Payment
CASHPAIDBankTransactionsCash Paid (Bank Txn)
EXPCLAIMExpenseClaimsExpense Claim
EXPPAYMENTPaymentsExpense Payment
BANKTRANSFERBankTransfersBank Transfers
MANUALJOURNALManualJournalsManual Journal Entries

Validation Method

Using SourceID, we will SQL join journal records with SourceType tables to validate the status and ensure:

  • Voided/Deleted transactions are excluded.
  • Only the most recent journal (based on JournalNumber) is retained.

For example, here’s what a deleted invoice looks like in JSON (Xero JSON Integration):


{
  "Type": "ACCREC",
  "Contact": {
    "ContactID": "eaa28f49-6028-4b6e-bb12-d8f6278073fc"
  },
  "DueDate": "\/Date(1518685950940+0000)\/",
  "LineItems": [
    {
      "Description": "Services as agreed",
      "Quantity": "4",
      "UnitAmount": "100.00",
      "AccountCode": "200"
    }
  ],
 "Status": "DELETED"
}

An example of SQL Joining query with Invoices

Journal Entry table filter records by

SourceType = ‘ACCREC’ (Accounts Receivable Invoice)
SourceID = ‘9b731dec-77cf-4c83-998e-c11861e5cf4b’

And matching in Invoices table

InvoiceID = ‘9b731dec-77cf-4c83-998e-c11861e5cf4b’

To handle the increase in journal entries, you can optimize your database design:

  • Index the intermediary table to speed up queries.
  • Partition the table to handle large volumes of data effectively.
  • Consider archiving older journal entries in a separate database or table to keep the working dataset manageable.

Conclusion: Finding the Right Balance

By following Xero API best practices, Xero Journal API offers robust features that ensure transparency and auditability in financial records.

However, the way it handles transaction updates by creating deleted or voided journal entries can complicate things for API developers.

By grouping journal entries, using intermediary tables, Joining with transactions table and optimizing database storage.

Developers can efficiently manage this complexity without sacrificing the benefits of Xero’s transparent approach.

For more Xero API integration strategies, see our guides on XERO invoice synchronization and trial balance data extraction.

With the Multiple Journal Entries solutions provided in this article, Xero developers can overcome the challenges of working with multiple journal entries and ensure their integrations with Xero remain smooth, efficient, and scalable.

Final Thoughts

If you’re working with Xero API and facing challenges managing journal entries, the key is to group, store, and optimize.

By implementing the solutions outlined above, you can handle transaction updates effectively while maintaining data integrity and performance.

Article by

Chintan Prajapati

Chintan Prajapati, a seasoned computer engineer with over 20 years in the software industry, is the Founder and CEO of Satva Solutions. His expertise lies in Accounting & ERP Integrations, RPA, and developing technology solutions around leading ERP and accounting software, focusing on using Responsible AI and ML in fintech solutions. Chintan holds a BE in Computer Engineering and is a Microsoft Certified Professional, Microsoft Certified Technology Specialist, Certified Azure Solution Developer, Certified Intuit Developer, Certified QuickBooks ProAdvisor and Xero Developer.Throughout his career, Chintan has significantly impacted the accounting industry by consulting and delivering integrations and automation solutions that have saved thousands of man-hours. He aims to provide readers with insightful, practical advice on leveraging technology for business efficiency.Outside of his professional work, Chintan enjoys trekking and bird-watching. Guided by the philosophy, "Deliver the highest value to clients". Chintan continues to drive innovation and excellence in digital transformation strategies from his base in Ahmedabad, India.