National Health AuthorityNHA Docs

Command Palette

Search for a command to run...

HPR ID & Authentication

Create a Health Professional Registry ID from Aadhaar, find an existing one, verify the communication mobile, and log in to obtain the HPR user token.

An HPR ID (also called HPID) is a health professional's Aadhaar-verified digital identity — the professional equivalent of an ABHA. Everything else in Milestone 4 depends on it: professional registration writes against it, and facility onboarding is performed by a facility manager who holds one.

This page covers three things:

  1. Create an HPR ID from a verified Aadhaar.
  2. Find an existing HPR ID so you don't create duplicates.
  3. Log in to get the HPR user token (x-hprid-auth / hprToken) that registry writes require.

Prerequisites

All calls below send Authorization: Bearer $SYSTEM_TOKEN (the gateway/system token from M4 setup). Aadhaar number, OTP, mobile, email and password are RSA-encrypted — see Data encryption.

Create an HPR ID

Aadhaar is no longer verified with a generateOtp / verifyOTP OTP pair. Instead you generate a one-time Aadhaar link, open it in the professional's browser, and poll isAuthenticated until they finish. Once authenticated, verifyOTP (now just { txnId }, no OTP) returns the verified demographics.

The flow is: generate the Aadhaar link → open it in the browser → poll for completion → fetch verified demographics → check for an existing account → pick a username → verify the communication mobile (if it differs from the Aadhaar mobile) → create the account.

sequenceDiagram
  participant App as Your app
  participant User as Professional (browser)
  participant HPR as NHPR API
  App->>HPR: POST /aadhaar/generateLink
  HPR-->>App: { txnId, url }
  App->>User: Open url in browser
  User->>User: Aadhaar consent + OTP on ABDM gateway
  loop until true or timeout
      App->>HPR: POST /aadhaar/isAuthenticated { txnId }
      HPR-->>App: false
  end
  App->>HPR: POST /aadhaar/isAuthenticated { txnId }
  HPR-->>App: true
  App->>HPR: POST /v2/registration/aadhaar/verifyOTP { txnId }
  HPR-->>App: verified demographics
  App->>HPR: POST checkHpIdAccountExist / suggestion / createHprIdWithPreVerified

Generate a one-time Aadhaar authentication link scoped for NHPR registration. Returns a txnId and a url; the link is valid for 5 minutes (regenerate if it expires).

POST/aadhaar/generateLink

Returns a txnId and an Aadhaar auth url (host healthidbeta.abdm.gov.in). Carry the txnId through every subsequent step.

cURL
curl -X POST "https://apihspsbx.abdm.gov.in/v4/int/aadhaar/generateLink" \
-H "Authorization: Bearer $SYSTEM_TOKEN" \
-H "Content-Type: application/json" \
-d '{
  "scopes": ["nhpr-register"],
  "source": "NHPR"
}'
Response
{
"txnId": "ece312f8-6e22-4d62-9dc1-...",
"url": "https://healthidbeta.abdm.gov.in/abdm/aadhaar/gateway/auth?link_id=xxxx"
}

Scope & source changed

The correct body is { "scopes": ["nhpr-register"], "source": "NHPR" }. Older integrations that sent ["hpid"] / a custom source will fail against the current NHPR flow.

Redirect the professional to the returned url (host healthidbeta.abdm.gov.in). They give Aadhaar consent and complete the OTP on the ABDM Aadhaar gateway — your app never handles the Aadhaar OTP. Open it in a new tab / in-app browser and keep the txnId to poll against.

Open the Aadhaar link
// url + txnId came from generateLink
window.open(url, "_blank"); // or redirect the current tab

Poll the authentication status

After redirecting, poll isAuthenticated with the txnId on a short interval until it returns true (or you hit a timeout). The response is a bare boolean, not an object.

POST/aadhaar/isAuthenticated

Returns true once the professional has completed Aadhaar verification for this txnId, false otherwise. Poll in a loop with a delay (e.g. every 3s) until true or the 5-min link expires.

