Skip to content

Vendor bills

Where does supplier spend actually live in each ledger? Not all of it is in the bill object. QuickBooks splits accrual bills from immediate card and cash purchases into two entirely different entities, and a vendor-spend figure that reads only Bill under-reports — often dramatically.

Concepts
10
Divergences
4
Structural
3

Endpoints

Xero

GET /Invoices?where=Type=="ACCPAY"

Plus /BankTransactions for direct spend

QBO

SELECT * FROM Bill

Plus Purchase for card and cash spend

NetSuite

SuiteQL: FROM transaction WHERE type IN ('VendBill','Check')

Plus expense reports

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
Vendor bills fields compared across Xero, QuickBooks Online and NetSuite
ConceptXeroQBONetSuite
Accrual bill
Partial

Invoice, Type: ACCPAY

Native

Bill

Native

vendorbill

Immediate spend (card, cash, direct debit)The row that breaks vendor spend dashboards.
Native

BankTransaction, Type: SPEND

Separate endpoint entirely

Native

Purchase

PaymentType: Cash / Check / CreditCard. Posts no accounts payable

Native

check, expensereport, card charge

Account-based line
Native

AccountCode on the line

Native

AccountBasedExpenseLineDetail

Native

expense sublist

A distinct sublist from items

Item-based line
Partial

ItemCode on the line

Same line shape

Native

ItemBasedExpenseLineDetail

Native

item sublist

Participates in receipt matching and inventory

Payables control account
Partial

Implicit

The CREDITORS system account

Native

APAccountRef

Selectable per bill

Native

account

Any AcctPay account

Billable to a customer
Native

LinkedTransactions

The billable-expenses API: links an ACCPAY or SPEND line to a customer or ACCREC invoice

Native

BillableStatus + CustomerRef per line

Native

isbillable + customer per line

Purchase-order match
Absent

—

Not exposed in the API; only PurchaseOrder Status BILLED

Partial

LinkedTxn to PurchaseOrder

Link plus line copy; no receipt object

Native

Two- and three-way match

Item receipt records, quantity and price variance

Approval
Partial

Status: SUBMITTED

A single soft flag, not a workflow

Absent

—

No approval concept in the API

Native

approvalstatus + SuiteFlow

Multi-step routing, enforced server-side

Duplicate detection
Absent

—

Warns in the UI, nothing in the API

Absent

—

Partial

Configurable

Vendor + reference uniqueness, script-enforced

Outstanding amount
Native

AmountDue

Native

Balance

Native

amountremaining

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 splits accrual from cash, and both are spend

QBO · Xero

A vendor invoice you will pay later is a Bill. A card swipe is a Purchase, which posts no accounts payable and does not appear in any Bill query. Companies that run most spend on cards can have the majority of their expenses invisible to a Bill-only integration.

Do — Every spend aggregate reads Bill and Purchase — in Xero, Invoice ACCPAY and BankTransaction SPEND. Name the metric for what it contains.

Sharp edge

NetSuite's two sublists are not interchangeable

NetSuite · QBO

A vendor bill carries an expense sublist (account, amount, segments) and an item sublist (item, quantity, rate, receipt matching). Item lines participate in three-way match and inventory costing; expense lines do not. Flattening both into one lines array loses the distinction, and the loss shows up the moment someone asks why a bill will not match its receipt.

Do — Carry a lineKind discriminator of 'account' | 'item' in the canonical model. QBO needs it too, for its two DetailTypes.

Structural

Approval is real in NetSuite and decorative elsewhere

NetSuite · Xero · QBO

Xero's SUBMITTED status is a flag any user can set. QBO's API has no approval concept whatsoever. NetSuite has server-enforced multi-step routing that your write may enter and not clear — a successful API call does not mean an approved bill.

Do — Approval state is ours for Xero and QBO, mirrored from NetSuite. Write-back is capability-gated and hidden where the capability is false.

Structural

Three-way match exists in one of the three

NetSuite

Only NetSuite models goods receipt as a record and reconciles quantity and price across PO, receipt and bill. QBO offers a link between a bill and a purchase order, with no receipt and no variance; Xero's API exposes no bill-to-PO link at all, only a purchase order whose Status has moved to BILLED.

Do — The match component computes the variance itself for QBO, from whatever quantities the linked documents carry, and labels it as our calculation rather than the ledger's. For Xero there is no link to compute from: any PO-to-bill pairing is ours, proposed and confirmed by the user.

The same fact, different payloads

Stacked rather than tabbed — a reader comparing two shapes should not have to hold one of them in memory.

QBO — account-based expense line on a Bill

QBO
{
  "VendorRef": { "value": "41" },
  "TxnDate": "2026-09-07",
  "DueDate": "2026-10-07",
  "APAccountRef": { "value": "33" },
  "Line": [{
    "DetailType": "AccountBasedExpenseLineDetail",
    "Amount": 4500,
    "AccountBasedExpenseLineDetail": {
      "AccountRef": { "value": "62" },
      "ClassRef": { "value": "3" },
      "BillableStatus": "NotBillable",
      "TaxCodeRef": { "value": "NON" }
    }
  }]
}

NetSuite — expense sublist and item sublist on one bill

NetSuite
{
  "entity": { "id": "41" },
  "trandate": "2026-09-07",
  "duedate": "2026-10-07",
  "subsidiary": { "id": "2" },
  "expense": { "items": [{
    "account": { "id": "62" }, "amount": 4500,
    "department": { "id": "7" }, "memo": "September rent"
  }] },
  "item": { "items": [{
    "item": { "id": "310" }, "quantity": 100, "rate": 12
  }] }
}

The type the components consume

bills.ts
type DocumentLine = {
  id: string;
  /** NetSuite expense vs item sublist; QBO's two DetailTypes; Xero's one shape. */
  kind: "account" | "item";
  description?: string;
  quantity?: string;
  unitAmount?: Money;
  accountId?: string;        // resolved even when the source only stored an item
  itemId?: string;
  net: Money;
  tax: TaxBreakdown;         // never a bare scalar
  dimensions: LineDimension[];
  billable?: { customerId: string; status: "billable" | "billed" | "not_billable" };
  source: SourceRef;
};

What this changes in the interface

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

Spend spans several document types
SpendDashboard renders booked, accrued and committed as three series and never sums them into one 'spend' number. The source composition is stated in the caption.
Approval workflow exists on one source
ApprovalChain reads capability. Where the ledger has no workflow, the chain is ours and is labelled as ours — never presented as the ledger's state.
Receipt records exist only in NetSuite
ThreeWayMatch shows a variance it computed for Xero and QBO, with the inputs visible, and the ledger's own match result for NetSuite.
No duplicate detection in the APIs
DuplicateBillAlert is entirely our control surface, running on vendor, amount, date proximity and reference. It cannot be delegated to the source.

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.