Linekeeper

Changelog

What shipped, when, and what's still missing. Dated newest first.

Releases

17 Oct 2026
0.34.0

Plainer words, and a correction about analytics

  • A correction. Earlier entries and the privacy policy said the site ran no analytics. That was wrong. Cloudflare Web Analytics, switched on in Cloudflare's dashboard rather than in our code, was counting page views all along. It stays, and the privacy policy now says so. It sets no cookies and doesn't fingerprint visitors.
  • Stripe is now listed as a processor. It gets your email and workspace name when you pick a plan, and was missing from the list.
  • Sign-in attempt counters are deleted after about an hour. They hold IP addresses and the email typed at sign-in, and expired ones were never cleaned up. Now they are, and the privacy table lists them.
  • One pricing answer was wrong. "What if I go over?" said nothing stops working. Allowances are hard caps, as the rest of the page says. The answer is gone and the matching line in the terms is fixed.
  • Copy across the site, the docs and the app is shorter and plainer.
16 Oct 2026
0.33.0

Scan the delivery: a handheld scanner, the phone camera, and labels it learns

  • The count sheet has a Scan box. A handheld barcode scanner works out of the box: they type the code and press Enter, so every scan adds one to the matching line, which flashes so you can see which. Typing a code by hand works the same way.
  • Scan with the phone camera. It uses the browser's own barcode reader where there is one (Chrome on Android, Mac and Windows), and a bundled reader where there isn't, including Safari on iPhone, loaded only when someone presses the button. Each label counts once while it stays in view, then again when the next box comes into view. "In view" is measured in frames the reader actually read, not seconds, so a slow phone never counts one box twice. The camera switches off the moment you save, cancel, or leave the screen. The picture never leaves your browser.
  • It learns your box labels. Boxes usually carry a retail barcode (an EAN or UPC), not the supplier's own item code. The first time a label isn't recognised, Linekeeper asks which line it is and remembers the answer for that supplier, so the next scan of that label just counts. The UPC and EAN forms of the same barcode count as one label.
  • The bundled reader is served from this site, never from a third-party CDN (its default), so pages still make no request to anyone else.
  • Tested end to end in real Chrome: a fake camera feed of a real EAN-13, with both readers, including with the CPU slowed eight times to make sure a slow frame never double-counts (npm run test:scan).
  • New: POST /api/barcodes; the count sheet now lists each line's known labels.
16 Oct 2026
0.32.0

Count the delivery: check what's in the box against what was confirmed

  • Every confirmed document now has a Goods received section. When the delivery arrives, press "Count the delivery" and enter what's actually in the box, line by line. Big plus and minus buttons for a phone in one hand, an "Everything matches the document" shortcut for the common case, and a place to list anything that arrived but wasn't on the document. This is the third leg of the match: the order, the supplier's document, and the goods.
  • A short box keeps the rest owed. Confirming credits the order with what the document says was sent. A count replaces that with what actually arrived, so if the box is short the order reopens with the difference still owed, and the next document from the supplier can be matched against it. A recount that finds the rest closes it again.
  • A line the document left off but that was on your order is on the count sheet too, expecting nothing, in case it arrived anyway.
  • Differences go into the supplier's Memory ("Received 249 of HSS-06, 1 short of the 250 on the document") and into the dispute email, which now offers itself whenever a count differs, even if the document itself matched.
  • Two people recounting the same box can't both change the order book: a recount names the version of the count it was based on, and the second one is told to reload.
  • Also fixed: on a phone, a long email address in the app header pushed "Sign out" off the screen. It now truncates.
  • New: GET/PUT /api/documents/:id/receipt. Counts are included in the account export. Counting needs the confirm permission, since it changes the order book.
16 Oct 2026
0.31.0

