PHR Realtime Events
All PHR-patient real-time events are published to a single per-ABHA Pusher channel,
phr-{hash} (see phrChannelForAbha in pusher-service.ts).
The frontend resolves this channel name (plus the Pusher public key) from
GET /v1/realtime/channels?abhaAddress=..., then subscribes and listens for the events below.
All events are emitted via triggerUserEvent(abhaAddress, event, payload).
Most operator-facing events (consent lifecycle, care-context linking, health-info pushes, subscriptions, NHCX) emit on the facility channel via
triggerFacilityEventand never reach the PHR app. The exceptions are listed below: the patient self-fetch pair, the patient-share acknowledgement, andnotification:created, which is fanned out to both channels whenever the notification carries anabhaAddress.
The authoritative list is REALTIME_EVENTS.phr in
realtime.events.ts, which
GET /v1/realtime/channels returns as its events field — bind by constant name rather
than hard-coding the strings below. For the endpoint contract (request/response shape,
auth, and the GET /v1/realtime/events replay fallback) see the Realtime section of
NHCX & Platform.
Events
| Event | Triggered when | Source |
|---|---|---|
user-linking:on-discovered |
Discovery result is ready (care contexts found, or an error such as ABDM-1010) | handleOnDiscover (user-linking.callback.service.ts), and the rare sync path in user-linking.service.ts |
user-linking:init |
HIP receives ABDM's init callback; OTP-based linking has started | handleInit |
user-linking:on-init |
HIU receives the init result; carries the linkRefNumber the frontend needs to confirm |
handleOnInit |
user-linking:confirmed |
HIP-side confirm: OTP verified, care contexts marked linked | handleConfirm |
user-linking:on-confirmed |
HIU-side confirm result delivered | handleOnConfirm |
patient-share:on-share |
HIU on-share callback lands — the patient's scan-and-share profile was accepted and a queue token assigned | handleHiuOnShare (patient-share.callback.service.ts) |
phr-self-fetch:granted |
A patient self-fetch consent (PATRQT) is granted — fired on grant and again when the artefact detail arrives, so treat it as idempotent |
handleConsentGranted / handleArtefactFetched (consent-callback.operations.ts) |
phr-self-fetch:syncing |
The health-information request for a granted self-fetch artefact was accepted; records are on their way. One per artefact on a multi-HIP grant | same as above |
notification:created |
Any notification is persisted with an abhaAddress — mirrors the facility bell into the PHR notifications tab |
createNotification (notification.service.ts) |
Payloads
user-linking:on-discovered
{
transactionId: string | null
patientRef: string | null
careContexts: { referenceNumber: string; display: string }[]
matchedBy: string[] // e.g. ["ABHA_ADDRESS"]
isError: boolean
errorCode: string | null // e.g. "ABDM-1010"
errorMessage: string | null
}
user-linking:init
{
transactionId: string | null
abhaAddress: string | null
careContextCount: number
expiresAt: string // ISO 8601, OTP/session expiry
linkRefNumber: string
}
user-linking:on-init
{
transactionId: string | null
linkRefNumber: string | null // pass this to /care-context/confirm
authenticationType: string | null // e.g. "DIRECT"
communicationMedium: string | null // e.g. "MOBILE"
communicationExpiry: string | null // ISO 8601
isError: boolean
errorMessage: string | null
}
user-linking:confirmed
{
transactionId: string | null
abhaAddress: string
linkedContexts: string[] // care context reference numbers
linkedAt: string // ISO 8601
}
user-linking:on-confirmed
{
transactionId: string | null
linkedContextCount: number
isError: boolean
errorMessage: string | null
linkedAt: string // ISO 8601
}
patient-share:on-share
{
requestId: string
status: string // "SUCCESS" when a token was assigned, else "ERROR"
tokenNumber: string | null // queue token to present at the counter
context: string | null // counter/department the token is for
expiry: string | null // ISO 8601
error: { code: string; message: string } | null
receivedAt: string // ISO 8601
}
Emitted for every on-share callback carrying an abhaAddress, including failures — check
status before showing a token. A notification:created follows on SUCCESS only.
phr-self-fetch:granted
{
consentId: string
}
Fires as soon as the grant callback lands, so the UI can advance from "Consent requested"
to "Consent granted" without waiting for on-fetch, which the sandbox delivers
unreliably. It fires a second time when the artefact detail arrives — dedupe on
consentId.
phr-self-fetch:syncing
{
consentId: string
}
The health-information request was accepted for one artefact; records will land in the LHR
shortly. A multi-HIP grant has one artefact per HIP and emits this once per artefact,
all with the same consentId, so it is not a completion signal — poll the records
endpoint for actual delivery.
notification:created
{
id: string
type: string // NotificationType enum, e.g. "CONSENT_GRANTED"
title: string
body: string | null
abhaAddress: string | null
metadata: Record<string, unknown> | null
sourceEvent: string // the event that caused it, e.g. "patient-share:on-share"
isRead: false
createdAt: string // ISO 8601
}
The identical payload also goes to the facility channel — this is the same notification
seen from the patient's side, not a separate one. Only notifications created with an
abhaAddress reach the PHR channel.