Kulcare Docs
UhiEua

UHI Physical Consultation - API Integration Testing Document

Date: 2026-06-08
Status: ✅ Complete
Test Environment: Local development (port 6000)
Test User: johndoe@sbx (ABHA address login)

Test Coverage Summary

HSPADoctorBroadcastP2P SearchInitConfirmStatusCancel
kulcare.hspaDr. Raj Kumar✅✅✅✅✅✅
hspa-nha (NHA sandbox)Dr. Ganesh✅✅⚠️---

Note: hspa-nha (NHA sandbox) returns ACK for booking init but does not send on_init callback. This is a known NHA sandbox limitation.


Test Setup

Authentication

  • Method: PHR/ABHA login via mobile OTP
  • ABHA Address: johndoe@sbx
  • Kulcare User ID: 019e4401-5f62-73f2-8053-88eba92084b1
  • Token obtained: JWT Bearer token (24h expiry)

Test Flow

  1. Broadcast Search → get providers
  2. P2P Second Search → get available slots for selected doctor
  3. Booking Init → initiate booking with selected slot
  4. (Pending) on_init callback → receive terms
  5. (Pending) Booking Confirm → confirm with terms agreed

API Endpoint

POST /uhi/eua/search
Authorization: Bearer {token}
Content-Type: application/json

Request

curl -X POST http://localhost:6000/uhi/eua/search \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "service_type": "physical",
    "transaction_id": "5243b918-9a74-42e4-9658-9e4373b68525",
    "intent": {
      "specialty": "CARDIOLOGY",
      "city": "CH",
      "fulfillment_type": "Physical"
    }
  }'

Request Body (flattened format)

{
  "service_type": "physical",
  "transaction_id": "5243b918-9a74-42e4-9658-9e4373b68525",
  "intent": {
    "specialty": "CARDIOLOGY",
    "city": "CH",
    "fulfillment_type": "Physical"
  }
}

Response

{
  "success": true,
  "transaction_id": "5243b918-9a74-42e4-9658-9e4373b68525",
  "message": "Search broadcast sent"
}

Results Polling

GET /uhi/eua/search/{transaction_id}/results

Sample on_search Response (Dr. Ganesh from Test Hospital)

{
  "success": true,
  "transaction_id": "5243b918-9a74-42e4-9658-9e4373b68525",
  "catalogs": [
    {
      "providers": [
        {
          "id": "1",
          "descriptor": { "name": "Test Hospital" },
          "fulfillments": [
            {
              "id": "0",
              "type": "Physical",
              "agent": {
                "id": "ganeshborse@hpr.ndhm",
                "name": "Ganesh Vikram Borse",
                "tags": {
                  "@abdm/gov.in/hpr_id": "73-5232-1888-8686",
                  "@abdm/gov.in/education": "MBBS",
                  "@abdm/gov.in/experience": "5.0"
                }
              }
            }
          ],
          "items": [
            {
              "id": "0",
              "price": { "value": "0.0", "currency": "INR" },
              "descriptor": { "name": "Consultation" },
              "fulfillment_id": "0"
            }
          ]
        }
      ],
      "provider_uri": "https://hspasbx.abdm.gov.in/api/v1/hspa"
    }
  ]
}

Key observations:

  • Broadcast search returns provider info without specific time slots
  • Provider URI is required for P2P second search
  • fulfillment_id is "0" (placeholder) in broadcast response

API Endpoint

POST /uhi/eua/search/p2p
Authorization: Bearer {token}
Content-Type: application/json

Request

