A few weeks ago I had to pull transactions out of a stack of bank statements. I reached for an LLM, got clean-looking JSON back, and almost shipped it. Then I counted the rows: 47, when the statement actually had 52. It looked right, so I nearly trusted it.
That gap is why I built pdftojson.dev.
The easy part of getting data out of a PDF is the extraction. Libraries and LLMs both do that fine. The hard part is knowing when the output is wrong, because wrong output usually looks completely fine. On one invoice you catch it by eye. On ten thousand statements you don't, and a silently dropped row is a wrong number nobody notices until month-end.
So the tool does two things. There's a free in-browser converter that turns a PDF into JSON, Markdown, CSV, XML or text, with nothing uploaded since it parses locally. And there's an API for the harder jobs: OCR for scans, table extraction, and a bank-statement endpoint that reconciles its own output. It checks that opening balance plus credits minus debits equals the closing balance, or it flags the statement as not cleanly parsed.
It's live, there's a free tier, and the API is $29/mo.
Where I'd love feedback:
Link: https://pdftojson.dev
Happy to answer anything about how it's built.
the local parsing barely gets mentioned and for bank statements that's the bigger sell tbh. does the api path upload, or is that the tradeoff for ocr?
the 47-vs-52 row thing is such a perfect example of why AI verification is harder than it looks. the output doesn't just fail -- it fails in a way that passes the eyeball test. your reconciliation approach is smart because it gives you a mathematical check that doesn't rely on human attention. curious whether you've seen patterns in which document types the LLM struggles with most?
Good question. The pattern so far: clean digital statements are basically solved, and the trouble concentrates in a few shapes. Dense multi-column layouts where two transactions sit side by side. Statements that wrap a long description onto a second line, where the model sometimes reads the wrap as a new row. And anything where the running-balance column is faint or missing, so there's less to cross-check against. Handwriting and low-quality scans fail too, but they fail obviously. The reconciliation earns its keep on the first group, the ones that look fine. Honestly not a big enough sample to call it science yet, more like field notes.
On your first question: "it checks its own work" is not a headline feature, it is a proof feature. Developers will assume they can verify it themselves right up until the first silent mismatch costs them a client, so the way to sell it is to show the failure, not the guarantee. If the API returns a flag when opening plus credits minus debits does not equal closing, put a real flagged statement in the docs with the exact response body. That is more persuasive than any claim on the landing page. On leading with reconciliation: I would lead with the plain use case since that is what people search for, and put the 47 versus 52 row story immediately underneath as the reason to pick you over a generic converter. On pricing, $29 for a solo dev is fine, but the people who need statement reconciliation at volume are usually agencies and bookkeeping shops, and they buy on pages per month, not seats. I would add one higher tier with a clear page cap and let the free browser converter keep doing top of funnel.
On the pricing-for-a-team question: for tools priced by individual usage like this, a clean way to test team pricing without guessing is to keep the $29/mo tier as-is for solo use and only add a seats-or-usage multiplier once someone hits volume that clearly benefits a team. Price for teams too early and solo devs bounce off a "starts at $99" page, even though your actual buyer today is a solo dev pulling bank statements. On the landing page: I'd lead with the plain PDF-to-JSON use case in the headline, since that's the searchable intent, and use the reconciliation story as the trust element right below it rather than the hook itself. The reconciliation detail is what makes someone stay and read, but it's not what gets them to click from a search result.
The offsetting-errors point is the one that'd worry me most too. We had a version of this on a trading signal engine: a duplicate cron job doubled up signal generation, but the daily aggregate stats still looked completely normal because the extra signals were roughly balanced between buy/sell, so nothing in the dashboard flagged it. Only caught it drilling into per-signal counts against the documented daily cap, which is basically your 'refusal rate' idea applied to a different domain — track the thing that should be bounded/consistent by construction, not just the thing that should look right in aggregate. For statements specifically, row-count-vs-expected-line-items feels like the cheapest version of that (page count * rough rows/page as a sanity band), before you even get to a full benchmark.
I'd want to track refusal rate too. A green check only shows that the parser produced a consistent story. It doesn't prove that every line was read correctly. We saw a smaller version of this with DictaFlow. The useful QA question isn't whether text came back. It's whether the system knows when to ask the user to review it. Links to the source lines make that boundary clear.
Reconciliation is the right hook, but I would narrow the promise from “checks its own work.” A statement can still balance after two offsetting extraction errors. I would expose three things in every result: whether balances reconcile, how many source rows and pages were covered, and links from each exception back to the source. Then publish a small benchmark with pass, flagged, and silent-miss rates. For financial documents, the number I care about is how often a bad parse gets refused instead of returned as clean.
This is the sharpest version of the critique, and you're right that "checks its own work" overpromises. Two offsetting errors that still balance is a real hole, and a reconciliation pass alone won't catch it. Exposing coverage is the fix I hadn't fully thought through: rows and pages seen versus expected, plus a link from each flagged line back to its spot in the source, so a human can adjudicate instead of trusting a green checkmark. The refusal rate is the honest headline too, how often a bad parse gets refused rather than returned clean. That's the number a finance team actually cares about, and the one I should be publishing. I don't have a clean benchmark yet, but you've just told me exactly what it should measure. Genuinely useful, thank you.
Your three questions have one answer, because they're the same question wearing three hats: you're treating self-verification as a feature when it's your entire category. You're not a PDF-to-JSON tool that also checks its work. You're a trustworthy-extraction tool, and the extraction is the free commodity that gets people in the door.
Q1, is "checks its own work" a reason to pay? It's the ONLY reason to pay, and your own story proves it. The extraction wasn't your problem, you got clean JSON. The silent wrongness was. Devs don't assume they'll verify it themselves, they assume it's right because it looks right, which is the exact trap you fell into at 47 rows. On ten thousand statements nobody eyeballs the count, so your reconciliation is the only thing between them and a wrong number at month-end. That's not a nice-to-have, it's the whole product. Everything else, you're right to give away free.
Q2, lead with reconciliation or plain conversion? Reconciliation, hard, and "too niche" is the wrong worry. Plain PDF-to-JSON is the commodity, every library and LLM does it, so leading with it makes you one of a thousand. The bank statement isn't your market, it's your proof, the sharpest possible demo of a general principle: output that surfaces its own silent errors. That principle covers invoices, any financial doc, any extraction where a wrong number costs money. Lead with the vivid specific that proves the general value. Don't retreat to the bland use case that erases your only differentiator.
Q3, pricing, is downstream of the same thing. $29 prices on convenience. But your value isn't convenience, it's risk elimination, and a team processing 10k statements where one silent error becomes a month-end fire-drill isn't comparing you to "verify it ourselves", they can't, that's the point. They're comparing you to eating the occasional catastrophic miss. Price teams on what one caught error is worth, not per seat. The error you prevent has a dollar figure, that's your anchor, not headcount.
So the forcing question: what's the most expensive single silent error a customer has told you it caught? That number is your homepage headline, your team price, and the answer to whether people pay, all at once.
This is the best articulation of the bull case I've had, and it's in direct tension with the other advice in this thread (lead with plain PDF-to-JSON, keep reconciliation second). Sitting with both, I think you're pointing at the positioning truth and they're pointing at the SEO reality, and those aren't the same axis. The term people search is "pdf to json", so that has to be the door for traffic. But once someone's on the page, retreating to "we convert PDFs" is exactly the commodity trap you describe. So where I'm landing: the category keyword gets them in, the silent-error story is what the page actually argues. Your forcing question is the sharp one, and I don't have the answer yet. Nobody's told me the dollar figure of an error they caught, because I'm too early. But it's now the first thing I ask every user, and when I have that number you're right that it's the headline. Thank you, this reframed the whole thing.
On your first question: I think "checks its own work" is a reason to pay, but not for the reason you'd expect. Nobody pays to skip checking one statement, they'll eyeball that one for free. They pay because six months from now someone asks "how do you know row 47 of statement #212 was extracted correctly", and "I looked at it in March" is not an answer anyone accepts. A stored, timestamped reconciliation result per document is.
I build compliance tooling, so this is the exact shape of problem I deal with: the value isn't the check itself, it's that the check leaves a record someone else can point to later without re-doing the work. If your landing page sells "accurate" it's competing with every other parser. If it sells "defensible", that's a different buyer entirely, and a much easier one to charge $29/mo to.
"Sell defensible, not accurate" is the sharpest line I've read on this. You're right that "accurate" puts me in a race with every parser, and it's both unwinnable and unprovable. "Defensible" is a different product: the value isn't that the number is right, it's that there's a stored, timestamped record showing the check ran and what it found, so "how do you know row 47 was right" has an answer that isn't "I looked at it in March." Right now the reconciliation result comes back in the response but I don't persist it as an artifact. Making it a durable, retrievable record per document is clearly what turns this from a converter into something a compliance team can stand behind. That's a genuinely different roadmap than the one I was on. Thank you.
That's the right instinct, and it's the more valuable roadmap too — a reconciliation result that only lives in a response is basically unauditable. If you persist it as a linked record per document, you're not just building a converter feature, you're building the artifact a compliance review actually needs. Curious how you're thinking about the storage layer for that — flat log vs. something queryable per-document?
The strongest part is that the invariant sits outside the parser: opening balance + credits − debits = closing balance. For high-stakes documents, I would expose three outcomes—reconciled, unreconciled, and insufficient inputs—and carry source-page and row references into the output. That keeps a green result honest: it means the arithmetic checks, not that every source field is semantically correct. Have you considered reporting reconciliation coverage as well as pass/fail (how many extracted rows participate in the check)? That can surface blank or merged rows that totals alone miss.
Yes, and the three-outcome framing is cleaner than what I have. Right now it's effectively a boolean, but "insufficient inputs" is a real third state: a statement where the opening or closing balance couldn't be read is not the same as one that was read and didn't balance, and collapsing them hides the difference. Coverage is the piece you and a couple of others have converged on, how many extracted rows actually participate in the check, so a green result can't be hiding a blank or merged row that the totals happened to survive. And carrying source-page and row references so each exception points back to the original is what makes it auditable rather than just green. That's the roadmap now. Thanks for laying it out so precisely.
Bank statements and invoices are the classic hard cases - multi-page tables where the LLM merges or splits rows silently. The failure signature to watch: row counts that are internally consistent but do not reconcile against totals. Anything handwriting-heavy (receipts) fails loudly instead, which is almost better. The pattern that matters commercially: extraction confidence and correctness are uncorrelated, so a confidence score does not substitute for your reconciliation check.
"Extraction confidence and correctness are uncorrelated" is the cleanest way I've heard it put, and it's exactly why I didn't lean on a confidence score. A model can be very confident about a row it just merged. The reconciliation works because it's external to the model, it's arithmetic on the numbers, so it catches the confident-but-wrong case a self-reported score never will. And you're right that the loud failures are the easy ones. It's the quiet, internally-consistent-but-wrong statements that actually hurt.
Thanks for the kind words - glad it landed. One thought on the "sit with the pricing" plan: put a date on it. Pricing paralysis is a silent killer for solo founders, and a placeholder line like "from $29/mo, team pricing scales with volume" converts better than a blank section - you can always change it the day the data justifies it. If a second pair of eyes helps on the rewrite, happy to look: I run a paid developer API myself (different category, same go-to-market loop), so I've just been through exactly this. Good luck with the launch, watching pdftojson.dev with interest.
Really appreciate the offer, I might take you up on it. "Put a date on it" landed. I'd been treating pricing as a someday-decision and you're right, that's just paralysis. I already took the "don't leave it blank" part and added a volume line rather than a gap, and a landing-page critique further down this thread flagged that the landing never states a price at all, so that's the next fix. Would genuinely value your eyes on the rewrite once I've done a proper pass. What's the API you're running, if you don't mind me asking? Useful to compare notes with someone a step ahead on the same loop.
Congrats on shipping. Disclosure up front: I do landing page critique, so read this as a peer note rather than a customer one.
On your second question: as of this morning the page already answers it. The headline is "Turn any PDF into clean, structured JSON." and the fold never mentions a bank statement; the reconciliation story is the fourth block below the fold. Whether that changed after the exchange above or was always so, the lead is settled, so here is the most expensive thing on the first screen now: the right half of your converter card. It is a 588x399 px panel that says "Your output appears here." and nothing else, at the exact moment a visitor is deciding whether to trust your parser with a file. You already have the perfect filler further down the page, the "Invoice #1042" structured sample. Pre-fill the panel with it, label it "Sample output, drop your own PDF to replace it", and add a "try a sample invoice" link in the dropzone for people with no PDF to hand. That turns half the hero from dead space into your demo.
Three more, in order:
The page never states a price. This post says $29/mo; the landing page's text contains no dollar amount, and the API's whole presence above the fold is a 19-px "API" nav link and a "Sign in" box. Put "from $29/month" in the mid-page API teaser, and relabel "Sign in" to "Get API key". Your pricing page's own headline, "Pay for pages, not seats", is also the answer to the seat question above; the landing page just never says it.
Mobile: the header takes two rows (118 px), the "Sign in" box wraps to "Sign / in", the format tabs lose "XML" off the right edge, and the dropzone label lands at y=679 of 844. Collapse the nav to one row and the dropzone climbs to the middle of the screen.
One trust point, because your fold says "Nothing uploaded": the page loads PostHog's session recorder, 157 KB, with input masking off in the config it serves, and your privacy page describes "aggregate analytics". I did not test what it captures, but a developer with the network tab open will ask before dropping a bank statement. 470 of the page's 629 KB are analytics; the product's own JS is 6 KB.
I ran our full teardown on your page and published it, free, nothing owed: https://squint.page/sample-17/ The output-panel and pricing points are worked through with exact rewrites there.
You published a full teardown? That's genuinely generous, thank you, I'll go through it properly. You nailed the two things: the output panel is dead space at the worst possible moment, and the page hides its own price. The "Sample output, drop your own PDF to replace it" framing for the hero is exactly the kind of fix I should have caught myself. Both are next on my list. Really appreciate you spending the time on a stranger's page.
Really interesting idea! The fact that the tool validates its own output is definitely valuable, especially for financial documents where a missing transaction can cause serious problems.
I don't think the reconciliation story is too niche—it actually makes the product stand out from generic PDF-to-JSON tools. You could lead with the broader PDF-to-JSON use case while quickly highlighting validation and reconciliation as your key differentiator.
As for pricing, $29/month seems reasonable for individual developers and smaller businesses. You could also consider a higher team or usage-based tier for companies processing larger volumes.
The biggest value proposition for me is simple: not just extracting data, but helping users know whether they can trust it. 🚀
Appreciate it. You and a couple of others have converged on the same advice: lead with plain PDF-to-JSON and keep reconciliation as the differentiator right behind it. That's clearly the move, and I'm reworking the page around it. Agreed on a volume tier for teams too, that one's going in. Thanks for the thoughtful read.
The reconciliation layer feels like the real differentiator.
Are users more willing to pay for trusted output, or just faster extraction?
One data point from the buyer side of the fence: we run PDF extraction inside our own product, and the pattern is exactly the split Taras is circling. Speed is a marketing metric, trust is a retention metric. Fast extraction wins the trial because nobody demos a converter with their hardest document; lost trust ends the subscription because one unflagged dropped row costs the user more than a year of API fees. What made the difference for us was making the verification VISIBLE: per-document confidence, a flagged-rows list, a one-glance summary of what the parser was unsure about. Users tolerate a wrong number they can see flagged far better than a suspiciously perfect output they have to audit themselves. If I were pricing this, that is the feature I would gate the volume tier on.
Honestly, so far trust is what people say they'd pay for, but speed is what gets them to try it in the first place. The pattern I keep seeing: someone shows up wanting a quick PDF-to-JSON, then the moment they hit a wrong number in a batch, the reconciliation becomes the thing they actually care about. So you probably need the fast extraction to get them in the door and the trust layer to keep the ones processing real volume. Still early though, so take that with a pinch of salt.
That distinction between what gets them to try and what makes the product valuable at volume is interesting. I’d like to dig into that a bit more privately — what’s the best email to reach you on?
Answers to your three questions, from the buyer's side:
Yes, "checks its own work" is the reason to pay — but only above a volume threshold. We process PDFs in our own product pipeline, and the failure mode you describe (a dropped row that looks perfectly fine) is exactly why a solo dev verifies by eye at 10 documents and stops being able to at 10,000. The buyer at volume is not choosing between your API and a free converter; they're choosing between your reconciliation flag and a month-end surprise. Lead with that for the API tier.
Landing page: lead with plain PDF-to-JSON. Reconciliation is your moat but it's a feature of one endpoint, and nobody searches for "self-reconciling converter". Category first, differentiator second — same reason a storefront leads with the product, not the QA process.
On pricing: $29/mo for a solo dev reads fair against the alternative (an hour of manual checking or one wrong number in a report). For teams, tie the tier to volume, not seats — the team of 3 processing 50k statements has the budget of a team of 10 processing 5k, and per-seat pricing makes you look cheap to your best buyer. A per-1k-statements overage above the base plan would match value to price better.
This is one of the most useful comments I've had, thank you. On (1), the volume-threshold framing is exactly right, and "your reconciliation flag vs a month-end surprise" is a sharper line than anything on my landing page right now. Below a handful of docs nobody needs it, so that's squarely an API-tier message. On (2), you've talked me out of leading with reconciliation. It is one endpoint, and nobody searches for a self-reconciling converter, so category first and differentiator second makes sense: plain PDF-to-JSON up top, reconciliation as the reason to stay once you're at volume. On (3), the per-seat point really lands. A small team can easily be my heaviest user, so tying the tier to statement volume with a per-1k overage fits the value far better than seats. I want to sit with the pricing before I change it, but that's the direction. Genuinely appreciate you taking the time to write this out.