FHIR R4 NRCeS profiles
FHIR R4 bundles to the NRCeS profiles ABDM validates
Every record that moves through ABDM is a FHIR R4 document bundle built to the profiles NRCeS publishes for India. Most hospital software stores medicines as “1-0-1” and test results as a name and a number. Send those as they are, and the connector builds, codes and validates the bundle.
01 Three ways in
Start from whatever your system already holds
Every route ends in the same place: a validated bundle attached to a care context, ready to be released when a patient consents.
- Plain fields
-
What a data-entry operator types
PUT /v1/care-contexts/{id}/recordtakes medicines with dose and frequency, test names with values and units, complaints, diagnoses and vitals, for an OP consultation, a prescription or a lab report. The connector assembles the NRCeS-profiled bundle from them. - A PDF
-
A scanned discharge paper or an outside report
Attach a PDF to a lab report or a consultation, or send it alone as a
HealthDocumentRecord. It is placed where the profile expects it — embedded in the report, or filed as a document reference — and carried once, never twice. - Your bundle
-
If you already build FHIR
PUT /v1/care-contexts/{id}/bundleaccepts a bundle of your own for any of the eight HI types, and runs it through the same validation. Discharge summaries, immunisation, wellness and invoice records go in this way.
02 From fields to FHIR
A lab report, as the LIS already has it
The request is the report as a technician would read it off the screen. The response says what was coded, and how.
-
Create the care context
POST /v1/care-contextswithhi_typeDiagnosticReport. The record’s type must match it, or the call is refused withhi_type_mismatch. -
Send the fields
Values like
11.2or<0.5become quantities; “Positive” stays text. Recognised units are UCUM-coded; anything else is kept as typed. -
Read the coding report
codinglists every item:callerif you sent the code,masterif the connector matched it,noneif it went as text. Enough for “4 of 5 tests coded” on your screen. -
Resend to correct it
A second
PUTreplaces the attached record, so a retry or a corrected report is safe.
PUT /v1/care-contexts/9b0e…/record
{
"hi_type": "DiagnosticReport",
"practitioner": {
"hpr_id": "meera.nair@hpr.abdm",
"name": "Dr Meera Nair"
},
"report_name": "Complete blood count",
"tests": [
{
"name": "Hb",
"value": 11.2,
"unit": "g/dL",
"reference_range": "13-17",
"interpretation": "low"
},
{
"name": "Peripheral smear",
"value": "Normocytic normochromic"
}
],
"conclusion": "Mild anaemia.",
"pdf": {
"data": "JVBERi0xLjcK…"
}
}
← 200 OK
{
"care_context": {
"hi_type": "DiagnosticReport",
…
},
"coding": [
{
"field": "tests[0]",
"source": "master",
"system": "http://loinc.org",
"code": "718-7"
},
{
"field": "tests[1]",
"source": "none",
"code": null
}
]
}
03 Health information types
Eight record types, and the code that says which
The Composition at the head of the bundle declares what the record is with a SNOMED CT code. It has to agree with the HI type the care context was created with; a mismatch is one of the things ABDM rejects on.
| HI type | Composition code | SNOMED CT display | From plain fields |
|---|---|---|---|
| OPConsultation | 371530004 | Clinical consultation report | Yes |
| Prescription | 440545006 | Prescription record | Yes |
| DiagnosticReport | 721981007 | Diagnostic studies report | Yes, lab |
| HealthDocumentRecord | 419891008 | Record artifact | Yes, a PDF |
| DischargeSummary | 373942005 | Discharge summary | Full bundle |
| ImmunizationRecord | 41000179103 | Immunization record | Full bundle |
| WellnessRecord | 419891008 | Record artifact | Full bundle |
| Invoice | — | None: text “Invoice Record” | Full bundle |
Invoice is the trap. The NRCeS InvoiceRecord profile has
no SNOMED CT type code, and code tables that give it
721981007 are borrowing the diagnostic studies report code.
The connector sends the type as text.
04 Validation
Rejected here, not by ABDM weeks later
A bundle that fails at the gateway fails when a clinician somewhere is waiting for it. Every bundle — built by the connector or uploaded by you — is checked for what ABDM actually rejects before it is stored.
- Structure
-
A document, in the right order
A Composition must exist and be the first entry, the bundle must declare its profile in
meta.profile, and the Composition’s code must agree with the declared HI type. - References
-
Nothing points at nothing
Every reference inside the bundle has to resolve to an entry in it, and the subject has to resolve to a patient. A dangling reference is the most common way a hand-built bundle fails.
- Fields
-
Refused, never silently dropped
A field that belongs to another record type is an error, not ignored. A prescriber is required whenever medications or investigations are sent, because NRCeS makes it mandatory. Implausible vitals are refused — which catches a weight in grams or a temperature typed into the pulse box.
-
Actually a PDF, and all of it
The bytes must start with
%PDF-and end with a%%EOFtrailer. That catches a renamed JPEG and an upload truncated in transit, and returnsinvalid_pdfwith the reason.
Errors name the field. Every refusal uses one shape,
{"error": {"code", "message", "details"}}, and
details says which field is wrong — including the ones
that belong to a different record type.
05How codes are assigned
Coded data is better for the patient’s next clinician, but a
wrong code is worse than none. So coding runs in a fixed order.
A code you send always wins, provided it is from a
system that item’s NRCeS profile allows. Otherwise the typed name
is matched against the connector’s verified master, ignoring
case, dots and spacing — so S. Creatinine,
SGPT and F.B.S. all match. There is no fuzzy
matching. Anything left over travels as text, which is valid FHIR.
Some names are left uncoded on purpose. “Sugar”,
“albumin” and “protein” also name urine tests,
so the operator has to pick the specific entry. For an operator
dropdown, GET /v1/terminology/lab-tests?q=hb and
GET /v1/terminology/diagnoses?q=fever search the same
master the matcher uses. Each code in it was checked against the HL7
terminology server and a second source.
06Prescriptions and consultations
A prescription’s dose, frequency and duration are kept word for
word, and the common forms are also structured so a PHR app can render
them: OD, BD, TDS,
1-0-1, HS, SOS; “5
days” or a bare 5; “500 mg” or “1
tablet”. Nobody has to retype a prescription into a
structured form for it to be shared.
An OP consultation is laid out in the sections the NRCeS OPConsultRecord profile defines — complaints, vitals, diagnoses, medications, investigations advised, notes, follow-up and an attached document — each as the resource type the profile expects. A follow-up can be a date or “in 7 days”, since the profile requires a date.
07After the bundle is built
The validated bundle is encrypted at rest and attached to its care context. It goes nowhere until the patient links that care context and consents to share it; then only the bundles the consent covers are selected, encrypted with Fidelius for the one requester and pushed. That half is the HIP integration. For a laboratory the whole of it is usually one call per report — see ABDM for labs — and the complete surface is on the ABDM API page.
Build your first bundle from a lab report
Sandbox credentials are issued on signup. Send one report as plain fields and see which tests come back coded.
FAQ Common questions