Skip to content

Attachments and the audit trail

Can you see who changed what, and get the source document? Only NetSuite has a real audit trail through its API. Xero gives you a per-record history feed; QuickBooks gives you a timestamp and no actor at all. Any evidence surface has to be honest about that.

Concepts
7
Divergences
2
Structural
1

Endpoints

Xero

GET /{Endpoint}/{Guid}/Attachments, /History

Per record

QBO

SELECT * FROM Attachable

Queried by AttachableRef, not by transaction

NetSuite

file records + SuiteQL: FROM systemnote

Field-level change log

The same concept in three vocabularies

Read across a row. Where a cell is absent, the concept has nowhere to live in that system — which is a design constraint, not a gap to paper over.

NativeNative
— A field or object exists for it
PartialPartial
— Exists with a caveat that changes what you can build
DerivedDerived
— Not stored — you compute it
AbsentAbsent
— Nothing in the API
Attachments and the audit trail fields compared across Xero, QuickBooks Online and NetSuite
ConceptXeroQBONetSuite
Attachment model
Native

Attachments sub-resource on most endpoints

Partial

Attachable entity with AttachableRef[]

Points back at the transaction

Native

file record in the file cabinet

Linked via a sublist

Upload
Native

PUT raw body to /Attachments/{FileName}

Native

Multipart POST to /upload

Partial

Base64 contents on a file record, then attach

Knowing an attachment exists
Native

HasAttachments flag on the record

Partial

Query Attachable

A second call per transaction unless batched

Native

Sublist on the record

Internal notes
Native

HistoryAndNotes

Read and append

Partial

PrivateNote

One free-text field

Native

memo, usernotes

Change historyThe row that decides whether an audit component can exist.
Partial

HistoryAndNotes

Per record, coarse — not field-level

Absent

None

No change history through the API at all

Native

systemnote

Field-level, queryable, with the actor

Who and when
Partial

UpdatedDateUTC + history entries

Partial

MetaData.{CreateTime, LastUpdatedTime}

No user

Native

owner, lastmodifiedby, per-field systemnote

Size limits
Partial

Around 25 MB per file, 10 files per record

Verify — vendor-specified

Partial

Around 100 MB per file

Verify — vendor-specified

Partial

File cabinet limits apply

What actually differs, and what you do about it

A difference stated without a response is trivia. Each of these carries the handling.

Structural

QuickBooks has no audit trail in the API

QBO

There is no endpoint for change history and no actor on any record. If a bookkeeper edits an invoice in QuickBooks, you will see a new LastUpdatedTime and nothing else — not what changed, not who changed it, not what it was before.

Do — Keep a before-and-after for every change we make and snapshot watched fields on every sync, so a diff can be reconstructed. Present it as our record, not the ledger's.

Sharp edge

Attachments are the largest thing you will sync

QBO · Xero · NetSuite

Files dominate an integration's storage and transfer cost, and QBO needs an extra query per transaction to discover them. Fetching every attachment eagerly on first connection is how a sync exceeds a daily call cap on day one.

Do — Sync attachment metadata eagerly and file bytes lazily, on first view or on an explicit archive action. Show a placeholder that is honest about the file not being fetched yet.

The type the components consume

attachments-and-audit.ts
type Attachment = {
  id: string;
  fileName: string;
  mimeType: string;
  bytes?: number;
  /** Metadata syncs eagerly; content is fetched on demand. */
  contentUrl?: string;
  fetchedContent: boolean;
  source: SourceRef;
};

type AuditEvent = {
  at: string;                    // ISO instant
  actor?: { id: string; name: string };   // absent on QBO, always
  action: "created" | "updated" | "voided" | "deleted" | "approved" | "synced";
  field?: string;                // NetSuite systemnote is field-level
  before?: string;
  after?: string;
  /** Ours or theirs. The UI must not blur the two. */
  observedBy: "us" | "source";
};

What this changes in the interface

The payoff. Every difference above that reaches the surface, and what the component does about it.

Lopifi-side edits can be invisible
AuditTrail states its coverage explicitly — 'changes we made, plus what the ledger reports' — and shows the last sync time. Silence is never presented as 'no changes'.
Attachment bytes are lazy
The document viewer shows a fetch affordance rather than a broken preview, and the fetch is a visible, cancellable action.

Where the accounting is explained

What consumes this payload

The normalised object above is what the components read. These are the surfaces it feeds, the words for the concepts in it, and the document that explains the accounting.

Compared acrossXero docsQuickBooks Online docsNetSuite docs

Works in your QuickBooks Online or Xero file

Get your books closed every month

Lopifi is building AI bookkeeping that keeps your books closed on US GAAP as transactions happen, with a CPA review every quarter, for $200 a month. We’re not open yet.

$200/month when we open. No card now.