A supplier sends a PO confirmation, invoice, or quote as a PDF. LineKeeper reads it, matches every line against your open order, and surfaces only the lines that don't agree. A person confirms the exceptions; a clean structured record goes to your system.
The problem
Someone on your team opens every confirmation, reads down the lines, and checks them by eye against what was ordered — quantities, unit prices, the promised ship date. Most of the time it all matches and the work was pointless. When it doesn't match, catching it late means a short shipment, a price you never agreed to, or a re-key error that rides the order all the way through.
Text extractors and Zapier-style flows pull the words off the page. They don't do the part that matters: reconcile the document against the order it belongs to and tell you what changed.
A worked line
One line off a supplier's PDF, lined up against the matching line on your order PO-10432.
| Source | Unit price | Line total | Verdict |
|---|---|---|---|
| Your order | 35.00 | 420.00 | expected |
| Their PDF | 39.00 | 468.00 | PRICE_MISMATCH |
The other three lines on this order matched and never reached a person. This one did.
How it works
Upload the PDF, or have the supplier reply to an intake address and it lands on its own. Every file is kept and addressable by hash.
PO number, supplier, currency, totals, promised ship date, and every line — SKU, description, quantity, unit price. Illegible fields come back empty with a confidence score, not a guess. Per-supplier hints sharpen layouts you see often.
LineKeeper finds the open order by PO number, lines up each row by SKU — falling back to description when codes don't match — and compares quantity, price, and totals within a tolerance you set.
Clean documents pass straight through. Only the ones with a flagged line need a look. Edit anything on screen; your correction re-matches the document and is remembered for that supplier.
What you see
Every line lands in one of these. Green passes without you. Amber and red are the only rows that need a person.
On confirm, your system gets one clean record — whatever the PDF looked like:
{
"po_number": "PO-10432",
"supplier": "Kaimai Components Ltd",
"matched_order_id": "ord_e0185346d66f",
"currency": "NZD",
"promised_ship_date": "2026-09-09",
"totals": { "subtotal": 1284.00, "tax": 192.60, "grand_total": 1521.60 },
"lines": [
{ "sku": "GSK-22", "quantity": 12, "unit_price": 39.00,
"match": "PRICE_MISMATCH", "expected": { "unit_price": 35.00 } }
],
"exceptions": ["TOTAL_MISMATCH"],
"review_status": "confirmed"
}
Pull it from GET /api/export/:id, or have it POSTed to your webhook the moment someone clicks confirm.
Who it's for
Dozens of supplier confirmations a week, every one a slightly different layout, every one checked by hand.
Buying components against POs, where a wrong quantity or price on line 7 becomes a line-down problem three weeks later.
Pricing
Early access. One workspace, unlimited suppliers, the full pipeline above. If the exception-matching doesn't save someone real time in the first week, it isn't for you and you don't pay.
What it doesn't do yet