cURL
curl -X POST "https://apihspsbx.abdm.gov.in/v4/int/aadhaar/isAuthenticated" \
-H "Authorization: ******" \
-H "Content-Type: application/json" \
-d '{ "txnId": "TXN_ID" }'
Response
false   // keep polling
// ...once the user finishes on the gateway:
true
Poll until authenticated
async function waitForAadhaar(txnId, { intervalMs = 3000, timeoutMs = 300000 } = {}) {
  const deadline = Date.now() + timeoutMs;
  while (Date.now() < deadline) {
    const res = await fetch(`${BASE}/aadhaar/isAuthenticated`, {
      method: "POST",
      headers: { Authorization: SYSTEM_TOKEN, "Content-Type": "application/json" },
      body: JSON.stringify({ txnId }),
    });
    if ((await res.json()) === true) return true; // done
    await new Promise((r) => setTimeout(r, intervalMs));
  }
  throw new Error("Aadhaar link expired or not completed in time");
}

Fetch verified demographics

Once authenticated, exchange the txnId for the KYC demographics. verifyOTP no longer takes an OTP — the OTP was handled in the browser link, so the body is just { txnId }.

POST/v2/registration/aadhaar/verifyOTP

Returns the verified name, masked mobile, photo, DOB and address from Aadhaar KYC. Use these to prefill the create-HPR-ID form.

cURL
curl -X POST "https://apihspsbx.abdm.gov.in/v4/int/v2/registration/aadhaar/verifyOTP" \
-H "Authorization: ******" \
-H "Content-Type: application/json" \
-d '{ "txnId": "TXN_ID" }'
Response
{
"txnId": "563109c8-...",
"mobileNumber": "******5126",
"photo": "<base64>",
"name": "Rahul Sharma",
"gender": "M",
"dob": "1990-01-01",
"address": {
  "house": "12A",
  "street": "MG Road",
  "district": "Bangalore",
  "state": "Karnataka",
  "pincode": "560001"
}
}

verifyOTP is now OTP-free

In the current NHPR flow verifyOTP carries only { "txnId" } — matching the HPID/HPR Swagger. The old generateOtpverifyOTP (with an RSA-encrypted otp) pair has been removed; the Aadhaar OTP is entered by the user on the gateway page instead.

Check for an existing account

Before creating anything, confirm this Aadhaar doesn't already have an HPR ID.

POST/v1/registration/aadhaar/checkHpIdAccountExist

If an account exists it returns the existing HPR ID and demographics with "new": false — stop and route the user to login. See Find an existing HPR ID for the full response.

cURL
curl -X POST "https://apihspsbx.abdm.gov.in/v4/int/v1/registration/aadhaar/checkHpIdAccountExist" \
-H "Authorization: Bearer $SYSTEM_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "txnId": "TXN_ID" }'

Swagger difference

The HPID Swagger models this body as { "txnId", "preverifiedCheck" }. The NHPR PDF sends only { "txnId" }. Both are accepted in the sandbox; add preverifiedCheck if you hit a validation error.

Get HPR ID suggestions

POST/v1/registration/aadhaar/hpid/suggestion

Suggests available username-style HPR IDs from the KYC name. The user picks one (or supplies their own) for createHprIdWithPreVerified.

cURL
curl -X POST "https://apihspsbx.abdm.gov.in/v4/int/v1/registration/aadhaar/hpid/suggestion" \
-H "Authorization: Bearer $SYSTEM_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "txnId": "TXN_ID" }'
Response
{ "hprIdSuggestion": ["asha.kumari", "ashakumari19", "asha.k1990"] }

Verify the communication mobile

Skip this if the professional's mobile matches the Aadhaar-linked number (check with demographicAuthViaMobile). Otherwise send and verify an OTP.

POST/v1/registration/aadhaar/generateMobileOTP

Sends an OTP to the communication mobile.

cURL
curl -X POST "https://apihspsbx.abdm.gov.in/v4/int/v1/registration/aadhaar/generateMobileOTP" \
-H "Authorization: Bearer $SYSTEM_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "mobile": "<RSA-encrypted mobile>", "txnId": "TXN_ID" }'
POST/v1/registration/aadhaar/verifyMobileOTP