Memory: what Linekeeper has learned about each supplier, and you can edit it

  • A new Memory tab. Every time a confirmed document shows something worth knowing next time, Linekeeper writes a short note about that supplier: "Charged NZD 39.00 for GSK-22 on PO-10432, against NZD 35.00 agreed", "Sent 45 of CLP-11, 15 short", "Left SHM-03 off the document". It also notes a price that matched its order but rose against the supplier's history, every correction someone makes to a reading, and every dispute and its resolution.
  • It's yours to edit. Add your own notes ("Ships on Tuesdays only", "Ask Jo about credits"), about one supplier or the whole workspace. Rewrite or delete anything, including what Linekeeper wrote; an edited note says so.
  • It shows up where it helps. When someone reviews a supplier's next document, the last few notes about that supplier sit under the comparison, with a link to the rest.
  • It never changes how a document is read. The memory informs the person, not the reader: a reader told a supplier usually short-ships might start seeing shortages that aren't on the page. Layout notes on the Suppliers tab still go to the reader, as before.
  • Corrections are matched line by line by each item's own code, so a line swapped for a different item is recorded as a new line, not as a "correction" to the old one. A PO number that already starts with "PO" no longer reads as "PO PO-10432", here or in the dispute email.
  • New: GET/POST /api/memory and PATCH/DELETE /api/memory/:id. The memory is included in the account export.
16 Oct 2026
0.30.0

Price history: catch a supplier who raises prices a little at a time

  • Every document now shows what the same supplier charged for each item before, on earlier confirmed documents in the same currency: the last price, the change since then and since the first time you saw the item, and a plain "rising" note when it has only ever gone up. The order check compares a document with its own purchase order, so it can't see a price that crept up while each new order was raised to match. This can.
  • A new Price drift table on the Suppliers tab lists every item whose confirmed price has moved since it first appeared, biggest move first, with the first and latest price and date. A change only counts when it's bigger than your price tolerance, the same rule a flagged line uses, so rounding noise stays out.
  • The dispute email reads like a person wrote it. It used to list internal codes such as PRICE_MISMATCH. It now says what's wrong with the real numbers: "we agreed NZD 35.00 each, your document says NZD 39.00", "we ordered 60, your document confirms 45", "on our order, but not on your document".
  • New: GET /api/documents/:id/price-history and GET /api/suppliers/price-drift. Only confirmed documents count towards history, so a reading nobody has checked never sets the baseline.
16 Oct 2026
0.29.0

An accessibility pass against Apple's design guidelines

  • Every link and text button is now at least 28px tall to tap or click, up from 16 to 22px, in the header, footer, docs sidebar and across the app. The clickable area grows, but nothing on screen moves.
  • Text follows your browser's font-size setting, not just zoom: all 132 type sizes moved from pixels to rem. Nothing changes at the default size.
  • Increase Contrast is supported. With it on, muted text and hairlines get darker.
  • The Enterprise label on the pricing page went from 3.8:1 contrast to 6.3:1, and the 10.5px footer and docs labels moved up to 11px, the smallest size Apple recommends.
  • Headings are in order on every page, which is what screen readers navigate by. The docs had no top-level heading at all, and the pricing page and this changelog skipped a level.
  • Server error messages now start with a capital letter, the file picker's button matches the rest of the app, and the empty order book no longer points to a form "above" that is actually below it.
  • Checked and already fine: no other contrast failures, every control has a label, no sideways scrolling at phone width, reduced motion is respected, and keyboard focus is visible.
  • Deliberately unchanged: dark mode. Apple's guidance is to support both appearances, but Linekeeper stays light, because that was the brief.
16 Oct 2026
0.28.0

Every webhook attempt is kept, so a failed delivery can be diagnosed

  • A confirmed document now has a Delivery history. Open it in the app and expand the panel to see every attempt to post it to your webhook, newest first: whether it went out when the document was confirmed or was resent by hand, the attempt number, the receiving host, the result, and how long it took. Before this, only the latest result was kept, so once a retry overwrote a failure there was no way to see what had gone wrong.
  • The log holds the receiving host only. It never stores the address you configured, which can carry a secret in its path or query, and it never copies the document's payload.
  • New: GET /api/documents/:id/deliveries, and the log is included in the account export. Documents confirmed before this release have no history to show.
  • This was the last item on the roadmap, so that list is empty now.