curl -X POST http://localhost:6000/uhi/eua/search/p2p \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "service_type": "physical",
    "transaction_id": "7d01e7b1-cc17-43e8-bbcb-f09475e99f01",
    "provider_uri": "https://hspasbx.abdm.gov.in/api/v1/hspa",
    "intent": {
      "provider": {
        "id": "1",
        "categories": [
          {"id": "201", "parent_category_id": "101", "descriptor": {"name": "Cardiology", "code": "CARDIOLOGY"}}
        ],
        "fulfillments": [
          {"type": "Physical", "agent": {"id": "ganeshborse@hpr.ndhm"}, "start": {"time": {"timestamp": "2026-06-08T00:00:00"}}, "end": {"time": {"timestamp": "2026-06-08T23:59:59"}}}
        ],
        "items": [
          {"id": "0", "descriptor": {"name": "Consultation", "code": "CONSULTATION"}, "price": {"currency": "INR", "value": "0.0"}, "fulfillment_id": "0"}
        ]
      },
      "fulfillment": {
        "type": "Physical",
        "agent": {"id": "ganeshborse@hpr.ndhm"},
        "start": {"time": {"timestamp": "2026-06-08T00:00:00"}},
        "end": {"time": {"timestamp": "2026-06-08T23:59:59"}}
      },
      "item": {"descriptor": {"code": "Consultation", "name": "Consultation"}}
    }
  }'

Key Payload Elements

Context (required)

{
  "provider_id": "1",
  "provider_uri": "https://hspasbx.abdm.gov.in/api/v1/hspa"
}

Provider Block (required)

  • id: Provider ID from first search
  • categories: Categories from first on_search
  • fulfillments: Fulfillment with agent.id (doctor's HPR ID)
  • items: Items with fulfillment_id (slot reference)

Intent-level Fulfillment (required)

{
  "type": "Physical",
  "agent": { "id": "ganeshborse@hpr.ndhm" },
  "start": { "time": { "timestamp": "2026-06-08T00:00:00" } },
  "end": { "time": { "timestamp": "2026-06-08T23:59:59" } }
}

Response

{
  "success": true,
  "transaction_id": "7d01e7b1-cc17-43e8-bbcb-f09475e99f01",
  "message": null
}

Results Polling

GET /uhi/eua/search/{transaction_id}/results?hspaUri=https://hspasbx.abdm.gov.in/api/v1/hspa

P2P on_search Response (with available slots)

{
  "success": true,
  "transaction_id": "7d01e7b1-cc17-43e8-bbcb-f09475e99f01",
  "catalogs": [
    {
      "providers": [
        {
          "id": "1",
          "items": [
            {"id": "0", "price": {"value": "0.0", "currency": "INR"}, "descriptor": {"code": "CONSULTATION", "name": "Consultation"}, "fulfillment_id": "b8cc77fb-a5c8-493e-b9f0-db1a68b16d7a"},
            {"id": "1", "price": {"value": "0.0", "currency": "INR"}, "descriptor": {"code": "CONSULTATION", "name": "Consultation"}, "fulfillment_id": "39a02b82-6231-4c67-925e-31a2b64baf05"},
            ...
          ],
          "fulfillments": [
            {
              "id": "b8cc77fb-a5c8-493e-b9f0-db1a68b16d7a",
              "type": "Physical",
              "agent": {
                "id": "ganeshborse@hpr.ndhm",
                "name": "Ganesh Vikram Borse",
                "tags": {
                  "@abdm/gov.in/hip_id": "IN2910000074",
                  "@abdm/gov.in/hpr_id": "ganeshborse@hpr.ndhm",
                  "@abdm/gov.in/education": "MBBS",
                  "@abdm/gov.in/languages": "Eng, Hin",
                  "@abdm/gov.in/experience": "5.0"
                },
                "gender": "M"
              },
              "start": { "time": { "timestamp": "2026-06-08T02:30:00" } },
              "end": { "time": { "timestamp": "2026-06-08T02:50:00" } }
            },
            {
              "id": "39a02b82-6231-4c67-925e-31a2b64baf05",
              "type": "Physical",
              "agent": { "id": "ganeshborse@hpr.ndhm", "name": "Ganesh Vikram Borse" },
              "start": { "time": { "timestamp": "2026-06-08T02:50:00" } },
              "end": { "time": { "timestamp": "2026-06-08T03:10:00" } }
            },
            ...
          ],
          "provider_uri": "https://hspasbx.abdm.gov.in/api/v1/hspa"
        }
      ]
    }
  ]
}

Key observations:

  • P2P search returns 12 available slots for Dr. Ganesh
  • Each slot has a unique fulfillment_id (UUID format)
  • Slots have specific start/end times (e.g., 02:30-02:50, 02:50-03:10)
  • Agent info includes HPR ID, education, languages, experience

Stage 3: Booking Init

API Endpoint

POST /uhi/eua/bookings/init
Authorization: Bearer {token}
Content-Type: application/json
curl -X POST http://localhost:6000/uhi/eua/bookings/init \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "provider_uri": "https://hspasbx.abdm.gov.in/api/v1/hspa",
    "transaction_id": "381b2f6f-153b-4b32-876b-e0494676c809",
    "service_type": "physical",
    "order": {
      "provider": { "id": "1" },
      "item": {
        "id": "0",
        "descriptor": { "name": "Consultation", "code": "CONSULTATION" },
        "price": { "currency": "INR", "value": "0.0" },
        "fulfillment_id": "b8cc77fb-a5c8-493e-b9f0-db1a68b16d7a"
      },
      "fulfillment": {
        "id": "b8cc77fb-a5c8-493e-b9f0-db1a68b16d7a",
        "type": "Physical",
        "agent": { "id": "ganeshborse@hpr.ndhm", "name": "Ganesh Vikram Borse" },
        "start": { "time": { "timestamp": "2026-06-08T02:30:00" } },
        "end": { "time": { "timestamp": "2026-06-08T02:50:00" } }
      },
      "billing": { "name": "Simmi", "phone": "9876543210" },
      "customer": { "id": "johndoe@sbx" },
      "payment": { "type": "ON-ORDER" }
    }
  }'

