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 provides three complementary resources: Immunization records doses given, ImmunizationRecommendation forecasts a next dose, and ImmunizationEvaluation assesses dose validity; a complete workflow also references Patient and related Resources.
  • 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.
  • VNCoreImmunization.vaccineCode.coding requires at least one coding from vn-vaccine-type-cs; a CVX coding is optional. The profile does not define a mandatory ATC slice.
  • The Patient → recommendation → administration → evaluation → sharing flow is an illustrative architecture. Integration channels, service levels, signing scope, and data recipients must be established by an authoritative specification or deployment agreement.
  • 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. Data flows, frequency, endpoints, and actor responsibilities must come from applicable implementing instruments or deployment agreements; this page does not infer a duty to update any particular API.

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 provide policy context for digitization, identity, and immunization-data sharing. Identity linkage, electronic signing, and VNeID synchronization apply only within the scope and conditions of the relevant instrument, official specification, and approved workflow.

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 may be delayed or distorted where manual aggregation remains; latency should be measured for each reporting flow and data period.
  • Experience from COVID-19 shows the need to test linkage among certificates, identity, and immunization history across platforms; this page does not assume that every existing system is either integrated or disconnected.

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 only where the workflow has an applicable basis
[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]

   ↓ shares an individual record when an endpoint/agreement permits
[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). vaccineCode is required and Must Support; its slicing requires at least one vn-vaccine-type-cs coding, while a CVX coding is optional. VN Core also marks patient, occurrenceDateTime, lotNumber, performer, protocolApplied (the dose series) as Must Support; Must Support does not make every optional element mandatory. 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"
      },
      {
        "system": "http://hl7.org/fhir/sid/cvx",
        "code": "102",
        "display": "DTP-Hib-Hep 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": "Bạch hầu-Ho gà-Uốn ván" }
          ]
        }
      ],
      "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 CVX

The VNCoreImmunization profile uses open slicing on Coding.system:

  • 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, ...).
  • CVX — CodeSystem http://hl7.org/fhir/sid/cvx, slice cvx 0..*. This coding is optional and should be sent only when a suitable CVX mapping exists for the actual vaccine type or product. Open slicing permits other codings under a deployment contract, but VN Core does not require ATC.

Beyond coding, three attributes — lotNumber, expirationDate, and manufacturer — are critical for traceability when a vaccine lot incident occurs. The expiry-warning window and blocking rules must follow the deployment's approved product, medication, and clinical-safety policies.

6. Illustrative workflow — newborn through end of pediatric series

The sequence below is an illustrative business architecture, not a service-level commitment or a duty automatically imposed on every system by VN Core or the cited instruments.

  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. If the program offers reminders, the operator configures an appropriate window (for example, 7-14 days) and an approved channel. This is a deployment parameter, not a VN Core requirement.
  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. Record the dose. After administration, the system creates an Immunization resource with status = completed. Apply an electronic signature only where an applicable instrument, contract, or approved workflow requires one, with the signing scope and verification mechanism defined separately.
  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. Share with a citizen application. When an official endpoint and agreement exist, the record may be synchronized to VNeID or another channel; display latency is a service SLA, not an assumed “within minutes” commitment.

Steps 6-8 are a reference model because public API documentation is not sufficient to confirm the endpoint, payload, or SLA. Add Composition, Provenance, or a signature only when an official specification or deployment contract requires it; VN Core does not make them mandatory by default.

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. Until a public exchange specification confirms the immunization structure, a Bundle document can be considered as an illustrative architecture:

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 (optional, when source history or a signature is needed)

VNeID receipt or sharing of this Bundle remains an architectural hypothesis until the competent authority publishes the corresponding API contract. IPS (International Patient Summary) can be evaluated separately for cross-border exchange, but Decision 1332/QĐ-BYT does not by itself prescribe it as an immunization format.

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

The recipient, deadline, and form for an AEFI report depend on event classification and the applicable immunization-safety or pharmacovigilance rules. Do not configure “24-48 hours to the Drug Administration of Vietnam” or “simultaneous VigiBase submission” as defaults without authority and a basis for that specific flow. A system may prioritize serious events under an approved procedure.

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. Each program must derive its service level from implementing guidance, the API agreement, and an approved surveillance need; “within minutes” and “end of day” are not default duties.

12. References

  • Law 114/2025/QH15 — Disease Prevention Law (issued 10/12/2025, effective 01/07/2026) — replaces the 2007 Law on Prevention and Control of Infectious Diseases (Law 03/2007/QH12).
  • Decision 1332/QĐ-BYT — Personal health record on VNeID — corpus code QD-1332-VNeID in legal framework.
  • Circular 13/2025/TT-BYT — Electronic medical records (effective 21/07/2025) — corpus code TT-13-2025.
  • Decision 2780/QĐ-BYT (29/08/2025) — Expanded Program on Immunization plan for 2026-2028.
  • Decree 137/2024/NĐ-CP — electronic transactions; assess its scope when a specific workflow requires an electronic signature.
  • FHIR R4 — Immunization, ImmunizationRecommendation, ImmunizationEvaluation, AdverseEvent.
  • CDC — CVX code table (optional international coding in the profile).
  • VN Core CodeSystem: http://fhir.hl7.org.vn/core/CodeSystem/vn-vaccine-type-cs — defined in input/fsh/terminology/VNVaccineTypeCS.fsh.