Skip to main content

Billing Service — Service Overview

Status: populated Owner: TBD Last updated: 2026-04-17 Companion: Service Template · 03 platform-services · 02 DDD · FHIR-first

1. Purpose

The billing-service owns the tenant-scoped financial ledger for the Ghasi-eHealth platform. It turns clinical activity (encounters, orders, procedures, dispensed medications, telehealth sessions, immunizations) into charges, aggregates those charges into patient accounts and invoices, posts payments, refunds, and adjustments, and produces statements for delivery. It is the platform's authoritative source for "what was charged, what was paid, and what remains outstanding" per patient, per facility, per tenant.

The service is FHIR-firstAccount, ChargeItem, Invoice, PaymentNotice, and PaymentReconciliation are the canonical exchange resources. An immutable local ledger is kept for operational performance, reporting, and ERP export.

2. Bounded Context

Financial Management — Patient Accounting. Classified as Supporting (not a commodity, but not a differentiator either): every national-scale EHR needs an accurate ledger, but the differentiating intelligence lives in clinical and scheduling. The context is bordered by:

BorderNeighbourInteraction
Upstreamregistration-service, scheduling-service, orders-service, medication-service, laboratory-service, radiology-service, immunizations-service, virtual-care-serviceConsumes billable-event streams to capture charges
Upstream (payer)claims-serviceConsumes remittance / ClaimResponse events to post adjustments and payer payments
Downstreamclaims-service, patient-portal-service, communication-service, population-health-service, external ERPPublishes charge/invoice/payment events for claim submission, statement delivery, patient balance display, revenue analytics, GL export

3. Responsibilities

AreaBilling owns
Charge captureChargeItem creation from encounter + order + procedure + dispense context, coded (CPT/HCPCS/ICHI/local), modified, priced
Price listsFacility- and program-scoped price books with effective dating
Patient accountingPatient Account aggregate: balance, aging buckets, statements, payment plans
Invoice lifecycleDraft → issued → paid / partially-paid / voided with line-item immutability after issue
Payment postingCash, card, bank transfer, mobile money (Afghanistan context), payer remittance; idempotent Idempotency-Key required
AdjustmentsWrite-offs, corrections, courtesy discounts, contractual adjustments; approval workflow by threshold
RefundsControlled, dual-approval above threshold; emits dedicated event
StatementsBatch statement runs (PDF, SMS-link, email); per-tenant schedule; delivery tracking
Multi-currency + taxAFN, AED, USD at minimum; per-facility VAT/tax rules with effective dates
Ledger exportGL/ERP batch export hooks (CSV/JSON) by tenant/facility/date range

4. Non-Responsibilities

AreaOwnerWhy not billing
Claim assembly + payer submissionclaims-serviceSeparation between patient accounting and payer lifecycle
Insurance coverage + eligibilityclaims-serviceCoverage checks sit alongside claim authoring; billing consumes results
Price quoting UX / portalpatient-portal-service + frontend BFFBilling provides APIs; portal renders patient balance views
Card processor integrationpayment gateway adapter (external)PCI scope stays out of core service; billing speaks an adapter port
Accounting journals & financial statementsCustomer ERPBilling exports events; GL lives in customer system
Clinical coding education / CDIclinical-notes + CDI toolingBilling validates codes at capture; it does not author them

5. Dependencies

5.1 Upstream

DependencyPatternPurpose
registration-serviceEvent consumerregistration.encounter.admitted/discharged.v1 → encounter context for charge capture
scheduling-serviceEvent consumerscheduling.appointment.completed.v1 → outpatient visit triggers charge
orders-serviceEvent consumerorders.service_request.completed.v1 → lab/rad/procedure charges
medication-serviceEvent consumermedication.administration.recorded.v1 / dispense events → drug charges
virtual-care-serviceEvent consumervirtual_care.billing.session_chargeable.v1 → telehealth encounter charge
immunizations-serviceEvent consumerimmunizations.administration.recorded.v1 → vaccine + admin fee charge
terminology-serviceAPICPT/HCPCS/ICHI/ICD validation and value-set membership
tenant-serviceAPIFacility metadata, price list ownership, tenant currency defaults
identity-serviceJWTActor identity + permission scopes for refund/adjustment approval
claims-serviceEvent consumerclaims.remittance.posted.v1 → auto-post payer payments + contractual adjustments
interop-service (fhir-gateway)APIWrites ChargeItem, Invoice, Account, PaymentReconciliation when external FHIR consumers request them

