HIP Identity & Linking (M1 root + M1 Identity/Linking)
What this covers
This document describes the facility-side (HIP) surface of orvo-abha that deals with a patient's ABHA (Ayushman Bharat Health Account) identity and with connecting ("linking") a patient's hospital records — visits, prescriptions, discharge summaries, etc., called care contexts — to that ABHA. In plain terms: when a walk-in patient visits a hospital or clinic that uses this backend, these are the APIs that (a) create a brand-new ABHA for them on the spot using their Aadhaar, (b) look up and re-use an ABHA they already have, (c) let staff search ABDM's national facility directory, and (d) establish the link between the patient's ABHA and their medical record at this facility, so that later on a doctor with the patient's consent can pull those records through ABDM.
There are two directions of traffic throughout this document:
- Outbound — either our own frontend (
orvo-hub, the facility staff dashboard, ororvo-web, the doctor-facing app) calling this backend, or this backend calling out to the ABDM gateway on their behalf. - Inbound ABDM callback — the ABDM gateway calling this backend asynchronously, seconds or minutes after an outbound request, to deliver an async result (ABDM's entire linking protocol is callback-driven: you ask, ABDM acks immediately, and the real answer shows up later as a POST to a URL you registered).
Every inbound callback in this document is called directly by ABDM's infrastructure over the public internet (no user session, no bearer token) — access control for these is IP/network-level, not application-level, and the handlers must acknowledge within ~5 seconds (HTTP 202) before doing any real work, per ABDM's own timeout contract.
Two authentication conventions recur throughout:
X-HIP-IDheader — used when our own frontend (usuallyorvo-hub, the facility operator dashboard) is calling us on behalf of a specific facility, but has no ABDM bearer/account token to present (it authenticates to us via an Orvo session cookie instead). We resolve the header to aFacilityrow server-side.Bearer <token>— used for two different kinds of tokens depending on the flow: (1) a short-lived ABDM account/X-token obtained from a patient's Aadhaar/ABHA OTP verification, forwarded to ABDM as passthrough auth for subsequent profile/address calls; or (2) an Orvo-issued session token for a logged-in PHR-style caller. Note: JWT signature verification is currently disabled backend-wide (requireAuthonly checks a Bearer token is present, not that it's valid) — this is a known, deliberate gap pending the Orvo auth model finalization, not something to treat as a quick fix.
Facility Enrollment — Aadhaar-only ABHA creation (M1 root)
Plain-English: this is the "create an ABHA on the spot" flow a receptionist or nurse runs when a walk-in patient has no ABHA yet, has their Aadhaar card, and consents to using it. It is doctor/staff-assisted — the patient is physically present and reads OTPs off their own phone — as opposed to the separate PHR-app self-service enrollment (self-declared/mobile-based) which is out of scope here. All routes are mounted at /v1/hip/enrollment.
POST /v1/hip/enrollment/request
Create Aadhaar OTP. Sends an ABHA-creation OTP to the mobile number linked to the patient's Aadhaar.
- Caller:
orvo-hub/orvo-webstaff UI. No auth header required (pre-identity, nothing to authenticate yet); rate-limited byauthLimiterplus an app-level OTP-resend guard keyed on the Aadhaar number. - Request:
{
"aadhaarNumber": "234567890123"
}
- Response (200):
{
"success": true,
"message": "OTP requested successfully",
"data": {
"txnId": "b1b6c3e7-5e2c-4c7f-9f02-9c8fbc3caa11",
"message": "OTP sent to Aadhaar-linked mobile"
}
}
- Flow: Staff types the patient's Aadhaar number in; this call kicks off ABDM's
enrollment/request/otpAPI. The returnedtxnIdthreads through every subsequent step of this enrollment.
POST /v1/hip/enrollment/verify
Create ABHA by verifying Aadhaar OTP. The patient reads the OTP that landed on their Aadhaar-linked phone; verifying it creates the ABHA account via KYC.
- Caller:
orvo-hub/orvo-web, no auth header. - Request:
{
"txnId": "b1b6c3e7-5e2c-4c7f-9f02-9c8fbc3caa11",
"otpValue": "123456",
"mobile": "9876543210"
}
Note mobile is required here even if it's the same number the Aadhaar OTP was sent to — ABDM's enrol/byAadhaar contract mandates a communication mobile regardless.
- Response (200): an account token bundle plus the ABHA profile, e.g.:
{
"success": true,
"message": "Enrollment verified successfully",
"data": {
"token": "eyJhbGciOi...",
"expiresIn": 1800,
"refreshToken": "eyJhbGciOi...",
"refreshExpiresIn": 1209600,
"ABHAProfile": {
"firstName": "Rajesh",
"lastName": "Kumar",
"dob": "15-08-1990",
"gender": "M",
"mobile": "9876543210",
"ABHANumber": "12-3456-7890-1234",
"phrAddress": []
}
}
}
- Flow: This is the moment the ABHA account is actually created in ABDM. If the communication mobile differs from the Aadhaar-linked one, ABDM withholds usable tokens until it's separately verified — that's what the next two endpoints are for. Otherwise, staff moves straight to picking an ABHA address.
POST /v1/hip/enrollment/mobile/request
Mobile Update — send OTP. Only needed when the mobile given at verify differs from the Aadhaar-linked one.
- Caller:
orvo-hub/orvo-web, no auth header; OTP-resend-guarded per mobile number. - Request:
{
"txnId": "b1b6c3e7-5e2c-4c7f-9f02-9c8fbc3caa11",
"mobile": "9123456789"
}
- Response (200):
{ "success": true, "message": "Mobile verification OTP sent successfully", "data": { ... } }
POST /v1/hip/enrollment/mobile/verify
Mobile Update — verify OTP. Confirms the alternate communication mobile so ABDM releases full tokens.
- Caller:
orvo-hub/orvo-web, no auth header. - Request:
{
"txnId": "b1b6c3e7-5e2c-4c7f-9f02-9c8fbc3caa11",
"otpValue": "654321"
}
- Response (200):
{ "success": true, "message": "Mobile verified successfully", "data": { ... } }
GET /v1/hip/enrollment/address/suggestions/:txnId
Get ABHA address suggestions. Since Aadhaar KYC already supplied the patient's demographics, only the txnId is needed to ask ABDM for candidate name@sbx-style handles.
- Caller:
orvo-hub/orvo-web, no auth header. - Request: path param only, e.g.
GET /v1/hip/enrollment/address/suggestions/b1b6c3e7-5e2c-4c7f-9f02-9c8fbc3caa11 - Response (200):
{
"success": true,
"message": "ABHA address suggestions fetched successfully",
"data": {
"txnId": "b1b6c3e7-5e2c-4c7f-9f02-9c8fbc3caa11",
"abhaAddressList": ["rajesh.kumar", "rajesh.kumar90", "rajeshk1990"]
}
}
POST /v1/hip/enrollment/address
Create ABHA address. Final step of enrollment — assigns the chosen (or custom) address to the new account.
- Caller:
orvo-hub/orvo-web, but requires a Bearer token — the account token returned fromverifyabove — in theAuthorizationheader (the controller returns 401 if absent). - Request:
{
"txnId": "b1b6c3e7-5e2c-4c7f-9f02-9c8fbc3caa11",
"abhaAddress": "rajesh.kumar",
"preferred": 1
}
- Response (200):
{ "success": true, "message": "ABHA address enrolled successfully", "data": { ... } } - Flow: Once this succeeds, the patient has a fully usable ABHA address (
rajesh.kumar@sbx), ready to be linked to care contexts (see the HIP-Initiated Linking and User-Initiated Linking sections below).
POST /v1/hip/enrollment/email/verify
Send email verification link. Optional profile-completion step.
- Caller:
orvo-hub/orvo-web. Bearer (account token) required. - Request:
{ "email": "rajesh@gmail.com" } - Response (200):
{ "success": true, "message": "Email verification link sent successfully", "data": { ... } }
GET /v1/hip/enrollment/profile
Get enrolled ABHA profile. Fetches the freshly created profile back, with address synthesized server-side by joining ABDM's separate addressLine1/addressLine2 fields.
- Caller:
orvo-hub/orvo-web. Bearer (account token) required. - Response (200): profile object as shown under
verifyabove, plus a combinedaddressfield.
GET /v1/hip/enrollment/profile/qr
Get enrolled ABHA profile QR code. Returns the ABHA QR as a base64 data URI (data:image/png;base64,...), convenient for direct <img> embedding.
- Caller:
orvo-hub/orvo-web. Bearer required. - Response (200):
{ "success": true, "data": "data:image/png;base64,iVBORw0K..." }
GET /v1/hip/enrollment/profile/card
Get enrolled ABHA card. Same idea, returns the printable ABHA card image as a base64 data URI.
- Caller:
orvo-hub/orvo-web. Bearer required. - Response (200):
{ "success": true, "data": "data:image/png;base64,iVBORw0K..." }
Facility Login — linking an existing ABHA (M1 root)
Plain-English: this is for the far more common case — the patient already has an ABHA from a previous visit or from the ABDM/PHR app — and staff just need to look it up and attach it to today's visit. All routes are mounted at /v1/hip/login.
There are two entry points ("login hints"):
abha-number— the 14-digit ABHA number. A patient may have multiple ABHA addresses under one ABHA number, so this path is two steps: verify OTP (returns a transfer T-TOKEN), thenverify/userto pick a specific address (returns a usable X-TOKEN).abha-address— thename@sbx/name@abdmhandle directly. Single-account, so OTP verification alone returns a usable X-TOKEN — noverify/userstep (and calling it for this hint is rejected by ABDM).
POST /v1/hip/login/request/otp
Request login OTP.
- Caller:
orvo-hub/orvo-web, no auth header; OTP-resend-guarded perloginHint:loginId. - Request (abha-number hint):
{
"loginHint": "abha-number",
"loginId": "12345678901234",
"otpMethod": "abdm"
}
otpMethod picks the OTP channel — aadhaar (Aadhaar-linked mobile) or abdm (ABHA/ABDM-registered mobile); defaults to abdm if omitted. It's ignored for the abha-address hint.
Alternative request (abha-address hint):
{
"loginHint": "abha-address",
"loginId": "rajesh.kumar@sbx"
}
- Response (200):
{ "success": true, "message": "OTP requested successfully", "data": { "txnId": "b1b6c3e7-5e2c-4c7f-9f02-9c8fbc3caa11" } }
POST /v1/hip/login/verify/otp
Verify login OTP.
- Caller:
orvo-hub/orvo-web, no auth header. - Request:
{
"loginHint": "abha-number",
"txnId": "b1b6c3e7-5e2c-4c7f-9f02-9c8fbc3caa11",
"otp": "123456",
"otpMethod": "abdm"
}
- Response (200): for
abha-number, a T-TOKEN transfer token requiringverify/usernext; forabha-address, a usable X-TOKEN directly (same shape as the token bundle above).
POST /v1/hip/login/verify/user
Verify user (abha-number only). Picks one specific ABHA address from the linked accounts under a multi-address ABHA number.
- Caller:
orvo-hub/orvo-web. Bearer (the T-TOKEN fromverify/otp) required. - Request:
{
"abhaAddress": "rajesh.kumar@sbx",
"txnId": "b1b6c3e7-5e2c-4c7f-9f02-9c8fbc3caa11"
}
- Response (200): usable X-TOKEN bundle, same shape as
verify/otp's abha-address response.
GET /v1/hip/login/profile
Get profile for the logged-in ABHA.
- Caller:
orvo-hub/orvo-web. Bearer (X-TOKEN) required, plus?loginHint=abha-numberor?loginHint=abha-addressquery param. - Response (200): ABHA profile object (same shape as enrollment's profile response).
GET /v1/hip/login/profile/card
Get ABHA card for the logged-in ABHA.
- Caller:
orvo-hub/orvo-web. Bearer required, plus?loginHint=.... - Response (200):
{ "success": true, "data": "data:image/png;base64,..." }
Gateway / Discovery utilities
Plain-English: a grab-bag of read-mostly endpoints for looking things up in ABDM's national directories (registered facilities/providers, government health programs, health lockers) and for managing this deployment's own registration as a HIP/HIU bridge service with ABDM. All routes are mounted at /v1/gateway. None of these carry patient data — they are directory/config lookups.
GET /v1/gateway/bridge-services
Fetch this deployment's bridge + registered services. Confirms what HIP/HIU/HEALTH_LOCKER/PHR roles and callback endpoints ABDM currently has on file for our bridge.
- Caller:
orvo-hubsettings/admin UI. No auth header (internal-only route, not patient-scoped). - Response (200):
{
"success": true,
"data": {
"bridge": {
"id": "IN0310000702",
"name": "Orvo Technologies Private Limited",
"url": "https://api.orvo.app/api/v3",
"active": true,
"blocklisted": false
},
"services": [
{
"id": "IN0310000702_1",
"name": "Orvo_HIP",
"types": ["HIP"],
"endpoints": {
"hipEndpoints": [
{
"use": "https://api.orvo.app/api/v3",
"connectionType": "HTTP",
"address": "https://api.orvo.app/api/v3"
}
]
},
"active": true
}
]
}
}
PUT /v1/gateway/bridge-services (POST alias also accepted)
Register/update a bridge service. Adds or updates a HIP/HIU/Health Locker/PHR service under this deployment's ABDM bridge. The POST alias exists purely because some CDN/WAF layers block PUT; the upstream ABDM call is still a PUT.
- Caller:
orvo-hubsettings/admin UI, or an internal operator script. No auth header. - Request:
{
"bridgeId": "SBXID_049344",
"serviceId": "IN0310000754",
"name": "Orvo_HIU",
"isHip": true,
"isHiu": false,
"isHealthLocker": false,
"isPhr": false,
"endpoints": {
"hipEndpoints": [
{
"use": "https://api.orvo.app/api/v3",
"connectionType": "HTTP",
"address": "https://api.orvo.app/api/v3"
}
]
},
"active": true
}
Note: isHealthLocker: true is accepted by this endpoint but ABDM/NHA must separately approve that role before it takes effect.
- Response (200):
{ "success": true, "message": "Bridge service registration submitted", "data": { ... } }
GET /v1/gateway/bridge-services/:serviceId
Fetch a single bridge service's registration details — role flags, active status, registration/creation/modification timestamps.
- Caller:
orvo-hubsettings UI. No auth header. - Response (200):
{
"success": true,
"data": {
"id": 4821,
"bridgeId": "IN0310000702",
"serviceId": "IN0310000702_1",
"name": "Orvo_HIP",
"isHip": true,
"isHiu": false,
"isHealthLocker": false,
"isPhr": false,
"active": true,
"registerTime": "2026-01-15T10:30:00.000Z",
"dateCreated": "2026-01-15T10:30:00.000Z",
"dateModified": "2026-01-15T10:30:00.000Z"
}
}
GET /v1/gateway/bridge-url
Fetch latest stored bridge callback URL. Purely a local DB read (not a live ABDM call) — returns the most recently persisted callback URL for the active facility, or null if never set.
- Caller:
orvo-hubsettings UI. No auth header. - Response (200):
{ "success": true, "data": { "url": "https://api.orvo.app/api/v3", "createdAt": "2026-06-01T08:00:00.000Z" } }or{ "success": true, "data": null }.
PATCH /v1/gateway/bridge-url
Update bridge callback URL. Persists a new callback URL locally, then forwards the update to ABDM as the registered callback for that facility's bridge/hipId. Both steps run for every call — the local write happens even if the downstream ABDM call subsequently fails.
- Caller:
orvo-hubsettings UI. No auth header. - Request:
{ "url": "https://api.orvo.app/api/v3" } - Response (202):
{ "success": true, "data": { "accepted": true } }
GET /v1/gateway/providers
Search the ABDM provider/facility directory.
- Caller:
orvo-hub/orvo-web. No auth header. - Request:
GET /v1/gateway/providers?name=Apollo—namemust be ≥3 characters.stateCode/districtCodeare accepted by the schema but not currently forwarded to ABDM by the service. - Own-identity filtering: results always exclude the entry matching this deployment's own system HIU/health-locker identity (
resolveSystemHiuId()), by comparingidentifier.id. Without this, a patient searching facilities from the record-linking flow could select "ourselves" as the target HIP, and ABDM always rejects that discovery request with"HIP and HIU cannot be same"— a combination that can never succeed, so it's filtered out before the client ever sees it. - Response (200):
{
"success": true,
"data": [
{
"identifier": { "name": "Apollo Hospitals Bengaluru", "id": "IN0310000850" },
"facilityType": ["HIP"],
"isHip": true,
"isHiu": false,
"isHealthLocker": false,
"isPhr": false
}
]
}
GET /v1/gateway/providers/:providerId
Fetch a single provider/facility's details.
- Caller:
orvo-hub/orvo-web. No auth header. - Response (200):
{ "success": true, "data": { "identifier": { "name": "Orvo Multispeciality Hospital", "id": "IN0310000702" }, "facilityType": ["HIP"], "isHip": true } }
GET /v1/gateway/government-programs
List government health-program entities registered in ABDM as facility-like entities.
- Caller:
orvo-hub/orvo-web. No auth header. - Response (200): array of
{ identifier, facilityType, isHip }entries.
GET /v1/gateway/health-lockers
List entities registered under the HEALTH_LOCKER role, with callback endpoints where available.
- Caller:
orvo-hub/orvo-web. No auth header. - Response (200): array of
{ identifier, facilityType, isHip, isGovtEntity, endpoints }entries.
PATCH /v1/gateway/bridge-config
Update bridge configuration — acknowledgement only. Bridge clientId/clientSecret credentials are managed out-of-band via environment variables and the encrypt-bridge-secrets script; this endpoint validates the body but otherwise no-ops.
- Caller:
orvo-hubsettings UI. No auth header. - Request:
{ "url": "https://api.orvo.app/api/v3" } - Response (202):
{ "success": true, "message": "Bridge configuration update received", "data": null }
HIP-Initiated Linking
Plain-English: this is the flow where the facility (not the patient) starts the process of connecting a patient's visit records to their ABHA — staff already has the patient's ABHA address on file and wants to attach today's OPD visit to it, without the patient actively "discovering and linking" through their own PHR app. It relies on a link token obtained first, then submits the actual care-context references for linking, then can additionally notify the patient (via PHR app or SMS).
Link Token — obtaining the token that authorizes linking (/v1/link)
POST /v1/link/token/generate
Generate a link token for a patient, by demographic authentication (name + gender + year of birth + ABHA address/number).
- Caller:
orvo-hub. Requires theX-HIP-IDheader (401 if missing). - Request:
{
"abhaAddress": "rajesh.kumar@sbx",
"abhaNumber": "23456789012345",
"gender": "M",
"name": "Rajesh Kumar",
"yearOfBirth": 1990
}
- Response (200) — normal case:
{
"success": true,
"message": "Link token generated successfully",
"data": { "requestId": "123e4567-e89b-12d3-a456-426614174000" }
}
The hub subscribes to a Pusher channel keyed by this requestId and waits for link-token:received/link-token:failed — the actual token arrives later via the inbound callback below.
On the known ABDM-1092 "duplicate request" condition, the service auto-recovers by returning the existing live request instead, possibly already linkTokenReady:
{
"success": true,
"data": {
"requestId": "9f8a7b6c-1234-4c7f-9f02-9c8fbc3caa11",
"linkTokenReady": true,
"abhaAddress": "rajesh.kumar@sbx",
"expiresAt": "2026-07-18T14:30:00.000Z"
}
}
- Flow: request accepted by ABDM → asynchronously the actual token is generated → ABDM POSTs it to our callback below → we persist it and fire the Pusher event → hub proceeds to
POST /v1/hip-linking/patient/links/care-context.
Inbound ABDM callback — POST /api/v3/hip/token/on-generate-token
ABDM's gateway POSTs the generated link token (or an error) here once it's ready.
- Caller: ABDM's gateway. No application auth (network/IP-level only). Note: this route runs
requireXHipId(a blocking check), unlike most other inbound callbacks in this codebase which use the non-blockingattachXHipId— worth flagging since ABDM doesn't reliably sendX-HIP-IDon every callback. - Request (success):
{
"abhaAddress": "rajesh.kumar@sbx",
"linkToken": "abcdef123456.eyJhbGciOi...",
"response": { "requestId": "123e4567-e89b-12d3-a456-426614174000" }
}
Request (error): { "error": { "code": "ABDM-1010", "message": "Patient not found" }, "response": { "requestId": "..." } }
- Response:
202 Accepted, empty ack body. - What happens next: on success, decodes the JWT expiry from the link token, updates the local
LinkTokenRequestrow toGENERATED, fireslink-token:receivedon therequestIdPusher channel. On error, marksFAILEDand fireslink-token:failed.
Care Context (local read) — /v1/care-context
GET /v1/care-context
List a patient's care contexts on file at this facility. Purely local (no ABDM call) — populates the "which visits/records to link" selection step.
- Caller:
orvo-hub. Resolves facility fromX-HIP-ID(falls back to the single active facility if absent). - Request:
GET /v1/care-context?abhaAddress=rajesh.kumar@sbx - Response (200):
{
"success": true,
"data": {
"careContexts": [
{
"id": "cc-001",
"careContextReference": "TMH-CC-001",
"display": "Visit 1",
"hiType": "OPConsultation",
"linked": false,
"abhaAddress": "rajesh.kumar@sbx",
"patientReference": "TMH-PUID-001"
}
]
}
}
linked only flips true once ABDM's on_carecontext callback confirms that reference. Empty array (not 404) if none on file.
HIP Linking — /v1/hip-linking
POST /v1/hip-linking/patient/links/care-context
Initiate linking of care contexts (ABDM M2 §4.3).
- Caller:
orvo-hub. RequiresX-HIP-ID. - Request:
{
"abhaAddress": "rajesh.kumar@sbx",
"abhaNumber": "23456789012345",
"patient": [
{
"referenceNumber": "TMH-PUID-001",
"display": "Rajesh Kumar",
"careContexts": [{ "referenceNumber": "TMH-CC-001", "display": "Visit 1" }],
"hiType": "OPConsultation",
"count": 1
}
]
}
- Response (200): ack only —
{ "success": true, "data": { "requestId": "..." } }. Actual result arrives viaon_carecontextbelow. - Notable: requires an existing non-expired link token for this
abhaAddress/abhaNumber; 422 if none found.
GET /v1/hip-linking/patient/links
Get all care contexts linked to a patient's ABHA, across every HIP (PHR-side).
- Caller: PHR-side caller. Bearer required.
- Request:
GET /v1/hip-linking/patient/links?limit=10 - Response (200):
{
"success": true,
"data": {
"Patient": {
"id": "rajesh.kumar@sbx",
"links": [
{
"hip": { "id": "IN0310000702_1", "name": "Orvo Test Hospital", "type": "HIP" },
"referenceNumber": "TMH-PUID-001",
"display": "Rajesh Kumar",
"hiType": "OPConsultation",
"careContexts": [{ "referenceNumber": "TMH-CC-001", "display": "Visit 1" }],
"dateCreated": "2026-07-18T10:00:00.000Z"
}
]
}
}
}
POST /v1/hip-linking/patient/links/notify
Notify the patient's PHR app that a link is complete.
- Caller:
orvo-hub. RequiresX-HIP-ID. - Request:
{
"notification": {
"patient": { "id": "rajesh.kumar@sbx" },
"careContext": { "patientReference": "TMH-PUID-001", "careContextReference": "TMH-CC-001" },
"hiTypes": ["OPConsultation"],
"date": "2026-07-18T10:00:00.000Z",
"hip": { "id": "IN0310000702_1", "name": "Orvo Test Hospital" }
}
}
- Response (200):
{ "success": true, "message": "Notification received successfully", "data": null } - Notable: requires a
LINKED, non-expired link token; 422 otherwise.
POST /v1/hip-linking/patient/links/sms/notify
Notify by SMS instead. Thin passthrough — no link-token lookup, no X-HIP-ID requirement (hip.id supplied directly).
- Request:
{
"requestId": "123e4567-e89b-12d3-a456-426614174000",
"timestamp": "2026-07-18T10:00:00.000Z",
"notification": {
"phoneNo": "9876543210",
"hip": { "id": "IN0310000702_1", "name": "Orvo Test Hospital" }
}
}
- Response (200):
{ "success": true, "message": "SMS Notification received successfully", "data": null }
POST /v1/hip-linking/notify-sms
Simplified SMS notify for mobile-only patients with no ABHA address yet — triggers ABDM to text a deep link to create one and self-link.
- Caller:
orvo-hub. RequiresX-HIP-ID. - Request:
{ "phoneNo": "9876543210" } - Response (200):
{ "success": true, "message": "SMS notification sent", "data": null }
HIP Linking — inbound callbacks
Inbound ABDM callback — POST /api/v3/link/on_carecontext
Final result of care-context linking (success/failure).
- Request (success):
{ "abhaAddress": "rajesh.kumar@sbx", "status": "Successfully Linked care context", "response": { "requestId": "123e4567-e89b-12d3-a456-426614174000" } }.statusis free text, matched case-insensitively for "success"/"linked". - Response:
202 Accepted,{ "message": "Care context callback received" }. - What happens next: marks exactly the submitted care-context references
linked: true; hub UI reflects the update.
Inbound ABDM callback — POST /api/v3/link/on_notify
Confirms whether the CM processed the patient/links/notify call.
- Request (success):
{ "requestId": "...", "timestamp": "...", "acknowledgement": { "status": "SUCCESS" }, "response": { "requestId": "..." } }(orerrorinstead ofacknowledgementon failure). - Response:
202 Accepted,{ "message": "Care context notification received" }.
Inbound ABDM callback — POST /api/v3/patients/sms/on-notify
Confirms SMS dispatch.
- Request:
{ "acknowledgement": { "status": "SUCCESS" }, "response": { "requestId": "..." } } - Response:
202 Accepted,{ "message": "SMS notification received" }.
User-Initiated Linking (UIL)
Plain-English: the opposite direction — the patient actively searches ("discovers") for their records at a chosen facility, then completes an OTP-confirmed link. This backend plays both roles simultaneously: HIU/PHR side (patient-triggered, calls ABDM) and HIP/facility side (receives ABDM's inbound requests). All outbound routes are mounted at /v1/user-linking.
PHR-side (patient-triggered)
POST /v1/user-linking/care-context/discover
Request discovery at a chosen HIP.
- Caller: PHR-app-equivalent frontend. Bearer +
X-HIU-IDrequired. - Request:
{
"hip": { "id": "cowin_hip_01" },
"unverifiedIdentifiers": [
{ "type": "MOBILE", "value": "+919876543210" },
{ "type": "ABHA_ADDRESS", "value": "rajesh.kumar@sbx" }
]
}
- Response (202): ack; match arrives via
on-discovercallback →user-linking:on-discoveredPusher event. ABDM-9999 duplicate-discovery serves the last cached result instead of erroring.
GET /v1/user-linking/care-context/discovery-result
Polling fallback.
- Caller: PHR-app-equivalent frontend. Bearer required.
- Request:
GET /v1/user-linking/care-context/discovery-result?hipId=IN0310000720&abhaAddress=rajesh.kumar@sbx - Response (200):
{ "success": true, "data": { "found": false } }if none within 2 hours (200, not 404), else the persisted result.
POST /v1/user-linking/care-context/init
Initiate the link after selecting discovered care contexts.
- Caller: PHR-app-equivalent frontend. Bearer +
X-HIU-IDrequired. - Request:
{
"transactionId": "f901b782-bfdf-4224-9f8d-da2cadc20c0d",
"patient": [
{
"referenceNumber": "TMH-PUID-001",
"display": "Rajesh Kumar",
"careContexts": [{ "referenceNumber": "TMH-CC-001", "display": "Visit 1" }],
"hiType": "OPConsultation",
"count": 1
}
]
}
- Response (202): ack. Server re-derives real
hiTypefrom the DB rather than trusting the caller.
POST /v1/user-linking/care-context/confirm
Complete the link with the OTP from init.
- Caller: PHR-app-equivalent frontend. Bearer +
X-HIU-IDrequired. - Request:
{ "token": "123456", "linkRefNumber": "d353b782-bfdf-4224-9f8d-da2cadc20c0d" } - Response (202): ack; result via
on-confirmcallback.
Facility-side outbound relay calls (called by orvo-hub, NOT ABDM — despite the "on-*" naming)
POST /v1/user-linking/care-context/on-discover, .../on-init, .../on-confirm — these forward the facility's resolved answer to an inbound ABDM discover/init/confirm request onward to ABDM's gateway. No auth middleware applied at the route level; reachable only by trusted internal callers (orvo-hub). All return 202 acks.
GET /v1/user-linking/callback-traces
Diagnostic endpoint listing persisted inbound UIL callbacks paired with our responses, for tracing stuck/failed linking attempts.
- Caller:
orvo-hub. Authenticates viaX-HIP-ID. - Request:
GET /v1/user-linking/callback-traces?limit=20&offset=0&transactionId=f901b782-bfdf-4224-9f8d-da2cadc20c0d - Response (200):
{ "success": true, "data": { "traces": [...], "pagination": { "total": 3, "limit": 20, "offset": 0, "hasMore": false } } }
User-Initiated Linking — inbound callbacks
All ack 202 Accepted immediately, process in background. Real paths require the /api prefix.
Inbound ABDM callback — POST /api/v3/hip/patient/care-context/discover
ABDM asks the facility to check for matching records. HIP id via X-HIP-ID header (non-fatal). Forwarded onward via on-discover relay.
Inbound ABDM callback — POST /api/v3/hip/link/care-context/init
ABDM instructs the facility to begin the link (send OTP). Forwarded via on-init relay.
Inbound ABDM callback — POST /api/v3/hip/link/care-context/confirm
ABDM delivers the patient's OTP submission (lenient schema — token/linkRefNumber may be nested or flat). Forwarded via on-confirm relay.
Inbound ABDM callback — POST /api/v3/hiu/patient/care-context/on-discover
Confirms discovery result back to our HIU/PHR side; persists result and fires user-linking:on-discovered Pusher event.
Inbound ABDM callback — POST /api/v3/hiu/patient/care-context/on-init
Confirms link-init (OTP dispatched) back to our HIU/PHR side.
Inbound ABDM callback — POST /api/v3/hiu/patient/care-context/on-confirm
Confirms final link-confirm result; linked care contexts become available for LHR sync; Pusher event notifies the patient-facing UI.
Facilities management
Plain-English: internal CRUD for the list of facilities this backend can act as an ABDM HIP/HIU on behalf of. Mounted at /v1/facilities; no auth header at the route level (admin/internal surface).
- GET /v1/facilities — list all, ordered by creation time.
- POST /v1/facilities — create;
name/mainAppFacilityId/hipId/hipNamerequired; lazily provisions aBridgeConfigfromABDM_M234_CLIENT_ID/ABDM_M234_CLIENT_SECRETenv vars if needed; 409 on duplicate unique field, 422 on missing fields. - GET /v1/facilities/:id — fetch by server id; 404 if not found.
- PATCH /v1/facilities/:id — partial update (name, mainAppFacilityId, hfrFacilityId, hipId, hipName, active);
bridgeId/environmentimmutable here; 404/409/422 as applicable. - DELETE /v1/facilities/:id — permanent delete; does not cascade to Consent/CareContext/BridgeConfig rows.
Example facility object: `{ "id": "a1b2c3d4-...", "mainAppFacilityId": "FAC-1024", "name": "Orvo Multispeciality Hospital", "hfrFacilityId": "IN2910000123", "hipId": "IN0310000702_1", "bridgeId": "IN0310000702", "hipName": "Orvo Multispeciality Hospital", "environment": "sandbox", "active": true, "createdAt": "...", "updatedAt": "..." }