Confirms the OTP.

cURL
curl -X POST "https://apihspsbx.abdm.gov.in/v4/int/v1/registration/aadhaar/verifyMobileOTP" \
-H "Authorization: Bearer $SYSTEM_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "otp": "<RSA-encrypted otp>", "txnId": "TXN_ID" }'

Create the HPR ID

Create the account from the pre-verified Aadhaar transaction. email and password must be RSA-encrypted; profilePhoto is a base64 image string.

POST/v2/registration/aadhaar/createHprIdWithPreVerified

Returns the professional's HPR ID (number + username) and an HPR user token.

cURL
curl -X POST "https://apihspsbx.abdm.gov.in/v4/int/v2/registration/aadhaar/createHprIdWithPreVerified" \
-H "Authorization: Bearer $SYSTEM_TOKEN" \
-H "Content-Type: application/json" \
-d '{
  "txnId": "TXN_ID",
  "email": "<RSA-encrypted email>",
  "idType": "hpr_id",
  "domainName": "@hpr.abdm",
  "firstName": "FirstName",
  "middleName": "",
  "lastName": "LastName",
  "password": "<RSA-encrypted password>",
  "profilePhoto": "<base64 image>",
  "hprId": "abcXXXX19",
  "sourceType": "AADHAAR",
  "hpCategoryCode": 6,
  "hpSubCategoryCode": 33,
  "clientId": "",
  "stateCode": "27",
  "districtCode": "472",
  "council": false,
  "role": 3
}'
Response
{
"token": "eyJhbGciOiJSUzUxMiJ9...",
"hprIdNumber": "71-XXXX-XXXX-XXXX",
"hprId": "abcXXXX19@hpr.abdm"
}

Field rules (from the HPR workbook)

hprId (username): at least 4 characters; letters and digits only, plus a dot (.) — no other special characters. Use the suggestion API for at least 3 options.
email: must contain @, a valid domain, and no spaces (encrypt before sending).
password: minimum length 8; at least one uppercase, one lowercase, one number and one special character; no consecutive (conjugate) digits or letters; must not contain the first or last name; the UI's confirm-password must match.

Aadhaar & OTP validation

A valid Aadhaar is a 12-digit number and the Aadhaar OTP is a 6-digit number — both are validated on the ABDM gateway during the link step, so your app no longer collects them directly.

Category, sub-category & role codes

hpCategoryCode, hpSubCategoryCode and role are code values. Categories and roles are small fixed lists; fetch the authoritative sub-category list from the masters API, but the values used by the create-HPR-ID API are:

hpCategoryCodeCategory
1Doctor
2Nurse
6Pharmacist
roleMeaning
1Healthcare Professional
2Facility Manager
3Healthcare Professional and Facility Manager
hpSubCategoryCodeSub-categoryFor
1Modern Medicinedoctor
2Dentistdoctor
3Ayurvedadoctor
4Unanidoctor
5Siddhadoctor
6Homoeopathydoctor
89Sowa-Rigpadoctor
220Yoga and Naturopathydoctor
7Registered Auxiliary Nurse Midwife (RANM)nurse
8Registered Nurse (RN)nurse
9Registered Nurse and Registered Midwife (RN & RM)nurse
10Registered Lady Health Visitor (RLHV)nurse
33Pharmacistpharmacist

Two different sub-category tables

These sub-category codes are the ones for createHprIdWithPreVerified. The professional registration API uses a different sub-category numbering — don't reuse codes across the two APIs. Prefer the masters API in both cases.

Find an existing HPR ID by Aadhaar

Use this to recover a professional's existing HPR ID (and rich demographics) straight from their Aadhaar. It reuses the same link + poll authentication as account creation, then reads the result from checkHpIdAccountExist.

POST/aadhaar/generateLink

Returns a txnId and Aadhaar auth url.

