Skip to main content

Claims Management

The @openinsure/claims package manages the complete claims lifecycle from First Notice of Loss (FNOL) through final closure. The module integrates with the billing system for reserve accounting, the document system for attachment management, and the compliance engine for state-specific handling requirements.

Claims Lifecycle

FNOL Filed


┌─────────────┐
│ open │ ◄── Assignment, initial contact, coverage verification
└──────┬──────┘


┌─────────────┐
│investigating│ ◄── Field investigation, recorded statements, expert engagement
└──────┬──────┘

┌────┴────────────────────────┐
│ │
▼ ▼
┌──────────┐ ┌────────────┐
│ reserved │ │ litigated │ ◄── Suit filed, defense counsel assigned
└──────┬───┘ └──────┬─────┘
│ │
▼ ▼
┌──────────────┐ ┌────────────┐
│ in_settlement│ │ in_defense │
└──────┬───────┘ └──────┬─────┘
│ │
└──────────┬──────────────┘

┌──────────┐
│ settled │ ◄── Settlement agreement executed
└──────┬───┘


┌──────────┐
│ closed │ ◄── All payments disbursed, file closed
└──────────┘

At any stage:
─── denied ──► closed (coverage denied)

FNOL — First Notice of Loss

Claims can be filed via the API, the policyholder portal, the producer portal, or by an adjuster directly.

File a Claim

POST /v1/claims
Authorization: Bearer <token>
Content-Type: application/json

{
"policyId": "pol_01J8...",
"dateOfLoss": "2025-06-15T14:30:00Z",
"reportedAt": "2025-06-15T18:00:00Z",
"lossType": "BODILY_INJURY",
"lossCause": "SLIP_AND_FALL",
"lossDescription": "Customer slipped on wet floor in lobby. Treated at ER.",
"estimatedLoss": 45000,
"claimant": {
"name": "Jane Smith",
"phone": "802-555-1234",
"address": "123 Main St, Burlington, VT 05401"
},
"location": {
"address": "456 Commerce Dr, Burlington, VT 05401",
"description": "Lobby entrance"
}
}

Response:

{
"id": "clm_01J8...",
"claimNumber": "GL-2025-000042",
"status": "open",
"policyId": "pol_01J8...",
"assignedAdjusterId": "adj_01J8...",
"dateOfLoss": "2025-06-15T14:30:00Z",
"coverageVerification": {
"policyInForce": true,
"coverageApplies": true,
"reservedAmount": 45000,
"sublimitApplicable": null
}
}

Assignment Rules

Claims are auto-assigned based on:

  1. Line of business — GL claims go to GL-licensed adjusters.
  2. Geography — Prefer adjusters licensed in the loss state.
  3. Workload — Round-robin among available adjusters below the workload threshold (configurable, default 35 open claims).
  4. Severity — Claims above $100,000 are assigned to senior adjusters.
  5. Manual override — Supervisors can reassign at any time.

Reserve Management

Case Reserves

Every open claim has a case reserve — the adjuster's best estimate of the ultimate loss and expense to settle the claim.

POST /v1/claims/:id/reserves
Authorization: Bearer <adjuster_token>
Content-Type: application/json

{
"indemnityReserve": 35000,
"expenseReserve": 12000,
"rationale": "ER bills confirmed at $8,200. Ongoing PT likely. Attorney involved."
}

Reserve changes are logged to claim_reserve_history — no in-place updates. The audit trail shows every reserve movement with adjuster, date, amount, and rationale.

Reserve Adequacy Flags

The system automatically flags reserves that appear inadequate:

FlagTrigger
ROUND_NUMBERReserve is an exact round number (suggests placeholder)
RAPID_INCREASEReserve increased >50% in 30 days
EXCEEDED_ESTIMATEPaid-to-date + reserve exceeds original estimate by >25%
APPROACHING_POLICY_LIMITReserve exceeds 80% of applicable policy limit
IBNR_OUTLIERClaim's development pattern is 2+ standard deviations from cohort

IBNR Reserves

Incurred But Not Reported (IBNR) reserves are calculated at the organization level by the actuarial module. OpenInsure provides:

  • Chain Ladder method for standard lines
  • Bornhuetter-Ferguson method for immature lines with limited data
  • Manual IBNR entry for actuary override
GET /v1/analytics/:orgId/ibnr?asOf=2025-06-30

# Returns:
{
"asOfDate": "2025-06-30",
"method": "CHAIN_LADDER",
"ibnrByLine": {
"GL": { "ibnr": 285000, "confidence": "HIGH" },
"CYBER": { "ibnr": 140000, "confidence": "MEDIUM" }
},
"totalIBNR": 425000
}

Subrogation Workflow

When a third party is responsible for the loss, the claims module tracks subrogation recovery.

POST /v1/claims/:id/subrogation
Authorization: Bearer <adjuster_token>
Content-Type: application/json

