ABDM V3 API Migration Guide (2026): What Changed from v0.5, Full Endpoint Map and Working Patterns
Digital Growth Lead
Writes about healthcare technology, interoperability, and AI-driven transformation across modern care systems.

Migrating an ABDM integration from v0.5 to V3 means moving every gateway call under /api/hiecm with v3 paths, moving your callback routes under /api/v3, sending the V3 headers (REQUEST-ID, TIMESTAMP, X-CM-ID and X-HIP-ID or X-HIU-ID) on every call, getting sessions from gateway/v3/sessions, and moving Milestone 1 to the V3 ABHA APIs. What does not change is the asynchronous pattern: most callbacks, discovery included, are still acknowledged with HTTP 202 and answered later through an on-* endpoint.
This ABDM V3 API migration guide maps what changed, gives the V3 endpoint list we use in production-grade integrations, shows the patterns for sessions, callbacks, discovery, consent and data transfer, and ends with a migration checklist and a test plan for the sandbox. It is written from building V3 integrations for hospital software and comparing them call by call with an integration NHA has already certified. Updated September 2026.
What changed in ABDM V3, in short
| Area | v0.5 | V3 |
|---|---|---|
| Gateway base | https://dev.abdm.gov.in/gateway/v0.5/... | https://dev.abdm.gov.in/api/hiecm/... (sandbox), https://apis.abdm.gov.in/api/hiecm/... (production) |
| Session | /gateway/v0.5/sessions | /api/hiecm/gateway/v3/sessions with grantType: client_credentials |
| Callbacks to you | /v0.5/... paths on your bridge | /api/v3/hip/..., /api/v3/hiu/..., /api/v3/consent/... on your bridge |
| Headers | Authorization and X-CM-ID | Authorization, REQUEST-ID, TIMESTAMP, X-CM-ID, and X-HIP-ID or X-HIU-ID |
| Correlation | Request ID in the body | Body requestId must equal the REQUEST-ID header on on-* replies |
| M1 (ABHA) | Health ID APIs | V3 ABHA APIs on a separate host: abhasbx.abdm.gov.in/abha/api/v3 (sandbox), abha.abdm.gov.in/api/abha/v3 (production) |
| Discovery | Asynchronous | Still asynchronous: 202, then on-discover |
If you would rather have the migration done or reviewed for you, our ABDM integration services team migrates and re-certifies hospital software on V3.
Why V3, and is v0.5 still supported?
V3 is the current ABDM API generation. The official NHA reference implementation, the ABDM wrapper, is built on V3, and new integrations and NHA test cases are written against V3 paths. Treat v0.5 as legacy: plan new work on V3 and migrate existing integrations before you depend on a v0.5 path that may stop answering.
The "discovery is synchronous" myth
Several guides, including an earlier version of this one, describe V3 patient discovery as synchronous, with the patient's care contexts returned in the HTTP response. That is not how the certified integrations we compared against behave. In V3, ABDM calls your /api/v3/hip/patient/care-context/discover route; you answer with HTTP 202 straight away, run the patient match in the background, and send the result to /api/hiecm/user-initiated-linking/v3/patient/care-context/on-discover.
// V3 discover: acknowledge first, answer asynchronously
app.post('/api/v3/hip/patient/care-context/discover', async (req, res) => {
await queue.add('discover', {
inboundRequestId: req.headers['request-id'],
hipId: req.headers['x-hip-id'],
body: req.body
}); // store it
res.status(202).end(); // ACK now, before any matching
});
// Worker: match the patient, then reply to on-discover
worker.on('discover', async ({ inboundRequestId, hipId, body }) => {
const match = await findPatient(hipId, body.patient); // your HMIS lookup
const replyId = uuid(); // body requestId = REQUEST-ID header
const reply = { requestId: replyId, timestamp: new Date().toISOString(),
transactionId: body.transactionId, response: { requestId: inboundRequestId } };
if (match && match.careContexts.length > 0) {
reply.patient = [{
referenceNumber: match.id,
display: match.name,
careContexts: match.careContexts.map(c => ({ referenceNumber: c.ref, display: c.display })),
hiType: 'OPConsultation',
count: match.careContexts.length
}];
reply.matchedBy = ['MR']; // MOBILE or MR
} else if (match) {
reply.error = { code: 'NOTHING_TO_LINK', message: 'All your records at this facility are already linked.' };
} else {
reply.error = { code: 1000, message: 'No matching patient found' };
}
await gateway.post('/user-initiated-linking/v3/patient/care-context/on-discover', reply,
{ requestId: replyId, hipId });
}); Three details from the certified behavior we follow: send matchedBy as MOBILE or MR, because the sandbox PHR app rejects other values; answer a patient who is not found with error code 1000 rather than staying silent; and when the patient matches but every record is already linked, send a message that says so, because an empty list makes the PHR app report a failure. Match on your own patient ID where the request carries it; it avoids ABDM's duplicate discovery errors.
V3 sessions and the headers every call needs
const HIECM = process.env.ABDM_ENV === 'production'
? 'https://apis.abdm.gov.in/api/hiecm'
: 'https://dev.abdm.gov.in/api/hiecm';
let token = null, expiresAt = 0;
async function session() {
if (token && Date.now() < expiresAt - 60_000) return token;
const res = await axios.post(`${HIECM}/gateway/v3/sessions`,
{ clientId: process.env.ABDM_CLIENT_ID, clientSecret: process.env.ABDM_CLIENT_SECRET, grantType: 'client_credentials' },
{ headers: { 'Content-Type': 'application/json', 'REQUEST-ID': uuid(), 'TIMESTAMP': new Date().toISOString(), 'X-CM-ID': 'sbx' } });
token = res.data.accessToken;
expiresAt = Date.now() + res.data.expiresIn * 1000; // use expiresIn from the response
return token;
}
function headers(requestId, facility) {
return {
'Content-Type': 'application/json',
'Authorization': `Bearer ${facility.token}`,
'REQUEST-ID': requestId, // same value as body.requestId where the body has one
'TIMESTAMP': new Date().toISOString(),
'X-CM-ID': facility.cmId, // "sbx" in the sandbox
...(facility.hipId ? { 'X-HIP-ID': facility.hipId } : {}),
...(facility.hiuId ? { 'X-HIU-ID': facility.hiuId } : {})
};
} - REQUEST-ID must match. On every
on-*reply, the body'srequestIdand the REQUEST-ID header carry the same value. A mismatch is one of the quietest V3 failures. - X-HIP-ID for HIP calls, X-HIU-ID for HIU calls. Sending the HIP header on an HIU consent request is a common NHA test failure.
- Refresh from
expiresIn. Do not hard-code a token lifetime.
Bridge URL and routing callbacks in V3
The bridge URL is set once per client ID with PATCH /api/hiecm/gateway/v3/bridge/url, and you can read what is registered with GET /api/hiecm/gateway/v3/bridge-services. Every callback for every facility under that client ID arrives at the same base URL; route by path and by the X-HIP-ID or X-HIU-ID header.
Three rules decide whether callbacks work in V3: answer every callback with 202 immediately and do the work in a background worker; never drop an unknown callback silently; and keep your tunnel or ingress healthy, because ABDM does not resend a lost consent notification. More debugging patterns are in our bridge URL and callback debugging guide.
ABDM V3 endpoint reference
These are the V3 paths as used in the integrations we build, checked against a certified reference. Gateway paths are relative to the HIECM base; callback paths are on your bridge URL.
You call the gateway (HIECM base)
| Purpose | V3 path |
|---|---|
| Session token | POST /gateway/v3/sessions |
| Register or read the bridge URL | PATCH /gateway/v3/bridge/url, GET /gateway/v3/bridge-services |
| Public certificates | GET /gateway/v3/certs |
| HIP link token for a patient | POST /v3/token/generate-token |
| Link care contexts | POST /hip/v3/link/carecontext |
| SMS the patient about a new record | POST /hip/v3/link/patient/links/sms/notify2 |
| Answer discovery | POST /user-initiated-linking/v3/patient/care-context/on-discover |
| Answer link init and confirm | POST /user-initiated-linking/v3/link/care-context/on-init, .../on-confirm |
| Acknowledge a consent (HIP) | POST /consent/v3/request/hip/on-notify |
| Acknowledge a data request (HIP) | POST /data-flow/v3/health-information/hip/on-request |
| Report a finished transfer | POST /data-flow/v3/health-information/notify |
| Answer Scan and Share | POST /patient-share/v3/on-share |
| Request consent (HIU) | POST /consent/v3/request/init, POST /consent/v3/request/status |
| Acknowledge consent and fetch the artefact (HIU) | POST /consent/v3/request/hiu/on-notify, POST /consent/v3/fetch |
| Request health data (HIU) | POST /data-flow/v3/health-information/request |
ABDM calls you (bridge URL)
| Callback | V3 route on your bridge |
|---|---|
| Link token result | /api/v3/hip/token/on-generate-token |
| Patient discovery | /api/v3/hip/patient/care-context/discover |
| Link init and confirm | /api/v3/hip/link/care-context/init, /api/v3/hip/link/care-context/confirm |
| Consent granted or revoked (HIP) | /api/v3/consent/request/hip/notify |
| Health data request (HIP) | /api/v3/hip/health-information/request |
| Scan and Share profile | /api/v3/hip/patient/share |
| ABHA deactivation or opt-out | /api/v3/hip/patient/abha/deactivate |
| Consent request acknowledged (HIU) | /api/v3/hiu/consent/request/on-init |
| Consent granted, denied, revoked or expired (HIU) | /api/v3/hiu/consent/request/notify |
| Consent artefact (HIU) | /api/v3/hiu/consent/on-fetch |
| Data request acknowledged (HIU) | /api/v3/hiu/health-information/on-request |
| Encrypted data push (HIU) | the dataPushUrl you sent, for example /api/v3/hiu/health-information/push |
The complete, callable set with sandbox and production variables is in our public ABDM V3 Postman collection.
Consent and data transfer in V3
The consent and data flow keep their shape in V3; the paths and headers are what change.
- HIP side. On
/api/v3/consent/request/hip/notify, store the consent and acknowledge withconsent/v3/request/hip/on-notify. On/api/v3/hip/health-information/request, acknowledge withhip/on-request, build the FHIR bundles for the consented care contexts, encrypt each with Fidelius using fresh HIP key material, push them to the requester'sdataPushUrlwith an MD5 checksum of the encrypted content, then report the result withdata-flow/v3/health-information/notify. - HIU side. Raise the consent with
consent/v3/request/initand X-HIU-ID, acknowledge the grant, fetch the artefact, request the data with your Fidelius public key and data push URL, decrypt what arrives, and delete the records and keys when the consent is revoked or expires. Our HIU reference architecture covers storage and purge.
The V3 consent request body (HIU)
{
"requestId": "0b7e0f1a-4c2d-4f5e-9a1b-2c3d4e5f6a7b",
"timestamp": "2026-09-28T05:00:00.000Z",
"consent": {
"purpose": { "text": "Care Management", "code": "CAREMGT", "refUri": "http://terminology.hl7.org/ValueSet/v3-PurposeOfUse" },
"patient": { "id": "patient@sbx" },
"hiu": { "id": "YOUR-HIU-ID" },
"hip": { "id": "HIP-ID-IF-YOU-WANT-ONE-HOSPITAL" },
"requester": { "name": "Dr. Test Doctor", "identifier": { "type": "REGNO", "value": "REG-NUMBER", "system": "REGISTRY-SYSTEM-URL" } },
"hiTypes": ["OPConsultation", "DiagnosticReport", "Prescription"],
"permission": {
"accessMode": "VIEW",
"dateRange": { "from": "2025-01-01T00:00:00.000Z", "to": "2026-09-28T00:00:00.000Z" },
"dataEraseAt": "2026-10-28T00:00:00.000Z",
"frequency": { "unit": "HOUR", "value": 1, "repeats": 0 }
}
}
} - To ask every provider that holds the patient's records, leave the
hipkey out entirely. Sending"hip": nullis rejected. - When you later request the data, copy the granted
dateRangefrom the fetched consent artefact exactly as returned; a reformatted date range fails with ABDM-1063.
The V3 data push body (HIP to HIU)
{
"pageNumber": 0,
"pageCount": 1,
"transactionId": "transaction-id-from-the-request",
"entries": [{
"content": "BASE64-ENCRYPTED-FHIR-BUNDLE",
"media": "application/fhir+json",
"checksum": "MD5-OF-THE-ENCRYPTED-CONTENT",
"careContextReference": "OPD-2026-09-28-001"
}],
"keyMaterial": {
"cryptoAlg": "ECDH",
"curve": "Curve25519",
"dhPublicKey": { "expiry": "2026-09-29T05:00:00.000Z", "parameters": "Curve25519/32byte random key", "keyValue": "HIP-PUBLIC-KEY" },
"nonce": "HIP-NONCE"
}
} Large transfers are split into pages. We generate a fresh HIP key pair and nonce for every page and never reuse them across pages; the receiver needs the key material in each page to decrypt that page's entries. After the last page, the HIP reports the transfer with data-flow/v3/health-information/notify, and the HIU reports what it received, per care context, with its own notify.
Scan and Share in V3: what the QR carries
A facility's Scan and Share QR identifies the facility's HIP ID and a counter code; decoded, it can appear as a small object such as {"hipId":"IN0000000000","code":"1"}, where code identifies the registration counter. When a patient scans it, ABDM calls your /api/v3/hip/patient/share route with the patient's profile; you register or match the patient and answer patient-share/v3/on-share with a token number for the queue. Use a different counter code for each registration counter so you know where the patient is standing.
"ABDM gateway not responding": what to check first in V3
- Network blocks. ABDM's hosts sit behind a web application firewall. Some developer networks and VPN exits are refused with 403 before your request reaches the API; test from the server that will run the integration.
- The wrong base or version. A v0.5 path on the V3 base, or the sandbox base with production credentials, fails in confusing ways.
- Missing headers. A missing TIMESTAMP, X-CM-ID or X-HIP-ID is refused even when the token is valid.
- Callbacks that never arrive. Check the registered bridge URL with
bridge-services; after a change, allow time before callbacks move, and make sure the tunnel or ingress is alive.
Specific error codes and fixes are in our 25 common ABDM errors guide and the public ABDM V3 error catalog.
ABDM v0.5 to V3 migration checklist
- Inventory every v0.5 call you make and every callback you handle.
- Map each one to its V3 path; set the sandbox and production HIECM and ABHA bases as configuration.
- Switch sessions to
gateway/v3/sessionsand add the V3 headers to every call. - Move callback routes under
/api/v3, keep answering 202 first, and re-register the bridge URL. - Make every
on-*reply carry the same request ID in body and header. - Move M1 to the V3 ABHA enrolment and two-step login APIs.
- Run NHA's test cases for every milestone in the sandbox, fix, and run them again.
- Cut over in production and watch callback and error logs closely for the first week.
How to test your ABDM V3 integration in the sandbox
- Expose your server on a public HTTPS URL and register it as the bridge URL.
- Check registration with
bridge-servicesbefore testing callbacks. - Test discovery and linking from a PHR app with a sandbox ABHA, and confirm
on-discover,on-initandon-confirmare accepted. - Test consent and data transfer end to end, including revoke, and check the receiving side can decrypt every record.
- Log every exchange with its REQUEST-ID so any failure can be traced and reported to sandbox support.
In our own V3 testing in September 2026, a full M3 run against the sandbox delivered every value in every test record intact: 526 of 526 values and 30 of 30 attachments. The full integration path, from sandbox registration to go-live, is in our ABDM integration step-by-step guide, and what each milestone covers is in the ABDM milestones guide.
Migrating to ABDM V3 or starting fresh? Our ABDM integration team migrates, tests and re-certifies hospital software on V3. Talk to our team for a review of your integration.
Ready to scale?
Talk to our healthcare engineering team about building, integrating, and shipping faster.
Frequently Asked Questions
Is ABDM v0.5 still supported?
What is the biggest change in ABDM V3?
Is ABDM V3 discovery synchronous?
What is hiecm in ABDM?
How do I get an ABDM V3 session token?
Can I run v0.5 and V3 side by side during migration?
Why is the ABDM gateway not responding to my V3 calls?
Where can I find the full list of ABDM V3 endpoints?


