Design scalable insurance claims processing system
LeagueSoftware Engineer · Technical ScreenLast updated
Walks through designing a scalable insurance claims processing system: ingestion, validation, routing, and the reliability and consistency trade-offs. Includes a worked system design solution.
Design an end-to-end insurance claims processing system for a health-focused insurer. The system handles a claim's full lifecycle — from submission, through validation and human review, to payment — and must be robust enough to support future growth.
The actors and core capabilities the system must support:
Actors
- Members / policyholders — submit claims, upload supporting documents (receipts, medical reports), and track claim status.
- Providers (clinics, hospitals) — optionally submit claims on behalf of members.
- Claims adjusters — review claims, request additional information, approve/deny, and trigger payments.
- Admins / operations — configure business rules, view dashboards, run reports, and inspect audit history.
Core functionality
- Members/providers can submit a claim containing policy and member identifiers, one or more claim items (procedures, services, or medications with dates, codes, and amounts), and attachments (PDFs, images).
- The system validates claims against policy coverage and business rules (coverage limits, pre-authorizations, exclusions).
- Claims move through a workflow: Submitted → Under review → Pending info → Approved / Denied → Paid.
- Members view claim status and history via web or mobile.
- Adjusters can prioritize, search, and process claims efficiently.
- On approval, the system integrates with a payment system to pay providers/members.
- The system maintains an audit trail for compliance (who changed what, and when).
Your design should address: (1) APIs and user flows for the key operations (submit, view status, adjuster processing); (2) the high-level architecture (services/components and their interactions) and storage choices; (3) a data model for the core entities (Claim, ClaimItem, Policy, Member, Attachment, ClaimEvent, Payment); (4) the workflow / state machine for claim processing; (5) scalability, reliability, and data consistency across services; (6) security (authentication, authorization, data privacy, audit logging); and (7) integration with external systems (payment processors, policy administration) plus reporting/analytics.
Constraints & Assumptions
- Scale: tens of thousands of active users; millions of claims accumulating over time (modest write throughput — on the order of a few writes/sec even at peak).
- Durability: high availability and zero claim-data loss — claims have financial and regulatory consequences.
- Latency: common reads (view status/history) should return in roughly 200–500 ms; submission may be accepted quickly with adjudication completing asynchronously.
- Security & compliance: claims are sensitive health (PHI) and financial data; assume HIPAA-grade controls are required (encryption in transit and at rest, least-privilege access, audit logging).
- You may assume an existing Policy Administration System (PAS) is the system of record for members, policies, and plan/benefit design, and an external payment processor moves money. The system you design owns the claim lifecycle and calls these.
Clarifying Questions to Ask
- What exactly do we own versus integrate with — does an existing PAS own members/policies/coverage rules, and is payout via a third-party processor?
- What is the realistic claim volume and growth rate, and what share of claims should be auto-adjudicated versus routed to a human adjuster?
- Which regulatory regime applies (e.g. HIPAA, state prompt-pay / "clean claim" rules), and what are the required audit-retention and disclosure-accounting obligations?
- How do provider claims actually arrive — portal/API JSON only, or also standardized EDI (X12 837) files, with 835 remittances coming back?
- What are the SLA expectations for the Pending info state, and what should happen when that timer expires (auto-deny vs. escalate to a human)?
Hints
Hint 1
Start with scope and sizing: Before drawing boxes, separate what you *own* (claim lifecycle, workflow, adjudication, audit) from what you *integrate with* (a Policy Administration System that owns members/policies/coverage; an external payment processor). Then do back-of-envelope math: a few million claims over years at "tens of thousands of users" is only ~1–2 writes/sec — this is a correctness-and-compliance problem, **not** a high-QPS sharding problem. Let that conclusion drive every later decision.
Hint 2
The claim lifecycle is a state machine: The workflow is the heart of this design. Model it as an explicit **finite state machine** with a transition table — every action is a guarded transition. Think about how to make each transition atomic (status change + audit record) and how to stop two adjusters from both "winning" the same claim (optimistic concurrency / a compare-and-set `WHERE status = :expected`).
Hint 3
Avoid the dual-write trap around money: "Update the DB, then publish an event to trigger payment" is two operations — a crash between them either drops the payment or fires a phantom one. Reach for the **transactional outbox** pattern (write the event row in the same transaction as the state change; a relay publishes it) and make every consumer **idempotent**, since the bus is at-least-once. Pair this with a persisted idempotency key on submission *and* on payment so retries never double-create or double-pay.
Hint 4
Treat the data as PHI from the start: Claims carry protected health information plus financial data. Store money as integer minor units (never floats), keep large attachments in encrypted object storage (never in the DB), make the event log append-only/immutable, and design authorization as RBAC **plus object-level ownership** — a role alone shouldn't let a member read another member's claim. Logging *read* access to PHI is a distinct requirement from logging mutations.
Follow-up questions
- The *Pending info* SLA timer fires on a claim awaiting member documents. Walk through exactly what your system does — and why an automatic denial by the clock may be the wrong default for a health insurer.
- A payment-approval request to the external processor times out with no response. How does your design guarantee the provider is paid **exactly once** when you retry?
- An admin edits a coverage rule (e.g. tightens a limit). Should that re-decide claims already adjudicated under the old rule? Describe how you'd version rules so a config change is auditable and can't silently re-open settled claims.
- Adjuster search ("all UNDER_REVIEW claims for member X over $500, sorted by age") gets slow as data grows. How do you serve it without hammering the transactional database, and how do you keep that index consistent with the source of truth?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.