Milestone 3 Health Information User
Fetch patient history with consent, as an HIU
ABDM keeps no central copy of anyone’s records. When a clinician needs a patient’s history from another hospital or lab, the only way to it is a consent request the patient approves on their own phone — and then an encrypted transfer straight from the provider that holds it.
01 The flow
Ask, wait, fetch, read
Two calls from your software and two webhooks back. Everything between them — the gateway round trips, the artefact fetch, key exchange and decryption — happens on the connector.
-
Raise the consent request
POST /v1/consentsnames the patient’s ABHA address, the purpose, the HI types, the clinical date range and the clinician asking. It returns 202 atREQUESTED. -
The patient decides
In their PHR app, whenever they get to it. When they do, the connector fetches the signed artefact and sends
consent.granted— orconsent.denied. -
Fetch under the artefact
POST /v1/health-informationwith the granted artefact’s id fromGET /v1/consent-artefacts. You may narrow the date window; it is clamped to the consent and can never widen it. -
Read the records
health_information.receivedfires when the transfer completes.GET /v1/recordslists what arrived;GET /v1/records/{id}/contentreturns the decrypted bundle, and every read is audited.
POST /v1/consents
{
"abha_address": "asha.devi@sbx",
"purpose_code": "CAREMGT",
"hi_types": ["DiagnosticReport", "DischargeSummary"],
"date_from": "2025-09-01T00:00:00+05:30",
"date_to": "2026-09-07T00:00:00+05:30",
"expires_at": "2026-10-07T00:00:00+05:30",
"requester_name": "Dr Ravi Kumar",
"requester_identifier": {
"value": "MH-*****"
}
}
← 202 Accepted
{
"id": "c71d…",
"status": "REQUESTED",
"artefact_count": 0
}
# hours later, when the patient approves
{
"event": "consent.granted",
"data": {
"consent_request_id": "c71d…",
"status": "GRANTED",
"consent_artefact_ids": ["a09e…"]
}
}
02 The request
Design a request a patient will actually approve
The consent screen in the PHR app shows the patient exactly what you asked for. A request that reads as a fishing expedition gets denied, and one that is granted leaves you holding everything it covered.
- Scope
-
The narrowest window, the fewest types
Ask for what answers the clinical question — last year’s lab reports, not every record since birth. A focused request is more likely to be granted, and you inherit an erasure obligation for everything you receive.
- Identity
-
A named clinician, with a registration
requester_nameandrequester_identifierare shown to the patient when they decide, and ABDM rejects a request without the identifier. The type defaults to a registration number on the NMC register. - Two dates
-
Expiry and erasure are different things
expires_atis when the permission lapses;data_erase_atis when you undertake to destroy what you received. It defaults to the expiry, and the connector enforces it — it is not a retention setting you can relax later. - Narrowed
-
The patient can grant less than you asked
A patient may approve a shorter range or fewer types. The artefact carries the terms they actually granted, and those — not your request — are what the transfer is held to.
03Designing for the wait
The step nobody plans for is the gap between asking and hearing. A
patient in the consulting room may approve in a minute; one who was
sent the request at discharge may take days, or never open it. Your
software has to hold a request in REQUESTED without
blocking the clinician, show it on the patient’s chart as
pending, and change state when the answer arrives.
The connector sends consent.request_acknowledged once
ABDM has accepted the request, then one of
consent.granted, consent.denied or, later,
consent.expired. Build on the webhooks. Polling
ABDM for every open request spends a rate limit shared by everyone on
the connector, so POST /v1/consents/{id}/refresh exists
only for a notification that appears to have been lost.
04Receiving records
When you exercise an artefact, the connector mints ephemeral Fidelius
key material for that one request — ECDH over Curve25519 in its
short-Weierstrass form, HKDF-SHA256 and AES-256-GCM — and gives
ABDM a dataPushUrl carrying an unguessable per-request
token. Each HIP holding matching records encrypts its bundles to that
public key and posts them there directly; the gateway only brokers the
request.
Every bundle is decrypted, validated and stored encrypted at rest, tagged with the erase-by date from its artefact. A bundle that fails to decrypt or validate is kept as metadata with its status and validation issues, so you can see that a provider sent something broken rather than wondering why nothing arrived. When the transfer ends, the session’s private key is destroyed.
Records can arrive from several providers and in pages. The request
settles at completed or partially_received,
and health_information.received carries the entries
received and expected so your screen can say which.
05One facility, both roles
Most hospitals are both. The same facility carries a HIP id for the records it creates and an HIU id for the history it requests, and the two run under separate consents: artefacts are stored with a role, so one granted over your records is never mistaken for one granted to you. The provider half is on the HIP integration page, and what the bundles you receive contain is on FHIR integration.
06 Retention and revocation
Records you receive are not yours to keep
An HIU holds a patient’s records on the terms of one consent. When those terms end, so does access — enforced on the server, not left to a policy document.
- Erase-by
-
Purged when the date passes
An hourly sweep destroys every bundle whose artefact has reached its erase-by date, and expires artefacts past their validity so they cannot be exercised again. You receive
health_information.erased; the audit record of the erasure outlives the data. - Revoked
-
Closed at once, not at expiry
A record received legitimately last week is re-checked against its consent every time it is read. After revocation the read is refused immediately, the stored bundles for that artefact are erased, and you receive
consent.revoked. - Metadata
-
Listing is not reading
GET /v1/recordsreturns metadata only. Fetching content is a separate call, logged against your credential, because that is the moment a clinical record is disclosed.
GET /v1/records/7e42…/content
Authorization: Bearer swk_sand_…
← 403 Forbidden
{
"error": {
"code": "consent_no_longer_valid",
"message": "This record can no longer be accessed: The patient has revoked this consent."
}
}
# once the bundle has been erased
← 410 Gone
{
"error": {
"code": "record_erased"
}
}
Two refusals, two messages. “The patient revoked this” and “this consent expired” mean different things to a clinician — one is a conversation, the other a new request — so the reason is returned rather than a bare denial.
07 Certification
What M3 sign-off asks you to show
The HIU scenarios have to be run against the real ABDM sandbox, with records from a different sandbox HIP decrypting on your side.
| Scenario | Runs through | Shown by hand |
|---|---|---|
| Raise a consent request | POST /v1/consents |
The request appearing in the citizen’s PHR app |
| Granted or denied | GET /v1/consent-artefacts; consent.granted, consent.denied |
A grant narrower than the request, and the stored artefact showing it |
| Request and receive data | POST /v1/health-information, GET /v1/records |
Records from another HIP decrypting and rendering |
| Revocation and expiry | consent.revoked, consent.expired; the retention sweep |
Revoke in the PHR app, then the record refusing to open |
Budget roughly 4–12 weeks for M3, plus a security audit by a CERT-In empanelled auditor of typically 5–8 weeks. See the milestone guide for the full path to production.
Raise your first consent request
Sandbox credentials are issued on signup. Request a sandbox patient’s records, approve it in the PHR app, and read the bundle that comes back.
FAQ Common questions