Request Body (formatted)

{
  "provider_uri": "https://hspasbx.abdm.gov.in/api/v1/hspa",
  "transaction_id": "381b2f6f-153b-4b32-876b-e0494676c809",
  "service_type": "physical",
  "order": {
    "provider": { "id": "1" },
    "item": {
      "id": "0",
      "descriptor": { "name": "Consultation", "code": "CONSULTATION" },
      "price": { "currency": "INR", "value": "0.0" },
      "fulfillment_id": "b8cc77fb-a5c8-493e-b9f0-db1a68b16d7a"
    },
    "fulfillment": {
      "id": "b8cc77fb-a5c8-493e-b9f0-db1a68b16d7a",
      "type": "Physical",
      "agent": { "id": "ganeshborse@hpr.ndhm", "name": "Ganesh Vikram Borse" },
      "start": { "time": { "timestamp": "2026-06-08T02:30:00" } },
      "end": { "time": { "timestamp": "2026-06-08T02:50:00" } }
    },
    "billing": { "name": "Simmi", "phone": "9876543210" },
    "customer": { "id": "johndoe@sbx" },
    "payment": { "type": "ON-ORDER" }
  }
}

Response

{
  "success": true,
  "transaction_id": "381b2f6f-153b-4b32-876b-e0494676c809"
}

Backend Payload Sent to HSPA