cURL
curl -X POST "https://apihspsbx.abdm.gov.in/v4/int/aadhaar/generateLink" \
-H "Authorization: Bearer $SYSTEM_TOKEN" \
-H "Content-Type: application/json" \
-d '{
  "scopes": ["nhpr-register"],
  "source": "NHPR"
}'
Response
{
"txnId": "143ec756-d312-4a0a-b833-b4202fc394d9",
"url": "https://healthidbeta.abdm.gov.in/abdm/aadhaar/gateway/auth?link_id=xxxx"
}

Redirect the user to url, then poll isAuthenticated with the txnId until it returns true — exactly as in Create an HPR ID. Your app never handles the Aadhaar OTP; it is entered on the ABDM gateway page. When authenticated, read the account straight from checkHpIdAccountExist below.

Check whether an HPR ID exists

POST/v1/registration/aadhaar/checkHpIdAccountExist

"new": false ⇒ this Aadhaar already has an HPR ID (returned in hprId / hprIdNumber). "new": true ⇒ no account yet, proceed to create one.

cURL
curl -X POST "https://apihspsbx.abdm.gov.in/v4/int/v1/registration/aadhaar/checkHpIdAccountExist" \
-H "Authorization: Bearer $SYSTEM_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "txnId": "TXN_ID" }'
Response
{
"token": "eyJhbGciOiJSUzUxMiJ9...",
"hprIdNumber": "71-2665-5777-2713",
"hprId": "anujsharma1990@hpr.abdm",
"categoryId": 100,
"subCategoryId": 85,
"name": "Anuj Sharma",
"firstName": "Anuj",
"lastName": "Sharma",
"gender": "M",
"yearOfBirth": "1990",
"monthOfBirth": "11",
"dayOfBirth": "1",
"stateCode": "9",
"districtCode": "145",
"stateName": "Uttar Pradesh",
"districtName": "Ghaziabad",
"pincode": "201005",
"address": "C/O ... Sahibabad",
"profilePhoto": "<base64>",
"mobile": null,
"new": false
}

Verify the mobile matches Aadhaar

To decide whether a communication mobile needs its own OTP, ask the registry whether the number is the Aadhaar-linked one via a demographic auth.

POST/v2/registration/aadhaar/demographicAuthViaMobile

{ "verified": true } means the mobile is the Aadhaar-linked number and no separate mobile OTP is needed. If it returns false, fall back to the mobile OTP flow.

cURL
curl -X POST "https://apihspsbx.abdm.gov.in/v4/int/v2/registration/aadhaar/demographicAuthViaMobile" \
-H "Authorization: Bearer $SYSTEM_TOKEN" \
-H "Content-Type: application/json" \
-d '{
  "txnId": "TXN_ID",
  "mobileNumber": "<RSA-encrypted mobile>"
}'
Response
{ "verified": true }

Log in to get the HPR user token

Registry writes act on behalf of the professional, so they need that user's HPR token (sent as x-hprid-auth, or hprToken / hpr_token in the body). A returning user obtains it by logging in one of three ways. Every login call still carries your Authorization: Bearer $SYSTEM_TOKEN.

POST/api/v1/auth/authPassword

The simplest path — HPR ID + password returns the user token.

cURL
curl -X POST "https://apihspsbx.abdm.gov.in/v4/int/api/v1/auth/authPassword" \
-H "Authorization: Bearer $SYSTEM_TOKEN" \
-H "Content-Type: application/json" \
-d '{
  "idType": "hpr_id",
  "domainName": "@hpr.abdm",
  "hprId": "username@hpr.abdm",
  "password": "<RSA-encrypted password>"
}'
Response
{
"token": "eyJhbGciOiJSUzUxMiJ9...",
"expiresIn": 1739710198,
"refreshToken": null
}

Where the token goes next

Hold on to this token. Professional register/update and the email/mobile verification APIs take it in the body as hprToken / hpr_token; HFR basic-information and submit-facility take it as the x-hprid-auth header.

Sources

  • ABDM NHPR — Register Professional & Create HPR ID (v2.0, 22-06-2026)
  • ABDM NHPR — Search Facility & Find HPRID by Aadhaar
  • ABDM NHPR — Update Professional (login/auth section)
  • ABDM HPR Test Cases workbook (field validations)
  • HSP Swagger — HPID / HPR OpenAPI specs (ground truth)