12 Oct 2026
0.27.0

A demo page you can try without an account

  • /demo shows three supplier documents checked against their orders, with nothing to sign up for or upload. Pick Kaimai, Brandt or Thornbury and see the supplier's PDF beside what Linekeeper found: a handwritten price rise, a short shipment, a substitute nobody ordered, a line the supplier dropped. The comparison uses the same markup and styles as the app, so it is what you see after signing up.
  • The results are not hand-written. They are captured from the real product for these exact files by npm run demo:results, and npm test fails if the saved copy ever goes stale, so the page cannot drift from what the matcher actually does.
  • Linked from the header, the footer, the homepage, the sitemap and llms.txt.
12 Oct 2026
0.26.0

Fonts from our own domain, and renewal terms where you decide

  • No page makes a request to Google any more. IBM Plex Sans and Mono now load from /assets/fonts instead of Google Fonts. Loading a font from Google's servers hands the visitor's IP address to Google, and a 2022 Munich court case treated exactly that as a privacy violation. The Latin Extended files are included, so macrons in names like Māori and Whanganui render in the right typeface, and they only download when a page contains one.
  • Renewal terms now sit next to the plan buttons, in Settings and on the pricing page, instead of only in the terms: plans renew monthly until you cancel, you can cancel from the same panel with no fee, the service runs to the end of the paid period, and the first-week refund applies.
  • The terms and the sign-up page now say plainly that Linekeeper is for businesses and for people 18 or over acting for one. There is no age field: it is a business tool and is not directed at children, so a clear statement is enough.
  • The privacy policy's note on fonts and analytics was updated to match. Checked while there: no analytics, session recording, or advertising scripts exist anywhere in the site or the app, and the product sends no email of its own.
11 Oct 2026
0.25.0

Now we can tell which link a signup came from

  • The marketing pages remember where a visitor first arrived from: the utm_ and ref parameters on the link, the website that linked them (domain only), and the page they landed on. It stays in their own browser until they create an account, then the app sends it to us once. Nothing is sent for a visitor who never signs up, there is no cookie, and nothing goes to a third party. Links that carry utm_source automatically, like the ones some AI assistants add, are captured the same way.
  • First touch wins, with one exception: a visit that arrived with no parameters and no referrer tells us nothing, so a later visit that does is allowed to replace it. The server keeps the value once, only for the account's owner, and only inside the account's first day, so a later link, a colleague's browser, or an old account signing in on a stale browser can never rewrite where an account came from.
  • New: npm run attribution (add --remote for production) prints signups per source, medium and campaign, with how many of each tried a document of their own and how many are paying. Test accounts are left out.
  • The privacy policy now says all of this plainly, and its line about analytics was reworded to match: still no analytics service or third-party tag, but one small script of ours does read where you came from.
  • The homepage's structured data gained a one-line description saying what Linekeeper is and isn't, since other products share the name.
2 Oct 2026
0.24.0

New, off by default: share a supplier's layout notes anonymously

  • Settings → Supplier note sharing. Turn it on and the free-text layout notes you write for a supplier (the kind of thing that says "totals are on page 2") are shared, keyed only by a normalized version of the supplier's name, so a different account's first document from that same supplier can start with a head start instead of none, and you get the same back for a supplier someone else has already dealt with. Off for every account until you switch it on.
  • Deliberately narrow: only the hint text you type yourself is ever eligible. Prices, quantities, delivery dates, confirmed documents, and anything in the examples a correction builds up are never shared, pooled, or touched by this: on or off, that was already true and stays true. The shared table itself carries no account identifier at all, not just a hidden one, so a contribution can't be traced back to the account that made it.
  • The homepage and privacy policy were updated to disclose this plainly rather than leave the old blanket "never pooled" line standing next to a feature that's a narrow, genuine exception to it.
