Skip to main content

Billing Service — Event Schemas

Status: populated Owner: TBD Last updated: 2026-04-17 Companion: Service Template · Event-driven arch · NAMING

1. Envelope

All events follow the platform EventEnvelope (CloudEvents 1.0 profile):

{
"specversion": "1.0",
"id": "01J0...", // ULID
"source": "ghasi/billing-service",
"type": "billing.invoice.issued.v1",
"subject": "billing.invoice.issued.v1", // NATS subject
"time": "2026-04-17T10:00:00Z",
"datacontenttype": "application/json",
"tenantid": "ten_01J0...",
"actorid": "usr_01J0...",
"correlationid": "req_01J0...",
"data": { ... }
}
  • Subject = type per NAMING.
  • Versioning: vN suffix. Breaking changes open v(N+1) alongside vN for a deprecation window.

2. Published events

Subject / TypeAggregateRetention classConsumers
billing.charge.captured.v1Charge10y (financial)claims-service, ERP, audit-service, population-health-service
billing.charge.reversed.v1Charge10yclaims-service, ERP, audit-service
billing.invoice.drafted.v1Invoice30d (operational)patient-portal-service
billing.invoice.issued.v1Invoice10yclaims-service, patient-portal-service, communication-service, audit-service
billing.invoice.voided.v1Invoice10yclaims-service, audit-service
billing.invoice.paid.v1Invoice10yclaims-service, patient-portal-service, audit-service
billing.payment.posted.v1Payment10yclaims-service, ERP, audit-service, patient-portal-service
billing.payment.reversed.v1Payment10yclaims-service, ERP, audit-service
billing.refund.requested.v1Refund10yaudit-service, communication-service (notify approver)
billing.refund.approved.v1Refund10yaudit-service
billing.refund.rejected.v1Refund10yaudit-service
billing.refund.issued.v1Refund10yERP, audit-service
billing.adjustment.applied.v1Adjustment10yclaims-service, ERP, audit-service
billing.statement.started.v1StatementRun30dops dashboards
billing.statement.generated.v1StatementRun1ycommunication-service, audit-service
billing.statement.delivered.v1StatementRun1yaudit-service
billing.price_list.published.v1PriceList5yaudit-service, tenant-service
billing.account.suspended.v1Account10ypatient-portal-service, audit-service

3. Consumed events

SubjectProducerHandler outcome
registration.encounter.discharged.v1registration-serviceCaptureCharge for each billable item
scheduling.appointment.completed.v1scheduling-serviceCaptureCharge for outpatient visit code
orders.service_request.completed.v1orders-serviceCaptureCharge for ordered procedure / lab / radiology
medication.administration.recorded.v1medication-serviceCaptureCharge for drug + administration fee
immunizations.administration.recorded.v1immunizations-serviceCaptureCharge for vaccine + admin fee
virtual_care.billing.session_chargeable.v1virtual-care-serviceCaptureCharge for telehealth encounter
laboratory.result.finalised.v1laboratory-serviceCaptureCharge for result fees if not already captured
radiology.study.finalised.v1radiology-serviceCaptureCharge for study fees
claims.remittance.posted.v1claims-servicePostPayment(PAYER_REMITTANCE) + ApplyAdjustment(CONTRACTUAL)
claims.claim.denied.v1claims-serviceNotify billing queue for rework; no ledger impact
tenant.facility.updated.v1tenant-serviceInvalidate price-list cache for facility
gdpr.subject_request.received.v1platformParticipate — anonymize personal fields (retain financial record per law)

4. Payload schemas

4.1 billing.charge.captured.v1

{
"chargeId": "chr_01J0...",
"accountId": "acc_01J0...",
"patientId": "pat_01J0...",
"encounterId": "enc_01J0...",
"facilityId": "fac_01J0...",
"serviceDate": "2026-04-10",
"code": { "system": "CPT", "code": "99213" },
"modifiers": [{ "system": "CPT-MOD", "code": "25" }],
"units": 1,
"unitPrice": { "currency": "AFN", "minor_units": 250000 },
"taxAmount": { "currency": "AFN", "minor_units": 0 },
"totalAmount": { "currency": "AFN", "minor_units": 250000 }
}

4.2 billing.invoice.issued.v1

{
"invoiceId": "inv_01J0...",
"accountId": "acc_01J0...",
"patientId": "pat_01J0...",
"facilityId": "fac_01J0...",
"issuedAt": "2026-04-17T10:00:00Z",
"currency": "AFN",
"subtotal": { "currency": "AFN", "minor_units": 250000 },
"tax": { "currency": "AFN", "minor_units": 12500 },
"total": { "currency": "AFN", "minor_units": 262500 },
"lineCount": 3
}

4.3 billing.payment.posted.v1

{
"paymentId": "pay_01J0...",
"accountId": "acc_01J0...",
"method": "CASH",
"amount": { "currency": "AFN", "minor_units": 262500 },
"reference": "RCPT-2026-00042",
"allocations": [
{ "invoiceId": "inv_01J0...", "amount": { "currency": "AFN", "minor_units": 262500 } }
],
"postedAt": "2026-04-17T10:02:00Z"
}

4.4 billing.adjustment.applied.v1

{
"adjustmentId": "adj_01J0...",
"accountId": "acc_01J0...",
"amount": { "currency": "AFN", "minor_units": -50000 },
"reason": "CONTRACTUAL",
"relatedInvoiceId": "inv_01J0...",
"claimId": "clm_01J0..."
}

4.5 billing.refund.issued.v1

{
"refundId": "rfd_01J0...",
"originalPaymentId": "pay_01J0...",
"accountId": "acc_01J0...",
"amount": { "currency": "AFN", "minor_units": 100000 },
"reason": "SERVICE_NOT_RENDERED",
"approvedBy": "usr_01J0...",
"postedAt": "2026-04-17T11:00:00Z"
}

4.6 billing.statement.generated.v1

{
"runId": "srun_01J0...",
"facilityId": "fac_01J0...",
"asOfDate": "2026-04-30",
"generated": 482,
"failed": 1,
"completedAt": "2026-05-01T03:14:00Z"
}

4.7 billing.account.suspended.v1

{
"accountId": "acc_01J0...",
"patientId": "pat_01J0...",
"reason": "NON_PAYMENT_90D",
"suspendedAt": "2026-07-02T09:00:00Z"
}

5. NATS JetStream configuration

StreamSubjectsReplicasRetentionMax ageStorage
BILLINGbilling.*3Limits30 days operational / mirrored to archive for 10 yearsFile
BILLING_DLQbilling.dlq.>3Limits90 daysFile

6. Delivery semantics

  • At-least-once delivery; consumers must idempotently dedup on CloudEvents id.
  • Ordering is per subject-partition; within an account, events are processed in order via subject-level consumer ack.
  • Dead letter: 5 redelivery attempts → billing.dlq.<subject>.

7. Schema registry

All schemas are registered in the platform schema registry under ghasi.billing.*. Consumer schema-conformance tests live in test/contract/*.schema.spec.ts.