Oscar Pro Billing Integration¶
This document defines the FHIR mapping and implementation details for integrating Oscar Pro's billing module with the Nexus EMR FHIR IG. The initial driver is the Nexus Jarvis Billing product, which reads Oscar billing context (demographics, historic bills, dx list, provider info) to generate post-encounter OHIP billing code recommendations and writes the accepted codes back to Oscar's billing module.
Overview¶
Oscar Pro stores Ontario physician billing in two linked tables:
billing_on_cheader1— invoice/claim header (one row per submitted bill)billing_on_item— line items per fee code within a bill (one row per OHIP service code)
The existing ca.kai.fhir.converter.r4.InvoiceConverter already emits a FHIR R4 Invoice resource with inline lineItem[] components mapping from these tables. This integration formalises that mapping via:
- The new
NexusEmrCoreInvoiceprofile - Three extensions on
Invoice:oscarBillingStatus,shadowBill, andserviceLocation(reference to aNexusEmrCoreLocationcarrying the SLI code). Note (1.9.9): Oscar'spay_programnow lives on FHIR-nativeInvoice.type.coding[payProgram]rather than a custom extension — consumers should readInvoice.type.codingin 1.9.9+. - An
identifier[ohipBillingNumber]slice onNexusEmrCorePractitioner - Code-system aliases for OHIP Schedule of Benefits, OHIP diagnostic codes, and ICD-9
Scope¶
Phase 1 covers Ontario (OHIP) on Oscar Pro only. Other provinces and other backends are out of scope for this iteration; nothing on this page should be read as a commitment for them.
Definitions¶
- OHIP — Ontario Health Insurance Plan, the provincial single-payer program
- FHO / FHN — Family Health Organization / Family Health Network — Ontario capitation-based physician payment models (~60% of Ontario FPs)
- FHG — Family Health Group, a blended FFS model
- FFS — Fee-for-Service (traditional per-service billing)
- FHO+ — Enhanced FHO model launching 2026-04 with 30-50% shadow billing rates
- Shadow Bill — a submission under a capitated model that records service delivery but pays at a fraction of FFS rates (for tracking and utilization-based funding)
- RMB — Reciprocal Medical Billing (billing OHIP-equivalent for non-Ontario health card holders)
- WCB — Worker's Compensation Board (Oscar source label — in Ontario this maps to the WSIB, Workplace Safety and Insurance Board)
Use Cases¶
As an AI billing recommendation module (Jarvis), I need to:
- Read a provider's recent encounter notes, demographics, dx list, and historic bills to understand context
- Detect the provider's payment model (FHO/FHN/FHG/FFS/FHO+) from Oscar signals
- Generate applicable OHIP fee codes based on encounter content
- Write accepted billing codes back to Oscar's billing module as new
billing_on_cheader1+billing_on_itemrows - Preserve Oscar's 10-code billing status enum across the FHIR round-trip
Architecture¶
flowchart LR
subgraph oscar["Oscar Pro"]
t1[("billing_on_cheader1<br/>+ billing_on_item")]
t2[("dxresearch")]
t3[("casemgmt_issue *")]
t4[("demographic")]
t5[("provider")]
end
subgraph fhir["FHIR R4 (Nexus EMR IG)"]
c1[InvoiceConverter<br/>existing]
c2[ConditionConverter<br/>needs overload]
c3[PatientConverter<br/>existing]
c4[PractitionerConverter<br/>existing]
r1([Invoice<br/>+ 3 extensions])
r2([Condition<br/>+ category])
r3([Patient])
r4([Practitioner<br/>+ ohipBillingNumber])
end
subgraph nexus["Nexus / Jarvis"]
j1[Read historic bills]
j2[Read dx context]
j3[Read demographics]
j4[Read provider info]
j5[Generate<br/>recommendations]
j6[Provider review]
j7[Write accepted codes]
end
t1 --> c1 --> r1 --> j1
t2 --> c2
t3 -.-> c2
c2 --> r2 --> j2
t4 --> c3 --> r3 --> j3
t5 --> c4 --> r4 --> j4
j1 & j2 & j3 & j4 --> j5 --> j6 --> j7
j7 -- Invoice POST --> c1 -- toOscarObject --> t1
* CPP → Condition path is net-new — CaseManagementIssue source not currently converted.
Mapping Documents¶
- Oscar to FHIR — field-by-field mapping from Oscar source tables to FHIR
Invoice/Condition/Practitioner/Patient/Encounterresources - FHIR to Oscar — reverse mapping for write-back (Jarvis → Oscar billing module)
- Write-Back Design — open questions + decision log for the Jarvis → Oscar round-trip
Extension URL Provenance¶
Nexus EMR IG profiled extensions:
oscar-billing-status-extension— raw 10-code Oscar billing status enumoscar-billing-shadow-bill-extension— boolean flag for FHO/FHN capitated submissionsoscar-service-location-extension— (added in 1.9.9) Reference to aNexusEmrCoreLocationcarrying the SLI code onidentifier[sliCode]; replaces the raw-stringapps.health/Invoice/locationextension
1.9.9 refactor — pay_program moved off extensions: previously oscar-billing-pay-program-extension; now Invoice.type.coding[payProgram] (native FHIR, bound to OscarPayProgramCS). The extension was removed. Converters emitting against 1.9.9 must use the native type.coding slot.
Additional extension URLs referenced in the mapping YAMLs but NOT authored in this IG:
The existing InvoiceConverter already emits ~15 extension URLs under https://apps.health/Invoice/* and https://apps.health/InvoiceLineItem/* namespaces (see InvoiceExtensionUrls.java + InvoiceLineItemComponentExtensionUrls.java). These are emitted in the wild today but do not yet have corresponding StructureDefinition / Extension profiles in the Nexus EMR IG. They include:
| Category | Extension URL stem | Oscar field |
|---|---|---|
| Invoice header | apps.health/Invoice/admission-date |
billing_on_cheader1.admission_date |
| Invoice header | apps.health/Invoice/appointment-no |
billing_on_cheader1.appointment_no |
| Invoice header | apps.health/Invoice/facility-num |
billing_on_cheader1.facilty_num (sic) |
| ~~Invoice header~~ | ~~apps.health/Invoice/location~~ |
~~billing_on_cheader1.location~~ — superseded 1.9.9: now oscar-service-location-extension → Reference(NexusEmrCoreLocation) with SLI on identifier[sliCode] |
| Invoice header | apps.health/Invoice/manual-review |
billing_on_cheader1.man_review |
| Invoice header | apps.health/Invoice/paid |
billing_on_cheader1.paid |
| ~~Invoice header~~ | ~~apps.health/Invoice/pay-program~~ |
~~billing_on_cheader1.pay_program~~ — superseded 1.9.9: now Invoice.type.coding[payProgram] with $OscarPayProgramCS |
| Invoice header | apps.health/Invoice/payee |
billing_on_cheader1.payee |
| Invoice header | apps.health/Invoice/province |
billing_on_cheader1.province |
| Invoice header | apps.health/Invoice/ref-lab-num |
billing_on_cheader1.ref_lab_num |
| Invoice header | apps.health/Invoice/total-deleted |
derived |
| Invoice header | apps.health/Invoice/visit-type |
billing_on_cheader1.visittype |
| Line item | apps.health/InvoiceLineItem/diagnostic1 |
billing_on_item.dx |
| Line item | apps.health/InvoiceLineItem/diagnostic2 |
billing_on_item.dx1 |
| Line item | apps.health/InvoiceLineItem/diagnositc3 ⚠️ typo |
billing_on_item.dx2 |
| Line item | apps.health/InvoiceLineItem/header-id |
billing_on_item.ch1_id |
| Line item | apps.health/InvoiceLineItem/last-updated |
billing_on_item.timestamp |
| Line item | apps.health/InvoiceLineItem/service-date |
billing_on_item.service_date |
| Line item | apps.health/InvoiceLineItem/status |
billing_on_item.status |
| Line item | apps.health/InvoiceLineItem/hin-verion ⚠️ typo |
— |
Decision needed: should Nexus EMR IG author StructureDefinition profiles for each of these (aligning the IG with what's already on the wire), or treat them as converter-internal and leave un-profiled? Recommend authoring profiles for the line-item dx extensions (DIAGNOSTIC_1/2/3) at minimum since they carry clinical coding semantics; the header extensions are largely administrative and can remain un-profiled if bandwidth is tight.
Open Questions¶
- [ ] Rejected-claim handling in Phase 1? — the requirement is that a rejection reason and a suggested correction are surfaced, but Oscar's
raDetail/ remittance-advice integration is deferred to Phase 2. Undecided: whether Phase 1 ships without the rejection loop. If it must not, the converter work expands significantly. - [ ]
Invoice.statusdraft state for provider-review intermediate? — the write-back design must decide whether Jarvis POSTs indraftstatus awaiting provider-accept →issuedtransition, or postsissuedonly after provider confirms. Seewrite-back-design.md. - [ ] Payment-model detection strategy — no single Oscar column identifies FHO/FHN/FHG/FFS/FHO+; must be derived from multiple signals (
provider.onMohLastRosterReportDate+demographic_ext.ENROLLMENT_PROVIDER+ historicalbilling_on_cheader1.statusdistribution). See the payment-model detection notes in the source-table analysis.
Known Converter Gaps¶
All file:line references are absolute paths under oscar-pro/src/main/java/.
| # | Gap | Source location |
|---|---|---|
| 1 | R4 EncounterResourceProvider missing (only DSTU2 exists — ca/kai/fhir/resource/dstu2/EncounterResourceProvider.java) |
N/A — net-new R4 file needed |
| 2 | Invoice.status emits HAPI InvoiceStatus.NULL sentinel for Oscar H and I; X is incorrectly emitted as ISSUED (should be cancelled) |
ca/kai/fhir/converter/r4/InvoiceConverter.java:510-540 |
| 3 | ConditionConverter writes literal "icd9" as Coding.system instead of http://hl7.org/fhir/sid/icd-9-cm |
ca/kai/fhir/converter/r4/ConditionConverter.java:139-141 |
| 4 | ConditionConverter doesn't set Condition.category (neither problem-list-item nor encounter-diagnosis) |
ca/kai/fhir/converter/r4/ConditionConverter.java:81-161 |
| 5 | ConditionConverter only reads DxResearch; CPP CaseManagementIssue source not converted |
ca/kai/fhir/converter/r4/ConditionConverter.java:81 |
| 6 | InvoiceLineItemComponentExtensionUrls.DIAGNOSTIC_3 URL misspelled (diagnositc3) |
ca/kai/fhir/converter/r4/extension/InvoiceLineItemComponentExtensionUrls.java:8 |
| 7 | InvoiceLineItemComponentExtensionUrls.HIN_VERSION URL misspelled (hin-verion) |
ca/kai/fhir/converter/r4/extension/InvoiceLineItemComponentExtensionUrls.java:13 |
| 8 | Copy-paste bug: IDENTIFIER_APPTPROVIDER_NO + IDENTIFIER_ASSTPROVIDER_NO both set to "provider_ohip_no" |
ca/kai/fhir/converter/r4/InvoiceConverter.java:57-60 |
| 9 | APPS_HEALTH_CODE_SYSTEM_URL placeholder on chargeItemCodeableConcept + dx extensions — needs real OHIP SoB + ICD-9 URIs |
ca/kai/fhir/converter/r4/InvoiceConverter.java:356,370-383 |
| 10 | Encounter.length unpopulated; duration lives on casemgmt_note.hourOfEncounterTime + minuteOfEncounterTime |
ca/kai/fhir/converter/r4/EncounterConverter.java + ca/kai/caseManagementNote/CaseManagementNote.java:112-117 |
| 11 | InvoiceConverter.getInvoiceStatus default: branch throws InvalidRequestException on unknown Oscar status (fragile for new billing status codes) |
ca/kai/fhir/converter/r4/InvoiceConverter.java:535-539 |