23 Sep 2026
0.23.3

Fixed: a deploy could leave a browser running new HTML against old CSS

  • Cloudflare's own default for static assets caches app.css, site.css, motion.js, and viewer.js for 4 hours with no check back to the server at all. A tab already open when a deploy lands would keep the old file for up to 4 more hours while everything else on the page updated: new positioning JS running against a stale grid stylesheet, for instance, produces a layout, just a badly broken one, with nothing in the console to explain why. These four now go through a small function that asks for revalidation on every load (a cheap 304 when nothing changed) instead of the fixed 4-hour default: the origin side of this is live; a zone-level cache setting still needs a one-time change before it takes effect end to end. If Settings still looks wrong, a hard reload clears whatever was already cached before this shipped.
23 Sep 2026
0.23.2

Settings is a real mosaic now, not just a grid claiming to be one

  • Cards in Settings pack the page by actual height now: a short card no longer leaves dead space beside a tall neighbor while later cards start a fresh row below it. CSS Grid's auto-flow: dense (what was there before) only backfills column gaps within a single row: it can't let a later card rise into the vertical space a short one leaves, since Grid rows are fixed horizontal bands. This measures every card by hand and drops each one into whichever column is currently shortest, the standard masonry approach, and re-runs automatically whenever a card's size changes, covering the view opening, each of the six settings sections loading in on its own, and Team appearing only for an owner.
23 Sep 2026
0.23.1

Fixed: choosing a plan failed with no explanation

  • Every billing error (checkout, the billing portal, crediting a document pack) was returned as HTTP 502. Cloudflare's edge treats 502 (and 504) as its own connectivity errors and silently replaces the response body with a generic page before it reaches the browser, so the real reason never made it past the network tab: the app just showed "request failed (502)". The three endpoints now return the error's real status, and the payment provider's own message reaches the person trying to pay.
  • That's how this surfaced a second, unrelated problem: every plan's configured Stripe price was actually a product ID, not a price ID, so no plan could be purchased at all. Being able to see "No such price" instead of a bare 502 is what made it findable.
23 Sep 2026
0.23.0

The app has weight now, and the roadmap caught up to what's actually shipped

  • The document drop zone materializes on drag-in and reverses on drag-out, instead of a flat class-swap: border and scale ease in over 280ms, and a rapid drag-in-out-in cancels and restarts from wherever the motion actually is rather than replaying from the start. Skips straight to the instant two-state swap under reduced motion.
  • Switching tabs now cross-fades the incoming panel (180ms) instead of an instant cut. The outgoing panel still disappears immediately: the app's layout doesn't yet support two panels occupying the same space for a frame, so only the arrival gets the fade.
  • The app header picked up the same translucent, blurred material the marketing site's header has used all along (backdrop-filter: blur(10px)): it was the one sticky surface in the product still rendering as a flat card.
  • The changelog's "known limits" and "what's next" lists were badly out of date: partial shipments, multi-PO documents, per-supplier tolerances, CSV import, and roles have all shipped (0.16.0–0.20.0), and a purchasing-system connector has existed since 0.10.0: none of that was reflected here, on the pricing FAQ, or in the docs' limits section. All three brought in line with what the product actually does. The one real gap that's left: webhook delivery history isn't kept, so a past attempt can't be inspected or replayed: that's now the only item on the roadmap.
23 Sep 2026
0.22.1

Two more labels caught by a live pass, not the static one

  • The document-viewer's "1 page" counter and its found/handwritten/unreadable legend were both set at 11.5px, half a pixel under the floor the previous pass fixed everywhere else, missed because they only exist once a document is actually open, so the static file scan never saw them. Caught by re-running the detector against the live, populated page instead of the empty one.
23 Sep 2026
0.22.0