5.2 Downstream consumers

ConsumerPatternWhat they consume
claims-serviceEvent consumerbilling.invoice.issued.v1 → candidate for payer claim
patient-portal-serviceAPI (BFF)Account balance, invoice list, statement PDFs, payment submission
communication-serviceEvent consumerbilling.statement.generated.v1 → SMS/email delivery
population-health-serviceEvent consumerRevenue + utilisation analytics
ERP / GL adapterEvent consumer + batch exportbilling.charge.captured.v1, billing.payment.posted.v1, billing.adjustment.applied.v1
audit-serviceEvent consumerAll billing events → retention 10+ years

6. Slice Involvement

SliceScopeMilestone
S2 — Revenue CaptureCharge capture from encounters, basic patient accounts, simple invoice + cash paymentM1
S3 — Statement & PayerInvoice issuance, statement runs, payer remittance ingestion, multi-currency, taxM2
S4 — EnterpriseGL export, payment-plan management, refund approval, dashboards, ERP adaptersM3

7. Architectural Freeze Points

FreezeWhat is frozenBy
F-BILL-01Monetary representation: Money = { currency: ISO-4217, minor_units: bigint } — no floatsEnd of M1
F-BILL-02Ledger append-only invariant — no in-place mutation on ledger_entriesEnd of M1
F-BILL-03Event schemas v1 (billing.charge.captured.v1, billing.invoice.issued.v1, billing.payment.posted.v1, billing.adjustment.applied.v1, billing.refund.issued.v1, billing.statement.generated.v1)End of M2
F-BILL-04Idempotency-Key contract for POST /payments and POST /refundsEnd of M1

8. Readiness levels

LevelTarget milestoneCriteria
L2M1Charge capture, account balance, cash payment posting in a single facility
L3M2Multi-facility, issued invoices, statement runs, payer remittance, SLO tracking
L4M3Refund approvals, GL export, ERP adapters, chaos-tested, dashboards in Grafana

9. Architecture diagram

10. Key design decisions

  1. Immutable ledger, derived views. ledger_entries is append-only. account_balances and aging views are materialised for reads; corrections are new reversing entries, never updates.
  2. Money is integer minor units. Floats are banned. All arithmetic is in bigint minor units plus ISO-4217 currency to eliminate rounding bugs across AFN, AED, USD, etc.
  3. Idempotency-Key on financial mutations. POST /payments, POST /refunds, and POST /adjustments require Idempotency-Key. Replay returns the original resource; conflicting payload with same key returns IDEMPOTENCY_CONFLICT (409).
  4. Price list is effective-dated. Charge capture resolves price by facility_id + code + service_date with lookup precedence (tenant → facility → national fallback).
  5. Multi-currency per tenant. Each tenant has a default currency; each account is pinned to a currency at creation. Cross-currency invoicing is forbidden.
  6. VAT / tax is policy-driven. Tax rules live in tax_rules with effective windows and country/facility scoping; invoices snapshot applied rates at issue time.
  7. Licensing gate at edge. The service is an optional module; unlicensed tenants receive MODULE_NOT_ACTIVE (403) before any data access.
  8. Separation of duties. Refund/write-off approvals are enforced in-service via billing:refund:approve scope and threshold config; dual-approval for amounts above tenant-defined limits.
  9. PCI stays out. No PAN/CVV ever enters the service. Card processing is delegated to a gateway adapter that returns a tokenised payment reference.
  10. FHIR-first exchange. External systems read/write via Account, ChargeItem, Invoice, PaymentReconciliation through interop-service/fhir-gateway. Internal REST exists for low-friction UX.

11. Source reconciliation

Populated from services/billing-service/_sources/billing/ (SPEC, TECHNICAL_REQUIREMENTS, SOLUTION_DESIGN, API_DOCS, EVENT_MODEL, TRACEABILITY_MATRIX, backlog). Re-framed from the legacy "EHR billing module" framing to platform billing service consumed by every clinical producer (including the EHR sub-product). Event names were renamed from BILLING.* (module subjects) to the platform-canonical billing.*.v1 form per NAMING. Legacy FR-BILL-001..010 are preserved in API_CONTRACTS.md and EPICS/USER_STORIES in the "Legacy ref" columns.