Skip to main content

Blood bank discovery

Blood bank discovery is the smallest service on UHI: one call pair. Your app sends a search with a blood group, a component and a location, and gets back blood banks with unit counts, addresses and phone numbers.

Read UHI services first, for the context block, the acknowledgement model, signing and the two transports.

Scope

Discovery only: search and on_search. There is no booking or reservation. Put the blood bank's phone number somewhere the user cannot miss it, because calling is how a unit gets held.

Service identity

FieldValueNote
context.domainnic2008:86906Fixed. A wrong value means no HSPA answers your search
context.core_version0.7.1Must match exactly
context.actionsearch or on_searchSet by the sender
message.intent.fulfillment.typeBloodStockFixed for every blood bank search

Who is involved

Both roles are open here. An organisation can onboard as either or both.

RoleWhat it does
EUAA patient or clinician facing app. Sends searches, receives results at its callback URL
HSPAA blood bank management system or aggregator. Answers searches from its own inventory database

At the time of the document there was one registered blood bank HSPA on the network: e-RaktKosh, the centralised blood bank management system.

NHA sets a bar for the HSPA role. Your blood bank database has to be maintained independently and cover stock at a scope and quality comparable to e-RaktKosh. Integrations built on manually maintained or infrequently updated records will not be approved for production.

The flow

StepWhoWhat happens
1Your EUAPosts search to the gateway with blood group, component and location
2GatewayReturns HTTP 200 with an acknowledgement. This confirms receipt only
3GatewayRoutes the search to every registered blood bank HSPA
4HSPAQueries its inventory database
5HSPAPosts on_search to the gateway with availability and unit counts
6GatewayForwards on_search to your consumer_uri
7Your EUAReturns HTTP 200 and aggregates results as they arrive

There is no end signal. Responses land one at a time and nothing tells you the last one has arrived. Use a timeout window of 10 to 15 seconds, and display results as they come in.

Two search modes

Blood group and component filters work with either mode.

ModeMandatoryOptionalBehaviour
GPS and radiuslocation.gps, location.radiusBlood group, componentReturns matching blood banks within the radius. Group and component default to All if omitted
State and districtlocation.state (name and code), location.district (name and code)Blood group, componentReturns matching blood banks in that district

Support both. GPS returns incomplete results where blood bank density is low, and state and district is the only option when GPS is unavailable.

context is the standard UHI block, with domain fixed to nic2008:86906 and action set to search. Set city to std:011 as the default. The filters live in message.intent.

FieldValueWhat it is
item.descriptor.nameBlood group name or AllThe group being searched, for example O+Ve
item.descriptor.codeBlood group code or -1Numeric code from the master list below. -1 means all groups
category.descriptor.nameComponent nameFor example WholeBlood, PlateletConcentrate
category.descriptor.codeComponent codeNumeric code from the master list below
fulfillment.typeBloodStockFixed
fulfillment.start.time.timestampISO 8601Start of the availability window
fulfillment.end.time.timestampISO 8601End of the availability window
location.gpslatitude,longitudeSearch origin, for GPS mode
location.radius.typeCONSTANTFixed, for GPS mode
location.radius.valueNumeric stringRadius in km, for example 10.0
location.radius.unitkmFixed
location.state.nameState name in capitalsFor example DELHI
location.state.codeNumeric state codeFor example 7
location.district.nameDistrict name in capitalsFor example SOUTH
location.district.codeNumeric district codeFor example 83

Sample, GPS with a specific group and component

{
"context": {
"domain": "nic2008:86906",
"country": "IND",
"city": "std:011",
"action": "search",
"core_version": "0.7.1",
"consumer_id": "<YOUR_EUA_ID_FROM_NHA_ONBOARDING>",
"consumer_uri": "<YOUR_HTTPS_CALLBACK_URL>",
"message_id": "5cc46ce0-cd96-11ef-957f-718cff4e4e0a",
"timestamp": "2025-01-08T07:58:36.421576Z",
"transaction_id": "5cc46ce0-cd96-11ef-957f-718cff4e4e0a"
},
"message": {
"intent": {
"item": {
"descriptor": { "name": "O+Ve", "code": "15" }
},
"category": {
"descriptor": { "name": "WholeBlood", "code": "11" }
},
"fulfillment": {
"type": "BloodStock",
"start": { "time": { "timestamp": "2025-01-08T13:28:36" } },
"end": { "time": { "timestamp": "2025-01-08T23:59:59" } }
},
"location": {
"gps": "17.3788008,78.4368212",
"radius": { "type": "CONSTANT", "value": "10.0", "unit": "km" }
}
}
}
}

To search every blood group at once, set item.descriptor.name to All and item.descriptor.code to -1.

Sample, state and district

Replace the location block. Everything else is the same.