The app now matches its own design system, and confirming leads with the reason to look twice

  • Confirming a document now shows why it needs a look before it shows the buttons that decide it. The "N values need your eyes" warning was rendering below Confirm/Reject, so a hurried reviewer (or anyone tabbing through by keyboard or screen reader) could confirm a hand-altered price without ever seeing why it was flagged. It now renders first.
  • Buttons, tags, and inputs in the app now use the same pill/accent system the marketing site already commits to. The app's chrome had drifted to a flat, ink-colored, sharp-cornered variant nobody had reconciled since the last visual pass: different radius, different primary color, different focus-ring color. Fixed at the token level, so it applies everywhere at once rather than button by button.
  • Every functional label in the app is now readable. The muted label color used for nearly every section heading, form label, and table header fell short of WCAG AA contrast (3.5–3.6:1 against a 4.5:1 floor), and a cluster of labels ran under the 11px legibility floor. Both fixed at the color-token and type-scale level, which cascaded the improvement across the marketing site too, not just the app.
  • Three long sentence-length labels on the Suppliers form no longer render in forced uppercase: a rule already written down for exactly this case, just not yet applied there.
  • The app now has a real <h1> (it had none), and wide tables and the tab bar get a soft edge-shadow that only appears on the side there's actually more to scroll to: no more silently clipped columns with no hint they're there.
  • Found and fixed along the way: a button hover state that looked right but dropped white-on-green text contrast to 3.8:1, caught by re-running the same detector after the first pass, before it ever reached production.
  • Run via a full design critique and technical audit (dual independent assessments, cross-verified against the live app): 230 detected issues site-wide before this pass, 87 after: all from fixing five shared CSS tokens, not page-by-page patching.
22 Sep 2026
0.21.0

A chart on the dashboard, icons in the nav, and a look at what a plan buys

  • Dashboard: last 14 days, as a chart. A stacked bar per day, split into what came back clean and what needed a person, in the same two colors the status tags already use everywhere else. Built from the same recent-documents fetch the dashboard already made, so a quiet stretch or a new account just draws short or empty bars honestly, not a chart padded out with numbers that never happened.
  • Icons in the main navigation. Dashboard, Review, History, Suppliers, Settings, and Tutorial each get a small hand-drawn mark instead of bare text, in the same line-weight as the logo mark.
  • Supplier scorecard: a rate bar, not just a count. Each supplier's "needs review" number now sits beside a small bar showing what share of their documents that actually was, so a supplier with 2 of 3 flagged reads differently at a glance than one with 2 of 30.
  • Pricing page: a meter beside every plan, four bars filling in one at a time from Basic to Volume, echoing the same ascending-bars mark used for Dashboard in the app nav: a plan is visibly "more" than the one before it, not just a bigger number in the same spot.
  • Confirmed against both themes: everything above reads correctly in dark mode, which this deployment supports by explicit toggle rather than following the OS automatically.
21 Sep 2026
0.20.0

Invite people, and decide what they can do

  • Team, in Settings. Whoever creates a workspace is its owner: full access, always, and the only one who can invite, remove, or change anyone's permissions. Anyone the owner invites is a member, starting with nothing turned on until the owner grants it.
  • Three permissions, each independently grantable: confirming or rejecting a document (the one that fires the webhook, pushes to accounting, and draws down the order book), managing settings and connections (webhook URL, price tolerances, purchasing/sales/accounting connections), and managing billing (subscriptions, packs, the Stripe portal). A member without a permission can still see everything in that area, just not change it: the buttons are visibly disabled, not silently refused.
  • Inviting, removing, and changing permissions is owner-only and not itself grantable, so a member can never widen their own access or anyone else's.
  • There's no outgoing invite email: inviting someone returns a one-time link, the same shape a forgotten-password link already worked, for the owner to send however they'd send anything else. It works for 7 days, and re-inviting a still-pending address issues a fresh one and updates its permissions.
  • New: GET/POST /api/team and PATCH/DELETE /api/team/:id, all owner-only.
  • Removing someone ends their sessions immediately, on every device.
21 Sep 2026
0.19.1

