M1 ABHA API
ABHA integration through one REST API
Every ABHA flow NHA certifies as Milestone 1, as ordinary REST calls: create an account, prove an existing one, print the card, and write the result onto your own patient record. This is the developer’s view — for what an ABHA is and why a citizen holds one, read the ABHA and Ayushman Bharat overview.
01 The surface
What an ABHA integration calls
Six groups of endpoints. All but Scan & Share authenticate with your credential alone, so one integration serves every facility on your account.
- Create
-
Enrol a new ABHA
Aadhaar OTP is the common case. Mobile OTP creates an ABHA address, and the number follows only after KYC. Demo Auth and biometric creation exist for patients without a phone, each behind an NHA permission.
- Verify
-
Log in to an existing ABHA
By ABHA number, mobile or Aadhaar, with one OTP. When a mobile carries several ABHAs the session stops at
account_pendingand you name the one the patient means. - Find
-
Find ABHA, sending nothing
A lookup that spends no OTP and asks for no consent. It returns masked hits for the operator to confirm, each with an index that a biometric capture can then prove.
- Read
-
Profile, card and QR
A normalised profile, and the ABHA card and QR as bytes the front desk can print without a second round trip. They use the citizen’s own token, so fetch them while the session is alive.
- Link
-
Write it onto your patient
Name your facility and MRN when a flow starts and the verified ABHA lands on that patient when it completes — or link the session afterwards.
- Counter
-
Scan & Share
The patient scans a counter QR in their own ABHA app. Their profile arrives with a token number, and your desk looks the arrival up by the token the phone is showing.
02 At the counter
Six patients, six routes
Design for the nine o’clock OPD line: one operator, and patients who did not all bring a charged phone. Only the routes that need the phone in hand spend an OTP.
| The patient | Route | Calls | OTP |
|---|---|---|---|
| Has an ABHA app on their phone | Scan & Share | GET /v1/profile-shares |
No |
| Knows their ABHA or Aadhaar, phone at home | Find ABHA, then fingerprint or iris | POST /v1/abha/search, then …/biometric |
No |
| Has an ABHA and their phone | Login by OTP | POST /v1/abha/login, then …/verify |
Yes |
| No ABHA, has their phone | Aadhaar or mobile enrolment | POST /v1/abha/enrolment/aadhaar |
Yes, once |
| No ABHA, no phone | Demo Auth enrolment | POST /v1/abha/enrolment/demo-auth |
No — needs a BENEFIT-NAME |
| No ABHA, no phone, certified scanner | Biometric enrolment | POST /v1/abha/enrolment/biometric |
No — needs NHA to enable it |
Missing from the table: checking an existing ABHA against the
demographics you already hold. ABDM v3 has no such call. The
write-ups that describe one are describing HealthID v1’s
confirmWithDemographics, which was retired. Do not promise it
to a hospital.
03 Enrolment
Creating an ABHA from Aadhaar
Two OTP-bearing calls and an address choice. The session carries the state between them, so the counter screen only ever holds a session id.
-
Start with the Aadhaar number
Send your facility and MRN with it if the desk already has them. The number is RSA-sealed with ABDM’s public key (OAEP with SHA-1, the padding ABDM mandates) before it leaves the connector, and never reaches a database or a log.
-
Verify the OTP
UIDAI texts the Aadhaar-registered mobile. A different mobile for the ABHA needs its own OTP before it counts as verified — and an unverified number cannot receive the linking SMS that M2 sends.
-
Choose an address
The session waits at
address_pending. List the suggestions, let the citizen pick, post the choice. A new account can have no address yet, so never read the first element of the list blind. -
Receive the webhook
abha.createdarrives signed. If you named a patient at the start, the ABHA has been written onto that record.
# start — sealed here, never stored
POST /v1/abha/enrolment/aadhaar
{
"patient_reference": "MRN-1001",
"aadhaar_number": "XXXXXXXX9012"
}
← 201 Created
{
"id": "7b21e0c4-…",
"flow": "enrol_aadhaar",
"status": "otp_sent"
}
# verify
POST /v1/abha/enrolment/{session_id}/verify
{
"otp": "******",
"mobile": "98XXXXXX10"
}
← 200 OK
{
"status": "address_pending"
}
# then pick the address
GET /v1/abha/enrolment/{session_id}/addresses
POST /v1/abha/enrolment/{session_id}/address
04 No phone
Find ABHA, then prove it
For the patient who has an ABHA but not the phone it texts. The search proves nothing; the capture that follows proves everything.
-
Search by mobile
No OTP is sent and nothing reaches the citizen. An empty
resultslist is an answer, not an error: they may not have an ABHA yet. An Aadhaar variant is accepted too, though NHA’s guide documents only the mobile body. -
Confirm the person, not the number
The operator reads back the name, gender and masked number, and picks a hit by its
index— which means something only inside this session. Check itsauth_methodsfirst: an account withoutAADHAAR_BIOwill refuse a capture. -
Capture on a certified device
Name the index, then submit the PID block from a UIDAI-certified fingerprint or iris device. It travels exactly as the device encrypted it for UIDAI, and is never logged or stored.
-
Now the number is real
The completed verification returns the profile with the full ABHA number, ready to write onto the patient. Verifying an existing ABHA this way needs no extra NHA entitlement.
POST /v1/abha/search
{
"mobile": "98XXXXXX10"
}
← 201 Created
{
"id": "3fa85f64-…",
"status": "search_results",
"results": [
{
"index": 0,
"abha_number": "91-5259-8743-XXXX",
"masked": true,
"name": "Asha Devi",
"gender": "F",
"kyc_verified": true,
"auth_methods": ["AADHAAR_OTP", "AADHAAR_BIO"]
}
]
}
↑ masked: never write this onto a patient
# name the hit
POST /v1/abha/search/{session_id}/biometric
{
"method": "bio",
"index": 0
}
# send the capture from the RD device
POST /v1/abha/login/{session_id}/biometric/verify
05 Failure modes
Where M1 integrations break
Each of these looks like a bug in your code and is not. Two are handled below the API you call; the third is a set of permissions only NHA can grant.
- Masks
-
Storing a masked ABHA number
Find ABHA returns numbers like
91-5259-8743-XXXX. Written onto a patient, that string looks exactly like a linked ABHA and matches the citizen nowhere. Its digits are a prefix of the real number, so even comparing against it reports “a different ABHA” for the citizen’s own record. - Tokens
-
Using a T-token as an X-token
A mobile login returns a short-lived transaction token while an ABHA still has to be chosen; an Aadhaar or ABHA-number login returns the citizen’s own X-token. Send the wrong one to a profile read and ABDM answers with a 401 that says nothing about why.
- Permissions
-
Assuming every route is switched on
Biometric ABHA creation is off by default and needs NHA to enable it for your client id. Demo Auth needs a
BENEFIT-NAMEthat NHA issues per integrator for a named programme, and no default can be invented for it. Driving-licence enrolment is implemented, but NHA does not enable it in the sandbox.
06Linking the ABHA to your patient record
An ABHA on its own is not an integration; an ABHA on your MRN is. Pass
patient_reference on any start request — the
hospital is the one your key serves, so there is nothing else to name
— and the ABHA number, address and ABDM’s demographics are
written onto that patient when the flow completes.
Demographics your system already holds are not overwritten.
A desk that registers first and verifies later calls
POST /v1/abha/sessions/{session_id}/patient instead, any
time before the session expires: 201 when it created the
patient, 200 when it updated one.
Care contexts in M2 are linked to that ABHA, so this is the step HIP integration builds on.
07Scan & Share at the counter
Fetch one QR payload per counter from
GET /v1/facility/scan-share-qr?counter_code=OPD-2
and render it yourself. The patient scans it in their ABHA app, which
authenticates them; ABDM pushes their profile, the connector answers
with a token number their phone displays, and a
patient.profile_shared webhook fires. The operator enters
the token in
GET /v1/profile-shares?token_number=104
and registers from the demographics that come back. Drop
token_number for the day’s queue in arrival order.
Two things to know. NHA specifies no token-board API — its playbook leaves token generation and queue display to the HMS — so the token counter, its daily reset and the queue are this connector’s own surface, not ABDM’s. And the facility must exist in HFR and be linked to the bridge before ABDM will deliver a share, which the HFR integration page covers.
08Getting M1 certified
ABHA is certified as Milestone 1, and the integration is typically a few weeks of it. After self-testing against the NHA sandbox, an NHA-empanelled agency runs functional testing against the M1 test cases, and a CERT-In empanelled auditor performs the WASA security audit — 5–8 weeks including remediation, ending in a Safe-to-Host certificate — before NHA’s own review of 2–4 weeks.
Test cases with a user-interface half — consent text, a resend timer, the card on screen — are demonstrated in your own software. What comes after M1 is in the milestone guide, rollout at a facility in ABDM for hospitals, and what ABDM is covers the network itself.
Run an enrolment against the sandbox today
Sandbox keys are issued on signup. Enrol a sandbox test Aadhaar, link
it to a test MRN, and watch abha.created arrive.
FAQ Common questions