{
"potentialRecovery": 28000,
"responsibleParty": {
"name": "Green Valley Maintenance LLC",
"insurer": "Acme Insurance",
"claimNumber": "ACI-2025-887621",
"adjusterContact": "bob.jones@acmeins.com"
},
"subroStatus": "DEMAND_SENT",
"demandAmount": 35000,
"demandDate": "2025-08-01"
}

Subrogation status codes:

StatusDescription
IDENTIFIEDThird party identified, evaluating recovery potential
DEMAND_SENTDemand letter sent to third party or their insurer
NEGOTIATINGCounter-offer received, negotiating
RECOVEREDFull or partial recovery received
CLOSED_NO_RECOVERYRecovery not pursued or pursuit exhausted

Litigation Tracking

When a claimant files suit, the claim transitions to litigated status and triggers defense counsel assignment.

POST /v1/claims/:id/litigate
Authorization: Bearer <adjuster_token>
Content-Type: application/json

{
"suitFiledDate": "2025-07-20",
"courtJurisdiction": "Chittenden County Superior Court, VT",
"caseNumber": "23-CV-0481",
"defensePanel": "auto", // use program's panel counsel, or provide counsel_id
"trialDate": "2026-03-15"
}

Litigation features:

  • Defense billing management — Counsel submits invoices via the portal, adjuster approves against litigation budget.
  • Diary management — Automated reminders for deposition deadlines, discovery cutoffs, mediation dates.
  • Coverage position letters — Template-driven reservation of rights and coverage denial letters.
  • Verdict/settlement tracking — Record outcome, final payment amounts, and close litigation file.

Settlement Negotiation

POST /v1/claims/:id/settle
Authorization: Bearer <adjuster_token>
Content-Type: application/json

{
"settlementAmount": 27500,
"expenseAmount": 9800,
"claimantName": "Jane Smith",
"releaseType": "GENERAL_RELEASE",
"payeeName": "Jane Smith",
"payeeAddress": "123 Main St, Burlington, VT 05401",
"paymentMethod": "CHECK"
}

Settlements above the adjuster's authority level require supervisor approval:

Adjuster LevelAuthority Limit
Associate$10,000
Adjuster II$25,000
Senior Adjuster$75,000
Supervisor$250,000
ManagerUnlimited (carrier authority applies)

Payment Disbursement

Once a settlement is approved, payment is disbursed via the billing module:

POST /v1/claims/:id/payments
Authorization: Bearer <admin_token>
Content-Type: application/json

{
"paymentType": "SETTLEMENT",
"amount": 27500,
"payeeType": "CLAIMANT",
"payeeName": "Jane Smith",
"paymentMethod": "CHECK",
"memo": "Settlement of claim GL-2025-000042 per release dated 2025-09-01"
}

Payment types:

TypeDescription
SETTLEMENTFinal settlement payment to claimant
MEDICALMedical expense payment (direct to provider)
DEFENSE_EXPENSEDefense counsel invoice payment
EXPERT_EXPENSEExpert witness, IME, or appraiser fees
SUBROGATION_RECOVERYRecovery received from third party (negative — income)

Claim Closure

POST /v1/claims/:id/close
Authorization: Bearer <adjuster_token>
Content-Type: application/json

{
"closureReason": "SETTLED",
"finalPaidIndemnity": 27500,
"finalPaidExpense": 9800,
"closingNotes": "Settled for $27,500. Release executed 2025-09-01. File closed."
}

On closure, the system:

  1. Sets all reserves to zero (closed with final payments known).
  2. Posts the final paid amounts to the loss run.
  3. Updates the organization's loss ratio statistics.
  4. Triggers a bordereaux update for claims reporting.

Document Management

See the Claims Attachments API for file upload and retrieval. Supported types: PDF, JPEG, PNG, TIFF, DOCX. Max 10 MB per file.

POST /v1/claims/:id/attachments
Content-Type: multipart/form-data

file=@police_report.pdf
documentType=police_report
GET /v1/claims/:id/attachments
# Returns: { data: Document[], total: number }

Salvage Recovery

When a total loss or significant property claim results in recoverable assets, the salvage module tracks the asset from identification through disposition and recovery. The API is at /v1/claims/:id/salvage, implemented in apps/api/src/routes/claims/salvage.ts.

Creating a Salvage Record

POST /v1/claims/:id/salvage
Authorization: Bearer <adjuster_token>
Content-Type: application/json

{
"itemDescription": "2023 Freightliner Cascadia — cab and chassis",
"estimatedValue": 18000,
"disposition": "pending",
"storageLocation": "ABC Towing, 1234 Industrial Blvd, Houston TX",
"storageStartDate": "2025-07-01T00:00:00Z",
"dailyStorageCost": 45,
"notes": "Title held. Awaiting auction date."
}