Webhook URL can no longer point at your own network

  • Setting a webhook URL now rejects a loopback, private, or link-local address (127.0.0.1, 10.x, 172.16-31.x, 192.168.x, 169.254.x, which also covers the 169.254.169.254 cloud metadata address, and their IPv6 equivalents), alongside the existing https-only rule. Found while testing the retry work above: nothing stopped the field from being pointed inward.
21 Sep 2026
0.19.0

Bulk order import, and webhooks that don't give up after one try

  • Import orders from a CSV. A new "Import orders from a CSV" panel on Review, beside the existing "add an order by hand": one row per line item, columns po_number, supplier_name, currency, sku, description, quantity, unit_price. Rows sharing a po_number are grouped into one order, in the order they first appear in the file; a row missing po_number, supplier_name, or both sku and description is skipped and counted, not fatal to the rest of the file. For an account whose order book already lives in a spreadsheet, this replaces re-typing it order by order.
  • The CSV parser handles quoted fields, commas and newlines inside a quoted cell, escaped quotes, and both Unix and Windows line endings by hand: no dependency pulled in for it. Up to 5,000 rows and 500 lines per order.
  • A missing required column, or a file with no sku or description column at all, is rejected up front with a specific message, before any row is read.
  • Outgoing webhooks now retry once. Previously a webhook delivery was attempted exactly once, inline with confirming a document, and a failure just sat there until someone happened to look. Now a timeout, a network error, or a 5xx/429 response from your endpoint gets one automatic retry a moment later, in the same request. A 4xx is left alone, since sending the identical request again wins nothing.
  • A "Retry webhook" button on a confirmed document's Review screen, shown whenever the last delivery wasn't a 2xx: after fixing whatever was wrong with the receiving end, or just to try again. Re-sends the exact same payload and signature the original send used, to whichever URL is configured now, via the new POST /api/documents/:id/retry-webhook.
  • A retried delivery's outcome is recorded as e.g. 500 (retried), not just the final status, so the history shows that a retry happened rather than looking like it worked on the first try.
21 Sep 2026
0.18.0

Multi-PO documents

  • A consolidated invoice or combined shipment note covering more than one purchase order is now split and matched against each order separately, line by line, instead of only ever matching one PO per document.
  • The reader tags a line with its own PO only when the document actually says it differs from the document's main one; every ordinary single-PO document, which is nearly all of them, reads exactly as it always has.
  • The review screen labels a line that belongs to a different order, and says plainly when a document matched more than one PO.
  • The export payload and webhook carry this the same way: po_number/matched_order_id always name the primary order, a new secondary_pos field and per-line po_number are only present at all when a document actually used them.
21 Sep 2026
0.17.0

Partial shipments and back-order splits

  • An order now remembers what's actually been delivered against it, across however many documents it takes. Ship 40 of 100 today, the rest next month: the second document is compared against the 60 still owed, not the original 100, and the order closes itself once every line is fully delivered.
  • A short delivery is still flagged for review the first time, exactly as before: this tracks what's owed, it doesn't wave through a partial shipment unread.
  • The review screen shows the full story on a partially-fulfilled line: what's still owed, what was already received, and a plain note when a document completes an order that started elsewhere.
  • Still not handled: a single document that spans more than one PO. Every document matches exactly one order.
21 Sep 2026
0.16.0