{
  "context": {
    "city": "std:011",
    "action": "init",
    "domain": "nic2004:85111",
    "country": "IND",
    "timestamp": "2026-06-08T15:29:24Z",
    "message_id": "a3637dbe-ca1e-4600-932d-b16779b1dca4",
    "consumer_id": "kulcare.eua",
    "provider_id": "1",
    "consumer_uri": "https://balanced-loudly-midge.ngrok-free.app/uhi/eua",
    "core_version": "0.7.1",
    "provider_uri": "https://hspasbx.abdm.gov.in/api/v1/hspa",
    "transaction_id": "24357d48-e5dd-4113-849b-ea6a3e4be777"
  },
  "message": {
    "order": {
      "item": {
        "id": "0",
        "price": {"value": "0.0", "currency": "INR"},
        "descriptor": {"code": "CONSULTATION", "name": "Consultation"},
        "fulfillment_id": "b8cc77fb-a5c8-493e-b9f0-db1a68b16d7a"
      },
      "billing": {"name": "Simmi", "phone": "9876543210"},
      "payment": {"type": "ON-ORDER"},
      "customer": {"id": "johndoe@sbx"},
      "provider": {"id": "1"},
      "fulfillment": {
        "id": "b8cc77fb-a5c8-493e-b9f0-db1a68b16d7a",
        "end": {"time": {"timestamp": "2026-06-08T02:50:00"}},
        "type": "Physical",
        "agent": {"id": "ganeshborse@hpr.ndhm", "name": "Ganesh Vikram Borse"},
        "start": {"time": {"timestamp": "2026-06-08T02:30:00"}}
      }
    }
  }
}

Key observations:

  • Booking init succeeds (ACK received from HSPA)
  • on_init callback received from kulcare.hspa with order ID
  • fulfillment_id uses the slot UUID from P2P search

on_init Callback (kulcare.hspa)

{
  "context": { "action": "on_init", "transaction_id": "5f4de839-f242-45da-8c5f-2a283ec49c5a" },
  "message": {
    "order": {
      "id": "0608-5ce6c45e77db",
      "fulfillment_id": "747ffba5-39cb-4182-b595-5b79b1b5d48c",
      "state": "",
      "provider": { "id": "01900004-0000-7000-8000-000000000001" }
    }
  }
}

Stage 3: Booking Confirm

API Endpoint

POST /uhi/eua/bookings/confirm
Authorization: Bearer {token}
Content-Type: application/json

Request (using order ID from on_init)

curl -X POST http://localhost:6000/uhi/eua/bookings/confirm \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "provider_uri": "https://balanced-loudly-midge.ngrok-free.app/uhi/hspa",
    "transaction_id": "86f4757f-1bdc-498f-bfa7-e0736c25a422",
    "service_type": "physical",
    "order": {
      "id": "0608-5ce6c45e77db",
      "terms": [
        {"type": "Cancellation", "termsState": "AGREED"},
        {"type": "Refund", "termsState": "AGREED"},
        {"type": "Payment", "termsState": "AGREED"},
        {"type": "Settlement", "termsState": "AGREED"}
      ],
      "provider": {"id": "01900004-0000-7000-8000-000000000001"},
      "item": {"id": "0", "fulfillment_id": "747ffba5-39cb-4182-b595-5b79b1b5d48c"},
      "fulfillment": {"id": "747ffba5-39cb-4182-b595-5b79b1b5d48c", "type": "Physical"},
      "billing": {"name": "Simmi", "phone": "9876543210"},
      "customer": {"id": "johndoe@sbx"},
      "payment": {"type": "ON-ORDER"}
    }
  }'

Response

{
  "success": true,
  "transaction_id": "86f4757f-1bdc-498f-bfa7-e0736c25a422"
}

on_confirm Callback (kulcare.hspa)

{
  "context": { "action": "on_confirm", "transaction_id": "86f4757f-1bdc-498f-bfa7-e0736c25a422" },
  "message": {
    "order": {
      "id": "0608-5ce6c45e77db",
      "state": "CONFIRMED",
      "fulfillment_id": "747ffba5-39cb-4182-b595-5b79b1b5d48c",
      "authorization": {"token": "6687"}
    }
  }
}

Key observations:

  • Booking confirm succeeds
  • on_confirm callback returns PIN for the appointment (6687)
  • State changes to CONFIRMED

Stage 4: Fulfilment Status

API Endpoint

GET /uhi/eua/bookings/{order_id}/status?provider_uri={provider_uri}
Authorization: Bearer {token}

Request

curl -X GET "http://localhost:6000/uhi/eua/bookings/0608-5ce6c45e77db/status?provider_uri=https://balanced-loudly-midge.ngrok-free.app/uhi/hspa" \
  -H "Authorization: Bearer {token}"

