The work on this page is covered by a non-disclosure agreement with ScaleXP and their end client. Client names, specific data structures, and business details are not disclosed. This is not just a legal requirement. It reflects how I approach every engagement. Client data stays private. Always.

n8n AutomationFinance Systems

How ScaleXP ships backend automation their clients can trust with live financial data

ScaleXP · Notion and Automation Consulting · Ongoing

Code can be reverted. A line written into a live general ledger cannot. That one fact set every rule in this build.

4
workflows in production
~1,300
contacts kept in sync
2
systems, one source of truth
Built withn8nXero APITeamwork APIn8n Data TablesGmail

The Problem

A creative production agency ran delivery in Teamwork and money in Xero. Projects, tasks and expenses on one side. Invoices, bills and the chart of accounts on the other. The same client existed in both, keyed once into each, and at month end a person reconciled the two by hand.

ScaleXP designs Notion workspaces and the automation around them. They brought Abhiman Labs in to own the backend for this one and build the sync properly.

The harder half of the brief was not the syncing. It was the writing. Teamwork is a project tool, and a wrong record there is a wrong record. Xero is a live general ledger, and a wrong record there is a line in an audit trail with a date on it. It does not get deleted. It gets corrected, and somebody's accountant does the correcting. An automation that writes into that has to be right on the first pass, on every run, with nobody watching.

One identity across two systems

Teamwork calls them companies. Xero calls them contacts. They are the same organisations, held twice, with two sets of IDs and often two spellings of the same name.

  1. 01Reference tagBoth records already point at each other. Exact, nothing else to check.
  2. 02Exact nameThe two names are identical.
  3. 03Name minus the project code"TIT000 - Titanium" is tried against "Titanium".
  4. 04EmailThe stored addresses agree.
  5. 05Fuzzy scorePunctuation stripped, "&" read as "and", Pty Ltd and LLC removed, then scored.last resort
The first rung that answers wins. The ones under it are never evaluated.

The first run does the matching. Every run after it reads the answer. A confirmed pair gets a permanent reference written onto both records, each one pointing at the other, and around 1,300 contacts carry one. A rename on either side no longer breaks the link.

Invoices, bills, and the files that belong with them

With identity settled, the money follows a fixed path.

Teamworkevery row passes the same gateXero
Companiesboth waysContacts
Invoicesto Xero, with a return pathSales invoices, as drafts
Expensesboth waysBills
Projectsto Xero onlyProject code tracking
Files and receiptsto Xero onlyAttachments
both waysone way

Project codes land in Xero as a tracking category, and the valid options are pulled live on the run rather than read from a list captured at build time. A code that has since been retired is never written, and a Xero bill that has already been paid is left alone with the change flagged instead.

Receipts and project files attached in Teamwork are pushed onto the matching Xero record, so the document sits with the transaction instead of in a folder someone has to go and find. A file is matched by the invoice number in its filename, read past differences in case and spacing, so a receipt saved by hand as "inv 8921 second page" still finds INV8921. It counts as synced only once Xero confirms it, so a failed upload is retried on the next run rather than marked done.

Every sales invoice is created as a draft. A person reviews it and sends it.

Rule 01

Never write on a guess

Name matching is the load-bearing part of the whole system, so it carries the strictest rule. Every candidate pair is scored before anything is written anywhere.

The middle band is the design. A pair inside it looks like a match and might not be, which is precisely where an automation with no middle band writes a bill against the wrong supplier. A short name also cannot match a longer one just by being a fragment of it.

Rule 02

Confirm the write, do not trust the response

The orchestration logic is a single code node, over 30KB of it. Pushing a change to it is an API call, and a success response from an API means the request was accepted. It does not mean the right bytes are sitting in the workflow.

So every push is read back. The node is fetched after the write and md5 checked against the source file on disk. If the two hashes disagree, the deploy is not finished.

n8n adds a second version of the same question. Editing a workflow only changes its draft. Production keeps running whatever was published last, which means a workflow can look correct in the editor and still be executing older logic on schedule. So every publish is re-read live and the active version confirmed to be the one just written.

Rule 03

Test without touching the client's data

Every test run uses pinned fixtures. The credentialed nodes are handed their input instead of being allowed to fetch it, so no node in a test ever reaches a real Xero or Teamwork endpoint. Where a test genuinely needs a record to exist, that record is fictional, created and deleted immediately, with the deletion verified by reading the record back.

The client's ledger is not a staging environment. Nothing in the build treats it as one.

What happens when it is not sure

It stops. Not the whole run, just that record, which is left untouched and handed to a person instead.

There is one digest email per run. Not one per record, which is how a notification channel turns into something people filter into a folder they never open. A clean run sends nothing at all, so an email from this system means a decision is waiting. Volume has a ceiling too. Each run writes at most 40 records per direction, anything over the cap carries to the next run, and the runs come every 12 hours, staggered 15 minutes apart.

The quietest rule is the one that matters most in a two-way sync. If both sides already hold the same value, nothing is written. That single check is what stops two systems that each watch the other from bouncing the same record back and forth on every cycle.

What changed for the team

Before
Keyed into Teamwork, then keyed again into Xero
Reconciling the two systems was a month end job
A missing link surfaced weeks later
No way to tell which record was correct
After
Keyed once. It is in Xero on the next cycle
Reconciliation is the exception, not the routine
A record it will not link is an email that day
Every pair carries one reference on both sides

What changed in the system

Before
Linking meant a person reading two names and deciding
Nothing recorded which company matched which contact
A problem was found by whoever went looking
No line between odd and needs a decision
After
Writes at 95, asks at 85 to 95, ignores below
Every pair carries a reference, rechecked each run
Every failure reaches a person on the run it happened
One digest per run, 40 writes per direction

The Result

Four workflows run in production behind a shared error notifier, and around 1,300 contacts stay matched across Teamwork and Xero with nobody maintaining the mapping.

Nobody watches it run. That is what the rules above buy. It is built to stop rather than improvise, and anything that does not clear the bar waits with an email attached to it.

For the agency, a record is keyed once and is in both systems by the next cycle. Month end is a check rather than a rebuild, and the audit trail in Xero holds what the team actually did rather than what survived being typed twice.

ScaleXP still routes their backend automation work to Abhiman Labs, and this was one project of several. If you run a consultancy that needs a specialist behind the technical layer of your client work, that is the conversation to start.

4 workflows in production · ~1,300 contacts in sync · 12 hour cycle · 40 writes per direction per run
← Back to all work