The Ayushman Bharat Digital Mission (ABDM) is a government initiative that aims to develop a digital health infrastructure for India. An overview of ABDM can be found here. The ABDM aims to improve the efficiency and transparency of healthcare data transfer between patients, medical institutions, and healthcare service providers. It also allows patients to securely store their medical information and share with others as needed. The National Health Authority (NHA) is implementing Ayushman Bharat Digital Mission (ABDM) to create a digital health ecosystem for the country. ABDM intends to support different healthcare facilities like clinics, diagnostic centers, hospitals, laboratories and pharmacies in adopting the ABDM ecosystem to make available the benefits of digital health for all the citizens of India. In order to make any digital solution ABDM compliant, it has to go through 3 milestones and obtain AND certification.
ABDM Wrapper is created to solve the challenges and issues faced by integrators to bring their systems into ABDM ecosystem. Wrapper aims to abstract complex workflows and algorithms exposing clean and simple interfaces for integrators. Wrapper abstracts implementation of HIP and HIU workflows involved in Milestone 2 and Milestone 3.
Wrapper is a springboot application packaged with mongodb database. Wrapper can be deployed on existing HMIS's / health facility's infrastructure.
There are sets of interfaces which wrapper exposes and the existing services need to invoke them to implement ABDM workflows.
At the same time if HMIS is an HIP, then existing services should expose a set of interfaces which wrapper needs to invoke to get information from health providers.
The callback apis which gateway would be making to wrapper should be behind facility's firewall.
* Skip if ABHA Address already exists.
ABHA Address can be created using:
- Mobile Number
- Aadhaar Number
- E-mail
After creating the ABHA Address, your id should look like "yourAbha@sbx"
There are two ways to get wrapper and related applications running on your system:
Install docker and docker-compose: You can install docker desktop from here to get both.
System Requirements:
Using default docker-compose.yaml, you can bring up wrapper and mongodb services. Using compose-wrapper-mockgateway.yaml, you can bring up wrapper, mongodb and mock gateway services.
This repository provides two other services:
If you need to bring these services up, then you need to install gradle from here
System Requirements:
Recommended RAM: Systems with more than 8 GB RAM
Get Access Token.
curl --location 'https://dev.abdm.gov.in/gateway/v0.5/sessions' \
--header 'Content-Type: application/json' \
--data '{
"clientId": <client id provided>,
"clientSecret": <client secret provided>
}'
Register bridge url
curl --location --request PATCH 'https://dev.abdm.gov.in/gateway/v1/bridges' \
--header 'Authorization: Bearer <your accessToken>' \
--header 'Content-Type: application/json' \
--data '{
"url": <your bridge url>
}'
Check the BRIDGE URL and Facilities
curl --location 'https://dev.abdm.gov.in/gateway/v1/bridges/getServices' \
--header 'Authorization: Bearer your accessToken' \
--header 'X-CM-ID: sbx' \
--data ''
Wrapper API's you can check here
FHIR Module API's you can check here
If the actual ABDM Gateway is up and running and responding properly:
docker-compose up --build
Install on Linux
do have instructions on how to start the service as well.gradle bootrun
In case ABDM sandbox gateway is down or not responding properly, you can use this mock gateway to test out your workflows. The ways to bring up the application are:
gatewayBaseUrl=http://gateway:8090
and comment gatewayBaseUrl=https://dev.abdm.gov.in/gateway
docker-compose -f compose-wrapper-mockgateway.yaml up --build
Install on Linux
do have instructions on how to start the service as well.gatewayBaseUrl=http://gateway:8090
and comment gatewayBaseUrl=https://dev.abdm.gov.in/gateway
gatewayBaseUrl=http://gateway:8090
to gatewayBaseUrl=http://localhost:8090
- url: http://abdm-wrapper:8082
to - url: http://localhost:8082
cd mock-gateway
mvn spring-boot:run
gradle bootrun
Proxy Server Settings:
Testing can be done majorly in 3 parts:
We need to first add patient's details into wrapper's database. There are different ways by which we can do that:
docekr ps
docker exec -it abdm-wrapper_mongodb_1 bash
mongosh
use abdm_wrapper
patients
by running db.createCollection('patients')
db.patients.insert({
"name": "patient's name",
"gender": "M",
"dateOfBirth": "DOB in yyyy-mm-dd",
"patientReference": "patient's reference",
"patientDisplay": "patient's display name",
"patientMobile": "patient's mobile number",
"abhaAddress": "patientAbhaAddress@sbx"
})
patients
collection and a patient entry with the folloing values:
curl --location --request PUT 'localhost:8082/v1/add-patients' \
--header 'Content-Type: application/json' \
--data-raw '[{
"name":"Govada Venu Ajitesh",
"abhaAddress":"govada2704@sbx",
"patientReference":"govada2704",
"gender":"M",
"dateOfBirth":"YYYY-MM-DD",
"patientDisplay": "Govada Venu Ajitesh",
"patientMobile":"Patient mobile"
}]'
gradle bootRun
http://localhost:8081/v1/test-wrapper/upsert-patients
curl --location 'https://dev.abdm.gov.in/gateway/v0.5/sessions' \
--header 'Content-Type: application/json' \
--data '{
"clientId": <client id provided>,
"clientSecret": <client secret provided>
}'
curl --location --request PUT 'https://dev.abdm.gov.in/devservice/v1/bridges/addUpdateServices' \
--header 'Authorization: Bearer <accessToken from previous curl command>' \
--header 'Content-Type: application/json' \
--data '[
{
"id": "Demo_Ajitesh_HIP",
"name": "Demo Ajitesh HIP",
"type": "HIP",
"active": true,
"alias": [
"Demo_Ajitesh_HIP"
]
}
]'
Adding of a patient in a particular facility
POST
Request /v1/profile/share
{
"token":"Wrapper generated token number for the user"
"hipId":"the Facility id"
"requestId": "499a5a4a-7dda-4f20-9b67-e24589627061",
"timestamp": "1970-01-01T00:00:00.000Z",
"intent": {
"type": "string"
},
"location": {
"latitude": "string",
"longitude": "string"
},
"profile": {
"hipCode": "12345 (CounterId)",
"patient": {
"healthId": "<username>@<suffix>",
"healthIdNumber": "1111-1111-1111-11",
"name": "Jane Doe",
"gender": "M",
"address": {
"line": "2nd cross street",
"district": "Chennai",
"state": "TamilNadu",
"pincode": "600301"
},
"yearOfBirth": 2000,
"dayOfBirth": 0,
"monthOfBirth": 0,
"identifiers": [
{
"type": "MOBILE",
"value": "9800083232"
}
]
}
}
}
}
{
"status":"SUCCESS or FAILURE",
"healthId":"Patient's ABHA number which you get in the request call",
"tokenNumber":"token generated from wrapper which you get from /v1/profile/share"
}
It's up to the patient to link the careContexts, the patient can use user-initiatedLinking to link those existing records.
POST
Request to /v1/sms/notify
{
"requestId": "{{$guid}}",
"timestamp": "{{$isoTimestamp}}",
"notification": {
"phoneNo": "92932245554",
"hip": {
"name": "Max Health",
"id": "Predator_HIP"
}
}
}
{
"clientRequestId": "cfde0a5f-ee14-43ff-96db-998772277435",
"code": 0,
"httpStatusCode": "ACCEPTED",
"message": "DeepLinking request has been accepted by gateway"
}
Follow the steps to link care contexts:
When a discover request will land on HIP wrapper, Wrapper will follow this workflow:
It will search for patient in its database based on the logic suggested by ABDM
If it finds patient in its database then it will ask HIP for unlinked care contexts
If it does not find patient in the database, then it will ask HIP to search for patient using the same logic which is recommended by ABDM.
So, HIP needs to implement following apis and expose endpoints for wrapper:
Please note that if HIP has added patients in the wrapper database with adequate details then this api will not be called. But at the same time
any request for non-existent patient can come to wrapper so in which case HIP will have to implement /v1/patient-discover
:
POST
Request:
{
"requestId": "499a5a4a-7dda-4f20-9b67-e24589627061",
"timestamp": "2024-03-11T07:22:52.213Z",
"transactionId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"patient": {
"id": "<patient-id>@<consent-manager-id>",
"verifiedIdentifiers": [
{
"type": "MR",
"value": "+919800083232"
}
],
"unverifiedIdentifiers": [
{
"type": "MR",
"value": "+919800083232"
}
],
"name": "chandler bing",
"gender": "M",
"yearOfBirth": 2000
}
}
{
"abhaAddress": <>,
"name": <>,
"gender": <>,
"dateOfBirth": <>,
"patientReference": <>,
"patientDisplay": <>,
"patientMobile": <>,
"careContexts": [{
"referenceNumber": <>,
"display": <>
}],
}
Now, in the scenario where wrapper has found patient in its database, it will ask HIP for care contexts. HIP shall
send all the care contexts for this patient and wrapper will filter out the care contexts which are unlinked and
send them to gateway as response to discover request. So, HIP should implement /v1/patients-care-contexts
GET
Request: /v1/patients-care-contexts/<patientId>
{
"abhaAddress": <>,
"patientRefernce": <>,
"patientDisplay": <>,
"careContexts": [{
"referenceNumber": <>,
"display": <>
}],
}
On PHR App
Linked Facility
> Click on (+)
-> Search for the facility (name of the registered facility)Fetch Records
.Link Records
/v1/request/otp
POST
Request /v1/request/otp
{
"abhaAddress":"someone@sbx"
"patientReference":"patient id at the facility"
}
{
"requestId":"",
"status":"SUCCESS or FAILURE"
"error":{
"code":1000,
"message":"If the status if failed or occured any error"
}
"linkRefNumber":"Unique id for the otp request"
}
POST
Request /v1/verify/otp
{
"loginHint":"Discovery OTP request"
"requestId":""
"authCode":"The OTP"
"linkRefNumber":"The same unique id while making a request for OTP"
}
{
"requestId":"",
"status":"SUCCESS or FAILURE"
"error":{
"code":1000,
"message":"If the status if failed or occured any error"
}
"linkRefNumber":"Unique id for the otp request"
}
After confirmation, a message will be displayed saying "Successfully Linked".
Follow the steps to link care contexts. The linking can be achieved by two modes:
DEMOGRAPHICS
.
curl --location 'localhost:8082/v1/link-carecontexts' \
--header 'Content-Type: application/json' \
--data-raw '{
"requestId": "3773b790-0d5f-4063-a94b-42f07affab86",
"requesterId":"Predator_HIP",
"abhaAddress":"ajiteshx@sbx",
"authMode":"DEMOGRAPHICS",
"hiTypes": [
"DiagnosticReport",
"DischargeSummary",
"HealthDocumentRecord",
"ImmunizationRecord",
"OPConsultation",
"Prescription",
"WellnessRecord"
],
"patient": {
"careContexts": [
{
"referenceNumber": "visit-ajitesh-3-29/02/2024",
"display": "ajitesh OP-3-on 29/02/2024"
}
]
}
}'
gradle bootRun
curl --location 'http://localhost:8081/v1/test-wrapper/link-carecontexts-demographics'
clientRequestId
in your response.
curl --location 'localhost:8082/v1/link-status/<clientRequestId>'
curl --location http://localhost:8081/v1/test-wrapper/link-status
{
"requestId": "cbf6cd81-88ae-44e8-9ce5-e8c1e5e3b247",
"status": "Care Context(s) were linked",
"error": null
}
MOBILE_OTP
.
curl --location 'localhost:8082/v1/link-carecontexts' \
--header 'Content-Type: application/json' \
--data-raw '{
"requestId": "3773b790-0d5f-4063-a94b-42f07affab86",
"requesterId":"Predator_HIP",
"abhaAddress":"ajiteshx@sbx",
"authMode":"MOBILE_OTP",
"hiTypes": [
"DiagnosticReport",
"DischargeSummary",
"HealthDocumentRecord",
"ImmunizationRecord",
"OPConsultation",
"Prescription",
"WellnessRecord"
],
"patient": {
"careContexts": [
{
"referenceNumber": "visit-ajitesh-3-29/02/2024",
"display": "ajitesh OP-3-on 29/02/2024"
}
]
}
}'
gradle bootRun
curl --location 'http://localhost:8081/v1/test-wrapper/link-carecontexts-mobile-otp'
curl --location 'localhost:8082/v1/verify-otp' \
--header 'Content-Type: application/json' \
--data '{
"loginHint": "hipLinking",
"requestId":"3fec25a3-5e2a-45c0-ac74-3f16e94d7654",
"authCode":"570251"
}'
gradle bootRun
curl --location 'http://localhost:8081/v1/test-wrapper/verify-otp'
clientRequestId
in your response.
curl --location 'localhost:8082/v1/link-status/<clientRequestId>'
curl --location http://localhost:8081/v1/test-wrapper/link-status
{
"requestId": "cbf6cd81-88ae-44e8-9ce5-e8c1e5e3b247",
"status": "Care Context(s) were linked",
"error": null
}
curl --location 'localhost:8082/v1/consent-init' \
--header 'Content-Type: application/json' \
--data-raw '{
"requestId": "71abf992-7005-436c-a231-e42e5cd21d19",
"timestamp": "2024-03-01T21:20:08.701Z",
"consent": {
"purpose": {
"text": "string",
"code": "CAREMGT"
},
"patient": {
"id": "ajiteshx@sbx"
},
"hiu": {
"id": "Predator_HIP"
},
"requester": {
"name": "Dr. Venu AJitesh",
"identifier": {
"type": "REGNO",
"value": "MH1001",
"system": "https://www.mciindia.org"
}
},
"hiTypes": [
"OPConsultation"
],
"permission": {
"accessMode": "VIEW",
"dateRange": {
"from": "2023-02-16T11:43:18.548Z",
"to": "2024-02-15T11:43:18.548Z"
},
"dataEraseAt": "2024-10-16T11:43:18.548Z",
"frequency": {
"unit": "HOUR",
"value": 1,
"repeats": 0
}
}
}
}'
Note: If you are using mock gateway, then you need to provide HIP and care context details as well.
sample-hiu
directory and running gradle bootrun
. clientRequestId
in your response.
Use that clientRequestId's value to fire consent status request using postman:
curl --location 'localhost:8082/v1/consent-status/<clientRequestId>'
curl --location 'http://localhost:8083/v1/test-wrapper/consent-status`
GRANTED
{
"status": "CONSENT_FETCH_ACCEPTED",
"error": null,
"httpStatusCode": "OK",
"initConsentRequest": { //Initiated consent details
"requestId": "1657430f-8639-419d-bdbc-e6ab361c311a",
"timestamp": "2024-04-17T17:53:34.441Z",
"consent": {
"purpose": {
"text": "string",
"code": "CAREMGT",
"refUri": null
},
"patient": {
"id": "g_ajitesh2001@sbx"
},
"hip": null,
"careContexts": null,
"hiu": {
"id": "Demo_Ajitesh_HIP"
},
"requester": {
"name": "Dr. Venu AJitesh",
"identifier": {
"type": "REGNO",
"value": "MH1001",
"system": "https://www.mciindia.org"
}
},
"hiTypes": [
"DiagnosticReport",
"DischargeSummary",
"HealthDocumentRecord",
"ImmunizationRecord",
"OPConsultation",
"Prescription",
"WellnessRecord"
],
"permission": {
"accessMode": "VIEW",
"dateRange": {
"from": "2023-02-16T12:45:18.548Z",
"to": "2024-03-15T11:43:18.548Z"
},
"dataEraseAt": "2024-04-18T16:25:54.941Z",
"frequency": {
"unit": "HOUR",
"value": 1,
"repeats": 0
}
}
}
},
"consentDetails": { // GRANTED consent details
"grantedOn": "2024-04-19T15:33:46.146Z", //deniedOn
"dateRange": {
"from": "2023-02-16T12:45:18.548Z",
"to": "2024-03-15T11:43:18.548Z"
},
"dataEraseAt": "2024-04-18T16:25:54.941Z",
"hiTypes": [
"DiagnosticReport",
"DischargeSummary",
"HealthDocumentRecord",
"ImmunizationRecord",
"OPConsultation",
"Prescription",
"WellnessRecord"
],
"consent": [ // If the consent is EXPIRED it will be in shown in EXPIRED entry.
{
"status": "REVOKED",
"consentArtefacts": [
{
"id": "b480ac3b-c5a7-4ff4-9cc2-366ae94f2a99",
"lastUpdated": "2024-04-17T17:55:09.652Z",
"hipId": "Predator_HIP",
"careContextReference": [
"visit-venu-12/02/2024",
"f233b018-c4e8-4ae3-b5f9-33cbbb0a892c",
"visit-ajitesh2001 3/04/2024"
]
}
]
},
{
"status": "GRANTED",
"consentArtefacts": [
{
"id": "b3395b53-b44c-4670-a65f-fca2802cedc8",
"lastUpdated": "2024-04-17T17:53:51.044Z",
"hipId": "Predator_HIP",
"careContextReference": [
"visit-venu-12/02/2024",
"f233b018-c4e8-4ae3-b5f9-33cbbb0a892c",
"visit-ajitesh2001 3/04/2024"
]
},
{
"id": "7e1ea746-b25c-4087-b2c3-8fd08ab66c58",
"lastUpdated": "2024-04-17T17:53:51.077Z",
"hipId": "Predator_HIP",
"careContextReference": [
"visit-venu-12/02/2024",
"f233b018-c4e8-4ae3-b5f9-33cbbb0a892c",
"visit-ajitesh2001 3/04/2024"
]
},
{
"id": "ae437aff-bbc0-42fa-8588-2745712b0167",
"lastUpdated": "2024-04-17T17:53:51.090Z",
"hipId": "NIT-N-Ajitesh",
"careContextReference": [
"visit-ajitesh2001 1/04/2024"
]
}
]
}
]
}
}
/v1/health-information
to provide health information for a given care context.POST
handler and should accept a request body:
{
"hipId":"The Faility ID"
"careContextsWithPatientReferences": [
{
"patientReference":"APOLLO_12334",
"careContextReference":"OP Visit 20-06-2024"
}
]
}
{
"healthInformationBundle": [
{
"careContextReference": "OP Visit 20-06-2024",
"bundleContent": "Stringified FHIR bundle"
}
]
}
hipBaseUrl=http://host.docker.internal:8081
hipBaseUrl=http://host.docker.internal:<your service port>
hipBaseUrl=http://localhost:8081
hipBaseUrl=http://localhost:<your service port>
getHealthInformationPath=/v1/health-information
getHealthInformationPath=<your path>
You can post health information request in one of the following ways:
curl --location 'localhost:8082/v1/health-information/fetch-records' \
--header 'Content-Type: application/json' \
--data '{
"requestId":"b1427c20-74f8-49b9-becd-7c8790b7860f",
"consentId":"3a7c740e-2fbb-4a8b-8297-30d0bc12c57c"
}'
curl --location 'http://localhost:8083/v1/test-wrapper/health-information'
You can check the status of health information request by:
clientRequestId
in your response.
Use that clientRequestId's value to fire health information status request using postman:
curl --location 'localhost:8082/v1/health-information/status/<clientRequestId>'
curl --location 'http://localhost:8083/v1/test-wrapper/health-information-status`
/health-information/status/<clientRequestId>
{
"status": "ENCRYPTED_HEALTH_INFORMATION_RECEIVED",
"error": null,
"httpStatusCode": "OK",
"decryptedHealthInformationEntries": [
{
"careContextReference": "visit-venu-1-06/02/2024",
"bundleContent": "{\"identifier\":{\"system\":\"http://hip.in\",\"value\":\"1ad6c4a6-b049-11ee-9c45-0050568837bb\"},\"entry\":[{\"resource\":{\"date\":\"2024-01-04T15:36:45+05:30\",\"custodian\":{\"reference\":\"Organization/66\",\"display\":\"Demo "}
}
]
}
This repository offers few helper sample applications:
Sample HIP
Check this page for more details on this.
Sample HIU
Check this page for more details on this.
Check this page to see FAQs.
Check this page to see frequently faced issues.
Check this page to get more details on this.