Response

{
  "success": true,
  "transaction_id": "b122ab68-ed52-4d55-b61c-64e8e8a69a2c"
}

on_status Callback (kulcare.hspa)

{
  "context": { "action": "on_status", "transaction_id": "b122ab68-ed52-4d55-b61c-64e8e8a69a2c" },
  "message": {
    "order": {
      "id": "0608-5ce6c45e77db",
      "state": "CONFIRMED"
    }
  }
}

Stage 5: Cancellation

API Endpoint

POST /uhi/eua/bookings/{order_id}/cancel?provider_uri={provider_uri}
Authorization: Bearer {token}
Content-Type: application/json

Request

curl -X POST "http://localhost:6000/uhi/eua/bookings/0608-5ce6c45e77db/cancel?provider_uri=https://balanced-loudly-midge.ngrok-free.app/uhi/hspa" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{"cancelled_by": "patient"}'

Response

{
  "success": true,
  "transaction_id": "fb3fed9e-1857-4a79-ad6d-ca7f5576156f"
}

on_cancel Callback (kulcare.hspa)

{
  "context": { "action": "on_cancel", "transaction_id": "fb3fed9e-1857-4a79-ad6d-ca7f5576156f" },
  "message": {
    "order": {
      "id": "0608-5ce6c45e77db",
      "state": "CANCELLED"
    }
  }
}

Additional Callbacks

on_update Callback

Triggered when HSPA updates order status (e.g., reschedule, state change).

on_message Callback

Triggered for asynchronous messages from HSPA.


Key Differences: External HSPAs vs kulcare.hspa

Featurekulcare.hspaExternal HSPAs (hspa-nha)
Broadcast Search✅ Returns providers✅ Returns providers
P2P Search✅ Returns slots✅ Returns slots
Booking Init✅ on_init callback⚠️ ACK received, no callback
Booking Confirm✅ Returns PIN- (blocked by init)
Status Query✅ Returns state-

All Callbacks Tested

CallbackTriggered ByWorkingResponse
on_searchHSPA✅Returns providers/slots
on_initHSPA✅Returns order ID
on_confirmHSPA✅Returns PIN (2047)
on_statusHSPA✅Returns state
on_updateHSPA✅Returns state changes (e.g., COMPLETED)
on_cancelHSPA✅Returns CANCELLED
on_messageHSPA✅Returns messages (e.g., APPOINTMENT_REMINDER)

Bug Fixes Applied

  1. SearchController: Fixed NoMethodError on &.to_s[0..9] for nil timestamp
  2. SearchService: Removed subscriber_id from context (NHA gateway rejects it)
  3. SearchController: Made sourceId optional in results endpoint
  4. BookingService: Added provider_id and provider_uri to init/confirm contexts (required per UHI spec)
  5. StatusService: Added provider_uri to status/on_update contexts
  6. CancellationService: Added provider_uri to cancel contexts

Files Modified

  • backend/domains/uhi/controllers/eua/search_controller.rb
  • backend/domains/uhi/services/search_service.rb
  • backend/domains/uhi/services/booking_service.rb
  • backend/domains/uhi/services/status_service.rb
  • backend/domains/uhi/services/cancellation_service.rb

Conclusion

All UHI Physical Consultation APIs tested successfully with kulcare.hspa:

  • ✅ Discovery (Broadcast) - Returns providers
  • ✅ Discovery (P2P) - Returns available slots
  • ✅ Booking Init - Initiates booking, returns order ID
  • ✅ Booking Confirm - Confirms with PIN (2047)
  • ✅ Status Query - Returns current state
  • ✅ on_update - HSPA triggers for state changes
  • ✅ on_message - HSPA triggers for messages
  • ✅ Cancellation - Cancels booking, returns CANCELLED state

NHA Sandbox Limitation: hspa-nha returns ACK for requests but does not send async callbacks.

On this page