Immunization and TCMR via FHIR — bringing the digital vaccination record into Law 114/2025 on Disease Prevention

Law 114/2025/QH15 (issued 10/12/2025, effective 01/07/2026) replaces the 2007 Law on Prevention and Control of Infectious Diseases (Law 03/2007/QH12). The new law requires public-health information systems to keep immunization data connected and shared within the national health database, and to report immunization activity per Ministry of Health rules. This page explains how to use three FHIR R4 resources — Immunization, ImmunizationRecommendation, and ImmunizationEvaluation — together with VNeID (Vietnam's national digital identification app) and its personal health record (PHR) module to build a life-long immunization record covering both the Expanded Program on Immunization (EPI/TCMR) and private-pay immunization, on top of international standards.

TL;DR

  • FHIR R4 ships three resources that are enough on their own: Immunization records doses given, ImmunizationRecommendation forecasts the next dose, and ImmunizationEvaluation assesses each dose's validity.
  • Law 114/2025/QH15 (effective 01/07/2026) requires immunization data to be connected and shared in the national health database — not necessarily real time, but must follow Ministry of Health (MoH) reporting rules.
  • VN Core uses the CodeSystem http://fhir.hl7.org.vn/core/CodeSystem/vn-vaccine-type-cs for vaccine codes by target disease; ATC (http://www.whocc.no/atc) supplements at the pharmaceutical product level.
  • Standard workflow: newborn Patient created → ImmunizationRecommendation pre-loaded against the TCMR schedule → reminders pushed via VNeID/SMS → vaccine administered with digital signature → ImmunizationEvaluation auto-generated → record pushed to the national gateway and VNeID.
  • Adverse events (AEFI) are recorded via the AdverseEvent resource, linked back to the originating Immunization; outcome must use the FHIR R4 codes (resolved, recovering, ongoing...).

1. Context — Law 114/2025 and the TCMR program

Immunization is one of the highest-impact public-health interventions ever deployed. Vietnam launched its Expanded Program on Immunization (EPI, locally known as TCMR) in 1981 and has since brought several infectious diseases under control. However, immunization data infrastructure remains fragmented across private clinics, public facilities, and the Ministry of Health reporting gateway — leaving surveillance lagging in real time and making it hard to retrieve a single individual's full immunization history.

Law 114/2025/QH15 (passed by the National Assembly on 10/12/2025, effective 01/07/2026) is the new Disease Prevention Law replacing the 2007 Law on Prevention and Control of Infectious Diseases (Law 03/2007/QH12). The new law extends scope to non-communicable diseases and requires public-health information systems to be connected and to share data within the national health database. Specifically for immunization, it codifies the duty to report immunization activity per Ministry of Health (MoH) guidance — giving a legal basis to compel every immunization site to update data into the shared system.

Law 114/2025 sits alongside Decision 1332/QĐ-BYT on the personal health record (PHR) module within VNeID, Circular 13/2025/TT-BYT on electronic medical records (EMR, effective 21/07/2025), and Decision 2780/QĐ-BYT dated 29/08/2025 on the Expanded Program on Immunization plan for 2026-2028. Together these three documents define the technical context: immunization data must be digitized, tied to the personal identification number, digitally signed per regulation, and pushed into the citizen's individual vaccination record on VNeID.

2. The problem the sector faces today

Ask a simple question — "has this baby finished her 5-in-1 series?" — and the answer too often depends on a creased pink card in the mother's handbag. Four recurring issues:

  • Paper vaccination cards get lost or torn, and cannot be retrieved remotely when the family moves.
  • Higher-tier clinicians can't pull a patient's history from lower-tier facilities, leading to duplicate doses or missed ones.
  • Surveillance reporting lags 1-3 months because aggregation from facility level up to provincial Centers for Disease Control and the MoH is still manual.
  • The COVID-19 pandemic exposed this weakness: vaccination certificate verification had to be hastily built on a separate platform that never integrated with the existing TCMR system.

FHIR R4 doesn't invent a new solution; it standardizes how data flows between systems. When immunization sites, provincial data warehouses, the national gateway, and VNeID all speak the same "language" — the Immunization resource with the same minimum field set — a life-long immunization record becomes feasible.

3. FHIR data architecture for immunization

The reference model has four layers, with FHIR as the interoperability layer between systems:

[Immunization site — commune health station, hospital, private clinic]
   ↓ creates Immunization, signs digitally per Decree 137/2024
[Provincial FHIR server — health data warehouse]
   ↓ aggregates, reconciles by CCCD (national ID number)
[National data gateway — Ministry of Health / Department of Preventive Medicine]
   ↓ scheduled and ad-hoc reports
[Surveillance dashboard + WHO/Gavi reports]

   ↓ pushes individual record
[VNeID — personal health record / vaccination passbook]

The "provincial FHIR server" layer doesn't have to be built from scratch — it can be a module inside the HIS, a FHIR façade in front of legacy databases, or a shared service operated by the Department of Health. The critical constraint is that every system pushing data in must conform to the VNCoreImmunization profile, so semantics stay consistent during aggregation.

4. The three core resources

4.1. Immunization — the administered dose

The Immunization resource records a dose given (or a documented reason it was not given). VN Core marks the following elements Must Support: vaccineCode (Vietnamese vaccine type code mandatory, ATC recommended), patient, occurrenceDateTime, lotNumber, performer, protocolApplied (the dose series). Example of the second 5-in-1 dose in TCMR:

{
  "resourceType": "Immunization",
  "status": "completed",
  "vaccineCode": {
    "coding": [
      {
        "system": "http://fhir.hl7.org.vn/core/CodeSystem/vn-vaccine-type-cs",
        "code": "dpt",
        "display": "Bạch hầu-Ho gà-Uốn ván (DPT-VGB-Hib 5in1)"
      },
      {
        "system": "http://www.whocc.no/atc",
        "code": "J07CA09",
        "display": "Diphtheria-Haemophilus influenzae B-pertussis-poliomyelitis-tetanus-hepatitis B"
      }
    ],
    "text": "Vaccine 5in1 (DPT-VGB-Hib) — TCMR"
  },
  "patient": { "reference": "Patient/baby-001" },
  "encounter": { "reference": "Encounter/imm-enc-001" },
  "occurrenceDateTime": "2026-09-15T09:30:00+07:00",
  "primarySource": true,
  "location": { "reference": "Location/tyt-phuong-vinh-tuy" },
  "manufacturer": { "reference": "Organization/polyvac" },
  "lotNumber": "L2026-0915-A",
  "expirationDate": "2027-12-31",
  "site": {
    "coding": [
      { "system": "http://terminology.hl7.org/CodeSystem/v3-ActSite", "code": "LT", "display": "Left thigh" }
    ]
  },
  "route": {
    "coding": [
      { "system": "http://terminology.hl7.org/CodeSystem/v3-RouteOfAdministration", "code": "IM", "display": "Intramuscular" }
    ]
  },
  "doseQuantity": { "value": 0.5, "unit": "mL", "system": "http://unitsofmeasure.org", "code": "mL" },
  "performer": [
    { "actor": { "reference": "Practitioner/dd-le-thi-hoa" } }
  ],
  "protocolApplied": [
    {
      "series": "TCMR Quốc gia — 5in1",
      "doseNumberPositiveInt": 2,
      "seriesDosesPositiveInt": 3,
      "targetDisease": [
        { "coding": [{ "system": "http://fhir.hl7.org.vn/core/CodeSystem/vn-vaccine-type-cs", "code": "diphtheria", "display": "Bạch hầu" }] },
        { "coding": [{ "system": "http://fhir.hl7.org.vn/core/CodeSystem/vn-vaccine-type-cs", "code": "pertussis", "display": "Ho gà" }] },
        { "coding": [{ "system": "http://fhir.hl7.org.vn/core/CodeSystem/vn-vaccine-type-cs", "code": "tetanus", "display": "Uốn ván" }] },
        { "coding": [{ "system": "http://fhir.hl7.org.vn/core/CodeSystem/vn-vaccine-type-cs", "code": "hep-b", "display": "Viêm gan B" }] },
        { "coding": [{ "system": "http://fhir.hl7.org.vn/core/CodeSystem/vn-vaccine-type-cs", "code": "hib", "display": "Hib" }] }
      ]
    }
  ]
}

4.2. ImmunizationRecommendation — next-dose forecast

The ImmunizationRecommendation resource carries the output of a rule engine that runs over the TCMR schedule and the patient's dose history. Each recommendation entry specifies the vaccine, target disease, dose number in series, and the recommended timing window.

{
  "resourceType": "ImmunizationRecommendation",
  "patient": { "reference": "Patient/baby-001" },
  "date": "2026-09-15",
  "recommendation": [
    {
      "vaccineCode": [
        {
          "coding": [
            { "system": "http://fhir.hl7.org.vn/core/CodeSystem/vn-vaccine-type-cs", "code": "dpt", "display": "DPT-VGB-Hib (5in1)" }
          ]
        }
      ],
      "targetDisease": {
        "coding": [
          { "system": "http://fhir.hl7.org.vn/core/CodeSystem/vn-vaccine-type-cs", "code": "diphtheria", "display": "Bạch hầu" }
        ]
      },
      "forecastStatus": {
        "coding": [
          { "system": "http://terminology.hl7.org/CodeSystem/immunization-recommendation-status", "code": "due", "display": "Due" }
        ]
      },
      "doseNumberPositiveInt": 3,
      "seriesDosesPositiveInt": 3,
      "dateCriterion": [
        {
          "code": {
            "coding": [
              { "system": "http://loinc.org", "code": "30981-5", "display": "Earliest date to give" }
            ]
          },
          "value": "2026-10-15"
        },
        {
          "code": {
            "coding": [
              { "system": "http://loinc.org", "code": "30980-7", "display": "Date vaccine due" }
            ]
          },
          "value": "2026-10-30"
        }
      ]
    }
  ]
}

4.3. ImmunizationEvaluation — dose validity

After a dose is administered, the system needs to determine whether it was valid (right age, sufficient interval since the prior dose, correct vaccine for the target disease, and so on). That's the role of ImmunizationEvaluation:

{
  "resourceType": "ImmunizationEvaluation",
  "status": "completed",
  "patient": { "reference": "Patient/baby-001" },
  "date": "2026-09-15",
  "immunizationEvent": { "reference": "Immunization/imm-001" },
  "targetDisease": {
    "coding": [
      { "system": "http://fhir.hl7.org.vn/core/CodeSystem/vn-vaccine-type-cs", "code": "pertussis", "display": "Ho gà" }
    ]
  },
  "doseStatus": {
    "coding": [
      { "system": "http://terminology.hl7.org/CodeSystem/immunization-evaluation-dose-status", "code": "valid", "display": "Valid" }
    ]
  },
  "doseNumberPositiveInt": 2,
  "seriesDosesPositiveInt": 3
}

When doseStatus returns valid, the system advances the dose series and recomputes the next ImmunizationRecommendation. If invalid (for example, given before the minimum interval), the dose doesn't count and the child must be revaccinated.

5. Vaccine coding — vn-vaccine-type-cs and ATC

VN Core recommends every vaccineCode carry at least two codings:

  • Vaccine type code by target disease — CodeSystem http://fhir.hl7.org.vn/core/CodeSystem/vn-vaccine-type-cs. This list is mandatory in the VNCoreImmunization profile and ships with 25 initial codes (BCG, hepatitis B, DPT, polio, Hib, measles, rubella, measles-rubella, Japanese encephalitis, rotavirus, pneumococcal, HPV, tetanus, influenza, rabies, varicella, COVID-19, ...).
  • WHO ATC — CodeSystem http://www.whocc.no/atc. Used for international interoperability at the pharmaceutical product level. For example: J07CA09 for the 5-in-1 vaccine (DTP-Hib-Polio-HepB), J07AM01 for tetanus vaccine, J07BC01 for monovalent hepatitis B. When using ATC, the combination code must match the actual vaccine — never assign J07AM01 (tetanus) to a 5-in-1 vial.

Beyond coding, three attributes — lotNumber, expirationDate, and manufacturer — are critical for traceability when a vaccine lot incident occurs. The system should warn three months before expiration and block use of expired lots at the point of care.

6. End-to-end workflow — newborn through end of pediatric series

  1. Patient registration. When a baby is born, the facility creates a Patient resource and links the electronic birth certificate with the Ministry of Public Security to issue the 12-digit personal identification number (PIN). That number goes into the identifier slice cccd.
  2. Pre-load ImmunizationRecommendation. Right after Patient creation, the engine pre-generates a life-long immunization schedule per the National TCMR plan.
  3. Reminders. 7-14 days before each scheduled dose, the system pushes a notification via VNeID or SMS to the parents — listing the vaccine name, the time window, and a suggested location.
  4. Verify at the point of care. The nurse scans the QR code on VNeID or types the CCCD to load the current Patient + Recommendation; checks the vaccine, lot, expiration date, and contraindications (via AllergyIntolerance).
  5. Administer and digitally sign. Right after the injection, the system creates an Immunization resource with status = completed and applies the practitioner's digital signature per Decree 137/2024/NĐ-CP.
  6. Push to the national gateway. The Bundle containing the Immunization is POSTed to the provincial FHIR server, then aggregated to the national data gateway.
  7. Auto-evaluate. The engine generates an ImmunizationEvaluation automatically — if valid, the dose is marked complete and the next Recommendation is computed.
  8. Sync to VNeID. The record propagates to the baby's personal health record on VNeID, visible to parents within minutes.

Steps 6-8 are "reference model — pending official spec": the VNeID push API for immunization is still being finalized. When the spec lands, this Bundle may need to add Composition and Provenance to satisfy the format requirements.

7. National TCMR schedule 2026 and vaccine codes

The table below reflects the TCMR schedule per Decision 2780/QĐ-BYT for 2026-2028, mapped to codes in the vn-vaccine-type-cs CodeSystem so that engines can query directly:

Vaccine vn-vaccine-type-cs code Age Doses
Tuberculosis (BCG)bcgNewborn1
Hepatitis B birth dosehep-bWithin 24h of birth1 (plus the dose inside 5-in-1)
5-in-1 (DPT-HepB-Hib)dpt2-3-4 months3
Oral polio (OPV)polio2-3-4 months3
Inactivated polio (IPV)polio5 months1
Measles monovalentmeasles9 months1
Measles-Rubellameasles-rubella18 months1
DPT boosterdpt18 months1
Japanese encephalitis Bje12-18 months3
Pneumococcal (new from 2026)pneumococcal2-4-6 months3
HPV (new from 2026)hpvGirls 9-14 years2

The ImmunizationRecommendation engine reads this table as reference data, combines it with the patient's Immunization history, and computes a catch-up schedule when a child is late or has missed doses.

8. The vaccination passbook on VNeID

Decision 1332/QĐ-BYT lays the groundwork for the personal health record (PHR) on VNeID, in which the vaccination passbook is a key module. The recommended data structure is a Bundle document containing:

Bundle (type = document)
├── Composition (title = "Vaccination passbook — patient name")
├── Patient (the subject, with CCCD/personal ID number)
├── Immunization × N (every dose given, in chronological order)
├── ImmunizationRecommendation (upcoming doses with timing)
└── Provenance (digital signature of the issuing facility)

The citizen can share this Bundle through VNeID when traveling abroad, studying overseas, or seeking care outside Vietnam. For international compatibility, the IPS (International Patient Summary) profile can serve as a condensed version — currently a "reference model — pending official spec" from HL7 Vietnam and the Ministry of Health.

9. Surveillance reporting and multi-source data

Once every immunization site pushes standardized Immunization resources into the national gateway, the surveillance dashboard can query with standard FHIR Search syntax:

GET /Immunization?vaccine-code=http://fhir.hl7.org.vn/core/CodeSystem/vn-vaccine-type-cs|measles
   &date=ge2026-09-01&date=le2026-09-30
   &_count=0
→ Bundle (searchset) — total = number of measles doses given in September 2026

The dashboard can group by province/commune, age cohort, or vaccine type to spot under-coverage areas. Periodic reports to WHO, UNICEF, and Gavi can be automated through the API rather than aggregated manually in Excel. Note: any data crossing Vietnam's borders must comply with Law 91/2025/QH15 (Personal Data Protection Law) and Decree 356/2025/NĐ-CP — in particular the cross-border transfer impact assessment dossier requirement.

10. ADR/AEFI — adverse events following immunization

Adverse Events Following Immunization (AEFI) are recorded via the AdverseEvent resource, linked to the originating Immunization through suspectEntity.instance. FHIR R4 requires outcome to use one of the official codes: resolved, recovering, ongoing, resolvedWithSequelae, fatal, unknown. The code recovered is invalid in R4 — many examples on the web use it incorrectly.

{
  "resourceType": "AdverseEvent",
  "actuality": "actual",
  "category": [
    {
      "coding": [
        { "system": "http://terminology.hl7.org/CodeSystem/adverse-event-category", "code": "product-use-error", "display": "Product Use Error" }
      ],
      "text": "Adverse Event Following Immunization (AEFI)"
    }
  ],
  "subject": { "reference": "Patient/baby-001" },
  "date": "2026-09-15T18:00:00+07:00",
  "suspectEntity": [
    {
      "instance": { "reference": "Immunization/imm-001" }
    }
  ],
  "outcome": {
    "coding": [
      { "system": "http://hl7.org/fhir/adverse-event-outcome", "code": "resolved", "display": "Resolved" }
    ]
  },
  "seriousness": {
    "coding": [
      { "system": "http://terminology.hl7.org/CodeSystem/adverse-event-seriousness", "code": "Non-serious", "display": "Non-serious" }
    ]
  }
}

Operational warning

Every serious AEFI (anaphylaxis, death, severe sequelae) must be reported to the Drug Administration of Vietnam within 24-48 hours under pharmacovigilance rules, and simultaneously to WHO's VigiBase. The system should provide a priority channel for AEFIs flagged with seriousness = serious.

11. FAQ

11.1. How do TCMR and private-pay immunization differ in FHIR?

They both use the Immunization resource. The distinction sits in the type code from vn-vaccine-type-cs (the class attribute distinguishes tcmr from dich-vu) and in the payer source, typically captured via the linked Encounter or Coverage.

11.2. What about a newborn who doesn't have a CCCD yet?

Per the VNCorePatient profile guidance, children born from 2016 onward are issued the personal identification number at birth registration — this number goes into the identifier slice cccd. In edge cases where the number isn't yet issued, use the identifier slice gks (birth certificate number) as a temporary identifier alongside data-absent-reason for the CCCD slice. Parent information belongs in RelatedPerson with the guardian role — never stuffed into Patient.identifier.

11.3. How do we check for allergies before vaccinating?

Integrate the AllergyIntolerance resource into the verification screen. Before the "administer" button is pressed, the system queries the patient's AllergyIntolerance and cross-references vaccine ingredients — especially for egg allergy (influenza, measles vaccines) and latex allergy.

11.4. Is the COVID-19 vaccine part of TCMR?

As of today, COVID-19 (code covid-19) is classified as chien-dich (campaign) in vn-vaccine-type-cs, not tcmr. The Ministry of Health may reclassify it later if the epidemiological picture changes.

11.5. Is real-time data required?

Law 114/2025 doesn't specify a "real-time" threshold. The actual requirement is that data be connected and shared per MoH rules — which in practice ranges from a few minutes to end-of-day depending on the report type. The system should be designed to sync within minutes, leaving headroom for ad-hoc surveillance queries.

12. References