Skip to main content

Notifications and patient apps

The third kind of participant. A personal health record app registers on the exchange as a beneficiary service provider, subscribes on a beneficiary's behalf, and receives a readable message every time something happens to that beneficiary's claim. It sends no claims and answers no queries. It is the only role on the network whose whole job is to be told things.

This chapter is for anyone building such an app, and for a hospital or payer that also runs one.

The model: subscribe on login, last linked wins

When a beneficiary logs into an app with their ABHA, that app calls subscribe and becomes the recipient of every notification for that ABHA. Any earlier subscription is replaced. Only one app receives notifications for a beneficiary at any moment.

That rule is deliberate and it has consequences worth designing around.

  • There is no duplicate delivery to handle, and no fan-out.
  • A beneficiary who opens a second app silently stops receiving notifications in the first. Neither app is told.
  • Subscription is an action to take on every login, not once at install.

Before you start

  • Milestone 1. The app must have completed ABDM Milestone 1 integration.
  • Registration as a beneficiary service provider. Sandbox testing, sandbox certification, then onboarding to the production registry. The role code is 10009 and the registry ID may be the app's own client ID.
  • An HTTPS endpoint with TLS 1.2 or newer, and the ability to generate and validate JWTs.

Subscribing

curl --location --request POST 'https://hcxsbx.abdm.gov.in/v1/notification/subscribe' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <access token>' \
--header 'x-hcx-sender_code: phr-app-xyz@bsp' \
--header 'x-hcx-recipient_code: nhcx-gateway@hcx' \
--header 'x-hcx-timestamp: <iso timestamp>' \
--header 'x-hcx-correlation_id: <uuid>' \
--data-raw '{
"payload": "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00iLCJ4LWhjeC1zZW5kZXJfY29kZSI6InBoci1hcHAteHl6QGJzcCJ9.encrypted_key.iv.ciphertext.tag",
"_payload_plaintext": {
"subscription_id": "sub_ravi_001",
"topic_code": [
"workflow_events"
],
"recipient_code": "phr-app-xyz@bsp",
"subscriber": {
"id": "ravi@abdm"
},
"on_notification_url": "https://api.phrapp.com/v1/hcx/notification/on_subscribe"
}
}'

Notification subscribe in the API reference

The call is sealed like any other message on the exchange, with the app as sender and the gateway as recipient. The subscription service's live specification is at https://hcxsbx.abdm.gov.in/subscriptionhcxservice/swagger-ui/index.html, and Environments and Addresses lists it with the others.

FieldRequiredWhat it carries
subscription_idYesYour own unique identifier for this subscription
topic_codeYesAn array of topics, see below
recipient_codeYesYour participant code
subscriber.idYesThe beneficiary's ABHA address, for example ravi@abdm
on_notification_urlYesWhere notifications should be delivered
expiryNoWhen the subscription lapses
{
"subscription_id": "sub_ravi_001",
"topic_code": ["workflow_events"],
"recipient_code": "phr-app-xyz@bsp",
"subscriber": { "id": "ravi@abdm" },
"on_notification_url": "https://api.phrapp.example/v1/hcx/notification/on_subscribe"
}

Topics

TopicWhat arrives
workflow_eventsClaim lifecycle: preauthorisation, claim, payment
network_eventsExchange platform updates and maintenance
participant_eventsChanges to payer and provider registrations

Most apps need workflow_events alone. The field is an array, so subscribe to more than one where you have a reason.

The workflow codes for this exchange are N01 to a payer, N02 to a provider, N03 to a beneficiary and N04 for the acknowledgement.

Receiving a notification

The exchange posts to the on_notification_url you registered.

FieldWhat it carries
notification_idUnique per notification
topic_codeThe topic it arrived under
timestampISO 8601
subscriber.idThe beneficiary's ABHA
messageA human-readable sentence the app can display as it stands
domain_valuesOptional map of the domain headers, for audit or richer rendering
{
"notification_id": "notif_20260428_001",
"topic_code": "workflow_events",
"timestamp": "2026-04-28T14:30:00+05:30",
"subscriber": { "id": "ravi@abdm" },
"message": "Preauthorization approved for Rs. 50,000. Valid from 2026-04-28 to 2026-05-05. Reference: PA-2026-004567",
"domain_values": {
"x-hcx-correlation_id": "corr_20260428_12345",
"x-hcx-status": "response.complete",
"x-hcx-action": "preauth_response",
"x-hcx-amount_submitted": "75000.00"
}
}

The message field is the point of the whole exchange. It is written by the exchange to be shown to a patient without parsing, and an app that ignores it and renders its own sentence from domain_values is doing avoidable work and will drift from what every other app shows.

domain_values is where the named domain headers actually appear, and it is the clearest evidence in the corpus that domain headers are a real mechanism rather than a placeholder. Envelope Fields lists them.

Event types

EventStatus values
preauth_requestqueued, processing
preauth_responseapproved, rejected
claim_requestqueued, processing
claim_responseapproved, rejected
payment_noticepaid, pending
communicationinformation_required

Note that this vocabulary is not the workflow-code vocabulary and not the status-word vocabulary. It is a third, simpler set, designed for display.

Errors

CodeMeaningWhat to do
401Token expiredRegenerate and retry
403Not authorisedCheck your registry entry and role
409Subscription already existsShould not occur under last-linked-wins
500Gateway problemRetry with backoff

What the payer and provider do

Nothing extra. The exchange generates notifications from the traffic that already flows. A payer's ordinary responses feed them, and the payer's own notifications carry workflow N01.

For a hospital that also runs a patient app, the two are separate participants with separate codes and separate certificates, even inside one organisation.

Security and privacy

Four requirements from the integration document, none of them optional in production.

  • Store the access token encrypted, refresh before expiry, and never log the participant secret.
  • Enforce HTTPS with TLS 1.2 or newer on the callback.
  • Validate the JWT the exchange signs its call with, and check that sender_code is the exchange. The public key problem described in Governance and Audit applies here too.
  • Obtain explicit consent from the beneficiary before subscribing, and show the subscription state somewhere the beneficiary can find and change it.

That last one is the substantive difference between this role and the others. A hospital's participation is contracted; a patient app's is consented to, one beneficiary at a time.

What this chapter cannot tell you

The integration document is written against an older reading of the protocol than the rest of the corpus. It gives alg as RSA-OAEP rather than RSA-OAEP-256, and a token life of 6,000 seconds where other sources say 300 or 1,200. Follow the current protocol as Envelope Fields and Session Token give it, and treat the document's payload shapes as the part that is specific to notifications.

No sample notification bundle exists in the corpus, and no participant is recorded as having exercised this exchange.