Skip to content

Claims Lifecycle

A Claim represents a member's request for reimbursement of covered medical services. Claims are submitted complete — there is no DRAFT status in Olly's model. Once submitted, the claim moves through adjudication and, if approved, to payment.


Claim State Machine

What Happens at Each Transition

TransitionTriggerSide effects
[*] → SUBMITTEDClaims service receives and validates payloadclaims.submitted Kafka event published; EDI 837 generated by Mirth
SUBMITTED → UNDER_REVIEWKafka consumer begins adjudicationEligibility checked (gRPC), provider NPI verified (gRPC), accumulators loaded
UNDER_REVIEW → PENDING_INFOAdjudicator requests more docsClaimDocument record expected; member/provider notified
PENDING_INFO → UNDER_REVIEWRequired docs uploadedAdjudication resumes
UNDER_REVIEW → APPROVEDAll rules passAmountAllowed and AmountPaid computed on each ClaimLine; EOB PDF generated; claims.adjudicated Kafka event published
UNDER_REVIEW → REJECTEDCoverage gap, exclusion, or prior auth missingDenial reason codes written to ClaimLine.ReasonCode; member notified
APPROVED → PAIDBilling service processes provider paymentbilling.payment.completed event consumed by Claims; 835 remittance generated by Mirth
PAID → CLOSEDFinal reconciliationClaim record sealed; no further state changes permitted

ClaimLine Explained

Each Claim is itemised into one or more ClaimLine records — one per procedure or service rendered.

FieldTypeNotes
LineNumberintOrdering within the claim (matches 837 loop position)
ElementIDuuidThe PolicyElement (insured person) this line applies to
CoverageTermKeystringThe specific benefit category (e.g., "INPATIENT_HOSPITAL")
DescriptionstringHuman-readable service description
AmountClaimeddecimalWhat the provider billed
AmountAlloweddecimalCMS fee schedule or contracted rate
AmountPaiddecimalWhat the plan pays after deductible/coinsurance
ReasonCodestringANSI X12 adjustment reason code (e.g., "CO-97")
MetadatajsonbICD-10/CPT codes, modifier codes, place of service

The difference between AmountClaimed and AmountAllowed is the contractual write-off. The difference between AmountAllowed and AmountPaid is the member's cost-sharing responsibility (deductible + coinsurance + copay).


Prior Authorization Flow

Some procedures require pre-approval from the insurer before they are performed. If a claim arrives for a procedure that required prior auth but none was obtained, it is automatically rejected with reason code CO-15.

PriorAuth key fields:

FieldNotes
ProviderIDProvider requesting the auth
PolicyIDPolicy under which the member is covered
ProcedureCodeCPT or HCPCS code requiring authorization
StatusPENDING, APPROVED, or DENIED
SubmittedAtWhen the request was received
ReviewedAtWhen the clinical decision was made

Appeal Process

When a claim is REJECTED, the member or provider may file an appeal within the statutory window (typically 180 days). Appeals are handled as a new ClaimEvent with EventType = "APPEAL_SUBMITTED". The claim re-enters UNDER_REVIEW with an escalated reviewer assignment. A successful appeal transitions the claim back to APPROVED; an unsuccessful one closes with EventType = "APPEAL_DENIED".

The full audit trail of all state changes, actors, and notes is preserved in ClaimEvent records — these are append-only and never modified.


EDI 837 / 835 Context

Olly uses Mirth Connect as its EDI translation layer:

  • 837 (claim submission): Mirth parses inbound EDI 837P (professional) or 837I (institutional) files from clearinghouses and POSTs the structured payload to /internal/claims/edi-ingest. The Claims service creates the Claim and ClaimLine rows from this payload.
  • 835 (remittance advice): When a claim reaches APPROVED, Mirth subscribes to the claims.adjudicated Kafka topic and generates an 835 remittance advice file delivered to the provider's clearinghouse, containing the AmountPaid and ANSI adjustment reason codes per line.

Key Go Struct Fields at a Glance

go
type Claim struct {
    ID              uuid.UUID
    Locator         string      // e.g. "CLM-2026-009871"
    PolicyID        uuid.UUID
    TermID          uuid.UUID   // the PolicyTerm in effect on IncidentDate
    ClaimantPartyID uuid.UUID   // the member (Party) making the claim
    Status          ClaimStatus // SUBMITTED | UNDER_REVIEW | PENDING_INFO | APPROVED | REJECTED | PAID | CLOSED
    IncidentDate    time.Time   // date of service
    Document        []byte      // jsonb: raw submission payload, ICD-10/CPT codes
}

Olly Health Insurance Platform