Inspiration
Denied medical claims are one of the quietest, most expensive problems in healthcare. Billing teams get remittances back from payers, dense coded documents that say we're not paying this, and buried in that noise is real recoverable revenue. But working denials is slow and manual, so a lot of already-earned money just gets written off because the labor isn't worth it.
What pulled me in was the safety side. This is a domain where being wrong is expensive in a way that lands on real people. Appeal a line you should have written off and you waste staff hours. Bill a patient for something the provider is contractually obligated to absorb and you've hurt someone who did nothing wrong. So the obvious instinct, build a bot that files appeals automatically, is exactly the wrong instinct. I wanted to see if I could build something that does the tedious triage and drafting, shows its reasoning, and then stops and hands control back to a human. AI-assisted, never autonomous. That framing drove every decision.
The problem, by the numbers
Claim denials are a large and growing drain on healthcare providers:
- Roughly 11-15% of claims are denied on first submission. Kodiak Solutions put the initial denial rate at 11.81% in 2024, up from the prior year, and provider surveys from Premier found nearly 15% of claims to private payers denied initially.
- Denials are getting worse. In Experian Health's State of Claims 2025, 41% of providers said at least one in ten of their claims is denied, up from 30% in 2022.
- Most denied claims were payable all along. Industry analyses find that roughly 60-70% of denials are ultimately recoverable and get overturned when appealed. The money was earned. It's just stuck behind rework.
- Working a denial is expensive. The cost to fight a single denied claim rose to about $57 per claim in 2023 according to Premier, and full appeal efforts can run $100+. Providers spent an estimated $25.7 billion adjudicating claims that year.
- So a huge amount is simply abandoned. Because reworking costs real staff hours, a large share of denials never get resubmitted at all. Low-dollar lines get written off, and high-value ones eat the labor.
That last point is the gap ClaimJumper aims at. The bottleneck isn't whether a denial can be recovered, because most can. It's the human time to read the remittance, decide what each line deserves, and draft the appeal.
What it does
Upload a remittance and ClaimJumper turns it into a prioritized, human-controlled work queue.
- Every denied service line is triaged into a lane: appeal, corrected claim, patient bill, write-off, or human review, then sorted by deadline and dollar value.
- Appeals and corrected claims get a drafted letter generated from the actual remittance. Every point in the draft is grounded, citing the specific code or field it came from, so a biller can verify it instead of trusting it blindly.
- Safety-sensitive cases stop. They route to human review with the reason shown and no approve button. The tool will not act on its own.
- A person approves the drafts they want and downloads them with citations intact. ClaimJumper never sends or files anything with a payer.
How I built it
The stack is Next.js with the App Router, TypeScript, and Tailwind, with Zod schemas as the contract everything is measured against. The pipeline is a set of composable stages, ingest, triage, invariant enforcement, prioritization, and drafting, with no monolithic orchestrator, so each stage stays testable in isolation.
GPT-5.6 does the cognitive work. It turns the EOB image into structured claim and service-line data, and it writes the grounded draft artifacts. Codex was my pair programmer and accelerated the implementation, the regression tests, and the safety checks.
The safety guarantees are code-enforced, not model-trusted. The most important one: a deterministic rule ensures a contractual-obligation (CO) denial can never be routed to patient billing. That isn't a prompt asking the model to behave. It's an invariant in the code that overrides the model's output, and if it fires, the line goes to human review with the reason attached.
Challenges I ran into
The hardest bug of the build was one I almost shipped without noticing. Invariant enforcement was running twice, once inside the triage stage and once again in the API route. Enforcement rebuilds its list of override reasons from scratch each time it runs. So on the second pass, a line that had already been flagged for human review would fail to re-trigger the original rule, and the reason strings would come back empty. The lane stayed at human review, but the explanation for why disappeared.
That's the worst kind of failure for this product. The human review lane exists to tell a biller why the system stopped. A safety hold with no stated reason is a hollow warning, and it was corrupting the data before it ever reached the UI, so the interface was faithfully rendering nothing.
I caught it by writing a regression test that pinned the intended behavior first, watching it fail, and only then deciding on a fix. The fix was to remove the redundant second enforcement rather than patch the enforcement function, because nothing legitimately needed to enforce twice. The test stays in the suite as a guard so nobody reintroduces it.
The other real challenge was the discipline of not letting the model be the safety layer. It's tempting to write a very careful prompt and call it done. But a prompt is a request, not a guarantee. Anything that actually mattered had to be enforced in code and tested.
What I learned
Verify, don't assume. I worked with a rule that I would not assert a code fact I hadn't checked. Every signature, every enum, every shape got confirmed against the actual file before anything was built on top of it. That felt slow and it was the single highest-leverage habit of the whole build, because it's what surfaced the double-enforcement bug instead of papering over it.
Automated green is not the same as working. Tests passing and the build compiling can coexist with a completely broken experience. I made browser verification a required gate before every commit, and it caught things the test suite couldn't see.
Constrain the model, then trust it. GPT-5.6 is genuinely good at reading a messy remittance image and drafting a grounded letter. It's a much better parser and writer than I could hand-code. But the moment a decision has consequences, that decision belongs in deterministic code with a test around it. The right division of labor was letting the model handle judgment and language while the code holds the guarantees.
Scope is a feature. I deliberately kept this to a single remittance, session-only memory, no database, and no authentication. Cutting persistence meant the drafting and approval flow actually got finished and verified instead of half-built.
What's next
Multi-remittance workflows, persistence so a queue survives a refresh, payer-specific appeal templates, and tracking which appeals actually get overturned so the prioritization can learn from real outcomes. The thing I would not change is the human approval checkpoint. Speed is the feature. Autonomy isn't.
Built With
- codex
- gpt-5.6
- node.js
- openai
- react
- tailwind-css
- typescript
- vitest
- zod

Log in or sign up for Devpost to join the conversation.