{
"location": {
"state": { "name": "DELHI", "code": "7" },
"district": { "name": "SOUTH", "code": "83" }
}
}
FieldTypeWhat it is
context.actionstringon_search
context.provider_idstringThe responding HSPA
context.provider_uristringThe HSPA's callback URL
context.transaction_idstringEchoed from your search. Use it to correlate
catalog.descriptor.namestringHSPA or data source name, for example e-RaktKosh
providers[].idstringUnique ID for this blood bank record
providers[].descriptor.namestringBlood bank name
providers[].descriptor.short_descstringBlood bank type, for example Govt., Charitable/Vol
providers[].categories[].descriptor.namestringBlood component name
providers[].categories[].descriptor.codestringBlood component code
providers[].fulfillments[].typestringAvailable or NotAvailable
providers[].items[].descriptor.namestringBlood group name
providers[].items[].descriptor.codestringBlood group code
providers[].items[].quantity.countintegerUnits available for this group
providers[].items[].fulfillment_idstringPoints at the fulfilment record that says Available or NotAvailable
providers[].location.gpsstringBlood bank coordinates
providers[].location.addressstringFull address
providers[].location.city.namestringCity
providers[].location.state.namestringState
providers[].location.district.namestringDistrict
providers[].contact.phonestringBlood bank phone number
providers[].contact.emailstringBlood bank email

The part that trips people up

Availability is not a field on the item. Each provider declares a small set of fulfillments, one meaning Available and one meaning NotAvailable. Each blood group item points at one of them through fulfillment_id. A group with a unit count of 16 can still be unavailable. Resolve the link before you show a number to a user.

Sample response

{
"context": {
"domain": "nic2008:86906",
"action": "on_search",
"consumer_id": "<YOUR_EUA_ID_FROM_NHA_ONBOARDING>",
"consumer_uri": "<YOUR_HTTPS_CALLBACK_URL>",
"provider_id": "nha.hspa",
"provider_uri": "https://hspasbx.abdm.gov.in/api/v1/bloodbank",
"transaction_id": "c51c2800-cd96-11ef-957f-718cff4e4e0a",
"message_id": "c51c2800-cd96-11ef-957f-718cff4e4e0a"
},
"message": {
"catalog": {
"descriptor": {
"name": "e-RaktKosh",
"short_desc": "e-RaktKosh: A Centralized Blood Bank Management System"
},
"providers": [
{
"id": "0",
"descriptor": {
"name": "Janseva Blood Centre",
"short_desc": "Charitable/Vol"
},
"categories": [
{ "id": "0", "descriptor": { "name": "WholeBlood", "code": "11" } }
],
"fulfillments": [
{ "id": "0", "type": "NotAvailable" },
{ "id": "1", "type": "Available" }
],
"items": [
{
"id": "0",
"descriptor": { "name": "O+Ve", "code": "15" },
"quantity": { "count": 2 },
"category_id": "0",
"fulfillment_id": "1"
},
{
"id": "1",
"descriptor": { "name": "AB+Ve", "code": "17" },
"quantity": { "count": 16 },
"category_id": "0",
"fulfillment_id": "0"
}
],
"location": {
"gps": "18.5246036,73.792927",
"address": "Paud Road, Pune, Maharashtra",
"city": { "name": "Pune" },
"state": { "name": "Maharashtra", "code": "27" },
"district": { "name": "Pune", "code": "521" }
},
"contact": {
"phone": "8987628900",
"email": "contact@jansevabc.org"
}
}
]
}
}
}

In that response O+Ve points at fulfilment 1, which is Available. AB+Ve has a count of 16 but points at fulfilment 0, which is NotAvailable.

Blood group master list

Use these in item.descriptor.code.

CodeGroup
-1All
11A+Ve
12A-Ve
13B+Ve
14B-Ve
15O+Ve
16O-Ve
17AB+Ve
18AB-Ve
22Oh+Ve
23Oh-Ve

Blood component master list

Use these in category.descriptor.code.

CodeComponent
11Whole Blood
12Packed Red Blood Cells
13Fresh Frozen Plasma
14Single Donor Platelet
16Platelet Rich Plasma
17Cryoprecipitate
18Single Donor Plasma
19Plasma
20Platelet Concentrate
21Cryo Poor Plasma
23Random Donor Platelets
24Platelets Additive Solutions
28SAGM Packed Red Blood Cells
29Irradiated RBC
30Leukoreduced RBC

Known limitations

LimitationWhat to do about it
GPS search returns incomplete results where blood bank density is lowOffer state and district as a visible alternative, not a hidden fallback
Update frequency varies by blood bank. Some update in real time, others dailyShow a disclaimer that counts are indicative and may have changed. Tell users to call before travelling
Responses arrive asynchronously with no end signalUse a 10 to 15 second timeout and render results as they arrive
No pagination on on_searchExpect large payloads. Paginate or lazy load on the client
No booking or reservationShow the blood bank phone number prominently

Prerequisites

For an EUA:

  • ABDM M2 with HIE-CM completed. This is a hard prerequisite for any UHI service.
  • A publicly reachable HTTPS consumer_uri.
  • Ed25519 signing with BLAKE-512 body hashing.
  • Asynchronous handling. Do not block on a synchronous reply to search.

For an HSPA:

  • An independently maintained blood bank database with real-time or near real-time inventory, comparable in scope and quality to e-RaktKosh.
  • A publicly reachable HTTPS provider_uri to receive searches from the gateway.
  • Ed25519 signing on every outbound response.
  • Sandbox integration and written sign-off before production.

What is missing here

  • No error code list is published for this service.
  • No response time SLA is published for HSPAs beyond an acceptable latency window.
  • State and district codes are issued at onboarding. Delhi is 7 and South district is 83.

Next