> ## Documentation Index
> Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Insurance & Eligibility Verification — Integration

> Feature ID: PM-02 Status: 📝 Planned Last Verified: 2026-02-18 Spec Reference: PM-02-insurance-eligibility-verification.md Last Updated: 2026-02-18

**Feature ID:** PM-02\
**Status:** 📝 Planned\
**Last Verified:** 2026-02-18\
**Spec Reference:** [PM-02-insurance-eligibility-verification.md](../../../specs/pm/specs/PM-02-insurance-eligibility-verification.md)\
**Last Updated:** 2026-02-18

***

## Table of Contents

* [Overview](#overview)
* [Quick Reference](#quick-reference)
* [Decision Trees](#decision-trees)
* [Pattern Library](#pattern-library)
* [Integration Points (from Spec)](#integration-points-from-spec)
* [API / Data Contracts](#api--data-contracts)
* [Labeled Code Examples](#labeled-code-examples)
* [Event Contracts](#event-contracts)
* [Security and RLS](#security-and-rls)
* [Common Mistakes](#common-mistakes)
* [Pre-Flight Checklist](#pre-flight-checklist)
* [Related Docs](#related-docs)

***

## Overview

PM-02 provides multiple insurance policies per patient, real-time and batch eligibility verification via X12 270/271 and AHCCCS, benefit detail capture, coordination of benefits, and coverage gap detection. It depends on PM-01 (patient registration); integrates with PM-08 (claims), PM-15 (clearinghouse), and AHCCCS (direct eligibility).

***

## Quick Reference

| Item                 | Value                                                                     |
| -------------------- | ------------------------------------------------------------------------- |
| Core tables          | `pm_insurance_policies`, `pm_eligibility_checks`, `pm_payers`             |
| Key dependencies     | PM-01, PM-08, PM-15, AHCCCS                                               |
| Required permissions | `pm.insurance.view/manage`, `pm.eligibility.run`, `pm.payers.view/manage` |
| Traceability         | `request_trace_id` required for external eligibility requests             |

***

## Decision Trees

### Eligibility execution path

1. Select active policy by coverage priority.
2. Choose check type (`real_time`, `batch`, or `manual`).
3. Send X12 270/271 through PM-15 or direct AHCCCS path.
4. Persist normalized result in `pm_eligibility_checks`.
5. Surface status to PM-08 claims flow gate.

### Coverage gap handling

1. Evaluate policy effective and termination dates.
2. If gap detected, flag workflow and route to staff for remediation.
3. Record remediation actions in policy and audit history.

***

## Pattern Library

| Pattern                     | Usage                                                             |
| --------------------------- | ----------------------------------------------------------------- |
| Data + API dual integration | PM-02 stores policy state and calls PM-15/AHCCCS for verification |
| Request trace contract      | External eligibility calls include trace IDs for replay/audit     |
| Claims gate pattern         | PM-08 checks PM-02 eligibility status before claim submission     |

***

## Integration Points (from Spec)

| Dependency                   | Pattern      | Purpose                                                                                     |
| ---------------------------- | ------------ | ------------------------------------------------------------------------------------------- |
| PM-01 (Patient Registration) | Data         | Patient linked to insurance policies; `pm_insurance_policies.patient_id` → `pm_patients.id` |
| PM-08 (Claims)               | Data / Event | Eligibility verified before claim submission; eligibility result informs claim workflow     |
| PM-15 (Clearinghouse)        | API          | 270/271 transactions via clearinghouse; request\_trace\_id for auditing                     |
| AHCCCS                       | API          | Direct eligibility verification (member ID, CIS ID, MCO assignment)                         |

***

## API / Data Contracts

### Insurance Policies — `pm_insurance_policies`

**Invocation pattern:** `supabase.from('pm_insurance_policies').select(...).eq('organization_id', orgId).eq('patient_id', patientId)`\
**Authentication:** Supabase JWT; RLS enforces org isolation. Application layer also filters by `organization_id` (defense-in-depth).\
**RBAC:** `pm.insurance.view` (read), `pm.insurance.manage` (write)\
**Tenant enforcement:** `organization_id` required on all mutations; RLS USING + WITH CHECK on UPDATE.\
**Idempotency:** Policy uniqueness enforced by `UNIQUE(organization_id, patient_id, payer_id, policy_number)`.

**Request schema (Insert):**

```typescript theme={null}
interface InsurancePolicyInsert {
  organization_id: string;       // UUID — required
  patient_id: string;            // UUID — FK to pm_patients
  payer_id: string;              // UUID — FK to pm_payers
  policy_number: string;         // Required
  group_number?: string;
  subscriber_name?: string;
  subscriber_dob?: string;       // DATE (ISO 8601)
  relationship_to_subscriber?: 'self' | 'spouse' | 'child' | 'other';
  coverage_type?: 'commercial' | 'medicaid' | 'medicare' | 'tricare' | 'self_pay' | 'sliding_scale' | 'other';
  priority_order: number;        // 1 = primary, 2 = secondary, etc.
  effective_date: string;        // DATE (ISO 8601)
  termination_date?: string;
  copay?: number;
  coinsurance_pct?: number;
  deductible?: number;
  oop_max?: number;
  bh_benefits?: Record<string, unknown>;
  status?: 'active' | 'inactive' | 'terminated';  // default: 'active'
  deleted_at?: string | null;    // TIMESTAMPTZ; null = active record
}
```

### Eligibility Checks — `pm_eligibility_checks`

**Invocation pattern:** `supabase.from('pm_eligibility_checks').insert({ ... }).eq('organization_id', orgId)`\
**Authentication:** Supabase JWT; RLS enforces org isolation.\
**RBAC:** `pm.eligibility.run` (create), `pm.insurance.view` (read results)\
**Traceability:** `request_trace_id` REQUIRED for every external 270/271 or AHCCCS call.\
**Caching:** Eligibility results cached in `pm_eligibility_checks`; use `next_check_due` to determine when re-verification is needed.\
**Performance SLA:** Real-time p95 \< 5s; history load p95 \< 1s (NFR-1).

**Request schema (Insert):**

```typescript theme={null}
interface EligibilityCheckInsert {
  organization_id: string;       // UUID — required
  patient_id: string;            // UUID — FK to pm_patients
  policy_id?: string | null;     // UUID — FK to pm_insurance_policies (optional)
  check_type: 'real_time' | 'batch' | 'manual';
  request_trace_id?: string;     // Required for external calls (audit trail)
  response_status?: string;      // e.g. 'active_coverage', 'inactive', 'not_found', 'error'
  eligible?: boolean;
  benefit_details?: BenefitDetails;
  next_check_due?: string;       // TIMESTAMPTZ (ISO 8601)
}

// benefit_details JSONB schema (spec Errata E-2)
interface BenefitDetails {
  deductible?: { individual: number; family: number; met: number; remaining: number };
  copay?: { office_visit: number; specialist: number; emergency: number };
  coinsurance?: { in_network_pct: number; out_of_network_pct: number };
  out_of_pocket_max?: { individual: number; family: number; met: number };
  visit_limits?: { bh_outpatient?: number; bh_inpatient_days?: number; used?: number };
  preauth_required?: boolean;
  referral_required?: boolean;
  behavioral_health_carveout?: { payer_name: string; payer_id: string; phone: string };
}
```

### Payers — `pm_payers`

**Invocation pattern:** `supabase.from('pm_payers').select(...).eq('organization_id', orgId).is('deleted_at', null)`\
**RBAC:** `pm.payers.view` (read), `pm.payers.manage` (write)\
**Soft delete:** `is_active = false` for logical disable (hidden from dropdowns); `deleted_at` for true soft-delete.

**PHI Logging Guidelines:**

* **Allowed log fields:** `check_id`, `patient_id` (UUID only), `check_type`, `eligible`, `organization_id`
* **Prohibited:** `benefit_details` contents, `policy_number`, `subscriber_dob`, `subscriber_name`
* **Retention:** Audit trail in `pf_audit_logs`; no PHI in application logs or edge function stdout

**Error response schema:**

```typescript theme={null}
interface PM02ErrorResponse {
  code: number;         // 4001 = tenant violation, 4002 = duplicate policy, 4003 = eligibility timeout
  message: string;      // Sanitized user-facing message (never raw DB error)
  field?: string;       // Field causing the error (for validation errors)
}
```

***

## Labeled Code Examples

### Example: eligibility check request payload

```typescript theme={null}
const eligibilityCheckInsert: EligibilityCheckInsert = {
  organization_id: 'org-uuid',
  patient_id: 'patient-uuid',
  policy_id: 'policy-uuid',
  check_type: 'real_time',
  request_trace_id: 'trace-271-uuid', // REQUIRED for external calls
};
```

### Example: normalized eligibility result with structured benefit\_details

```typescript theme={null}
const eligibilityResult = {
  eligible: true,
  response_status: 'active_coverage',
  benefit_details: {
    deductible: { individual: 1500, family: 3000, met: 250, remaining: 1250 },
    copay: { office_visit: 25, specialist: 50, emergency: 150 },
    coinsurance: { in_network_pct: 20, out_of_network_pct: 40 },
    out_of_pocket_max: { individual: 5000, family: 10000, met: 275 },
    visit_limits: { bh_outpatient: 30, bh_inpatient_days: 20, used: 4 },
    preauth_required: true,
    referral_required: false,
    behavioral_health_carveout: {
      payer_name: 'Beacon Health Options',
      payer_id: 'BHO-001',
      phone: '800-555-0100',
    },
  },
  next_check_due: '2026-03-18T00:00:00Z',
};
```

***

## Event Contracts

* **Outbound:** Eligibility check completed may be consumed by PM-08 (claims) or workflow; document in [EVENT\_CONTRACTS.md](./EVENT_CONTRACTS.md) if events are added.
* **Inbound:** None specified in PM-02 spec.

***

## Security and RLS

* RLS on `pm_insurance_policies`, `pm_eligibility_checks`, `pm_payers`. Use SECURITY DEFINER helpers that resolve organization and profile access via `pf_user_role_assignments`. All UPDATE policies include WITH CHECK (constitution §5.2.4).
* Eligibility and benefit data are PHI; no cross-tenant visibility. Permission keys: pm.insurance.view, pm.insurance.manage, pm.eligibility.run, pm.payers.view, pm.payers.manage.

***

## Common Mistakes

| Mistake                         | Impact                        | Fix                                                      |
| ------------------------------- | ----------------------------- | -------------------------------------------------------- |
| Missing `request_trace_id`      | Hard-to-debug payer responses | Require trace ID for every external request              |
| Ignoring policy priority order  | Incorrect COB behavior        | Enforce `priority_order` during checks and claims gating |
| Incomplete RLS WITH CHECK rules | Tenant write leakage          | Ensure UPDATE policies include USING + WITH CHECK        |

***

## Pre-Flight Checklist

* [ ] Validate RLS on all PM-02 tables.
* [ ] Validate permission keys and role mappings.
* [ ] Validate real-time + batch eligibility test flows.
* [ ] Validate PM-08 blocks claims when eligibility is missing/failed.
* [ ] Validate AHCCCS and clearinghouse fallback behavior.

***

## Related Docs

* [CROSS\_CORE\_INTEGRATIONS.md](./CROSS_CORE_INTEGRATIONS.md)
* [EVENT\_CONTRACTS.md](./EVENT_CONTRACTS.md)
* [API\_CONTRACTS.md](./API_CONTRACTS.md)
