How it works
A three-way match asks one question of every bill a vendor sends: do what you ordered, what arrived, and what you were billed for agree? Doing it properly is a week of the close. Doing it by sampling is how the fourteenth pallet fee gets paid. MatchRail does the checking, every night, and hands you only the handful that disagree. Here is what that looks like, step by step.
// 001
Connect the ledger you already close on
Link QuickBooks or Xero and MatchRail reads your purchase orders and bills where they already live. Link Stripe and it sees the payments that settled them, so a bill that was paid before its match passed is flagged rather than quietly closed. There is nothing to migrate and no new place to enter a bill — if you switch MatchRail off tomorrow, your books are exactly where you left them.
The grants are the narrowest that do the job. Xero is connected read-only and Stripe is connected read-only. Only QuickBooks is asked for write access, and only so a correction you approved can be posted back.
// 002
Record what actually arrived
This is the step that does not exist anywhere else, and the reason a bookkeeper on QuickBooks or Xero cannot run a three-way match today: neither ledger has a goods receipt. QuickBooks Online’s Accounting API carries no item-receipt entity of any name — item receipts are a QuickBooks Desktop feature — and Xero’s /Receipts endpoint is, in its own specification’s words, draft expense claim receipts, meaning employee expenses. A Xero purchase order goes from authorised straight to billed with no received state in between.
So MatchRail owns that document. You record what arrived against the purchase order and the third column of the match fills in. A receipt records quantities, never prices: the unit price always comes off the purchase order, so a receiving clerk can never be the person who introduces a price into the comparison.
// 003
The pass matches three ways overnight
Every night MatchRail pulls what changed on each connected rail since its last watermark — incrementally, so it reads a night of documents rather than your whole ledger — and compares each bill against its purchase order and its receipt:
- Billed quantity against received quantity, line by line.
- Billed unit price against the price the purchase order agreed.
- The document total against that price times the quantity actually received, which catches freight and surcharges that never appear on a line.
- The vendor and document number against every earlier bill, which catches a second copy.
All of it in integer cents. A floating-point rounding error must never be able to invent a variance or hide one. And if a rail does not answer, the pass records the failure and does not advance its watermark — an empty answer from a ledger is indistinguishable from “nothing was billed”, and a matcher that accepted one would clear a book on the strength of an outage.
// 004
What agrees clears without you
A variance clears only when it is inside both bands: 1% of the purchase order’s own figure and $25 in cash. Either band alone opens a hole — 1% of a $180,000 bill is $1,800 cleared with nobody looking, and $25 on a $30 bill is an 83% error cleared as rounding. Requiring both means the tighter one always binds: small bills are governed by the percentage, large bills by the dollar ceiling.
Quantity carries a tolerance of 0, and that is not a number waiting to be tuned. Quantities are counted, not measured: a unit is on the dock or it is not.
// 005
What disagrees reaches your queue
The morning queue is the exceptions and nothing else, biggest first. A match is clean if and only if it carries no variances, and the queue renders exceptions — so if a clean match ever appeared there, the matcher would be wrong. That is a test in the codebase, not a promise in a paragraph.
Each exception names its reason in the words a bookkeeper would use — billed 24, received 21, ordered at $12.50, billed at $14.10 — and shows the purchase order, the receipt and the bill side by side with the disputed line marked in all three columns. You are reading the disagreement, not taking our word for it.
// 006
You approve a correction; it waits, then posts
Where the fix is unambiguous MatchRail proposes it: re-price the line to the order’s price, re-quantity it to what arrived, void a second copy of a bill. Where two disagreements overlap it proposes nothing and says so, because a guess written into a ledger is worse than no guess.
Approving does not post. It queues the correction with an expiry 60 seconds out; the dispatcher sweeps every 15minutes and will not pick a row up before that expiry, so the window is a floor rather than a deadline. Undo is a single conditional update that races the dispatcher’s claim with exactly one winner — if undo wins, nothing was ever written.
And the gates fail closed. Past 500 auto-clears in a day the pass stops clearing and queues everything else regardless of tolerance. Past 50posts in a day the dispatcher stops writing to your ledger and the corrections wait for tomorrow’s budget. And it refuses outright to post a figure that moved after you approved it. There is no --force, no allowlist and no known-issues file anywhere in MatchRail: a gate that can be waived is a gate that gets waived.
Weighing this against the alternatives? Three-way matching sits in the top tier of most payables platforms, so where it lives matters as much as whether it exists — MatchRail vs BILL and MatchRail vs Ramp. For the mass-payout end of the category, see MatchRail vs Tipalti, and for the invoice-workspace model, MatchRail vs Stampli.
Want to see it on a real book? See the live demo →