Coverage
→
payer_plan_period
documented
primary
FHIR Coverage captures a patient's insurance enrollment (payer, plan, coverage period, subscriber relationship). It maps to OMOP payer_plan_period, which records continuous enrollment under a specific health benefit plan from a given payer. Unlike clinical event tables, payer_plan_period carries no _type_concept_id; it is purely administrative. One active Coverage resource produces one payer_plan_period row. Overlapping or adjacent periods for the same person/payer may be collapsed.
Conversion profile
omop-coverage-payer-plan-period
A FHIR instance converts to payer_plan_period iff it validates against this profile.
| Path | Card | Type | Binding / Fixed | Comment |
|---|---|---|---|---|
| Coverage.status | 1..* | fixed: active | Only active coverage produces a payer_plan_period row. | |
| Coverage.beneficiary | 1..* | Reference | Required for payer_plan_period.person_id. | |
| Coverage.period | 1..*MS | |||
| Coverage.period.start | 1..*MS | Required for payer_plan_period.payer_plan_period_start_date. | ||
| Coverage.payor | 1..*MS | Required for payer_concept_id / payer_source_value. |
ViewDefinition (Stage 1 flattener)
omop-coverage-payer-plan-period
11 columns · resource Coverage
| column name | FHIRPath | type |
|---|---|---|
| id | Coverage.id | id |
| subject_id | Coverage.beneficiary | Reference(Patient) |
| payer_plan_period_start_date | Coverage.period.start | dateTime |
| payer_plan_period_end_date | Coverage.period.end | dateTime |
| payer | Coverage.payor[0] | Reference(Organization|Patient|RelatedPerson) |
| payer_text | Coverage.payor[0] | Reference(Organization|Patient|RelatedPerson) |
| plan | Coverage.type.coding[0].code | code |
| plan_text | Coverage.type.text | string |
| sponsor | Coverage.policyHolder | Reference(Organization|Patient|RelatedPerson) |
| sponsor_text | Coverage.policyHolder | Reference(Organization|Patient|RelatedPerson) |
| family_text | Coverage.subscriberId | string |
Condition: Coverage.status = 'active'
Fields (17)
-
payer_plan_period_id←Coverage.idinteger · idPKrequiredSurrogate key. Generated via hash/sequence/lookup of Coverage.id. -
person_id←Coverage.beneficiaryinteger · Reference(Patient)FK→PERSONrequiredResolve Patient reference to integer person_id via the same ID mapping used by the Patient mapper. -
payer_plan_period_start_date←Coverage.period.startdate · dateTimerequiredCoverage start date. If absent, use ETL epoch or earliest known date. NOT NULL in OMOP.2 sources ▾
-
MIN(billablePeriod.start) grouped by patient+insurer (derived from EOB, not Coverage directly)
- avalon-fhir-omop(sql) refs/refs/avalon-fhir-omop/omop-views/models/omop_payer_plan_period.sql:30-51
-
period.start from Coverage (reverse direction: OMOP→FHIR, from payer_plan_period_start_date)
-
-
payer_plan_period_end_date←Coverage.period.enddate · dateTimerequiredCoverage end date. If absent or open-ended, use 9999-12-31 or ETL end date. NOT NULL in OMOP.2 sources ▾
-
MAX(COALESCE(billablePeriod.end, billablePeriod.start)) — uses start as fallback when end is absent
- avalon-fhir-omop(sql) refs/refs/avalon-fhir-omop/omop-views/models/omop_payer_plan_period.sql:30-51
-
period.end from Coverage (reverse direction: OMOP→FHIR)
-
-
payer_concept_id←Coverage.payor[0]integer · Reference(Organization|Patient|RelatedPerson)FK→CONCEPTmap:payertransform:resolve payor[0] -> Organization.name -> OMOP Payer vocabulary lookupOMOP Payer vocabulary concept (vocabulary_id='Payer', domain_id='Payer'). Resolve Organization reference, map name to payer concept. Default: 0. If payor references Patient (self-pay), use concept_id 436.2 sources ▾
-
Mapped via 130-entry ConceptMap (OMOP payer_concept_id ↔ FHIR v3-ActCode) — reverse direction (OMOP→FHIR)
-
All concept_ids = 0 or NULL (no vocabulary lookup performed)
- avalon-fhir-omop(sql) refs/refs/avalon-fhir-omop/omop-views/models/omop_payer_plan_period.sql:35-47
-
-
payer_source_value←Coverage.payor[0]varchar(50) · Reference(Organization|Patient|RelatedPerson)transform:resolve payor[0] -> Organization.name or Reference.displayVerbatim payer name or identifier. Resolve Organization reference and extract Organization.name. Fallback to Reference.display. Truncate to 50 chars.2 sources ▾
-
insurer.display from ExplanationOfBenefit (no Coverage direct mapping)
- avalon-fhir-omop(sql) refs/refs/avalon-fhir-omop/omop-views/models/omop_payer_plan_period.sql:8-28
-
payor[0].display (from PPP.plan_source_value) — reverse OMOP→FHIR direction
-
-
payer_source_concept_id← constant integer · integerFK→CONCEPT=0Source concept for the payer if a non-standard vocabulary is used. Default: 0. -
plan_concept_id←Coverage.type.coding[0].codeinteger · codeFK→CONCEPTmap:plan_typetransform:map Coverage.type (v3-ActCode) to OMOP Plan vocabularyMap Coverage.type to OMOP Plan vocabulary. No standard OMOP vocabulary maps directly to Coverage.type. Default: 0. -
plan_source_value←Coverage.type.text | Coverage.class.where(type.coding.code='plan').name | Coverage.class.where(type.coding.code='plan').valuevarchar(50) · stringtransform:Use Coverage.type.text, or class entry where type.coding.code='plan'. Concatenate group+plan if both present.Plan name as it appears in source. Truncate to 50 chars. -
plan_source_concept_id← constant integer · integerFK→CONCEPT=0Source concept for the plan. Default: 0. -
sponsor_concept_id←Coverage.policyHolderinteger · Reference(Organization|Patient|RelatedPerson)FK→CONCEPTtransform:resolve policyHolder -> Organization.name -> OMOP Sponsor vocabulary lookupOMOP Sponsor vocabulary concept. The policyHolder (often the employer) is the sponsor. Default: 0. -
sponsor_source_value←Coverage.policyHoldervarchar(50) · Reference(Organization|Patient|RelatedPerson)transform:resolve policyHolder -> Organization.name or identifierSponsor name from policyHolder reference. Truncate to 50 chars. -
sponsor_source_concept_id← constant integer · integerFK→CONCEPT=0Source concept for the sponsor. Default: 0. -
family_source_value←Coverage.subscriberIdvarchar(50) · stringThe subscriber ID links all family members under the same policy. Truncate to 50 chars. -
stop_reason_concept_id← constant integer · integerFK→CONCEPT=0FHIR Coverage has no stop reason field. If Coverage.status='cancelled', could use a concept for cancellation. Default: 0. -
stop_reason_source_value← — varchar(50) · stringNot directly available from FHIR Coverage. Could store Coverage.status if not 'active'. -
stop_reason_source_concept_id← constant integer · integerFK→CONCEPT=0Default: 0.
Vocabularies
payer
| Source | Display | Concept ID | Concept Name |
|---|---|---|---|
| Medicare | Organization name containing 'Medicare' | 280 | Medicare |
| Medicare Managed Care | Medicare HMO/PPO payor | 281 | Medicare Managed Care |
| Medicaid | State Medicaid organization | 289 | Medicaid |
| Medicaid Managed Care | Medicaid MCO | 290 | Medicaid Managed Care |
| TRICARE | Military insurance | 296 | DoD TRICARE |
| VA | VA coverage | 302 | Veteran Care |
| Private | Generic commercial insurer | 327 | Private Health Insurance |
| HMO | HMO commercial plan | 329 | Commercial Managed Care - HMO |
| PPO | PPO commercial plan | 330 | Commercial Managed Care - PPO |
| Managed Care | Generic managed care | 340 | Managed Care, Unspecified |
| Self-pay | Coverage.type = 'pay' (self-pay) or payor references Patient | 436 | Self-pay |
| Charity | Charity coverage | 438 | Charity |
| Workers Comp | Workers compensation | 447 | Worker's Compensation |
| (unmapped) | Payor cannot be mapped to OMOP vocabulary | 0 | No matching concept |
plan_type
| Source | Display | Concept ID | Concept Name |
|---|---|---|---|
| EHCPOL | Extended healthcare | 327 | Private Health Insurance |
| HIP | Health insurance plan policy | 327 | Private Health Insurance |
| MCPOL | Managed care policy | 340 | Managed Care, Unspecified |
| SUBSIDMC | Subsidized managed care program | - | Medicare/Medicaid Managed Care |
| SUBSUPP | Subsidized supplemental health program | - | Medicare/Medicaid |
| MILITARY | Military health program | 296 | DoD TRICARE |
| VET | Veteran health program | 302 | Veteran Care |
| WCBPOL | Workers compensation | 447 | Worker's Compensation |
| CHAR | Charity program | 438 | Charity |
| pay | Self-pay | 436 | Self-pay |
| SAFNET | Safety net clinic program | - | HRSA Program |
Edge Cases
Missing Coverage.period
Both payer_plan_period_start_date and payer_plan_period_end_date are NOT NULL. Use ETL epoch date for start, 9999-12-31 or current date for end. Log warning.
Open-ended period (period.end absent)
Coverage is still active. Use 9999-12-31 or the ETL run date as payer_plan_period_end_date.
period.end < period.start
Data quality error. Skip the record or swap dates with a warning.
Coverage.status != 'active'
Skip Coverage resources with status cancelled, draft, or entered-in-error. Do not create a payer_plan_period row.
Multiple payor[] entries
OMOP has a single payer_source_value per row. Options: (a) take the first payor, (b) create one row per payor with the same period, (c) concatenate payor names (truncated to 50 chars).
payor references Patient (self-pay)
Set payer_source_value = 'Self-pay' or patient name, payer_concept_id = 436.
No Organization resource for payor
Use Reference.display as fallback for payer_source_value. If no display, use the reference string itself.
Overlapping Coverage periods (same person, same payer)
Collapse into a single payer_plan_period row with MIN(start), MAX(end). FhirToCdm does this via CanPayerPlanPeriodBeCombined() -- combines when payer+plan source values match.
Coverage.class[] absent
No plan details available. plan_source_value = null. Use Coverage.type.text if available.
Multiple Coverage resources for same person
Create one payer_plan_period row per Coverage (per payer/plan/period combination). May collapse adjacent/overlapping periods.
subscriberId too long for varchar(50)
Truncate to 50 characters.
Coverage from EOB (no discrete Coverage resource)
Derive payer_plan_period from ExplanationOfBenefit.billablePeriod + insurer. Group by patient+insurer, MIN/MAX dates.
Reference Implementations
- fhir-omop-ig(fsh) refs/refs/fhir-omop-ig/input/fsh/PayerPlanPeriod.fsh — Logical model defining all 17 payer_plan_period fields. No FML mapping from Coverage.
- mends-on-fhir(whistle) refs/refs/mends-on-fhir/whistle-mappings/synthea/whistle-functions/PPP_Coverage.wstl — Reverse direction (OMOP to FHIR). Delegates to zzPPP_CoverageImpl.wstl.
- mends-on-fhir(whistle) refs/refs/mends-on-fhir/whistle-mappings/synthea/whistle-functions/zzPPP_CoverageImpl.wstl — Implementation: Coverage.id from PPP_id (line 10), beneficiary from person_id (line 29), period from dates (lines 34-35), payor from plan_source_value (line 51), type via ConceptMap (lines 71-76).
- mends-on-fhir(json) refs/refs/mends-on-fhir/whistle-mappings/synthea/concept-maps/PPP.payor-concept-id--Coverage.type.json — ConceptMap with ~130 OMOP payer concept_ids mapped to FHIR v3-ActCode codes. Reverse direction.
- avalon-fhir-omop(sql) refs/refs/avalon-fhir-omop/omop-views/models/omop_payer_plan_period.sql — Derives payer_plan_period from ExplanationOfBenefit (not Coverage). GROUP BY patient+insurer with MIN/MAX dates. All concept_ids = 0 or NULL.
- FhirToCdm(csharp) refs/refs/FhirToCdm/CdmPersonBuilder.cs — PayerPlanPeriodsRaw list (lines 31-32), BuildPayerPlanPeriods + period collapsing (lines 486-507), SetPayerPlanPeriodId (lines 388-457).
- omop-fhir-data(json) refs/refs/omop-fhir-data/synthea-cohort-010/Payer_Plan_Period_0000000000.json — Synthea sample data: all concept_ids = 0, payer_source_value = UUID, plan_source_value = insurer name.