Push to Xero, QuickBooks, or MYOB. Plans that actually differ.

  • Accounting connections. Connect Xero, QuickBooks, or MYOB from Settings (Volume plan). Sign-in happens on the provider's own consent page, OAuth 2.0, the same shape as signing in to Linekeeper itself with Google or Microsoft: no key is ever pasted. Confirming a document pushes it in as a Bill, alongside whatever your webhook already does. A Bill lands as a draft wherever the provider supports one; approving it to pay stays a human decision.
  • Plan tiers now gate real features, not just volume. Basic is the base product. Starter adds outgoing webhooks and bulk CSV/JSON export. Standard adds full history search (free-text, flag, supplier, and date filtering) and the audit log. Volume adds a per-supplier price tolerance override and the accounting push above. The free trial and a cancelled subscription both keep full access regardless of tier, so cancelling never locks anyone out of their own past documents.
  • Signed webhooks. Generate a signing secret in Settings and every outgoing request carries a linekeeper-signature header (t=<unix>,v1=<hex>), the same convention Stripe uses for its own webhooks. Unsigned delivery is unchanged for anyone who hasn't generated one.
  • Dispute tracking. A flagged document can be marked open, disputed, or resolved. "Dispute with supplier" opens a pre-filled email (recipient pulled from that supplier's saved contact address, if set) and marks it disputed in one click.
  • Per-supplier scorecard. The Suppliers tab now shows, per supplier: documents read, how many needed a person, how many are disputed, and the last document date.
  • A per-supplier price tolerance override (Volume plan): one supplier's prices can run a looser or tighter tolerance than the account default, without changing it for everyone else.
  • Dashboard tab, now the default landing screen: what needs a look right now, this month's usage, how many systems are connected, and one-click shortcuts, instead of dropping straight into Review.
  • Tutorial tab: a four-step walkthrough of the real pipeline against the real screens, with a one-click demo run.
  • Settings reorganized into a mosaic layout instead of a uniform grid: cards with more to say (billing, connections, activity) take two tracks, and shorter cards pack the leftover space instead of leaving gaps.
  • Repriced with real margin. The old Volume tier ($200 for 2,000 docs) was pricing below the measured ~$0.14/document cost of a real extraction. New ladder: Basic $9/10 docs, Starter $49/100, Standard $119/350, Volume $249/1,000, enterprise above that by conversation. A document pack now requires a Starter subscription or higher, rather than a bare trial account.
  • Illustrative pricing slider on the pricing page: drag to see the real per-document rate at any volume, interpolated between the actual plan prices, not a separate number.
  • Fixed: a document's resolution status could get marked but not persist if the mail client opened before the save finished. The save now completes first.
  • Fixed: opening /app#settings directly (a bookmark, a reload) could permanently show billing as "Unavailable.", it was rendering before account data had loaded.
  • Fixed: the supplier scorecard hung on "Loading…" forever for any account with zero saved suppliers.
  • Fixed: the BigCommerce mark in the integrations grid was nearly invisible: a checkerboard transparency pattern baked into the source image as real pixels was defeating the crop. All 13 integration logos reprocessed.
  • Structured data (JSON-LD) and an llms.txt added for search and AI answer engines; the privacy policy now discloses the accounting-connection data flow.
7 Sep 2026
0.14.0

The allowance is a real number now

  • Your plan's monthly allowance is a hard cap. When it is reached, uploads stop and say so, naming both ways on: buy a pack of documents, or move up a plan. No silent overage, no bill you find out about later.
  • Document packs: one payment, no expiry, drawn on only once the month's allowance is gone. A busy month costs you once instead of raising your subscription forever.
  • Built-in demo documents never count against anything. Their reading ships with them, so running one costs nothing and is not charged for.
  • A handwritten correction now says what it replaced. If the printed figure is still on the row, the mark sits on it and the question reads "the page prints 35.00 and the reader took 39.00 from what is written over it", rather than only that something was not typed.
  • Header fields are checked the same way, so a ship date moved by hand is caught, and dates are compared as dates so a correctly read one is never mistaken for handwriting.
7 Sep 2026
0.12.0

Three demo documents, and every original kept

  • The built-in demo is now three documents instead of one, and they have nothing in common: a New Zealand order confirmation, a German invoice, a Sheffield quotation. Different currencies, tax regimes, date formats, typefaces and logos, because supplier paperwork has no house style and a demo that pretends otherwise teaches you nothing.
  • Each one hides a different problem: a price raised by hand, a short shipment, a substitute nobody ordered, a line quietly dropped, and one amendment even a careful reader will not commit to.
  • The amendments are genuinely written on: drawn on the page and absent from the text layer, which is the same thing the reader sees on your own documents.
  • Every uploaded PDF is now archived, so the original is one click away from any past document for as long as you keep it.
7 Sep 2026
0.11.0

The page itself, marked up

  • The supplier's PDF now opens beside the comparison with every value read off it marked where it sits on the page.
  • Anything handwritten, stamped or scanned is picked out on sight: a PDF carries text for whatever was typed, so a value with nothing behind it was written on afterwards.
  • A value nobody could make out becomes a question with the spot on the page highlighted. Type what it says and the comparison runs again, before anything is confirmed.
7 Sep 2026
0.10.0

See the difference, not a table of it

  • Every document now opens on a side by side comparison: what you ordered against what arrived, aligned line by line, with the value that changed marked where it sits.
  • Each flagged line carries a note in plain language, with the money involved, so nobody has to work out what a verdict means.
  • Connect a purchasing system (Cin7 Core, Katana, Unleashed) and your order book fills itself.
  • Ten documents free on a new workspace, no card.
7 Sep 2026
0.6.0

Sign in with Google, and your documents back

  • Sign in with Google or Microsoft. No password to choose, and nothing changes for anyone who prefers one.
  • Download the original PDF of any document from the review screen: the extraction is an interpretation, the file is the evidence.
  • Bulk export every confirmed document as CSV (one row per line item) or JSON, respecting whatever filters are on screen.
  • Billing no longer needs a webhook. Subscription state is checked against Stripe directly when it goes stale.
  • The name settled: Linekeeper, one capital.
7 Sep 2026
0.5.0

Subscriptions

  • Plans priced by document volume. Cards are entered on Stripe and never touch Linekeeper.
  • Manage payment method, invoices, and cancellation from the billing portal in Settings.
  • Cancelling stops new documents being accepted. Everything already in the workspace stays readable and exportable.
7 Sep 2026
0.4.0

Accounts and history

  • Sign-up, sign-in, sign-out, and password reset. Sessions are cookie-based and last 30 days.
  • Every order, document, supplier, and correction is now scoped to an account. Nothing is shared between accounts.
  • Document history with search across filename, PO number, and supplier, plus filters on status, flag, supplier, and date range.
  • Settings: your own Anthropic API key, a webhook URL, and per-account price tolerances.
  • Audit log covering sign-in, order creation, uploads, confirmations, rejections, and settings changes.
  • Account-wide JSON export.
  • Rate limits on sign-in attempts and uploads.
6 Sep 2026
0.3.0

A name, and a front door

  • The product is called Linekeeper.
  • New marketing site: how it works, pricing, docs, changelog, and the legal pages.
  • The app moved to /app so the front page can explain itself first.
  • Interface rebuilt on the ledger palette: status colour is the only accent, and every number is monospaced.
6 Sep 2026
0.2.0

Email intake and per-supplier accuracy

  • Cloudflare Email Worker: suppliers reply to an intake address and the PDF is ingested with the sender as a hint. Nothing changes on their end.
  • Supplier profiles: aliases and free-text layout hints that go into the extraction prompt.
  • Corrections made during review are kept as worked examples and reused for that supplier's next document. Five most recent.
  • Thumbs up and down per document, with an optional note.
6 Sep 2026
0.1.0

First working pipeline

  • PDF in, structured record out: extraction with per-field confidence, order lookup by PO number, line matching by SKU then description, exception flags, human confirm.
  • The normalised export payload and GET /api/export/:id.
  • Optional webhook on confirm.
  • Runs against a built-in demo document when no API key is set, so the whole flow can be walked without signing up for anything.

The full list.

  • Model-based readingNot per-supplier templates, so unusual layouts and heavy handwriting still lean on the review gate. It improves per supplier as corrections accumulate.
  • No scheduled reportingNo digests, no alerts. You look at the queue, or your webhook tells your own system.

What's next.

Nothing is queued ahead of what people actually hit. If something is blocking you, say so and it goes first.