Disposition Statuses

StatusDescription
pendingSalvage identified, not yet disposed
retained_by_insuredInsured retains the asset (salvage deduction applied to settlement)
sold_at_auctionAsset sold through salvage auction
scrappedAsset scrapped with no meaningful recovery
donatedAsset donated (tax benefit may apply)
transferredAsset transferred to another party

Updating Salvage (Recording Recovery)

When salvage is disposed, update the record with actual recovery details:

PATCH /v1/claims/:id/salvage/:salvageId
Authorization: Bearer <adjuster_token>
Content-Type: application/json

{
"actualRecovery": 14200,
"disposition": "sold_at_auction",
"buyerName": "Southwest Auto Salvage",
"saleDate": "2025-08-15T00:00:00Z",
"titleTransferred": true
}

Updatable fields include:

FieldDescription
actualRecoveryDollar amount recovered from disposition
dispositionNew disposition status
buyerNameName of buyer (auction or private sale)
saleDateDate of sale or transfer
titleTransferredWhether vehicle/asset title has been transferred
storageLocationUpdated storage location
dailyStorageCostUpdated daily storage rate

Deleting Salvage Records

Only records in pending disposition can be deleted. Non-pending records return HTTP 409:

DELETE /v1/claims/:id/salvage/:salvageId
Authorization: Bearer <adjuster_token>

Audit Trail

All salvage operations generate entries in the claim_events table:

Event TypeTrigger
salvage_createdNew salvage record created
salvage_updatedSalvage record modified (disposition change, recovery recorded)
salvage_removedPending salvage record deleted

Each event records the actor user ID, role, and relevant details (salvage ID, item description, change set).

Storage Cost Tracking

For assets in physical storage (tow yards, warehouses), the system tracks:

  • storageLocation -- Facility name and address
  • storageStartDate -- Date storage began
  • dailyStorageCost -- Per-day rate

This data supports storage cost accrual and helps adjusters make timely disposition decisions to minimize holding costs.

Total Loss Workflow

When a vehicle or asset is damaged beyond economical repair, the total loss module manages the determination, settlement calculation, and title disposition. The API is at /v1/claims/:id/total-loss, implemented in apps/api/src/routes/claims/total-loss.ts.

Total Loss Determination

POST /v1/claims/:id/total-loss
Authorization: Bearer <adjuster_token>
Content-Type: application/json

{
"reason": "damage_exceeds_value",
"actualCashValue": 32000,
"deductible": 1000,
"priorDamage": 500,
"ownerRetainsSalvage": false,
"lienholderName": "Capital One Auto Finance",
"lienholderPayoff": 18000
}

Only one total loss record is allowed per claim. Attempting to create a second returns HTTP 409.

Total Loss Reasons

ReasonDescription
damage_exceeds_valueRepair cost exceeds the vehicle's actual cash value (most common)
constructive_total_lossRepair cost exceeds the state's total loss threshold (typically 75-80% of ACV)
theft_unrecoveredVehicle stolen and not recovered within the statutory period
regulatoryState regulation mandates total loss determination

Settlement Calculation

The system automatically calculates the settlement amount:

Settlement = ACV - Deductible - Prior Damage - Salvage Deduction (if owner retains)
  • ACV (Actual Cash Value) -- Fair market value of the vehicle immediately before the loss.
  • Deductible -- Policy deductible amount.
  • Prior Damage -- Deduction for pre-existing unrepaired damage.
  • Salvage Deduction -- Applied only when ownerRetainsSalvage is true. Represents the salvage value deducted from the settlement so the insured can keep the vehicle.

The result is floored at zero (settlement cannot be negative).

Title Status

The system determines the title status based on the total loss details:

Title StatusCondition
clearNo lienholder and owner does not retain salvage
lienholder_payoff_pendingLienholder payoff amount specified
retained_by_ownerOwner retains salvage (title branded as salvage/rebuilt)
title_transferredTitle has been transferred to the carrier or salvage buyer

Updating Total Loss Records

After the initial determination, the title status and settlement can be updated as the process progresses:

PATCH /v1/claims/:id/total-loss
Authorization: Bearer <adjuster_token>
Content-Type: application/json

{
"titleStatus": "title_transferred",
"settledAt": "2025-08-20T00:00:00Z"
}

Updatable fields: titleStatus, settledAt, lienholderName, lienholderPayoff.

Audit Trail

Total loss operations generate events in the claim_events table:

Event TypeTrigger
total_loss_determinedInitial total loss determination created (includes reason, ACV, settlement amount, title status)
total_loss_updatedTotal loss record modified (title transfer, settlement date, lienholder changes)

Authorization

All salvage and total loss endpoints require one of: adjuster, underwriter, org_admin, or superadmin role. Write operations (create, update, delete) exclude superadmin from the write path -- only adjuster, underwriter, and org_admin can modify records.