Compare commits

...

699 Commits

Author SHA1 Message Date
543f78e696 fix(pwa): add version query to bundle script tags to bust browser HTTP cache 2026-10-29 00:42:44 +05:30
ecb7eb9bd1 fix(pwa): recompile Doctor, Nursing, and MedicalStore bundles with classic React runtime to eliminate ES module import syntax error 2026-10-29 00:41:01 +05:30
47b64f7bf6 feat(seed,agents): enforce single Dr. Demo on installation and add HMS core skills & rules 2026-10-28 13:37:23 +05:30
565586aa6e fix(auth): prevent background AJAX/polling routes from hijacking post-login redirect 2026-10-28 00:40:32 +05:30
6c1c19153c security: remove obsolete ABDM sandbox docs, DreamSoft middleware references, and purge exposed credentials 2026-10-28 00:17:24 +05:30
2ae0ba5d6f docs: modernize README.md with comprehensive installation guide, medical templates seeder, and Gitea repository links 2026-10-28 00:05:29 +05:30
79ae8efa9e docs: add MedicalTemplatesLibrarySeeder and safe mode guarantee to Ubuntu installation guide 2026-10-27 23:37:16 +05:30
8ad2a2923f fix(seeds): ensure MedicalTemplatesLibrarySeeder preserves existing templates and inserts only missing ones 2026-10-27 23:23:35 +05:30
ad1df321c8 feat(templates): add comprehensive hospital medical templates library for pathology, radiology, ipd discharge, ipd documents, and opd 2026-10-27 23:17:52 +05:30
5be2644032 docs(install): add Ubuntu deployment guide, automated installer script, and starter database 2026-10-27 21:45:17 +05:30
61a3503fde fix(auth): polish centered login card overflow styling 2026-10-27 21:38:24 +05:30
1b34b92b3c feat(auth): add standalone layout support when accessing login-settings directly 2026-10-27 21:35:02 +05:30
2ed2bfa99c feat(auth): add Login Page Configuration Panel with Left/Center/Right layout and styling controls 2026-10-27 21:28:44 +05:30
aac71afc70 Refine hero for dark wallpaper: 3D format logo card with soft curved corners, radiant white heading with dark contour outline, and high-contrast meta text 2026-10-27 21:01:53 +05:30
eaf131f96e Adopt Johri Hospital official Soft Teal brand identity: ivory canvas with botanical leaf motif, deep navy typography, and seamless logo placement 2026-10-27 20:11:04 +05:30
c2f435b1c9 Refine hero: frosted logo mount for transparent dark navy logo, dark outlined heading without neon glare, and natural vertical lighting gradient 2026-10-27 19:47:25 +05:30
06bcd333a0 Refine login hero: standalone logo with ambient backdrop, 360-degree contour highlight for hospital title, remove pills and footer note 2026-10-27 19:38:05 +05:30
7bb751cc41 feat(auth/settings): add hospital login wallpaper upload and redesign right-docked login page
- Add login wallpaper upload, preview, and deletion in Hospital Profile settings

- Redesign login page with right-docked form and left hospital branding hero

- Implement clean blank neutral fallback when no wallpaper is configured

- Add automated unit tests for wallpaper rendering and fallback behavior
2026-10-27 12:19:07 +05:30
cb5c1e3230 fix(pharmacy): handle unique item_name collision and auto-expand column in abdm drug sync 2026-10-27 02:00:43 +05:30
1880ec60ae feat(pharmacy): implement abdm sync-pack command and local-first hybrid drug search 2026-10-27 01:53:21 +05:30
0d9e0b1ccf fix(pharmacy): high-contrast white text on active selection in drug search dropdown 2026-10-27 01:39:57 +05:30
728eaea113 feat(pharmacy): display full drug details with strength, formulation, and manufacturer in abdm search suggestions 2026-10-27 01:35:50 +05:30
cf25a00ef5 perf(pharmacy): optimize product master load with company ajax search and cached abdm drug lookup 2026-10-27 01:23:34 +05:30
40ce7b7a0f fix(mobile): add auto-search on typing in stock audit and remove copyright footer 2026-10-27 00:41:59 +05:30
c26b5bf01e fix(pharmacy): resolve internal doctor linking and auto-matching for mobile draft invoices 2026-10-27 00:32:25 +05:30
97ca466d2f fix(pharmacy): resolve CSRF, schema auto-migration, and error handling for mobile draft basket 2026-10-27 00:23:10 +05:30
9f6d9d3799 feat(pharmacy): add Central Pharmacy Mobile PWA with IPD/OPD/UHID search, Rx picker, draft billing, and physical stock audit 2026-10-26 23:49:28 +05:30
3c69ba9fe8 fix(layout): pin copyright footer to bottom on blank pages and all screen sizes 2026-10-26 23:19:38 +05:30
8737aa926d feat(pharmacy): show 4 frequent sales and billing buttons directly on top bar alongside store and reports dropdowns 2026-10-26 23:02:04 +05:30
f5eaad01c8 feat(pharmacy): consolidate navigation buttons into header dropdowns and expand working area 2026-10-26 22:55:09 +05:30
06efc03e1a feat(pharmacy): show salt under medicine name and separate Disc % and Scheme into individual columns 2026-10-26 22:45:27 +05:30
5a13ce2b56 feat(pharmacy): enhance PO creation with medicine master search, last PTR auto-fill, exact GST selection, and scheme/discount support 2026-10-26 22:31:00 +05:30
083a82dcb6 feat(pharmacy): add expired medicine disposal, quick return and rich product search
- Add direct expiry disposal (write-off) and quick return from Nearest Expiry report
- Add Disposal Register view and PDF audit certificate
- Add supplier info and rich selectable autocomplete in purchase return search
- Register disposal & quick return routes in Routes.php
2026-10-25 23:27:06 +05:30
51c06304d0 fix(billing & pharmacy): fix IPD medical bill package classification, default empty qty, and doctor ajax selection
- IPD Billing: replace ambiguous 'In Package' switch with explicit 'Include in IPD Bill (Normal)' / 'In Package (Covered)' dropdown selector in Medical Bills and Package tabs
- IPD Billing: return recalculated summary metrics from credit-type endpoint and update dashboard cards in real-time
- Pharmacy: classify IPD bills using ipd_credit_type instead of group_invoice_id to correctly show Package: No for credit bills and add to Total Credit
- Pharmacy Billing: default item quantity to blank instead of 0 to allow direct typing without backspacing, with validation against 0/empty submissions
- Pharmacy Invoice: add outside doctor/consulting doctor selection and auto-save via AJAX
2026-10-25 14:15:42 +05:30
6cc34057b5 fix(abdm): capture patient-modified consent dates, fix premature expiry, and update consent UI labels
- Extract and contrast both requested and patient-granted date ranges and eraseAt timestamps from ABDM consent artefacts
- Fix premature session expiration when patient grants longer consent validity than initially requested by HIU
- Update UI labels from Valid From / Valid To to Request From / Request To and Consent Valid Upto
- Show original requested dates struck-through and granted dates highlighted with Updated badges in consent detail modals
- Add visual indicators for patient-modified dates in consent requests tables
2026-10-25 06:39:25 +05:30
43d52163ab fix(abha-create): handle and sanitize upstream ABDM 500 error on address suggestions gracefully 2026-10-24 13:09:50 +05:30
5f9784d7ec feat(abdm & schema): drop patient_master.p_lname and add abha address selector to M1 verify flow 2026-10-24 12:56:13 +05:30
e946000fb9 Allow editing GRN Inspection Details with full item reconciliation and live inventory synchronization 2026-10-23 14:10:31 +05:30
9236ff1da9 fix(abdm): ensure m2LinkInit captures all careContexts and resolves accurate gender 2026-10-23 10:34:23 +05:30
42241beceb docs(abdm): add care context and FHIR standards documentation and agent rules 2026-10-23 09:53:56 +05:30
45f1888227 fix(abdm): preserve structured care context reference in patient referenceNumber during linking 2026-10-23 09:51:31 +05:30
e93ebf7bf6 fix(abdm): support multi-careContext patient array in m2LinkInit 2026-10-23 01:37:58 +05:30
c0196b7e9f fix(abdm): isolate discovery by pending links, session mapping, and historical era cutoff 2026-10-23 00:54:41 +05:30
e4bb4e3464 fix(abdm): partition care context discovery and linking by ABHA address 2026-10-23 00:42:39 +05:30
5219b8bfc6 fix: strictly enforce IP restriction, fix empty whitelist fallback, and update SW to v2 2026-10-22 15:33:26 +05:30
1bd8f57371 fix: explicitly set HTTP 200 on live queue success response 2026-10-22 15:22:27 +05:30
0020d0676c feat(security): restrict /app/queue and live OPD token feed to authorized hospital IPs (WASA CWE-200 remediation) 2026-10-22 15:19:28 +05:30
7547d00bb4 feat(security): place login throttle before CSRF and add visual CAPTCHA verification to login form 2026-10-22 14:45:04 +05:30
61b8bf6a71 feat(medical): use dynamic pharmacy name and hospital branding in GRN and PO print PDFs 2026-10-22 11:16:33 +05:30
9acc580fb7 fix(medical): resolve dynamic container target for Edit Invoice and master edit navigation 2026-10-22 11:06:59 +05:30
deea6529f7 Fix HTTP 500 on GRN view/edit: add self-healing schema migration and null-safe view rendering 2026-10-22 10:44:27 +05:30
09cd46d344 Fix GST calculations and synchronize GRN & Purchase Invoice columns with vendor bill structure 2026-10-22 09:58:04 +05:30
367f63f4f3 Fix WASA observations 5 and 6: user enumeration and login rate limiting 2026-10-21 18:00:25 +05:30
def0d4c80f fix(abdm): include patient_ref and local_patient_id in task pushData 2026-10-21 14:30:19 +05:30
6a247fdb63 fix(abdm): enforce strict ABHA uniqueness and demographic validation on patient linking 2026-10-21 13:59:29 +05:30
4f9f257923 fix(abdm): set link_status to linked on successful push and pass patient_ref 2026-10-21 13:00:56 +05:30
41c70c0151 fix(abdm): provide separate Document Reference section in InvoiceRecord so PHR renders DocumentReference accordion card with embedded PDF 2026-10-21 04:36:54 +05:30
2f0595a3a3 fix(abdm): section.entry should only hold Invoice and DocumentReference without Binary so PHR carousel renders document card 2026-10-21 03:53:46 +05:30
c54cde814c fix(abdm): enforce single section in InvoiceRecord Composition per NRCeS spec so DocumentReference and PDF attach to PHR 2026-10-21 03:40:48 +05:30
5ba548cbbc fix(abdm): enforce NRCeS ISO 8601 with Asia/Kolkata timezone offset across FHIR bundles and ABDM APIs to resolve midnight UTC date mismatch 2026-10-21 03:19:00 +05:30
dfd546b2c2 chore: add dev/ directory to .gitignore for local development tools and notes 2026-10-21 02:00:59 +05:30
050035e1b0 chore: untrack local dev debug scripts and internal notes from repository, update .gitignore 2026-10-21 01:57:44 +05:30
9d568463f1 feat: completely remove HealthPlix integration, controllers, views, and database columns 2026-10-21 01:33:13 +05:30
df2e41c9a4 docs: update repository URLs to Gitea and add deployment pull guide 2026-10-21 01:21:29 +05:30
d098221676 fix(abdm): unify medication request FHIR representation across OPD and discharge (generic salt subtitle, SNOMED food timing, and natural dosage instructions) 2026-10-19 23:06:12 +05:30
a454bd178c fix(abdm): finalize and sync OPD consult and prescription FHIR bundles only on print 2026-10-19 18:53:58 +05:30
ca7d7be953 Update DataTables to 1.13.11 2026-10-19 17:53:35 +05:30
c548c0dce3 Fix WASA security observations: security headers, CSP hardening, JS library updates, API authentication, and data scrubbing 2026-10-19 16:27:17 +05:30
8cbf55537f feat(pharmacy): implement Purchase Orders (PO) and Inward Goods Received Notes (GRN) workflow 2026-10-19 15:48:53 +05:30
65a071928c fix(abdm): force fresh discharge PDF generation and add column safety to byIpdRows 2026-10-19 11:13:20 +05:30
6f3b2a62d9 fix(abdm): populate salt and generic name in IPD discharge medication FHIR resources
- Populate generic salt name in MedicationRequest medicationCodeableConcept.coding[0] to prevent PHR apps displaying 'NA' subtitle
- Retain brand name in medicationCodeableConcept.text and secondary coding
- Extract med_salt from prescription records with automatic resolution from medicine masters and formulation heuristics
- Update discharge PDF and narrative to render generic salt names
- Add unit tests verifying generic salt mapping and dual coding in FHIR bundle
2026-10-19 10:16:05 +05:30
9272bb5a9c docs: add session handover for ABDM IPD discharge summary lifecycle 2026-10-17 13:19:20 +05:30
ab4b68b968 fix(abdm): allow CLI force resync in abdm:resync-discharge 2026-10-17 13:15:45 +05:30
fdd188df6e fix(abdm): generate physical exam observations, extract comorbidities, and trigger FHIR sync only on final discharge 2026-10-17 13:13:46 +05:30
0344561808 fix(abdm): deduplicate chief complaints and medical history, fix medication coding to NRCES spec, and resilient instruction parsing 2026-10-17 03:24:22 +05:30
0af2d557b2 Prefer English food_desc for CarePlan dietary advice in FHIR bundle 2026-10-17 02:49:28 +05:30
8a0396a2c8 Fix record_data column in resync-discharge 2026-10-17 02:48:42 +05:30
a6dd1f7a19 Fix gateway db credentials in resync-discharge 2026-10-17 02:48:11 +05:30
fed5f81296 Enhance resync-discharge with detailed gateway record verification 2026-10-17 02:47:45 +05:30
1290ac2bd8 Make enqueueIpdDischargeSync public with defaults 2026-10-17 02:46:37 +05:30
5cbc5b6743 Add abdm:resync-discharge command 2026-10-17 02:45:40 +05:30
a363e2d0a5 Fix discharge FHIR record full data: medications SNOMED 721912009, dietary advice care plan, and full PDF attachment 2026-10-17 02:44:32 +05:30
7dce405942 fix(security): exempt records/* and v3/* from CSRF filter for bridge communication 2026-10-17 01:42:19 +05:30
6c812236a8 feat(abdm): set autoLinkDelayMinutes to 1, regenerate FHIR bundle on print, map salt composition to reasonCode 2026-10-16 18:54:29 +05:30
ee57959873 fix(abdm): add fallback in abdm_documents 2026-10-16 13:40:11 +05:30
e41e6bd96f fix(abdm): enforce granted hi_types and dateRange, check live consent status before fetch, safe json parsing 2026-10-16 13:38:53 +05:30
7f6ae881e7 fix(security): remove unused vendor scripts (tinymce, echarts) and styles from login page 2026-10-15 21:29:00 +05:30
b03568f91c fix(security): resolve OWASP ZAP audit findings for CSP, HSTS, SRI, and private IP disclosure 2026-10-15 19:25:28 +05:30
11cf131f09 docs: add WASA security audit and mobile auth session handover document 2026-10-15 18:22:04 +05:30
de4f65807d feat(security): implement WASA audit mitigations, mobile anti-enumeration & device authorization, and user management fixes 2026-10-15 17:47:51 +05:30
a3c544a53c feat(user-management): enhance user management, permission handling, and charges invoice workflows
- Add UserProfileModel and migration for user profile data
- Enhance User Management views, controller, and doctor/nurse search integration
- Refactor handleAuthError to separate 401 session expiry from 403 access restriction
- Apply granular permission checks to sidebar navigation links
- Open Bed Status view for all authenticated users
- Support GET and POST on charges item routes and exempt billing charges from CSRF desync
2026-10-14 20:08:10 +05:30
81f3501157 fix(security): implement WASA compliance hardening and vulnerability remediation 2026-10-14 10:27:32 +05:30
ec377dafcd fix(abdm): populate full patient demographics (DOB, gender, mobile, address) in Find ABHA by Aadhaar 2026-10-12 12:54:29 +05:30
bccd1b14ae fix(abha): route find ABHA by Aadhaar to ABDM profile login verify endpoints 2026-10-12 12:33:25 +05:30
f50d0a10dd fix(abha): fix Aadhaar OTP verification rejection and error reporting 2026-10-12 12:24:39 +05:30
e28ed30116 fix(abdm): route findAadhaar OTP requests via AbdmConnectorFactory with bridge integration 2026-10-12 12:07:21 +05:30
e59bd8d2b7 feat(abdm): add Find ABHA by Aadhaar Number flow (M1 VRFY_ABHA_401 to VRFY_ABHA_405) 2026-10-12 11:58:53 +05:30
39017a43cf feat(abdm): enforce consent expiration, request-specific printing, and push sync enhancements 2026-10-09 17:38:51 +05:30
7472364002 chore: remove test command after verification 2026-10-08 20:56:59 +05:30
e8a33ba1f4 fix(abdm): improve patient name formatting and single document testing 2026-10-08 20:56:38 +05:30
3ed80ac293 fix(abdm): optimize memory and backtrack limit in abdm_records_pdf 2026-10-08 20:55:48 +05:30
31538a0cb4 test: add spark test command for ABDM PDF generation 2026-10-08 20:55:10 +05:30
6c8e062558 feat(abdm): add professional PDF export and print button for fetched health records 2026-10-08 20:52:42 +05:30
92acaee56f fix(abdm): preserve GRANTED status for completed consent sessions on reopen 2026-10-08 20:27:47 +05:30
31352156c9 fix(abdm): dynamically inspect columns in abdm_hiu_consent_artifacts to prevent unknown column hip_id error 2026-10-08 20:11:06 +05:30
b0a5338152 feat(abdm): restore M3 data fetch for self and same entity with multi-facility support 2026-10-08 20:04:59 +05:30
e5b80c75c5 revert: reverse M3 fetch records for same entity / self that caused website hang 2026-10-08 19:45:12 +05:30
c268dfe7db test: update TestPatientSearch cases to use local DB records for comprehensive coverage 2026-10-08 19:26:51 +05:30
94045fb218 test: add Meera Bisht test cases for ABHA search 2026-10-08 18:20:03 +05:30
be38960960 test: fix request mock injection in TestPatientSearch 2026-10-08 18:19:36 +05:30
228867ebe1 feat(patient): display both ABHA address and formatted ID in search results; add test search command 2026-10-08 18:19:01 +05:30
a2fd3e1658 feat(patient): enable patient search by ABHA ID and ABHA Address in quick and advanced search 2026-10-08 18:09:40 +05:30
acb8917854 Add test-doc-filter CLI flag 2026-10-08 17:55:58 +05:30
c8baa82059 Fix M3 fetch records to retrieve and display health data from same entity and external entities 2026-10-08 17:54:47 +05:30
e2974ec719 fix(abdm): persist HIP link status to db and sync patient profile verification badge 2026-10-08 17:05:45 +05:30
c72b5cc338 refactor(abdm): unify into a single Refresh link in consent request history 2026-10-08 16:00:09 +05:30
b05081001e fix(abdm): prevent system hang on live status check, support 24h/12h hour inputs, and release PHP session lock 2026-10-08 15:52:50 +05:30
5ad1598c21 fix(abdm): add explicit 12-hour AM/PM time pickers for consent modal and format all consent timestamps with AM/PM 2026-10-08 15:36:12 +05:30
5306271383 fix(abdm): add datetime-local to consent request, prevent browser hang with non-blocking fetch, and fix DB column queries 2026-10-08 15:22:33 +05:30
d2dd84b27f fix(ipd): define dischargeRaw and match care context reference on discharge health_records save 2026-10-08 14:31:33 +05:30
8fb03b3c8f fix(abdm): resolve discharge fhir preview ipd_id and remove synchronous blocking push on discharge save 2026-10-08 14:28:03 +05:30
72922eefbe chore: remove test bridge push command 2026-10-08 14:09:18 +05:30
c76ad4e8bd fix(abdm): ensure lab, radiology, and health document tasks load FHIR bundles and push to bridge 2026-10-08 14:08:34 +05:30
63cb6b810a fix(abdm): test doc step by step 2026-10-08 14:06:54 +05:30
13e4e0728b fix(abdm): use AbdmConnectorFactory::make 2026-10-08 14:04:27 +05:30
2a7eb6e034 feat(abdm): add test bridge push command 2026-10-08 14:04:05 +05:30
d826f3e072 fix(abdm): expand health_records local link query to match by patient reference and abha 2026-10-08 13:12:46 +05:30
3876a7444e fix(abdm): exclude local_only health_records stubs from care context discovery 2026-10-08 13:00:13 +05:30
0e8cc1fd41 fix(abdm): fix abdm_work_tasks column selection in hipPatientCareContexts 2026-10-08 12:59:32 +05:30
54b3fdf542 chore(abdm): add abdm:inspect-patient spark command 2026-10-08 12:58:38 +05:30
0939cb9ec1 fix(abdm): unify imaging lab types to RAD prefix, merge local record_links into linkedRefs, and prevent pending push queue starvation 2026-10-08 12:55:42 +05:30
dab7629dcd fix(abdm): only query health_records with existing bundle payload in pushPendingHealthRecords 2026-10-08 12:47:50 +05:30
18505968bd feat(abdm): add automatic invoice linking and syncOpenInvoices for OPD consultation fees and charge invoices 2026-10-08 12:46:12 +05:30
b3e7a2175f fix(abdm): make FHIR creation async local-only in web requests, auto-link every minute via cron, disable cooling delay 2026-10-08 12:30:47 +05:30
a7d83551fe fix(abdm): render invoice line items, rates, and net/gross totals in fetched records modal 2026-10-08 11:56:27 +05:30
9cb4ccd701 fix(abdm): resolve JSON parse error on fetch and auto-reconcile revoked consents 2026-10-08 11:41:30 +05:30
cb0a1967a4 fix(abdm): redact decrypted FHIR bundles from abdm_api_logs and increase memory limit in hiu-poll to prevent memory exhaustion 2026-10-08 11:27:32 +05:30
6b1cf04198 fix(abdm): use due_date instead of non-existent scheduled_date in immunization_records query in recordsFetch 2026-10-08 11:14:34 +05:30
1a5bb0efdf fix(abdm): dynamically format ImmunizationRecord display with vaccine name and date in recordsFetch 2026-10-08 11:12:48 +05:30
25ded76a45 fix(abdm): improve care_context_display propagation for immunization in health_records and recordsFetch 2026-10-08 11:11:52 +05:30
ad1e936591 fix(abdm): support GET/POST fallbacks in AbdmFhirInspector::previewBundle 2026-10-08 11:10:25 +05:30
f08f7d7c2d fix(abdm): handle response cleanly in autoPushRecord and update immunization_records push status 2026-10-08 11:08:50 +05:30
75e3a820cc fix(abdm): unify immunization payload, resolve CC IMM-53, add on-demand fetch and sync bundle 2026-10-08 11:07:08 +05:30
91d7fe77d2 fix(opd): remove nonexistent patient_id column from opd_fhir_documents insert 2026-10-08 10:38:53 +05:30
c9f378870e fix(abdm): define dateStr in health_records loop of findCareContextsForPatient 2026-10-08 10:26:43 +05:30
d949eca6a8 fix(abdm): add __construct to AbdmGateway to initialize db and connector 2026-10-08 10:23:59 +05:30
7d92e542ba feat(abdm): auto-link care contexts on print and record save without modal 2026-10-08 10:20:30 +05:30
204b5f22c6 feat(abdm): make recordsFetch body and reference parsing fully resilient 2026-10-08 09:56:48 +05:30
a4f8e8a445 feat(abdm): align modal hi_type values with standard ABDM HI Types 2026-10-08 09:54:40 +05:30
e8a2cf2cf3 feat(abdm): send care context reference in patient reference field for PHR app clarity 2026-10-08 09:48:15 +05:30
24abc51dea fix(abdm): omit single top-level hi_type when linking mixed care context batches 2026-10-08 09:39:21 +05:30
0cd0b6c6fc fix(abdm): define reportHtml before attachment check in buildLabReportBundle 2026-10-08 09:37:00 +05:30
e86e73d792 fix(abdm): isolate care context hi_types during linking and prevent multiple DocumentReference in DiagnosticReport 2026-10-08 09:34:34 +05:30
a72ab50777 fix(abdm): align OPConsultRecord vs PrescriptionRecord bundles, separate OPD consultation from prescription discovery, and clean FHIR presentation 2026-10-08 09:01:05 +05:30
5130c6b18a fix(abdm): sanitize care context display, fix discharge care_context_reference and bundle generation, fix taskboard sync patientId 2026-10-07 17:59:14 +05:30
f7761218d0 Normalize ABDM OTP resend/rate limit cooldown message from 30 seconds to 60 seconds 2026-10-07 16:52:16 +05:30
3a86369ea2 fix(push): sanitize patient name and send mapped gender to bridge for valid link-token generation 2026-10-07 16:26:25 +05:30
6f5d3113b6 fix(wellness): remove SNOMED 419891008 from Composition.type to avoid PHR app displaying HealthDocumentRecord 2026-10-07 16:07:48 +05:30
a44256b530 fix(abdm): replace ampersand and slashes in careContextDisplay to prevent ABDM-9999 Invalid display 2026-10-07 15:53:04 +05:30
8fc443f1ba fix(abdm): send hospital patient ref in nursing wellness push payload 2026-10-07 15:25:00 +05:30
e992c3be37 fix(abdm): enforce NRCES Wellness observation profiles, LOINC code retention, and practitioner performer 2026-10-07 14:41:15 +05:30
bd02f895c5 fix(abdm): resolve wellness patient mismatch in fetch, sugar LOINC codes, duplicate notifications and hi_type mapping 2026-10-07 14:20:41 +05:30
db76ad9759 fix(abdm): resolve patient flipping, duplicate document contexts, and health document FHIR fetch 2026-10-07 13:24:05 +05:30
d04f1d5c24 fix(abdm): adjust db property visibility in AbdmFhirInspector to inherit protected from BaseController 2026-10-07 12:20:42 +05:30
0fe48f2ec8 feat(abdm): show health documents in HIP link modal and create dedicated ABHA Filter & FHIR Inspector page 2026-10-07 12:16:56 +05:30
6ac211377b fix(abdm): use correct column names last_action_result and completed_at in abdm_work_tasks 2026-10-07 11:54:02 +05:30
a3537c0b29 feat(abdm): enable proactive ABDM bridge push and gateway linking for nursing wellness records 2026-10-07 11:50:51 +05:30
0441ebe08a feat(abdm): expand WellnessRecord to full comprehensive suite (Option B) with segmented tabs and labs 2026-10-07 10:15:42 +05:30
0b1d545a3c fix(abdm): enhance m2HealthInformationFetch and assembleFhirBundleForCareContext for standalone wellness records 2026-10-07 09:56:52 +05:30
49f6a8327d fix(abdm): select entity_type in health_records to discover standalone wellness care contexts 2026-10-07 09:50:16 +05:30
86dc076f5d fix(nursing): auto-create patient_wellness_records, generate full NRCES FHIR bundle on save, and discover standalone wellness care contexts 2026-10-07 09:47:23 +05:30
8d00536d3b docs: add session handover for unified OPD consult bundle and care context 2026-10-06 17:03:55 +05:30
04eff5e5ba Standardize OPD care context formatting and prevent duplicate session aliases 2026-10-06 16:59:39 +05:30
b0a08112d1 fix(fhir): add versionId and lastUpdated to DocumentBundle meta for full NRCES conformance 2026-10-06 16:54:01 +05:30
e2bb0b107a fix(abdm): enrich OPD and INVOICE care contexts with clinical components and bill summary 2026-10-06 16:49:15 +05:30
f367603962 fix(abdm): unify consult visit into single OPConsultRecord bundle and auto-sync on print 2026-10-06 16:40:30 +05:30
d46f222fa3 fix(abdm): set default sandbox linking OTP to 654321 and accept both 654321 and 123456 2026-10-06 15:46:50 +05:30
461c8263f3 fix(abdm): map patientfile to HealthDocumentRecord 2026-10-06 15:34:45 +05:30
298c2f3fba Filter unready care contexts in ABDM discovery and map hiType per context 2026-10-06 15:23:14 +05:30
d1daefde4e fix(abdm): unify opd consultation care contexts, prevent duplicates and premature fhir ready on unfilled booking 2026-10-06 15:00:33 +05:30
045f4c5116 feat(abdm-fhir): add dedicated Prescription and Immunization FHIR generators with NRCES validation 2026-10-06 12:38:33 +05:30
24819cb75c feat(abdm): configure official ABDM toolkit skills and achieve 100% NRCES 6.5.0 FHIR conformance 2026-10-06 12:25:48 +05:30
e553215ea1 feat(abdm): add ABHA address filter with care context & FHIR status inspector on task board 2026-10-06 11:38:26 +05:30
1fcdb82eea fix(abdm): auto-resolve patient demographics from patient_master for HIP care context linking and token generation
- Auto-resolve missing name, gender, year_of_birth, abha_address, and abha_number in hipLinkToken and hipLinkCareContext endpoints using patient_master lookup
- Calculate birth year with fallback to age (current_year - age) when DOB is 0000-00-00, empty, or invalid
- Support resolving ABHA identifier whether saved in abha_address or legacy abha_id column
- Pass patient_id from client link modal and views (opd_prescription_basic, Patient_Profile_Opd_V, Person_profile_V)
- Fix demographic resolution in AbdmTaskBoardSyncService for background OPD and work task publishing
- Add comprehensive PHPUnit test suite in tests/unit/Abdm/TestHipDemographicsCareContext.php
2026-10-06 10:53:19 +05:30
686513cf27 Fix ABDM live fetch and discovery for PrescriptionRecord and WellnessRecord 2026-10-06 09:38:40 +05:30
da61637c56 fix(billing,abdm): resolve patient profile edit error and enhance opd prescription fhir mapping
- Fix Undefined variable \ 500 error in Person_Edit_V.php
- Safeguard auth()->user() and variable access in Person_Edit_V.php and Person_profile_V.php
- Enhance getPrescriptionMedicines with fallback dosing, remarks, and SNOMED lookup for OP Consultation FHIR
- Add deep-link SMS notify and link verification in ABDM gateway and task board
- Add PatientEditViewTest covering profile and edit view rendering
2026-10-06 08:25:48 +05:30
6270b0517a fix(abdm,diagnosis): use plain paper template for radiology fhir pdf, fix modality title and strip conclusion html 2026-10-04 12:38:44 +05:30
414dc42c05 fix(diagnosis): resolve print template placeholders and base64 logo rendering
- Support hospital, patient, doctor, and date placeholders matching template variables
- Convert local logo and signature paths to base64 Data URIs for mPDF
- Apply token replacement to report body in single and compiled prints
- Add interactive placeholder toolbar in diagnosis template settings view
- Add unit tests in tests/unit/DiagnosisTemplateTokenTest.php
2026-10-03 02:45:22 +05:30
48d11b20df fix(abdm): eliminate dummy consultation bundles, fix Strategy 0 return bundle, add on-demand invoice FHIR, and ensure full multi-artifact HIU polling 2026-10-02 01:11:22 +05:30
1c41b4555b refactor(abdm): remove opd_fhir_documents fallback from recordsFetch and bind strictly to health_records 2026-10-01 20:46:38 +05:30
478722cf00 fix(abdm): fix recordsFetch health_records latest row selection and guard opd_fhir_documents fallback 2026-10-01 20:07:50 +05:30
e43bfbad71 feat(abdm): add task status filtering, search, and completed task visibility on task board
- Add getTasks() method with status filtering (all, open, completed, failed) to AbdmWorkTaskService
- Enhance AbdmTaskBoard to enrich all task types with health_records, invoice_code, and care contexts
- Add status toggle filter buttons (All, Open, Completed) with dynamic count badges to Task Board UI
- Add real-time fuzzy/keyword search input for instant filtering by invoice ID, patient name, ABHA, or task code
- Render completed/linked tasks with green LINKED badge, gateway reference, and FHIR Preview button
- Add unit tests in AbdmTaskBoardBackfillTest
2026-10-01 19:40:32 +05:30
2569f694c1 fix(abdm): normalize ABDM upstream errors and Please make a valid request to does not exist 2026-10-01 18:50:35 +05:30
5cc4486d9a fix(abdm): distinguish ABHA Number vs ABHA Address in lookup error messages and logs 2026-10-01 18:37:14 +05:30
7c1f0df410 fix(abdm): normalize bridge SQL errors in API logs and extract specific upstream hints 2026-10-01 18:06:08 +05:30
fd10df43c3 fix(abdm): resolve ABHA address verification, field error extraction, and task board sync
- Fix empty string fallback in validateAbha and EAtriaBridgeConnector to properly extract healthIdNumber and real fullName from data payload
- Skip generic bridge envelope messages in extractBridgeErrorText to surface specific field rejections like loginHint
- Translate non-existent ABHA address errors to 'ABHA Address does not exist or was not found in the ABDM registry'
- Support both 14-digit ABHA numbers and ABHA addresses in Diagnosis publish and ABDM Task Board
- Prevent completed task duplication in lab/radiology backfill
- Add unit tests in AbhaOtpErrorHandlingTest and AbdmTaskBoardBackfillTest
2026-10-01 17:12:17 +05:30
8dd34a9085 fix(abdm): improve radiology report title resolution and prevent completed task duplication 2026-10-01 15:27:50 +05:30
3358f56e3f Add unit tests for radiology report template ranking and imaging file lookup 2026-10-01 13:06:04 +05:30
38b96a1003 Fix radiology editor DICOM gallery context, match related templates, and remove manual ABDM panel 2026-10-01 12:59:45 +05:30
0b75b52377 fix(diagnosis): restore lab_test_no column in report tables to fix DataTables column count warning 2026-10-01 11:38:29 +05:30
1f4fcf6546 fix(diagnosis): resolve person name null concat in report list and handle large dicom file uploads 2026-10-01 11:24:29 +05:30
140c4908ee fix(patient): hide ABHA Create/Verify tab when patient already has an ABHA profile 2026-10-01 11:01:34 +05:30
734b9a2bc4 fix(abdm): evaluate cooling from clinical event date and prevent reset on taskboard view 2026-10-01 08:03:44 +05:30
376cb7eeb1 fix(abdm): remove 'Use Aadhaar-linked Mobile' skip button from Mobile OTP step 2026-09-30 17:50:24 +05:30
3df469bfab fix(abdm): implement communication mobile OTP verification, register route, and fix patient list modal DOM 2026-09-30 16:59:23 +05:30
d0082299e6 docs: update ABDM M2 handover guide with invoice care context linking and test suite stats 2026-09-30 12:36:42 +05:30
f7c30529a3 feat(abdm-m2): enable care context discovery and direct linking for invoice records 2026-09-30 12:25:01 +05:30
ccd5909fc6 docs: remove technical URLs, database fields and developer codes from user help guide 2026-09-30 00:24:40 +05:30
c27ec011a4 fix: update 'Back to HMIS' link to /dashboard in static help.html 2026-09-30 00:16:03 +05:30
731fcd4929 docs: comprehensive module-wise help manual and template design guide 2026-09-30 00:11:28 +05:30
ef658565df docs: add ABDM M2 test session handover guide 2026-09-29 23:54:09 +05:30
a33b376ecd feat(abdm-m2): add HIP link modal and care context discovery on patient registration 2026-09-29 23:48:33 +05:30
6bd24303e3 fix(abdm-m1): user friendly OTP errors, remove bridge request id from UI, and add beneficiary name consent collection 2026-09-29 23:14:48 +05:30
763af46de2 feat(radiology): add comprehensive templates and charge items seeder for X-Ray, CT-Scan, and MRI 2026-09-29 20:25:39 +05:30
1a21f16f7b fix(abdm): sync care context reference format and auto-push FHIR bundle on linking
- Align care context reference format (RAD- prefix for radiology, clean Ymd date) between discovery, shareDiagnosisReportBundle, and AbdmTaskBoardSyncService
- Automatically push FHIR document bundle to Bridge (POST /api/v3/records/push) on care context linking or already-linked confirmation in abdm_hip_link_modal
- Provide clear instructions to user regarding PHR app 'Fetch Records' pull flow
- Add unit test testShareDiagnosisReportBundleFormatsRadiologyCareContext
2026-09-29 15:06:31 +05:30
41d89a1969 feat(abdm): enhance care context discovery, async token retry, and modal backdrop cleanup
- Add multi-type care context discovery in AbdmGateway (DiagnosticReport, DischargeSummary, Immunization, OPConsult) with target task prioritization
- Implement automated retry backoff in EAtriaBridgeConnector for asynchronous ABDM link token callback delivery
- Handle already-linked contexts gracefully and synchronize Task Board row status on link completion
- Resolve modal backdrop freeze and inactive main screen on radiology report template update in PathLab_Report and welcome_message
- Add unit tests CareContextDiscoveryTest and EAtriaBridgeConnectorLinkTest
2026-09-29 14:02:22 +05:30
61206784f3 feat(abdm): implement care-context linking cooling window and timer reset on record modification
- Add cooling period configuration (60 min for OPD/Lab/Radiology/others, 24 hr for IPD Discharge) in AbdmConnector
- Add calculateCooling() logic in AbdmTaskBoardSyncService and skip automated linking during cooling window
- Touch and refresh work task timestamps on prescription save and IPD discharge summary save/print
- Update opd_fhir_documents on prescription edit rather than inserting duplicate bundles
- Enrich ABDM Task Board table and OPD consult list with active cooling badges, remaining minutes, and auto-link schedule
- Preserve manual 'Link Context' action on task board to allow immediate override anytime
- Update CLI commands (abdm:taskboard-sync, abdm:push-sync) with cooling counters and status logging
2026-09-28 18:29:50 +05:30
ed57228b98 docs: add ABDM M2/M3 live fetch and task board session handover 2026-09-28 03:42:34 +05:30
d0f7aa4542 feat(abdm): enable live fresh FHIR fetch on pull, remove old push options, and keep care context linking 2026-09-28 03:25:04 +05:30
90e63d2d58 fix(abdm): generate and publish OPD consultations as OPConsultRecord and support dynamic hi_type 2026-09-28 02:46:10 +05:30
b28b51965c fix(abdm): dynamically check ABHA columns in patient_master 2026-09-28 00:43:03 +05:30
9a70172cbc fix(abdm): use apointment_date in AbdmTaskBoardSyncService 2026-09-28 00:41:11 +05:30
c3fc0d98f0 feat(abdm): automate ABDM Work Task Board care-context linking via cron job 2026-09-28 00:40:03 +05:30
d255bb73f7 fix(cron): resolve TMP_CRON scope in manage_hms_cron.sh 2026-09-27 23:59:12 +05:30
0186e17f0f feat(abdm): implement automated deep-link SMS notify queue and Spark cron worker 2026-09-27 23:55:52 +05:30
524a991098 fix(opd): preserve template settings and flow while compacting font sizes for large prescriptions 2026-09-27 13:40:35 +05:30
8850620931 fix(opd): accurately calculate top margin delta from template @page and fix named header/footer preservation 2026-09-27 11:50:27 +05:30
b75a43fc32 fix(opd): maintain letterhead top and left margins and content width ratios in Rx print pagination 2026-09-27 11:37:16 +05:30
0397071be4 fix(opd): reorder prescription directions to Frequency | Relation to Food | Dose | Duration | Remarks and add legacy data safeguards 2026-09-27 09:02:03 +05:30
9b3e734ead fix(ipd_discharge): prevent duplicate surgery additions and fix procedure table dynamic updates 2026-09-25 07:41:10 +05:30
677472e6b0 fix(abdm): safely decode raw body in recordsFetch if getJSON fails 2026-09-24 13:13:24 +05:30
092e5cd193 fix(abdm): route health record push with FHIR bundle to /v3/records/push and unify care context reference format 2026-09-24 11:12:54 +05:30
0b048881e1 fix(opd): pass push_to_gateway flag when submitting FHIR bundle from standalone preview 2026-09-24 10:57:07 +05:30
3656bf9b94 Fix ABDM HIP link-token failure: strictly sanitize abha_number, decouple abha_address from 14-digit abha_id in profile & modal 2026-09-24 10:03:19 +05:30
24089f36a6 fix(abdm): auto-link ABHA address on discovery/confirm, resolve FHIR by patient_id on-demand, and display in profile 2026-09-24 09:33:19 +05:30
2f6b346e25 fix(abdm): add concurrency lock, optimize hiu-poll query, and add composite indexes 2026-09-24 08:03:57 +05:30
fcce8970fd fix(abdm): safe JSON parsing in m2LinkInit/Confirm and prevent abha_id null in audit log 2026-09-23 15:56:05 +05:30
0d71ce5ee4 fix(abdm): allow Bearer auth fallback and safe getJSON parsing in recordsDiscover 2026-09-23 15:21:56 +05:30
3f1e89d4be Fix IPD patient admit search error, add admission type filters to IPD patient list, remove redundant sidebar links, and add OPD Day Care template support 2026-09-23 10:12:42 +05:30
ccb05389e1 Prevent duplicate course/treatment submissions and add edit/update capability in IPD discharge 2026-09-23 08:32:36 +05:30
da82ec84d1 Prevent duplicate final diagnosis submissions and add edit/update capability in IPD discharge 2026-09-23 08:28:02 +05:30
c0cbf1c0bd Ensure strict sequential keyboard focus navigation across OPD Consult and IPD Discharge prescription controls 2026-09-23 08:15:09 +05:30
c0842d1502 IPD Discharge: add Form/Type-aware Dose/Strength autocomplete and fix Duration keyboard arrow key navigation in IPD & OPD 2026-09-23 07:52:04 +05:30
7f4b49a1c6 OPD: add smart Form/Type-aware autocomplete for Dose and Strength 2026-09-23 07:38:28 +05:30
7a653a06b6 OPD: preserve opd_med_master defaults and stop prescription overwrite 2026-09-23 07:12:53 +05:30
126a62b8d0 fix(opd): fix undefined patLastName and make FHIR and audit logging fail-safe in opd_prescription_save 2026-09-22 23:40:05 +05:30
659106c66a feat(opd,ipd): standardize complaint autosearch, square icon buttons, and Quick Autotext Chips 2026-09-22 22:07:48 +05:30
d35f85bf1b fix(ipd): append action cell to row so update and remove buttons render in complaint table 2026-09-22 21:47:13 +05:30
341c09d9c7 feat(ipd): enable autosearch and row-level update on discharge complaint table 2026-09-22 20:20:11 +05:30
79020e806b Move substitutes from medicine input form to Action column button below added medicines 2026-09-22 19:49:27 +05:30
93a6fdf89e Standardize Relation to Food (When) in IPD discharge to match OPD consult format 2026-09-22 19:35:44 +05:30
39ff463b57 feat(ipd): update discharge medicine form/type with full ABDM formulation list and auto route detection 2026-09-22 19:20:23 +05:30
0bb480aace feat(opd): expand formulation types with full ABDM/clinical specialty list (shampoo, soap, spray, susp, etc.) 2026-09-22 19:04:24 +05:30
c870e7eccc feat(opd): convert Formulation into standardized Form/Type select dropdown matching OPD consult 2026-09-22 18:55:08 +05:30
519a52bd73 fix(opd): change Dose from select dropdown to text input with suggestions in medicine workspace 2026-09-22 18:27:18 +05:30
4766c7c9fa fix: safeguard shell_exec with function_exists check in login and medical api 2026-09-22 13:03:19 +05:30
6e78e6010e feat: add Day Care & Emergency admission module with IPD conversion and clean patient names
- Add Day Care (<24h) and Emergency (Casualty) admission pathways with prefixes DC- and ER-
- Add dedicated physical wards, ESI 5-level triage, MLC tracking, and PADSS day care discharge
- Implement audited 'Convert to IPD' workflow with SBAR handover and automated bed transfer
- Support unified IPD billing with dedicated group headers for Day Care and Emergency charges
- Redesign Hospital Admission Desk with executive card layout and modern triage controls
- Add comprehensive user documentation and SVG flowchart in public/help.html
- Completely remove legacy patient_master.p_lname column from database and application code
2026-09-21 23:41:24 +05:30
ab3ab0c17f fix(medical-store): define billerName in saveSale and link sale_id to credit ledger 2026-09-18 05:55:50 +05:30
6ce81eedd8 feat(medical-store): auto-convert draft bills to invoice on checkout and reduce pending draft list 2026-09-18 05:49:20 +05:30
98652ce646 fix(medical-store): define walkinMobile and walkinUhid state when loading draft bills with phone number 2026-09-18 05:36:45 +05:30
bc90020c69 fix(medical-store): fix item rate picking and batch pricing when loading Mobile Draft bills into POS cart 2026-09-18 05:29:50 +05:30
e4e89fb34a feat(database): add migration for credit accounts, credit ledger, draft bills, and store user permissions 2026-09-18 05:17:22 +05:30
ecd596e0fb feat(medical-store): add mobile apps QR hub on login page, pharmacy ledgers, credit accounts, and 6-tier staff permissions 2026-09-18 05:11:02 +05:30
c49361c0fa feat: disable public registration on login page and add cron task management script 2026-09-17 13:06:13 +05:30
64e34678ec feat: close related organization case on IPD discharge 2026-09-16 15:53:53 +05:30
dd1acb88e1 feat: add IPD census PDF, collection payment filter, fix report panel visibility, and implement ABDM HIP linking
- Reports:
  - Add PDF export option with A4-L print layout for IPD Census & Discharge Report
  - Add Payment Type filter (OPD, Charge, IPD, ORG, All) to Collection Report with URL routing and summary table updates
  - Ensure superadmin/admin/developer visibility in Report Panel controller permission checks
- ABDM:
  - Implement HIP patient care-context linking and discovery integration
  - Add on-demand FHIR health record fetch endpoints for Bridge connector
  - Add ABDM HIP link modal view and wire to patient/person profiles and prescription
2026-09-15 23:21:30 +05:30
f2e27828bb fix(abha): make verification match modal aware of unique ABHA ID and dynamic titles 2026-09-12 05:23:33 +05:30
7e3c57f48f fix(patient): enforce unique ABHA ID and Aadhaar number on patient registration and updates 2026-09-12 04:30:10 +05:30
35e1018c6b fix(abdm): prevent modal redirect to profile step on wrong OTP verification 2026-09-12 01:48:33 +05:30
7c573403b2 fix(abdm): isolate Aadhaar mobile from ABHA registered mobile and sanitize asterisk placeholders in verification flow 2026-09-12 00:35:51 +05:30
fd492a2aa2 feat(abdm-m1): implement Create / Find ABHA Record wizard aligned with ABDM M1 specifications
- Reorder and streamline wizard into 5 steps (Aadhaar, Aadhaar OTP, Mobile OTP, ABHA Address, Profile & Card)
- Add Aadhaar vs Communication mobile matching to skip or mandate mobile OTP (CRT_ABHA_108 vs CRT_ABHA_109)
- Enforce full consent declarations with master 'I Agree' checkbox and step validation (CRT_ABHA_102)
- Enforce UIDAI Verhoeff algorithm pre-validation and normalize upstream loginId errors (CRT_ABHA_104 / VRFY_ABHA_403)
- Enforce ABHA address validation policy: 8-18 chars, dot/underscore in between only, duplicate detection (CRT_ABHA_112)
- Enforce 60s timer and maximum 2 resend attempts on both OTP verification steps (CRT_ABHA_106)
- Support instant jump to profile & card for existing accounts with 'ABHA Already Exist' notice (VRFY_ABHA_404)
- Update Patient Management and Profile view buttons to 'Create / Find ABHA Record'
2026-09-11 22:11:17 +05:30
93172c4a19 feat(pharmacy): add searchable All Invoices register tab with edit capabilities and POS draft auto-save/recovery 2026-09-10 09:50:34 +05:30
741269634e feat(pharmacy): add right-side patient old records, last dispensed medicines, and 1-click re-dispense/return desk 2026-09-10 09:23:59 +05:30
261a69bf2e feat(medical-store): set A5 invoice to landscape format (A5-L) and remove copy text button from thermal view 2026-09-10 08:22:20 +05:30
82cae89fae feat(medical-store): add server-side A4/A5 vector PDF generation with mPDF and 48-col plain-text thermal receipt printing 2026-09-10 08:09:10 +05:30
c8a2d50df9 feat(pos): slide-in bill print drawer on right side matching checkout drawer 2026-09-10 07:38:17 +05:30
45a570a2f6 feat(pos): full-width dispensing desk with slide-in checkout drawer and checkout button 2026-09-10 07:30:24 +05:30
5187fcf3ed feat(tax): standardize current GST slabs (0%, 5%, 18%, 40%, legacy 12%, 28%) across HMS and Medical Store 2026-09-10 07:13:04 +05:30
358416fc10 feat(medical-store): conditional pharma fields below product search with auto-fill from last batch and purchase 2026-09-10 06:47:49 +05:30
59514cd061 feat(medical-store): pharma stock entry with progressive disclosure, challan import, and history 2026-09-10 06:35:05 +05:30
48bb726b6d feat(medical-store): add edit purchase invoice option with stock adjustment and ledger reconciliation 2026-09-10 05:43:11 +05:30
ca6926015a fix(medical-store): remove third-party brand Marg from application and replace with generic Excel/CSV import 2026-09-10 04:58:59 +05:30
e635e823e5 feat(medical-store): add supplier ledger, payment tracking, short items book, and purchase orders 2026-09-10 04:49:00 +05:30
62397c5a98 feat(medical-store): inward purchase medicine auto-search and shared pharmacy master integration 2026-09-10 04:23:09 +05:30
101e0631a8 feat(medical-store): add supplier creation and editing modal in Supplier Directory 2026-09-10 03:53:33 +05:30
758bc4c452 docs: add session handover document for ABDM M1, M2, and M3 HIU fixes 2026-09-10 00:57:33 +05:30
b89bace2c9 fix(abdm): resolve 500 internal server error on ABHA patient request list 2026-09-09 18:46:28 +05:30
9176877d07 feat(abdm): implement M1 find ABHA by mobile flow & M2 user-initiated linking
- M1: Update Find ABHA via Mobile to compliance flow: Mobile Number -> Profiles -> OTP -> Complete Profile Fetched
- M2: Support walk-in non-ABHA patient discovery via demographic matching (verified mobile, gender, year of birth, name)
- M2: Implement care context linking endpoints (/records/link/init and /records/link/confirm) with OTP verification
- Add abdm_link_transactions database migration
- Support Bearer token and HMAC signature authentication for bridge callbacks over VPN
2026-09-09 17:52:20 +05:30
c82892f3d2 fix(medical-store): add complete base schema migration and devices table for remote server 2026-09-08 05:19:19 +05:30
d2f069e3c8 feat(medical-store): add B2C sales returns, same-invoice exchanges, and DB migrations
- Add B2C same-invoice exchange and pure refund workflows (Marg ERP standard)
- Support returning excess/unused medicines with proportional unit pricing on original invoice
- Auto-net return credits against new medicines in POS cart with refund outflow handling
- Implement stock replenishment for restocked batches with audit trail in mst_stock_audit
- Generate sequential GST Credit Notes in mst_sale_returns and mst_sale_return_items
- Update Thermal 80mm, A5, and A4 print templates with separated dispensed vs returned items
- Add CI4 migration 2026-09-08-000001_CreateMedicalStoreReturnsAndExchanges.php for remote execution
- Add standalone SQL script scripts/sql/2026-09-08_medical_store_b2c_returns_and_exchanges.sql
2026-09-08 05:07:45 +05:30
765286e7fa feat(medical-store): ABDM-compatible multi-building pharmacy, POS desktop keyboard workflow, unit dispensing, and split payments 2026-09-08 02:19:11 +05:30
ee7cf59c49 fix(abdm): enforce clinical decimal precision on vitals and temperature in FHIR bundles and task board 2026-09-07 16:11:24 +05:30
bb6589605a fix(abdm): resolve health document preview hang and wellness record display in task board
- Fix mPDF single-threaded server deadlock by replacing HTTP logo URL fallbacks with inline base64 data URIs
- Add fast path in DoctorDocument to read scanned NABH PDFs directly from disk without mPDF re-rendering
- Support doctor_document and patient_document entity types in task board health document preview
- Enhance task board preview form with in-modal PDF preview, image thumbnail, and download actions
- Populate Composition.encounter with AMB encounter and set Wellness Record display code
2026-09-07 00:46:17 +05:30
f3faa9c96e feat(abdm): integrate Online/ABDM discharge template with PDF attachment in FHIR bundle
- Dynamically resolve and generate PDF using designated Online/ABDM template (is_abdm=1) from ipd_discharge_templates
- Unify mPDF rendering logic between show_discharge and generateDischargeSummaryPdfBinary for exact byte-for-byte consistency
- Attach generated PDF as DocumentReference under SNOMED 373942005 (Discharge summary) in NRCES FHIR DocumentBundle
- Add quick-set actions and AJAX endpoints for Default and ABDM template selection in discharge template list UI
- Update unit tests covering DocumentReference generation and template resolution
2026-09-06 17:55:15 +05:30
9b3d9ef6ee fix(abdm): align IPD discharge summary FHIR bundle with NRCES standards and eliminate NA values in PHR 2026-09-06 08:09:11 +05:30
0e340d5155 fix(abdm): resolve patient row using id instead of p_id in saveIpdDischargeFhir 2026-09-05 20:43:02 +05:30
52f8d9691b feat(abdm): enhance IPD discharge FHIR generator with NRCES v6.5.0 single-coding and structured dosage instructions 2026-09-05 15:29:11 +05:30
4e1d5ed7af Update DischargeFhirGenerator section titles for initial FHIR fixes 2026-09-04 21:45:49 +05:30
a6bb1f7cda fix(fhir): ensure strict canonical display values for SNOMED/LOINC/HL7 codings to prevent PHR validation errors 2026-09-04 20:14:44 +05:30
6525422af4 fix(fhir): fix ABHA PHR app parsing error in discharge FHIR bundle - correct Observation category codes for vitals vs admission/discharge conditions - add missing category to investigation Observations (NRCES profile requirement) - strip empty unit/code from valueQuantity to avoid PHR parser rejection - fix greedy regex in Composition narrative that could produce malformed XHTML - remove 0 from isPlaceholderValue to stop silent stripping of numeric FHIR values 2026-09-04 19:57:17 +05:30
cefa73dbae fix(abdm): add comprehensive Composition XHTML narrative, resource narratives, and section displays for PHR display 2026-09-04 19:34:44 +05:30
1f26c3e4ef fix(abdm): split blood pressure into systolic and diastolic components for LOINC 85354-9 in IPD discharge FHIR 2026-09-04 19:14:55 +05:30
4e748dbaa8 fix(abdm): map admission/discharge encounter period, split vitals by admission/discharge, and attach size/hash to pdf document reference 2026-09-04 06:15:08 +05:30
c238fcfc40 fix(abdm): resolve correct column names for dose master tables in discharge fhir 2026-09-04 06:05:57 +05:30
9bca2630c3 fix(abdm): allow GET/POST for ipd_discharge_fhir_preview and render detailed error in preview modal 2026-09-04 05:55:51 +05:30
6566ec0b77 fix(abdm): handle missing optional params, catch location query exceptions, and safely boot billing controller in IPD discharge preview 2026-09-04 05:51:12 +05:30
5714f9f755 feat(abdm): add Encounter period admission/discharge times and location ward/bed mapping 2026-09-04 05:44:37 +05:30
4776bfb37b Enhance IPD discharge summary FHIR bundle: dual admission/discharge vitals, full medication dosage directions, dietary/discharge advice care plans, and IPD invoice PDF attachment 2026-09-04 05:39:45 +05:30
4058850941 fix(abdm): correct condition categories, snomed resolutions, vital signs and physical exam units in discharge fhir generator 2026-09-04 05:22:45 +05:30
df835008d5 Fix ABDM M1 multi-ABHA account selection payload compatibility and fallback handling 2026-09-03 20:13:46 +05:30
156d12adba Implement ABDM M1 multi-ABHA account selection for Mobile OTP login flow 2026-09-03 16:17:46 +05:30
29ac1ffe66 Update ABDM Work Task Board tab and header name to OPD Consult / Prescription Records 2026-09-03 14:33:37 +05:30
05622a12de Fix Consent ID, Consent Request ID, and date metadata resolution across ABDM client, workflow service, controller, and views 2026-09-03 12:37:11 +05:30
398ad3238e Fix ABDM live status check and reconcile to accurately extract nested EXPIRED, REVOKED, and DENIED consent states without being masked by transport status 2026-09-03 11:44:36 +05:30
e1280b3bbe Fix column name source_id to entity_id in abdm_work_tasks query in show_profile_opd 2026-09-03 06:57:21 +05:30
625c642b02 Fix patient age calculation in IPD discharge search ajax by querying DOB and using get_age_1 helper 2026-09-02 03:51:52 +05:30
adf4433f72 Completely sanitize Edit Remove text artifacts from remark field in IPD discharge 2026-09-02 03:31:23 +05:30
16463d4908 Fix IPD discharge medicine edit form: fix remark field off-by-one cell index and reset When dropdown when empty 2026-09-02 03:22:34 +05:30
2fcfbd922a Enhance IPD discharge summary: OPD-style Prescribed Medicines table for B&W printing, auto generic lookup, and suppress empty discharge summary heading 2026-09-02 02:53:17 +05:30
73780ac7dd fix: IPD discharge RxGroup add - fix UI not updating after apply_rx_group, and Remove All not deleting from DB
- discharge_create.php (JS): Fixed AJAX done handler to JSON.parse the
  raw string response (jQuery with dataType:'html' does not auto-parse
  JSON), then re-render #discharge_medicine_tbody from result.drugRows.
  Also fixed Remove All (#btn_discharge_med_reset) to send AJAX POST
  with action=remove_all_drugs so records are deleted from DB, not just
  cleared from the DOM.

- Ipd_discharge.php (Controller): In the AJAX JSON response block,
  resolve dosage/dosage_when/dosage_freq IDs to human-readable labels
  using getDoseMasterRows() before returning drugRows, so the table
  displays 'BD / After Food' instead of raw numeric IDs. Added new
  remove_all_drugs action that deletes all medicine rows for the IPD
  from both legacy (ipd_discharge_prescrption_prescribed) and classic
  (ipd_discharge_drug) tables. Added remove_all_drugs to both
  lightweight-action whitelists to skip the expensive getIpdPanelInfo()
  join.
2026-09-01 20:24:14 +05:30
b786fe7a08 fix(ipd_discharge): add query error catching and logging to add_drug controller action 2026-09-01 18:28:53 +05:30
e24b71bbc9 fix(ipd_discharge): enable serializeDischargeMedicineTable on form submit and robust JSON response handling 2026-09-01 18:24:50 +05:30
633ea2bbb8 fix(ipd_discharge): enforce strict server DB save confirmation before adding medicine to client DOM 2026-09-01 18:20:13 +05:30
144f0a20d5 fix(ipd_discharge): sync full medicine list on main form submit to replace stale DB entries 2026-09-01 18:15:46 +05:30
3fddb3ca26 fix(ipd_discharge): enable dual-source medicine loading and full form submit medicine sync 2026-09-01 18:07:18 +05:30
1f8651e3b3 fix(ipd_discharge): remove fragile tbody early-return guard in medicine remove handler 2026-09-01 17:51:23 +05:30
fe26588dca fix(ipd_discharge): instant DOM row removal on medicine delete & delete from all drug tables 2026-09-01 17:47:05 +05:30
419c015535 fix(ipd_discharge): update server-rendered medicine remove buttons with btn-remove-discharge-med class for AJAX deletion 2026-09-01 17:43:30 +05:30
bfe14048bc fix(ipd_discharge): resolve status 0 network error on medicine add and sync remove_drug via AJAX 2026-09-01 17:38:09 +05:30
599c4806bb feat(abdm & reports): align ABDM FHIR R4 Wellness & HealthDocument generators, add NABH IPD scanner, balance column in invoice list, and old payment received report 2026-09-01 14:05:17 +05:30
63ee0a19fd feat(nursing): add ABDM M2 wellness vitals, health document scanner, and barcode/QR patient search dock 2026-08-30 13:58:06 +05:30
596a684372 fix(abha): update ABHA Management card heading to 'Verify or Find ABHA Account' 2026-08-30 03:20:04 +05:30
5db3da6403 fix(setting): prevent standard form submit redirect on save button by using explicit AJAX functions and action=javascript:void(0) 2026-08-30 02:55:13 +05:30
f99ddbd851 fix(setting): change property access level to protected in OpdQueueSetting to match BaseController 2026-08-30 02:51:58 +05:30
31b2319419 feat(admin): add OPD Queue TV Settings panel for right-side ads upload, left-side bottom ad space, ticker text editing, and TTS pronunciation fixes 2026-08-30 02:49:59 +05:30
ac5d2710fa feat(pwa): add 5-item page-wise horizontal auto-carousel for left token tracker column 2026-08-30 02:23:03 +05:30
49267e65ec fix(pwa): resolve HEAD HTTP method 404 warning and add narrow mobile screenshot to manifest 2026-08-30 02:07:57 +05:30
0eaf05956e fix(pwa): register service worker immediately for automated PWA audit detection 2026-08-30 02:02:06 +05:30
c1a532ce95 fix(pwa): route sw.js and manifest.json dynamically with Service-Worker-Allowed header and exact screenshot dimensions 2026-08-30 01:58:52 +05:30
0135e6482a feat(pwa): 100% PWABuilder compliance with Service Worker, 512x512 icons, id, scope, and manifest metadata 2026-08-30 01:57:02 +05:30
c905d9c884 fix(tv): set WebSettings.LOAD_DEFAULT for auto server updates without re-installing APK 2026-08-30 01:46:02 +05:30
1b379bf3d4 feat(pwa): add Android TV native app project for OPD Queue TV display 2026-08-30 01:29:15 +05:30
09adbef59f fix(tv): rewrite OPD queue display with pure Vanilla ES5 JS for 100% Samsung Smart TV browser compatibility 2026-08-30 01:17:54 +05:30
882b036e9e feat(pwa): add OPD Queue & Token Display PWA app with right side ad showcase 2026-08-30 01:04:37 +05:30
e235989304 feat(pwa): add Android TV remote D-Pad focus styling 2026-08-30 00:52:06 +05:30
8d68afebbd feat(pwa): standardize hospital logo PWA icons and add in-app mobile module switcher 2026-08-30 00:18:15 +05:30
2d68a19584 feat(hms): add Document Type selection dropdown to HMS Desktop Scan Upload Modal and save document_type with badges 2026-08-29 04:45:28 +05:30
888b4039f6 fix(nursing): display Doctor Name on IPD patient bed cards and register all scanned document photos into file_upload_data table for HMS Scan Doc List popup 2026-08-29 04:40:16 +05:30
b64c8084c8 feat(cropper): integrate interactive document photo cropper with rotation and resize controls in Doctor & Nursing PWA Apps 2026-08-29 04:30:05 +05:30
38573f5b15 fix(nursing): resolve SQL column errors in opdList query, add Doctor filter dropdown, and Vitals Pending/Done status filter buttons 2026-08-29 04:25:57 +05:30
7bdfbab2bd feat(nursing): add OPD Patients list, Fill OPD Vitals, and Document Scan/Camera Upload features to Nursing PWA App 2026-08-29 04:16:08 +05:30
e4c6b398cc fix(hms): resolve base64 photo upload decoding and add professional image thumbnails to HMS Nursing Workspace Treatment Notes 2026-08-29 04:04:03 +05:30
e32feeb8d6 feat(doctor): make header lock button icon-only and add mobile camera photo capture for handwritten doctor notes and prescriptions 2026-08-29 03:55:50 +05:30
7a0631979a feat(doctor): add current date filter for OPD appointments and my assigned vs all hospital admissions toggle for IPDs 2026-08-29 03:41:09 +05:30
cd0b78d5fd style(doctor): upgrade mobile doctor app UI with Inter typography, initial avatars, status dot indicators, and executive glassmorphic cards 2026-08-29 03:30:39 +05:30
2400075867 feat(doctor): add mobile professional patient card view eliminating horizontal scrollbar on smartphones 2026-08-29 03:26:04 +05:30
d737ec0d1b fix(doctor): resolve IPD patient doctor mapping and add hospital-wide admission fallback 2026-08-29 03:16:25 +05:30
820c904eff fix(doctor): replicate exact HMS getCurrentAdmissions query joining ipd_master_doc_list and bed_assignment_history 2026-08-29 03:08:47 +05:30
5bfe0689f1 fix(doctor): correct IPD query columns (ipd_status, r_doc_id) to list admitted patients assigned to doctor 2026-08-29 03:05:46 +05:30
9665e820ec feat(doctor): copy full native HMS OPD consultation controls, vitals, findings, and direct PDF printing 2026-08-29 03:02:12 +05:30
4a0889a200 feat(doctor): fix Patient Age calculation via get_age_1 and add Full HMS OPD Consult Form modal 2026-08-29 02:59:15 +05:30
1571c23947 fix(doctor): map exact database column names for opd_prescription (date_opd_visit, complaints, diagnosis) and opd_prescrption_prescribed 2026-08-29 02:54:14 +05:30
15a2f28d0d feat(doctor): add OPD appointment queue list with status badges and mobile-optimized consultation prescription form 2026-08-29 02:49:44 +05:30
a6beb124cd feat(doctor): add Doctor App PIN auth, QR generator, DoctorCare EMR PWA (/app/doctor), and bedside clinical tools 2026-08-28 19:44:54 +05:30
405226d66c fix(header): append hmsAppsLauncherModal to document.body to fix modal backdrop overlay issue 2026-08-28 19:34:41 +05:30
e865b71500 fix(header): refactor Apps Launcher script to pure Vanilla JS to prevent $ reference error 2026-08-28 19:31:22 +05:30
6a65fc507d feat(apps): add Top Nav Apps Launcher Icon & 30-Day Device PIN Authentication Memory 2026-08-28 19:27:39 +05:30
7b0b1c3415 feat(auth): add Nurse PIN Security Authentication, App QR Codes, and Lock Screen for NursingCare PWA 2026-08-28 18:45:53 +05:30
6f199d9743 feat(pwa): launch Option A mobile-optimized Nursing Care PWA app at /app/nursing 2026-08-28 17:49:31 +05:30
3b43d35246 feat(api): add isolated PWA App route gateway and REST API v1 endpoints 2026-08-28 17:44:11 +05:30
345e4f5f99 feat(nursing): add entry history tables and edit capability to Vitals, Fluid, and Treatment panels 2026-08-28 04:01:58 +05:30
5c053422ec feat(nursing): move Nursing Entries History and Scanned Audit Trail to separate left menu tabs 2026-08-28 03:54:54 +05:30
307355f5a7 feat(nursing): add dynamic medical route options for Fluid Intake / Output 2026-08-28 03:26:02 +05:30
9a9dba1f8f fix(nursing): pre-fill saved Admission Snapshot fields and persist active workspace tab 2026-08-28 03:19:44 +05:30
863c17f9bc fix(config): dynamically resolve baseURL from request HTTP_HOST to prevent CORS errors on live servers 2026-08-28 02:46:01 +05:30
69f0e1fa45 feat(nursing): add Nursing Station Master, ABDM credentials to Nurse Master, and Visual Bed Grid at /ipd/patient 2026-08-28 02:43:37 +05:30
7c04828e99 feat(ipd): align IPD Discharge prescribed medicine form design and autotext with OPD Consult 2026-08-27 04:33:10 +05:30
a7727c9d9e fix(abdm): correct mobile ABHA discovery flow
Route Find ABHA via Mobile through standalone bridge OTP endpoints and remove exact placeholder values from generated FHIR bundles.
2026-08-24 23:19:21 +05:30
2ac6babd5d fix(report): prevent collection filter overlap
Give the payment date range more grid space and reduce the employee selector width.
2026-08-24 01:24:56 +05:30
7ec5149ccf feat(ipd): manage admission examination fields
Add an Admin CRUD master for IPD admission examination fields with enabled state, display order, field types, and select options.
2026-08-24 00:53:01 +05:30
40c68da430 fix(report): tolerate legacy IPD surgery schema
Guard optional surgery report joins and return a readable response when a site-specific schema mismatch occurs.
2026-08-24 00:34:47 +05:30
225721ae02 feat(report): add IPD surgery export report
Add a permissioned IPD surgery report combining discharge surgery, patient, diagnosis, OT, and matched billing details.
2026-08-24 00:01:58 +05:30
83fce47ee1 feat(report): add searchable permissioned IPD census hub
Organize the report hub into permission-filtered searchable panels and add a protected IPD census and discharge report.
2026-08-23 20:36:09 +05:30
8e80bc4a7b fix(dashboard): align OPD referral totals with patient list
Use patient profile referral values for the OPD dashboard, matching the report patient-list source and counts.
2026-08-20 23:50:30 +05:30
9ca9320fee fix(report): include zero-fee OPD visits
Remove the payment-mode exclusion from the OPD patient-list report so it matches dashboard appointment totals.
2026-08-20 23:34:37 +05:30
6a690e80db fix(abdm): separate IPD discharge clinical sections
Map IPD chief complaints, final diagnoses, discharge advice, hospital course, and follow-up into profile-valid discharge FHIR sections.
2026-08-19 05:59:32 +05:30
16be448b6f fix(abdm): align IPD discharge FHIR with NRCES profile
Use mandatory SNOMED discharge composition and section codings, model completed investigations as DiagnosticReportLab resources, and restore local M3 attachment/value-string rendering.
2026-08-19 04:41:27 +05:30
bd557ef709 Add discharge FHIR resource metadata 2026-08-19 03:56:58 +05:30
85720577f3 Add footer margin to discharge template builder 2026-08-18 18:18:37 +05:30
fdfbddbd03 Fix CKEditor alignment icon paths 2026-08-18 18:11:03 +05:30
655065d230 Add visible CKEditor alignment icons 2026-08-18 18:05:44 +05:30
8515e995f3 Show visible CKEditor alignment buttons 2026-08-18 18:03:37 +05:30
47ee7ca226 Add CKEditor toolbar alignment plugin 2026-08-18 17:58:55 +05:30
93886e3402 Fix discharge editor alignment controls 2026-08-18 17:56:00 +05:30
2113abc318 Add alignment controls to discharge CKEditor 2026-08-18 17:53:43 +05:30
9e35fe41fc Add discharge template CKEditor and watermarks 2026-08-18 17:50:51 +05:30
3b200e0290 Fail open when caching discharge PDF 2026-08-18 17:35:30 +05:30
306f8ef1c4 Refresh mPDF debug snapshot on build 2026-08-18 17:32:24 +05:30
afd0ba8a8c Show runtime mPDF header payload 2026-08-18 17:27:43 +05:30
16de9b0c0c Force discharge header onto first PDF page 2026-08-18 17:26:43 +05:30
f5743be68a Prevent duplicate discharge template content 2026-08-18 17:04:38 +05:30
4d5155a2f8 Avoid @page overriding discharge headers 2026-08-18 17:01:11 +05:30
0dbe4c6f64 Register discharge headers before first page 2026-08-18 16:50:42 +05:30
8a6319ac13 Render discharge template header with mPDF API 2026-08-18 16:46:09 +05:30
8cf0e42765 Activate discharge header with mPDF runtime API 2026-08-18 16:41:46 +05:30
28109df663 Build mPDF debug input on demand 2026-08-18 16:36:53 +05:30
53b79b5297 Add raw mPDF input debugger 2026-08-18 16:33:24 +05:30
ebf23b93e8 Use exact OPD header rendering pattern for discharge 2026-08-18 16:29:43 +05:30
94bcf4d37c Force discharge header on first page 2026-08-18 16:20:04 +05:30
b068fc3be2 Fix @page header activation for body-only template CSS 2026-08-18 16:13:53 +05:30
d87b38e7f0 Add mPDF reference doc; fix discharge PDF rendering 2026-08-18 16:02:46 +05:30
0ea3fc099a Use correct mPDF CSS-first structure for discharge 2026-08-18 15:59:23 +05:30
4835d34e0e Add Debug HTML button to discharge template editor 2026-08-18 15:55:09 +05:30
e353e5afdc Simplify discharge PDF to plain mPDF fragment 2026-08-18 15:42:01 +05:30
f69d10b417 Move discharge template CSS into PDF head 2026-08-18 15:40:22 +05:30
f9b1e02af8 Fix @page placement for mPDF discharge header 2026-08-18 15:37:22 +05:30
42abe7ed9b Use mPDF htmlpageheader for discharge header 2026-08-18 15:29:13 +05:30
1fec6c8677 Add IPD discharge template builder 2026-08-18 15:18:13 +05:30
e1de6e3215 Apply discharge header margin setting 2026-08-18 14:50:56 +05:30
c26589fa22 Render discharge header in PDF body 2026-08-18 14:48:23 +05:30
ce04de2adf Separate NABH audit template selection 2026-08-18 14:29:09 +05:30
aee50cb52f Rebuild IPD discharge template selection 2026-08-18 14:28:27 +05:30
2e7da51024 Add discharge header mode test buttons 2026-08-18 14:15:39 +05:30
80f9487e8f Show discharge header in HTML debug 2026-08-18 14:11:50 +05:30
8e9fe8fab3 Apply discharge template CSS to print fragments 2026-08-18 14:08:46 +05:30
e0ce677355 Make discharge header field authoritative 2026-08-18 13:58:14 +05:30
0047a0508a Respect blank discharge template headers 2026-08-18 13:46:35 +05:30
80593ba931 Preserve legacy discharge template headers 2026-08-18 13:40:52 +05:30
4b2c44c738 Add OPD patient list to report panel 2026-08-18 13:11:16 +05:30
903478ce59 Add OPD patient list report with refer by 2026-08-18 13:09:03 +05:30
9bec2d2a66 Improve OPD total report filter layout 2026-08-18 13:04:19 +05:30
16f244f6be Add Refer By OPD template placeholder 2026-08-18 13:00:28 +05:30
662aeed7f1 Include full days in OPD total report 2026-08-18 12:55:32 +05:30
cac5e3c4ec Clear OPD modal backdrop during navigation 2026-08-18 12:50:10 +05:30
95026b4cfd Fix ABDM OPD queue modal redirects 2026-08-18 12:25:55 +05:30
1bd93be698 fix(abdm): treat empty HIU sessions as pending, not failure
The bridge reply 'No HIU sessions found matching the criteria' means the facilities have not sent records yet. The consent-status step already handled that wording, but the data-fetch steps surfaced it as 'Auto flow failed'. Share the check via isPendingBridgeSessionError() and report a pending state that keeps polling.
2026-08-18 03:15:09 +05:30
fb2bfb8a8c fix(abdm): stamp consent status on its own request row
Reconciled status lived only on a separate reconcile row, whose correlation back to a session was rebuilt on every page load, so denied/expired requests reverted to REQUESTED after reopening. Write GRANTED/DENIED/EXPIRED/REVOKED onto the session's own consent_request row and treat a stamped terminal state as authoritative.
2026-08-18 03:11:09 +05:30
c6f415cfdc fix(abdm): file consent status under the right request
consent_request anchor rows only registered their HMS request_id, so reconcile rows (which carry the ABDM consent_request_id) matched nothing and fell back to the newest open session. A DENIED result therefore landed on the granted session, where GRANTED outranks it, and the denied request kept showing REQUESTED. Anchors now publish their ABDM ids, and the open-session fallback applies only when the row names no consent request or that session has not resolved its ABDM id yet.
2026-08-18 03:03:59 +05:30
1dbac7b367 fix(abdm): reconcile every open consent request
Check Live Status only reconciled the newest consent request, so requests the patient later denied or let expire in the PHR app stayed at REQUESTED. Reconcile all non-terminal sessions, expose each session request_id, and let a later revoked/expired/denied row override an earlier granted one.
2026-08-18 02:51:19 +05:30
7ae9a77d29 fix(abdm): save enrolment mobile on ABHA-created patients
ABDM does not echo the alternate mobile in aadhaar/verify-otp, so patients created from that response were saved without a phone number. Fall back to the enrolment mobile ABDM accepted, flag its origin via mobile_source, and state the origin in the wizard.
2026-08-18 02:51:14 +05:30
8be64239d5 fix(abdm): stop ABHA flow after Aadhaar-created account
ABDM v3 creates the ABHA inside aadhaar/verify-otp when an alternate mobile is supplied. HMS then ran a standalone mobile OTP login, which returned whichever ABHA owned that number (e.g. the parent's) and overwrote the child's record. Skip that step when an ABHA number is returned and show the operator an explicit alternate-mobile status instead.
2026-08-18 02:31:44 +05:30
841b15d27b fix(abdm): bind alternate mobile to enrolment
Use the dedicated Bridge enrolment-mobile OTP endpoints for child/dependent ABHA creation and reject any alternate-mobile response whose ABHA differs from the Aadhaar-verified identity.
2026-08-18 02:13:47 +05:30
c8f44e4493 fix(abdm): complete ABHA creation workflow
Split official and hospital ABHA cards, preserve profile/photo updates, improve existing-patient matching, require and forward communication mobile data, and show accurate Bridge OTP status and errors.
2026-08-17 06:43:37 +05:30
2e8304636b feat(abdm): add digital share records
Generate standardized Digital Share PDFs for invoice and diagnostic records, strengthen FHIR document validation and sync handling, and keep task-board submissions AJAX-only.
2026-08-16 17:35:42 +05:30
625987955e feat(abdm): improve bridge record delivery
Add NAT-safe Immunization and InvoiceRecord Bridge workflows, stable care-context handling, ABHA address enrichment, embedded invoice PDFs, M2 status synchronization, and strict Bridge response normalization.
2026-08-16 01:30:11 +05:30
68d256d9ba Retain ABDM audit trail 30 days and strip payloads after 2 2026-08-15 03:16:47 +05:30
2d13ba567e Store Aadhaar encrypted with masked display and hash-based search 2026-08-15 03:16:40 +05:30
00b949ad0a Push M2 records to gateway for NAT deployment and cover all 8 HI types 2026-08-15 03:16:32 +05:30
b25ab98fd7 Fetch official ABHA card and surface bridge card provenance 2026-08-15 03:16:25 +05:30
b4714270a9 Add combined ABDM log prune command and api log index 2026-08-14 13:14:13 +05:30
076b18de62 Prune abdm_api_logs and abdm_hiu_workflows to 2-day retention 2026-08-14 13:14:02 +05:30
d85b3f5998 Add 2-day retention pruning for abdm_hiu_workflows 2026-08-14 11:52:49 +05:30
a55c6899f0 Fix ABHA create profile card and photo handling 2026-08-14 04:10:55 +05:30
32d43ce02a Add ABDM OPD queue navigation for reception 2026-08-14 02:33:18 +05:30
d4d0e9cd82 Remove ABHA card download from mobile OTP modal 2026-08-14 02:14:33 +05:30
52dc9fb5fd Read top-level gateway_patient and card fields 2026-08-14 00:33:17 +05:30
be2c78914f Keep ABHA modals open when patient already linked 2026-08-14 00:07:12 +05:30
2103215077 Fetch official ABHA card on mobile OTP verification 2026-08-13 23:59:22 +05:30
7047d00ae4 Move mobile OTP verification into a modal 2026-08-13 23:51:32 +05:30
dfb669e8ed Fix ABHA Management panels and facility QR print 2026-08-13 23:40:57 +05:30
3ce584ddc8 Use QR scanner modal only for ABHA QR registration 2026-08-13 20:10:03 +05:30
6a6895ce35 Add ABHA QR scan registration flow 2026-08-13 19:51:14 +05:30
3470244061 Keep ABHA modals open until closed by operator 2026-08-13 19:35:58 +05:30
ea1945d842 Skip match modal when ABHA already linked 2026-08-13 19:29:07 +05:30
7cb57b5b28 Match ABHA patients by exact identifier or demographics 2026-08-13 19:23:46 +05:30
bc5fdb8c63 Fix ABHA patient matching for DD-MM-YYYY dates 2026-08-13 19:14:00 +05:30
167a68362a Distinguish official ABHA card from generated fallback 2026-08-13 19:05:36 +05:30
1f4e8fa0cd Send patient X-Token when fetching ABHA card 2026-08-13 18:36:25 +05:30
22e960a834 Detect ABDM Bridge test-mode address responses 2026-08-13 18:13:12 +05:30
d0a0bf984e Fix ABHA card fetch and address suggestions 2026-08-13 17:41:31 +05:30
3e70ff8c4a Redesign ABHA Aadhaar creation flow 2026-08-13 17:11:48 +05:30
73ad7ef11f Store ABHA card and improve patient comparison 2026-08-13 11:30:02 +05:30
6a670d4c48 Refine ABHA patient matching criteria 2026-08-13 11:21:38 +05:30
48d6073a37 Fix false ABHA candidate name matches 2026-08-13 11:15:53 +05:30
fe9f46cb65 Consume enriched ABHA gateway response 2026-08-13 11:03:53 +05:30
c698d5df32 Preserve complete ABHA verification profile 2026-08-13 10:57:38 +05:30
a5447cb83a Complete ABHA account verification flow 2026-08-13 10:36:20 +05:30
35fcb07434 Clarify open source use and paid services 2026-08-12 21:28:43 +05:30
d10f49c482 Restore finance medical credit workflow and update help 2026-08-12 16:17:25 +05:30
870fed5dcd fix: correct medical org grid columns 2026-08-12 15:32:09 +05:30
6ad28dd960 fix: restore medical payout routes and labels 2026-08-12 15:24:23 +05:30
d289bb5be1 feat: add OT workflow and allow zero payments 2026-08-12 13:38:25 +05:30
670f6d3f1f fix: respect configured discharge template content 2026-08-10 14:58:50 +05:30
4ca463cc1e feat: add payment editing and fix discharge templates 2026-08-10 14:48:33 +05:30
681ad44a69 fix: show access denied page for permission failures 2026-08-10 12:30:32 +05:30
711b093487 feat: add IPD nursing and discharge permissions 2026-08-10 00:55:18 +05:30
bd9b1771a9 feat: add clinical drill-down dashboards
Add interactive OPD, IPD, and diagnosis dashboards with historical date ranges, KPI summaries, doctor and department workload, referral breakdowns, and diagnostic workflow statuses.
2026-08-10 00:21:55 +05:30
9872e1c726 refactor: show management status as toasts
Route User Management and Role Master action results through fixed top-right notifications, including SPA partial responses, validation failures, session actions, and network errors.
2026-08-09 23:58:59 +05:30
8f25904a13 refactor: streamline user permission management
Move per-user permissions into row actions, add contextual module permission guides, show selected-user details, and relocate online sessions to the profile menu.
2026-08-09 23:45:35 +05:30
c263b9e4ac feat: add role and session access controls
Add configurable role management, expanded project permission coverage, secured module routes, and single-active-session enforcement with online user administration.
2026-08-09 23:21:16 +05:30
b2926d5a0b Add discharge diagnosis and narrative template masters
Integrate Final Diagnosis with canonical disease master data and add reusable My/Master template CRUD for discharge narrative sections, including summary investigations, course, other advice, and discharge summary.
2026-08-09 19:50:05 +05:30
b39688dade Fix IPD discharge form interactions
Restore surgery and procedure bindings after SPA updates, validate procedure dates without SQL errors, and prevent medicine autocomplete Enter from submitting while preserving layout and autofill.
2026-08-09 19:05:05 +05:30
5bfe68be37 Add formulation to medical stock export
Include the medicine formulation as a dedicated column in the medical store stock Excel report.
2026-08-09 14:08:25 +05:30
ea28bfa837 Improve discharge medication template output
Render class-only discharge medication tables with salt and medicine advice, and persist generic salt data from medicine search.
2026-08-09 13:45:50 +05:30
b264b8fd92 Fix IPD assigned doctor updates
Allow doctor assignments to be removed when the optional deletion archive table is unavailable, while retaining archival behavior where supported.
2026-08-08 15:17:35 +05:30
51f5a87f92 Include old UHID in OPD template output
Append patient old_uhid to the OPD {{uhid_no}} placeholder only when a value exists.
2026-08-08 08:48:12 +05:30
ee87802af1 Add IPD medical bill type controls
Filter IPD pharmacy credit bills, add package/include toggles with admission validation, and provide an inline invoice detail view.
2026-08-08 08:33:53 +05:30
561c0d9fc3 Add package checkbox for IPD pharmacy bill inclusion 2026-08-07 15:23:57 +05:30
a10acec63f Fix IPD package tab reload URL after package actions 2026-08-07 15:07:56 +05:30
3036b2189f Add failure-path diagnostics for OPD scan upload/list 2026-08-07 14:15:47 +05:30
a1a06c5dee Fix OPD scan list for live schema/path differences 2026-08-07 13:41:32 +05:30
4f906424a6 Add migration for refer master address fields 2026-08-07 12:36:02 +05:30
d5c7d1030c Show patient grid controls and scope datatable search to filtered results 2026-08-07 12:32:21 +05:30
5f443f307a Enhance patient search and enforce refer master validation 2026-08-07 12:24:48 +05:30
780ebaa263 feat: add referral search to patient and IPD flows
Load referral master data into patient registration/edit screens, persist patient referby, expose searchable referral inputs in patient and IPD forms, and make referral title editable as free text in referral master CRUD.
2026-08-07 11:18:50 +05:30
bedb1c922a Show old UHID in patient search results 2026-08-06 08:46:54 +05:30
dd36e3af54 Fix patient search old UHID matching 2026-08-06 08:43:25 +05:30
dcc366444b feat: show New Update Available badge when GitHub has newer commits
- Add checkForUpdates() with 10-minute cached GitHub API check
- Add fetchLatestCommitInfo() to get latest commit SHA + message from GitHub API
- Save deployed commit SHA to writable/deployed_commit.txt after each deploy
- Invalidate update cache on successful deploy so next check is always fresh
- Button turns yellow + red NEW badge when update available
- Show commit message and short SHA diff (deployed → latest) in alert
- Show green 'Up to date' with deployed SHA when already current
- GitHub API rate limit safe: checks once per 10 mins via file cache
2026-08-04 04:03:09 +05:30
41f07357d2 fix: clean up orphaned running entries, add timeout handling
- Remove initial 'running' history entry (orphans when PHP times out)
- Add purgeStaleRunning() to mark old 'running' entries as 'timeout' on next deploy
- Add set_time_limit(300) to prevent PHP timeout during large ZIP download
- Add timestamps to log file entries for easier debugging
- Include ZIP size and source URL in success detail
- History now keeps last 20 entries (was 12)
- Show dash instead of blank for entries with no detail
- Style 'timeout' status same as 'failed' (red pill)
2026-08-04 03:59:38 +05:30
3fed2b6740 fix: prevent modal hang/fade by moving it outside refreshable panel div
- Move detail modal from system_ops_panel.php to system_ops.php
- Modal is now outside #systemOpsPanel so panel refresh never destroys it
- Skip refreshPanel() while modal is open (prevents backdrop desync)
- Add hidden.bs.modal handler to clean up lingering backdrop and body classes
- Fix show.bs.modal handler to correctly read data-detail via jQuery .data()
- Add white-space:pre-wrap to detail content for readable log output
2026-08-04 03:55:27 +05:30
f349b33001 feat: show all network interfaces with type badges (LAN/VPN/Public)
- readNetworkStatus() now returns array of all interfaces instead of single string
- Parses 'ip addr' output (with ifconfig fallback) for all IPv4 interfaces
- Each interface classified as LAN / VPN / Public by name and IP range
- VPN detected by interface prefix: wg*, tun*, tap*, vpn*
- RFC1918 ranges (192.168.x, 10.x, 172.16-31.x) shown as LAN
- Display: icon + IP + interface name badge + type label per row
- Handles NAT servers showing both local LAN and VPN IPs simultaneously
2026-08-04 03:45:51 +05:30
1073ab8aca feat: graphical RAID display, remove server action buttons
- Remove Restart Web, Restart PHP-FPM, Shutdown, Reboot buttons
- Remove runServerAction() library method and action() controller
- Remove /system-ops/action route (no longer needed)
- Parse /proc/mdstat into structured array (name, level, health, drives)
- Show each RAID array as a card with colored drive icons per-slot
- Green drive = healthy, red = failed, blue = spare
- Show rebuild progress bar when array is rebuilding
- Internet status shown as colored badge with wifi icon
- Services shown as colored badges (green=running, grey=other)
2026-08-04 03:39:49 +05:30
eb81f1999f refactor: remove git-based update method, keep only direct GitHub deployment
- Remove 'Update HMS (Git)' button and related functionality
- Remove runUpdate() method from SystemOperations
- Remove update() controller method
- Remove /setting/admin/system-ops/update route
- Remove setup_git_config.sh (no longer needed)
- Keep 'Deploy from GitHub' button as the only update method
- Rationale: Direct GitHub deployment is more reliable and requires no git config

Result: Single, simpler deployment method that always works
2026-08-04 03:27:22 +05:30
b2fdf9751d test: add deployment verification test file
This file is used to verify the GitHub deployment feature works.
- Deployed via 'Deploy from GitHub' button
- Tests that files sync correctly from GitHub to live server
- Use presence of this file to confirm deployment success

Verification: Check live server for /var/www/html/hms_etria/TEST_DEPLOYMENT.txt
2026-08-04 03:23:05 +05:30
518b92ee46 fix: add missing routes for system-ops updateDirect and diagnose endpoints
- Add POST route for /setting/admin/system-ops/updateDirect
- Add GET route for /setting/admin/system-ops/diagnose
- Both endpoints were implemented but routes were missing

This fixes 'Request failed' error on Deploy from GitHub button
2026-08-04 03:20:01 +05:30
f3b8e28312 feat: add direct GitHub deployment as alternative to git pull
- New 'Deploy from GitHub' button downloads latest code directly
- No git configuration required - more reliable for git-unfriendly servers
- Automatically syncs changed files (skips .git, vendor, writable)
- Both methods available: git pull (if configured) or direct GitHub download
- Each has a clear confirmation dialog explaining the method
- Handles temporary extraction and cleanup automatically

This solves HMS deployment when git is not accessible to PHP process
2026-08-04 03:17:46 +05:30
cb4636e599 feat: add detailed git diagnostics endpoint
- New /setting/admin/system-ops/diagnose endpoint
- Shows git binary location, version, config values
- Includes file permissions and directory checks
- Displays actual git command outputs with exit codes
- Provides troubleshooting commands for setup

This helps debug git configuration issues without guessing
2026-08-04 03:13:59 +05:30
cc4ee09906 refactor: use local repository git config instead of global
- Skip problematic global .gitconfig in /var/www
- Use local repository config (.git/config) instead
- Avoids permission issues with /var/www directory
- Public repos don't need global config
- Simpler 4-step process with better error handling
2026-08-04 03:11:43 +05:30
b5950d48e3 fix: ensure .gitconfig created with www-data ownership from start
- Create .gitconfig as www-data user (not root)
- Ensures file has correct owner and permissions from creation
- Add fallback to use local repository git config if global fails
- Prevents 'could not lock config file' permission errors

This fixes the issue where www-data user cannot write to root-owned files
2026-08-04 03:10:06 +05:30
0e597b47da simplify: optimize setup script for public repositories
For public repos, only minimal git config needed:
- Fix corrupted .gitconfig file
- Set git user.name and user.email (required by git)
- Remove unnecessary SSL and SSH configuration
- Fix directory permissions for www-data user
- Test git status

Removed:
- SSH key setup (not needed for public repos)
- SSL verification config (not needed for public HTTPS)
- HTTPS remote URL configuration (already correct)

Updated from 8 steps to 5 simpler steps
2026-08-04 03:08:19 +05:30
a01771fa4d fix: handle corrupted .gitconfig file permissions
- Remove corrupted /var/www/.gitconfig file
- Create fresh .gitconfig with correct owner (www-data)
- Set proper permissions (600) before git config commands
- This prevents 'could not lock config file' permission errors
2026-08-04 03:06:41 +05:30
9156bb2ebd improve: comprehensive git diagnostics and automated setup script
Enhanced error reporting:
- Show detailed diagnostic information: git version, user config, email, remote, branch
- Check .git directory and config file existence
- Detect if repository has uncommitted changes
- Error categorization: PERMISSION, CONFIG, REPO, NETWORK, SSL, GIT errors
- Actionable error messages with command suggestions
- Report raw error output to log file for debugging

Added setup_git_config.sh script:
- Automated configuration for www-data user
- Creates .ssh directory with proper permissions
- Sets git user.name and user.email globally
- Disables SSL verification (for HTTPS repos)
- Configures git to use HTTPS remote URL
- Fixes directory ownership and permissions
- Tests git status to verify configuration

Usage on live server:
  sudo bash setup_git_config.sh

This script handles the common git configuration issues
that prevent 'Update HMS' button from working.
2026-08-04 03:04:53 +05:30
8f9920e71c improve: enhanced git status error messages with full diagnostics
Better error message handling:
- Show actual error output from git status
- Detect specific issues: missing config, SSL certs, repository corruption
- Parse error patterns for user-friendly messages
- Include git version, config, and remote info in error response

Added getGitDiagnostics() method:
- Returns git version
- Checks git config user.name and user.email
- Shows configured remote URL
- Displays current branch
- Helps diagnose setup issues

Error message now includes: [git version, user name, remote URL]
Helps users identify: missing user config, wrong remote, SSH vs HTTPS issues
2026-08-04 03:01:43 +05:30
ca570d6366 fix: resolve git command not found by checking common installation paths
- Added findGitCommand() method to check for git in common locations:
  * /usr/bin/git (standard Linux)
  * /bin/git (alternative location)
  * /usr/local/bin/git (compiled from source)
  * Falls back to 'which git' and 'command -v git'

- Uses absolute git path in all shell commands
- Fixes 'Git command not found' error on systems where git is not in PATH
- No dependencies added, uses PHP file_exists() + is_executable() checks
2026-08-04 02:59:42 +05:30
a024f89205 improve: enhanced git pull error handling with detailed diagnostics
Pre-checks before git pull:
- Verify .git directory exists
- Check if git command is available
- Run git status to detect permission/connectivity issues

Better error messages for common failures:
- Permission denied → 'Git directory may not be writable'
- Authentication failed → 'SSH keys may not be configured for www-data'
- Connection refused → 'GitHub server unreachable'
- fatal errors → Parse and return specific error details

Returns actual error message instead of generic 'Check logs for details'
2026-08-04 02:56:58 +05:30
b352bc9ff0 test: create test file for git pull verification
This file can be used to verify that the 'Update HMS' button successfully
pulls from GitHub on the live server. If this file appears in your remote
server directory after git pull, the update mechanism is working correctly.
2026-08-04 02:54:30 +05:30
87bf2d8368 improve: add 8-method fallback for internet connectivity check
- Method 1: ping to Google DNS (8.8.8.8)
- Method 2: DNS resolution via nslookup
- Method 3: DNS query using dig
- Method 4: curl HTTP HEAD to google.com
- Method 5: wget --spider
- Method 6: fsockopen to Google DNS (8.8.8.8:53)
- Method 7: curl to Cloudflare DNS (1.1.1.1)
- Method 8: PHP gethostbyname() for DNS resolution

Tries multiple DNS providers (Google, Cloudflare, Quad9)
Falls back to 'Offline' only if all methods fail
Handles firewalls, ICMP blocks, and missing commands
2026-08-04 02:50:23 +05:30
998eb7f2bf improve: add 6-method fallback for server IP detection
- Method 1: \['SERVER_ADDR'] from Apache/Nginx (most reliable)
- Method 2: /sbin/ip (absolute path, works if ip not in PATH)
- Method 3: Parse /proc/net/route for default gateway interface + IP
- Method 4: hostname -I (space-separated IPs)
- Method 5: ifconfig (fallback for older systems)
- Method 6: Socket connection to 8.8.8.8 (pure PHP, no shell commands)

Each method validates IP and skips loopback (127.x, ::1, ::ffff:127.x)
Fixes 'Unavailable' when shell commands fail or aren't available
2026-08-04 02:47:36 +05:30
1ade027b00 fix: prioritize real server IP, skip loopback (127.x, ::1)
- Changed primary method to: ip -4 addr show scope global (gets public/private IPs only)
- Added isLoopbackIp() helper to filter out loopback addresses (127.* and ::1)
- Fallback: hostname -I with loopback filtering
- Last resort: gethostbyname() with loopback check
- On remote server with eth0: 159.89.175.190, will now show public IP instead of 127.0.0.1
2026-08-04 02:45:01 +05:30
a4bccc765c fix: show server IP address in Network field instead of "Unavailable"
Three-level fallback chain:
1. gethostbyname(gethostname()) - PHP built-in, works on Linux and Windows
2. ip -4 addr show scope global | grep inet - Linux shell fallback
3. hostname -I - Linux shell secondary fallback

All results validated with FILTER_VALIDATE_IP before display.
2026-08-04 02:40:33 +05:30
bb8ed60216 fix: repair broken @media print CSS and add PDF tips modal
- Fixed split @media print blocks that caused all print rules to be orphaned
  (gallery section had added its own block which broke the main rules)
- Consolidated into one clean @media print block with proper A4 settings
- Print improvements: cover fills page 1, intro on page 2, each section
  starts on new page, screenshots print at fixed height, 3-col gallery grid
- Added "How to save as PDF" button with step-by-step modal overlay
- Steps guide: Destination → Save as PDF, A4 Portrait, Background graphics
- Both print bar buttons hidden in @media print
- @page: A4 portrait, 14mm/12mm/18mm margins, first page margin 0
2026-08-04 02:30:38 +05:30
7c63e738e8 feat: add real screenshots and complete module reference table from Word doc
Screenshots gallery:
- Replaced placeholder icons with 11 real PNG screenshots extracted from
  E-AtriaHMS.docx (Dashboard, Patient Search, ABHA Create, ABHA Register,
  IPD Billing Panel, OPD Queue, Bed Status Map, Charge Master, Stock Control,
  Report Panel, Admin Panel)
- Added new ABHA Register card showing 4 registration methods (Number,
  Scan ABHA QR, Scan Facility QR, Mobile OTP)
- Added new IPD Billing Panel card showing full tabbed panel layout
- Lightbox now opens real images on click
- Screenshots saved to public/assets/img/screenshots/image*.png

Module Reference Table (section 10):
- Added 25-row complete module reference table derived from Word document
- Covers Registration through Web/Cross-platform including LIS, RIS, OT,
  Emergency, Daycare, ABDM Dashboard, AI, Doctor's Workspace, RBAC
2026-08-04 02:26:16 +05:30
1f0f7566e8 feat: add screenshot gallery section to HMS presentation
- Added 9-card screenshot gallery section between intro and features
- Cards for: Dashboard, Patient Management, ABHA Creation, OPD Queue,
  Bed Status Map, Charge Master/Insurance Rates, Stock Control Center,
  Report Panel, Admin Panel
- Lightbox overlay for full-screen image viewing (keyboard Escape to close)
- Placeholder icons shown now; replace with real images by dropping PNGs
  into public/assets/img/screenshots/ and updating src on each card
- Added gallery CSS with hover lift effect and lightbox styles
- Print-friendly: lightbox hidden in @media print
2026-08-04 02:17:26 +05:30
0e6cf1664d feat: add HMS Features link on login page
- Added "View HMS Features & Capabilities" link below the login card
- Copied HMS_FEATURES_PRESENTATION.html to public/ so it is accessible
  via base_url without auth (same pattern as software-use-license.html)
- Link opens in a new tab
2026-08-04 02:05:09 +05:30
4d7ae0d669 docs: add HMS feature presentation (HTML + Markdown)
- HMS_FEATURES_PRESENTATION.html: full styled presentation with cover,
  professional introduction, 11 feature sections, tech stack, compliance,
  print/PDF button, and proper @media print A4 layout
- HMS_FEATURES_PRESENTATION.md: plain Markdown version of the same content
- system_ops.php: fix confirm dialog text for Update HMS button
2026-08-04 02:02:26 +05:30
155c3ec4b5 feat: add error details modal to update history
- Added "Details" column to Update History table
- Shows info icon button when error details are available
- Clicking button opens a modal with full error message
- Details displayed in pre-formatted text for easy reading
- Helps diagnose why HMS updates failed or timed out

When an update fails, users can now click the info icon to see the exact
git error output, making troubleshooting much easier.
2026-08-03 17:03:23 +05:30
f9c0fd1a72 fix: simplify HMS update to only git pull and add timeout protection
Update improvements:
- Renamed button from "Update System" to "Update HMS"
- Changed update to run only 'git pull' (removed database migrations)
- Added 60-second timeout to prevent system hangup
- Better error messages for timeouts and failures
- Logs update status (running/success/failed/timeout) to history
- Confirmation dialog now says "Pull latest HMS code from repository?"

This ensures quick updates without long-running migrations that could hang
the admin interface. Database migrations can be run separately as needed.
2026-08-03 17:00:21 +05:30
3720da9b16 feat: add visual progress bars to resource usage and improve CPU detection
Resource Usage improvements:
- Added visual progress bars for CPU, RAM, and Disk usage
- Progress bars use Bootstrap styling (success/info/warning colors)
- Display percentage and detailed metrics (e.g., RAM 4 / 128 MB (3%))
- Bars animate smoothly with CSS transitions

CPU detection enhancements:
- Added fallback to /proc/stat parsing when shell commands unavailable
- Added fallback to PHP getrusage() for CPU time estimation
- CPU now displays even when shell_exec is disabled
- Graceful fallback chain ensures data is always available

Progress bar styling:
- Success (green) for CPU
- Info (blue) for RAM
- Warning (orange/yellow) for Disk
- All bars styled with height, rounded corners, and smooth transitions
2026-08-03 16:56:50 +05:30
232bf3ef8a fix: add PHP built-in function fallbacks for system operations when shell_exec is disabled
When shell_exec() is disabled on the server (common in production), the system
operations panel now gracefully falls back to PHP built-in functions:

- gethostname() for hostname instead of shell 'hostname' command
- php_uname() for OS info instead of shell 'uname -a' command
- /proc/uptime parsing or unavailable status for uptime
- disk_free_space() and disk_total_space() for disk usage
- memory_get_usage() and PHP memory limit for memory usage
- Improved parsePhpMemoryLimit() to handle memory limit parsing

This ensures the admin panel shows meaningful information even in restricted
production environments where shell_exec is disabled for security reasons.
2026-08-03 16:52:46 +05:30
096ce5e199 feat: add System Operations tile to admin dashboard and include helper library
- Added System Operations link to Admin dashboard (app/Views/Setting/Admin/index.php)
- Uses load_form_div to load the system operations page inline
- Added SystemOperations library for server status collection and actions
- Tile uses server icon (bi-server) and appears in the admin panel grid
- Link: javascript:load_form_div(base_url('setting/admin/system-ops'), 'maindiv', 'System Operations')
2026-08-03 16:50:00 +05:30
89b862db31 feat: add admin system operations panel with AJAX refresh and server monitoring
- Added SystemOps controller with index and panel endpoints for dynamic content refresh
- Created system_ops_panel.php fragment for AJAX-based UI updates (no full page reload)
- Implemented 30-second auto-refresh using AJAX instead of location.reload()
- Fixed health badge contrast by adding explicit dark text color (#1f2937)
- Added jQuery availability checks to prevent script errors on page load
- Included server overview, resource usage, services, events, and update history
- Integrated delegated event handlers for action buttons (Update, Restart, Reboot, Shutdown)
- All buttons are protected with confirmation dialogs
- Layout maintains NiceAdmin card styling and responsive design

Routes added:
- GET /admin/system-ops/panel - returns panel fragment for refresh
2026-08-03 16:47:41 +05:30
37631c27a0 Improve patient search for legacy UHID values 2026-08-03 15:32:16 +05:30
e473be3ae7 Fix diagnosis print template dual-PDF flow and settings save bug
- Diagnosis.php: resolve doctor mapping via ABDM Report Doctor Mapping,
  compile pathology/diagnosis reports into separate Letter Head and
  Plain Paper PDFs, add compiled-pdf-links endpoint
- Routes.php: add diagnosis/compiled-pdf-links route
- pathology_detail.php: render/persist dual compiled PDF buttons
- Setting/Template.php: per-modality Letter Head / Plain Paper template
  mapping via hospital_setting keys
- Setting/Template/index.php: fix tile links using load_form (which only
  replaces #main) instead of load_form_div, which broke every internal
  AJAX reload (template type switch, modality switch, reset) on the
  diagnosis/discharge/document print template settings pages
- diagnosis_print_settings.php: fix corrupted watermark_alpha number
  input (missing step attribute) that silently blocked form submission
  for templates with non-integer-step legacy values
2026-08-03 02:43:50 +05:30
f57da52725 Refine IPD bill group row colspan and bold styling 2026-08-01 16:44:55 +05:30
6be0df028e Highlight IPD bill group headers and subtotals 2026-08-01 16:36:54 +05:30
b1846696a4 Prevent stale cached IPD bill PDF responses 2026-08-01 16:28:27 +05:30
71a7875fe1 Format IPD bill print group headers and subtotals 2026-08-01 16:21:22 +05:30
49d83dd105 Add PATIENT_TITLE discharge placeholder 2026-08-01 16:13:13 +05:30
53bc924c06 Polish IPD bill labels and wording 2026-08-01 16:05:16 +05:30
151ea7a53f Refine IPD charge display and billing print outputs 2026-08-01 15:55:00 +05:30
2ea2f9f2dc Show last assigned bed in IPD bill print 2026-08-01 15:41:59 +05:30
ee9bb7b560 Fix ABHA card barcode print rendering 2026-08-01 03:57:43 +05:30
f7a0beadb2 Fix ABHA card header layout 2026-08-01 03:38:56 +05:30
3d43375ec0 Balance ABHA card header branding 2026-08-01 03:32:00 +05:30
a28c8612e3 Update ABHA card header branding 2026-08-01 03:27:27 +05:30
fde98e9dee Always show OPD profile picture action 2026-08-01 03:12:52 +05:30
b10661c8d0 Refine OPD profile photo flow 2026-08-01 03:06:45 +05:30
7f9d288825 chore(opd): set appointment list DataTable default page length to 100 2026-08-01 02:56:07 +05:30
302f779ea2 fix(discharge): show in-hospital lab only for explicitly selected dates 2026-08-01 02:29:55 +05:30
d751ff9b4b fix(discharge): honor investigation checkbox selection and print manual/special investigations 2026-08-01 02:15:13 +05:30
bb448a38eb fix(discharge-template): stop DIETARY_ADVICE at review section 2026-07-31 18:07:21 +05:30
fb7ea94157 fix(discharge-template): resolve placeholders with flexible token matching 2026-07-31 17:51:01 +05:30
49a2027778 fix(discharge-template): prevent empty template payload on ajax save 2026-07-31 17:46:27 +05:30
d7e5f16f79 fix(ipd-discharge): honor updated DB template instead of forcing content-only fallback 2026-07-31 17:41:15 +05:30
7d5622d958 Harden ABHA cleanup against non-standard patient and OPD key columns 2026-07-30 14:34:08 +05:30
1429ffc567 Fix ABHA cleanup command for non-id bridge queue schemas 2026-07-30 14:32:46 +05:30
3c6121a4ad Gate legacy bridge events by ABHA verification and add cleanup command 2026-07-30 14:30:34 +05:30
b7f789b1c3 Fix auto-flow false failures and remove dead opd.fhir.generated bridge event
- Patient.php: broaden non-fatal-pending detection in abdm_content_auto_flow() to recognize more bridge error wordings (No HIU sessions found / matching the criteria) and HTTP 400, stopping spurious 'Auto flow failed' toasts.
- Opd_prescription.php: remove dead opd.fhir.generated bridge_sync_queue enqueue in storePrescriptionFhirBundle(). This unprefixed event type routed to the CSNOtk terminology bridge which has no consumer for it, always 404ing. Real ABDM sharing already works via DreamsoftConnector::sharePrescriptionBundle() (abdm.fhir.share.requested).
2026-07-30 06:25:45 +05:30
55bcaa7d09 Fix ABDM M3 HIU multi-facility consent session grouping and document display
- Fix groupWorkflowRowsIntoSessions() to correlate workflow rows by stable
  request_id/abdm_consent_request_id instead of chronological proximity to
  the newest CONSENT_REQUEST row. Background polling reconciles all
  historical sessions in one batch, so older sessions' rows previously got
  silently merged into the newest session, causing 'Show Data' to display
  an unrelated older session's single facility instead of all consented
  facilities.
- Skip synthetic orphan sessions (stray rows with no owning CONSENT_REQUEST)
  in getAbdmConsentRequestsList()/getAbdmConsentArtifactDetail() so they
  don't show as phantom history rows or get picked as 'most recent'.
- Fix abdm_documents() consent_request_id filter to match all known sibling
  artifact IDs for a session (via abdm_hiu_consent_artifacts), not just an
  exact single artifact id, so all facilities under one consent request
  appear together.
- Fix CreateAbdmHiuConsentArtifacts migration: reduce VARCHAR(180) to
  VARCHAR(100) on consent_request_id/artifact_id to satisfy MySQL's
  1000-byte composite key length limit (was silently failing to migrate).
- Add fetchAllArtifactsAfterGrant() cascade in M3HiuWorkflowService to fetch
  every known artifact under a granted consent, used by both the cron poll
  and a new abdm_check_live_status() endpoint/button.
- getLatestAbdmSyncSnapshot() session-scoping fix to avoid an older granted
  session masking a newer in-progress one.
- Relabel Dr. Joshi Clinic documents (previously mislabeled 'Test Hospital'
  from the HIP's own FHIR bundle Organization name).
2026-07-30 05:08:44 +05:30
82b7b27273 fix(abha): persist OTP-verified mobile number when bridge response omits it
Abha::verifyOtp() and Abha::verifyCommOtp() were overwriting the
user-typed, OTP-verified mobile number with whatever the ABDM bridge's
verify-otp response echoed back for 'mobile'. Many bridge responses
(especially plain mobile-OTP verification, as opposed to Aadhaar eKYC)
do not echo the mobile at all, so it silently became empty and was
never saved to patient_master.mphone1 during ABHA Register (By ABHA
Number / QR / Facility QR / Mobile OTP) or ABHA Create/Verify.

Fix: fall back to the originally submitted/verified mobile when the
gateway response omits it. Also updated Patient_V.php JS (Verify ABHA
tab, ABHA Register Method 1 and Method 4) to resend the mobile number
along with the verify_comm_otp call so the server has it available.

Address/email are unaffected by this bug: those fields are already
mapped via applyAbhaMetaColumns() when present, but the ABDM mobile-OTP
verification API generally doesn't return KYC demographic data (that
only comes from the Aadhaar-eKYC flow) - so they may legitimately
stay blank for phone-based registration methods.
2026-07-29 13:52:07 +05:30
a5bbe3cc20 fix(abdm): skip TLS verify on self-loopback FHIR gateway handoff call
HMS instances behind NAT with no live public IP can hit an expired/unreachable
TLS cert on their own base_url() when doing the internal handoff self-call to
AbdmGateway::share_prescription_bundle, causing 'Gateway handoff failed:
curl error 60: Peer's Certificate has expired'. This call never leaves the
local server, so skip peer verification by default via new
fhirGatewayHandoffSslVerify() helper. Set FHIR_HANDOFF_SSL_VERIFY=true in .env
to re-enable strict verification on deployments with a valid public cert.

Does not affect the actual outbound ABDM bridge submission (EAtriaBridgeConnector),
which keeps its own independent SSL verification/toggle.
2026-07-29 12:39:05 +05:30
7b1b81ce66 ABDM Fetch Data modal: show attached images/PDFs per document (lazy-loaded via abdm_document_detail, since the list endpoint strips attachments to keep it light) 2026-07-29 03:53:13 +05:30
0a31c6aa12 ABDM UI: remove redundant document-list panel, add Fetch Data button when no records found for a consent request 2026-07-29 03:41:29 +05:30
2e7e33238b Fix fatal memory-exhaustion crash in Consent Request History: cap response_json to NULL for data_fetch/hi_data_push_callback rows
Those operations can store the entire decrypted FHIR bundle (incl. base64 scanned-document attachments, sometimes MB per row) in response_json. fetchAbdmWorkflowRows()/getLatestAbdmSyncSnapshot() only ever read small consent-status/hi_types fields out of response_json, which never appear in bulk data_fetch payloads anyway, so cap it at the SQL level instead of buffering it into PHP memory just to build a list view.
2026-07-29 03:35:46 +05:30
448db54d4c Show fetched-record sections as plain bold headings (no collapse) and resolve DiagnosticReport result Observations to actual lab values 2026-07-29 03:22:35 +05:30
37dba1948e Redesign Consent Request History table columns and add Fetch/Show Data modal with FHIR section accordion 2026-07-29 03:16:24 +05:30
7129f6e17b Show Consent Request ID in Consent Request History and fetched-document list; persist consent_request_id per document 2026-07-29 03:05:02 +05:30
016c0fdf2f Fix duplicate ABDM document rows: dedup on bundle_id + care_context_reference, not transaction_id/consent_ref
Confirmed empirically: the SAME clinical document (identical FHIR Bundle.id) gets re-delivered by the bridge under a DIFFERENT transaction_id/consent_ref every time it is re-fetched (e.g. via the by-ABHA-address historical fetch, which returns every past consent session for the patient). The old dedup hash included transaction_id+consent_ref, so every re-fetch created a brand-new duplicate row instead of updating the existing one -- observed as literal duplicate rows in the OPD ABDM Fetched Data list (same date/title appearing 2-3x). bundle_id is set once by the HIP and is stable across re-fetches/consents, so pair it with care_context_reference to uniquely identify a document instead.
2026-07-29 02:44:14 +05:30
ad98afbe57 Add Method 1 (fetch by request_id) for self/current-session data + fix latest-consent-anchor drift bug
- M3HiuWorkflowService: data_fetch now supports fetch_by_request_id=1, sending request_id (not consent_id) per bridge Method 1 -- targets the current/self consent request's own session, distinct from Method 2 (consent_id, which can resolve to a stale session sharing the same artifact).
- Patient::abdm_content_fetch_only(): tries Method 2 (consent_id) -> Method 1 (request_id, self data) -> Method 3 (abha_address, historical fallback) in order, stopping as soon as real documents are found.
- Fixed a real pre-existing bug this surfaced: getLatestAbdmSyncSnapshot() used the same flawed 'status=SUCCESS implies COMPLETED' check (without requiring workflow_state=DATA_RECEIVED) already fixed elsewhere in computeConsentSessionDetail(). This let broad/historical data_fetch rows (status=success, but decrypted_data=[]) hijack priority-500 'best' selection and silently drift the resolved 'latest granted consent' to an unrelated historical consent_id after Method 3 fallback ran. Now requires workflow_state=DATA_RECEIVED, matching the earlier fix.
2026-07-29 02:31:29 +05:30
c87928c2bc Support Method 3 (fetch by abha_address) as fallback to surface historical ABDM records
Per bridge gateway team guidance, GET /v1/hiu/data/fetch?abha_address=... returns ALL historical decrypted records across every past consent for a patient, unlike the consent/request-scoped Methods 1/2 previously used exclusively. Added M3HiuWorkflowService support for a fetch_by_abha_address flag on the data_fetch operation, and wired abdm_content_fetch_only() to automatically fall back to this broader lookup when the consent-scoped fetch finds nothing new -- this surfaced 14 previously-invisible historical documents (consultation reports, pathology/cytology) for the test patient that were never being fetched before.
2026-07-29 02:19:56 +05:30
690dbf9572 Fix misleading 'fetched successfully' message on Fetch Records when no documents were actually saved
abdm_content_fetch_only() always returned phase=COMPLETED and 'Records fetched successfully' whenever the data_fetch API call itself succeeded (fetchResult.ok===1), even when documents_persisted+documents_updated was 0 (bridge/HIP hasn't actually delivered any records yet -- decrypted_data still empty, session status 'requested'). Now check documents_persisted+documents_updated: if 0, report phase=GRANTED with a clear 'not sent any records yet' message instead of falsely claiming success.
2026-07-29 02:08:25 +05:30
afd1de04bf Fix ABDM consent status showing COMPLETED before data actually arrived
computeConsentSessionDetail() treated any data_fetch/hi_data_push_callback row with status=success as proof the session reached COMPLETED. But the DB 'status' column only reflects whether the underlying API call/poll succeeded (no HTTP/transport error) -- NOT whether data was actually received; that's tracked separately via workflow_state (DATA_PENDING vs DATA_RECEIVED). A data_fetch poll that succeeds at the HTTP level but returns decrypted_data=[] (bridge still processing) was incorrectly marked COMPLETED instead of staying at GRANTED. Now also require workflow_state === DATA_RECEIVED for the COMPLETED phase.
2026-07-29 01:55:15 +05:30
67daaf8894 Fix ABDM consent modal showing all HI types as DENIED when granted via async data push
When a consent session's overall phase resolves to GRANTED/COMPLETED via a data_fetch or hi_data_push_callback row (proof data was actually fetched), but no consent_reconcile/consent_status row in that session ever recorded which hi_types were granted (e.g. data arrives via async push before any reconcile poll runs), grantedHiTypes stayed empty and every requested HI type was incorrectly marked DENIED. Fall back to treating the full requested set as granted when we have positive proof of GRANTED/COMPLETED but no negative evidence of per-type denial.
2026-07-29 01:44:17 +05:30
0a19ccb425 Fix ABDM Consent Request History UI showing blank/orphaned COMPLETED row: fetchAbdmWorkflowRows() now always includes every consent_request anchor row for the ABHA (merged with recent-200 window), so heavy per-artifact data_fetch polling volume can no longer push a session's CONSENT_REQUEST row out of range and break groupWorkflowRowsIntoSessions() 2026-07-29 01:21:54 +05:30
5cdf367f94 Fix stale dateRange.to in M3 consent_request: always refresh to current time at actual dispatch (was only clamping if in the future, so a retried/reused payload with a stale-past cutoff silently excluded newer records forever) 2026-07-29 00:27:46 +05:30
01d5efa1eb Add wipe_hiu_data_for_abha.php: full M3 HIU data wipe (documents+workflows+artifacts) for fresh consent testing 2026-07-28 23:54:31 +05:30
e803809506 M3 HIU: track every discovered consent artifact id per consent_request in new abdm_hiu_consent_artifacts registry, and re-poll each individually every cycle (merged fetch-by-request-id alone does not keep returning already-established artifact sessions) 2026-07-28 23:47:19 +05:30
e783a57c4d Fix M3 multi-artifact polling: pollNatGateway now passes consent_request_id (not single resolved artifact id) to data_fetch, so the bridge returns merged sessions across ALL linked HIP facilities in one poll 2026-07-28 23:37:31 +05:30
9f2460fed9 Remove obsolete one-off M3/M2 diagnostic scripts (root cause resolved) 2026-07-28 23:35:01 +05:30
fd0d571f9b Add diagnostic spark command abdm:hiu-reconcile-by-request to test consent_reconcile by consent_request_id 2026-07-28 23:14:20 +05:30
982690c195 check_transaction_lookup.php: add optional operation filter + limit args 2026-07-28 23:12:13 +05:30
81c9940860 Add safe delete script for abdm_hiu_documents rows by abha_address (dry-run by default, --confirm to delete) 2026-07-28 23:10:03 +05:30
d2c25b9e38 Add spark command abdm:hiu-fetch-by-consent for manual data_fetch of a specific consent artifact id 2026-07-28 22:57:57 +05:30
759d17d7a3 Add diagnostic: check_transaction_lookup.php for searching abdm_hiu_workflows/documents by transaction/consent id 2026-07-28 22:48:35 +05:30
7092f9845a Make check_hiu_documents.php read DB creds from .env instead of hardcoded local root credentials 2026-07-28 22:27:26 +05:30
1439ce0fcc Fix invalid ABDM HIType codes (HealthDocument->HealthDocumentRecord, Wellness->WellnessRecord) causing consent_request 400; fix extractErrorText for array-shaped bridge error responses 2026-07-28 22:16:22 +05:30
2525916c08 Add diagnostic to inspect raw consent_request response behind generic HTTP 400 error 2026-07-28 22:12:12 +05:30
6383e28abd Fix diagnostic script to collapse /api/api/ duplication and add sanity check + more candidate paths 2026-07-28 20:59:49 +05:30
51da7b068e Add diagnostic to probe candidate care-context-link bridge endpoints 2026-07-28 20:55:01 +05:30
449a683a7c Add one-off diagnostic script to dump full abdm_hiu_workflows response_json 2026-07-28 20:38:56 +05:30
2196de9959 Fix cron installer to use php83 instead of incompatible default php CLI 2026-07-28 20:21:23 +05:30
5fb87ea4b4 Extract and display ABDM DocumentReference/Binary attachments (images/PDFs/documents) in fetched record detail view 2026-07-28 17:52:43 +05:30
9536cd2990 Replace ABDM HIU M3 sidebar console with global ABHA Patient Request List (Phase 3 across all patients) 2026-07-28 17:06:41 +05:30
dec025d6bf ABDM Custom Request: default Expiry Date uses exact +1 year instead of +365 days 2026-07-28 16:57:34 +05:30
7256858562 ABDM Custom Request modal: Purpose as fixed dropdown + add Expiry Date field 2026-07-28 16:54:00 +05:30
25db2e5ddc ABDM OPD tab: replace flow buttons with per-patient Consent Request History list (Phase 3) 2026-07-28 16:42:20 +05:30
48d19f0ff7 ABDM: add manual Consent Request form with editable HI types + date range (Phase 2)
- New Patient::abdm_content_request_custom(int \) endpoint builds a custom
  consent{} block (purpose, hiTypes, permission.dateRange, dataEraseAt) from
  user-submitted hi_types[]/date_from/date_to/purpose form fields, instead of
  always using M3HiuWorkflowService::buildDefaultConsent()'s hardcoded
  OPConsultation+DiagnosticReport / 365-day defaults. Reuses the existing
  requester/hiu-id resolution and hiTypes normalization already built into
  preparePayloadForOperation() for the consent_request operation, so no
  M3HiuWorkflowService changes were needed.
- New route (POST) patient/abdm_content_request_custom/(:num).
- New 'Custom Request' button + '#abdmCustomConsentModal' form
  (Patient_Profile_Opd_V.php) with HI type checkboxes (OPConsultation,
  DiagnosticReport, Prescription, DischargeSummary, HealthDocument,
  ImmunizationRecord, Wellness, Invoice), Valid From/To date inputs
  (defaulted to today-365d..today), and a Purpose text field. On submit,
  reuses the existing auto-flow polling loop (runAutoFlowStep) with the
  returned request_id to track status through to data fetch.
- Live-verified end-to-end on patient 11 (Devender Singh): submitted a
  request for OPConsultation + DiagnosticReport + Prescription; sandbox
  granted only OPConsultation/DiagnosticReport, and the Phase 1 consent
  detail modal correctly showed Prescription as DENIED alongside the two
  GRANTED types, confirming the partial-grant per-HI-type breakdown works
  correctly end-to-end.
2026-07-28 16:23:47 +05:30
7f47045c55 ABDM: add per-HI-type Consent Detail view (Phase 1)
- New Patient::getAbdmConsentArtifactDetail() helper builds a requested-vs-granted
  HI type breakdown for a patient's current ABDM consent artifact, using the
  bridge-team-confirmed 'Option A' model: overall status is single-valued
  (GRANTED/REVOKED/EXPIRED/DENIED), per-type status is derived by comparing the
  requested hiTypes (from the saved consent_request request_json) against the
  granted hi_types array (already flattened onto responses by
  M3HiuGatewayClient). No bridge changes or DB migrations required.
- New Patient::abdm_consent_detail(int \) JSON endpoint + route
  patient/abdm_consent_detail/(:num).
- New 'View Consent' link + Bootstrap modal on the OPD ABDM tab
  (Patient_Profile_Opd_V.php) rendering a lifecycle stepper, consent metadata
  (Consent ID, Purpose, Valid From/To, Erase Date), and a per-HI-type table
  (Document Type / Permission / Status / Timestamp).
- Fixed a bug found during live testing: once a consent reaches COMPLETED
  (after a successful data_fetch), the highest-priority workflow row has no
  hi_types field (it's a FHIR data bundle), which was causing all granted
  types to show as DENIED. Now searches workflow history for the most recent
  row that actually carries the granted hi_types payload.
- Live-verified against patient 15 (Meera Bisht): both requested HI types
  (OPConsultation, DiagnosticReport) correctly show GRANTED with timestamps.
2026-07-28 16:17:10 +05:30
37c3592f69 ABDM: auto-expire stale pending consent requests after 1 hour
Previously, clicking 'Fetch ABDM Records' when a prior consent request was
stuck in REQUESTED/PENDING (no GRANTED/DENIED callback ever received from
the ABDM bridge/PHR - e.g. patient never opened/approved it in their PHR
app) would just resume/re-poll that same dead request indefinitely, since
getLatestAbdmSyncSnapshot() always prioritized the existing REQUESTED
request over starting a new one.

Now:
- getLatestAbdmSyncSnapshot() computes the age of a REQUESTED/PENDING
  snapshot's updated_at and marks restart_required = true once it has
  been pending for more than ABDM_PENDING_STALE_SECONDS (1 hour).
- abdm_content_auto_flow() honors this flag: when the last sync is stale,
  it no longer resumes the old request_id and instead falls through to
  create a brand-new consent_request against the bridge.

Verified locally: a 6h-old stale REQUESTED request for a test ABHA was
correctly abandoned and a fresh consent_request was created and granted
on the next 'Fetch ABDM Records' click, instead of re-polling the dead
request.
2026-07-28 14:36:15 +05:30
2c9e5755d2 Add check_remote_abdm_fetch.php diagnostic script for ABDM data_fetch troubleshooting on remote servers 2026-07-28 04:51:16 +05:30
becff35929 ABDM OPD tab: fix duplicate fetched-document rows + add dedicated Fetch Records action
- M3HiuDocumentRepository::persistFromDataFetch no longer includes the
  per-call request_id in the document dedup hash. request_id is unique
  every time data_fetch runs, so it was causing a brand-new duplicate
  row to be inserted on every re-fetch of the exact same ABDM document.
  Now dedup key is transaction_id + consent_ref + care_context_reference
  + bundle_id, which stays stable across repeated fetches -> re-fetches
  UPDATE the existing row instead of duplicating it.
- Added Patient::abdm_content_fetch_only() + route
  billing/patient/abdm_content_fetch_only/(id): a lightweight action for
  when consent is already GRANTED/COMPLETED. It calls data_fetch directly
  using the saved consent reference, skipping consent_request + reconcile
  polling entirely, avoiding unnecessary bridge calls/noise.
- Patient_Profile_Opd_V.php: added a 'Fetch Records' button that only
  appears once consent phase is GRANTED or COMPLETED, wired to the new
  endpoint; on success it refreshes the document list in place. The
  original 'Fetch ABDM Records' button still owns the full consent
  request -> reconcile -> fetch flow and already stops/re-enables
  correctly on DENIED/FAILED (verified, no change needed there).
- One-time cleanup: deduped existing abdm_hiu_documents rows in dev DB
  (13 -> 3) and recomputed doc_hash with the new stable key.
2026-07-28 04:34:08 +05:30
a5219bca2d ABDM Gateway settings: add admin UI toggle for SSL certificate verification
Adds a 'Verify SSL Certificate' switch on Admin -> ABDM Gateway page,
persisted as hospital_setting.ABDM_BRIDGE_SSL_VERIFY (default ON/secure).
Wired into M3HiuGatewayClient, EAtriaBridgeConnector, and the settings
page's own Test Connection check. Per-machine ABDM_BRIDGE_SSL_VERIFY env
var still overrides this DB setting for deployments needing a quick
local-only workaround. Verification stays on by default everywhere;
disabling it is an explicit, visible opt-in with an on-page warning.
2026-07-28 03:47:06 +05:30
b26920c6f4 ABDM bridge: allow opt-in SSL verify bypass via ABDM_BRIDGE_SSL_VERIFY env for envs with stale local CA bundles
Some local WAMP/XAMPP/Laragon PHP installs ship an outdated cacert.pem,
causing outbound HTTPS calls to the bridge to fail with cURL error 60
(SSL certificate problem). Rather than globally disabling certificate
verification (as bridge support suggested), verification stays ON by
default and can only be disabled per-deployment by explicitly setting
ABDM_BRIDGE_SSL_VERIFY=false in that machine's .env. The real fix on
affected machines is updating curl.cainfo in php.ini.
2026-07-28 03:37:23 +05:30
d7dae674cc chore: add more ABDM diagnostic scripts (multi-patient consent flow comparison) 2026-07-28 03:11:43 +05:30
768079c970 chore: add ABDM M3 HIU diagnostic scripts for consent workflow debugging 2026-07-28 03:08:52 +05:30
a1127522ef ABDM M3: flatten nested consent.status from bridge (root cause fix) and redesign OPD Fetch ABDM Records UI 2026-07-28 02:48:02 +05:30
716ad04d13 Fix duplicate ABDM consent requests: only treat consent_request submission failure as terminal FAILED 2026-07-28 02:36:27 +05:30
acc4e5c287 Prefer recent granted/completed over pending 404 snapshot 2026-07-28 02:28:57 +05:30
5c15424280 Promote granted consent status in snapshot ranking 2026-07-28 02:26:19 +05:30
98b25914d7 Include callback operations in ABDM sync snapshot 2026-07-28 02:15:34 +05:30
71e0c7cf24 Treat transient consent 404 as pending 2026-07-28 02:07:50 +05:30
c2a3e3054f Resolve fallback consent status in OPD flow 2026-07-28 01:53:44 +05:30
05d35f6021 Make OPD ABDM flow wait for first request 2026-07-28 01:46:36 +05:30
49969cb9be Simplify ABDM request flow for users 2026-07-28 01:28:08 +05:30
a15f5a0785 Handle failed ABDM consent reset and add status help 2026-07-28 01:05:25 +05:30
646347534d Harden consent date range across bridge and HIU paths 2026-07-28 00:46:47 +05:30
9a7bd9ed3a Clamp HIU consent dateRange.to to current UTC 2026-07-28 00:32:39 +05:30
90831d4b39 Harden ABDM bridge auth flow and sync handling 2026-07-28 00:14:49 +05:30
bf6090cfd5 Route consent status through flexible handler 2026-07-27 15:35:43 +05:30
3b6ed76a3c Reset stale ABDM request flow after bridge 404 2026-07-27 15:21:42 +05:30
0048cb1eff Resume granted consent flow on reconcile 404 and attempt direct fetch 2026-07-27 15:01:36 +05:30
698b9cd520 Prefer granted/completed ABDM state over latest 404 reconcile rows 2026-07-27 14:40:39 +05:30
c77201ec96 Persist and resume ABDM sync state on profile reload 2026-07-27 14:32:47 +05:30
8086bfbeb6 Stop ABDM auto-sync polling on reconcile 404 2026-07-27 14:28:42 +05:30
49698a72d7 Handle ABDM reconcile not-found as pending state 2026-07-27 14:18:07 +05:30
92a954a4cd Fix ABDM HIU auto-flow duplicate consent handling 2026-07-27 14:12:56 +05:30
9730f9a450 Update ABHA card branding assets 2026-07-25 22:26:28 +05:30
83c9a9f015 Show actual ABDM bridge messages in ABHA OTP flows 2026-07-25 22:25:31 +05:30
9a3f29660b Add modal preview for OPD history scans 2026-07-25 21:41:58 +05:30
f90bb94063 Enlarge OPD scan preview modal 2026-07-25 21:31:30 +05:30
39b5fc7c3e Use opd_no on OPD history header 2026-07-25 21:20:10 +05:30
4e060b9b98 Add patient details to OPD history header 2026-07-25 21:03:06 +05:30
f2e79a27a7 ABHA card: use official NHA/ABDM logo in header 2026-07-23 16:30:23 +05:30
3de17d955d ABHA card: remove official/bridge actions and improve local card data 2026-07-23 16:22:43 +05:30
e89e186281 ABHA: fetch official card via bridge API and print base64 card 2026-07-23 16:10:34 +05:30
3bda6f5291 ABDM M2 care-context outbound sync and server cron automation 2026-07-23 15:12:46 +05:30
0176079e7d Pharmacy product edit: debounce and cancel drug autocomplete requests 2026-07-23 12:11:28 +05:30
c84ea383e4 ABDM records/push: treat 201/409 as submitted, persist record IDs, and update OPD UI state 2026-07-21 01:32:30 +05:30
5d6acdd480 Implement ABDM bridge health record flows
- add facility QR support and OPD queue bridge fixes
- support care-context push warnings for lab, radiology, IPD and remaining HI types
- improve ABHA patient matching and diagnosis autocomplete performance
- clean up webcam streams on page navigation
2026-07-20 03:02:09 +05:30
2bd52532a0 Add ABDM M3 fetch option to Ayushman claim sheet 2026-07-19 01:19:56 +05:30
7a547eb443 Add E-Atria immunization master sync 2026-07-19 01:00:43 +05:30
82fd31d105 Add patient immunization module 2026-07-19 00:41:12 +05:30
629590d9ab ABDM: separate course section and include doctor in discharge FHIR 2026-07-17 18:40:19 +05:30
ca025a088e ABDM: hide empty investigations and standardize discharge headings 2026-07-17 18:33:43 +05:30
d7fe05e6b0 ABDM: enrich discharge FHIR with observations advice and risks 2026-07-17 17:59:54 +05:30
2335006c30 ABDM: enrich IPD discharge FHIR preview with clinical content 2026-07-17 17:48:41 +05:30
3b3e71341d ABDM: persist IPD discharge FHIR to sync outbox 2026-07-17 17:42:17 +05:30
e9b31e8475 Remove duplicate complaint subheading in print output 2026-07-17 17:32:47 +05:30
d6caf13be9 Ensure complaint narrative appears in discharge print output 2026-07-17 17:30:02 +05:30
7c76973ca3 Fix IPD discharge complaint live add/remove and section refresh sync 2026-07-17 17:23:43 +05:30
c4533b0294 Fix discharge print complaints section fallback 2026-07-17 16:42:08 +05:30
2b53c05a68 Add ABDM documents and patient profile sync UI 2026-07-16 18:23:40 +05:30
0e8e164335 Preserve repaired discharge HTML sections in mPDF
Serialize the full repaired body instead of only the temporary wrapper contents so DOMDocument recovery does not drop later discharge sections before mPDF rendering.
2026-07-15 21:16:25 +05:30
8270c8a049 Fix discharge mPDF rendering for malformed HTML
Normalize malformed discharge summary HTML before passing it to mPDF so browser-tolerated markup does not break PDF output.
2026-07-15 21:11:53 +05:30
bdae843f0a Fix duplicate OPD invoice payment redirect handling 2026-07-10 22:52:33 +05:30
02bfc02e39 Fix duplicate load_form execution and undefined OPD navigation 2026-07-10 22:46:49 +05:30
c5236ea2eb Fix duplicate OPD prescription print tab opening 2026-07-10 18:19:10 +05:30
3801610cdf Add mbstring-safe fallbacks in OPD prescription save 2026-07-10 01:18:34 +05:30
bb5f570ead Return JSON error response for OPD autosave exceptions 2026-07-10 01:11:49 +05:30
6767fce287 Fix OPD prescription autosave 500 on non-string payload values 2026-07-10 01:07:27 +05:30
5de65a73f1 Handle no-records cleanly without DataTable warning in Invoice lists 2026-07-10 00:45:07 +05:30
644449b3de Add safe load_form fallback and resilient invoice navigation 2026-07-10 00:39:58 +05:30
60d708c7b8 Fix Orgcase table 500 and prevent duplicate DataTable init 2026-07-10 00:34:49 +05:30
fb696863d4 Fix DataTables reinit and duplicate handlers in Invoice views 2026-07-10 00:25:00 +05:30
acabc6abdd ABDM HIU callback hardening, OPD ABHA optional confirm, and AJAX memory cleanup 2026-07-10 00:09:35 +05:30
658e67ad3b OPD: fix Select2 transport error and stale investigation results 2026-07-09 16:55:06 +05:30
2b32dfe5da OPD: reduce consult search min chars and wildcard threshold 2026-07-09 16:11:53 +05:30
e625233d96 Improve OPD history scan viewer with responsive sizing and modal zoom/pan 2026-07-08 15:35:01 +05:30
540de8c76e Enhance camera capture/edit permissions and fix OPD AdviceBlock rendering 2026-07-08 15:24:39 +05:30
fd8e96747d OPD consult: add floating draggable section bookmarks with persistent position 2026-07-07 15:17:58 +05:30
6407db9dbc Update HIU workflow, patient view, and related assets 2026-07-07 01:13:28 +05:30
f243aeeb04 Preserve OPD textarea newlines in print and refine IPD date filter layout 2026-07-06 18:49:10 +05:30
43f465e261 Fix OPD advice label and Hindi rendering in template output 2026-07-04 14:53:13 +05:30
fb460e02e8 Fix OPD AdviceBlock label rendering 2026-07-04 14:31:55 +05:30
068cbe8ccd Medical GST: persist item tax breakup and add backfill 2026-07-02 22:35:34 +05:30
ce15a42239 Medical reports: derive GST in sale summary 2026-07-02 21:13:53 +05:30
c2f1f76dcb IPD discharge: add edit action for prescribed medicines 2026-07-02 20:26:47 +05:30
c22c21d36c OPD template: keep {{investigation}} print order by sequence 2026-07-02 19:34:41 +05:30
c832b3a3e2 Add remote SQL script for investigation category backfill 2026-07-02 19:09:36 +05:30
681bb947b3 Investigation master: add category autofill action and rules 2026-07-02 19:05:33 +05:30
c930a54155 Investigations: use order_id sequence for profile apply and list order 2026-07-02 18:57:08 +05:30
c148b01466 OPD consult profiles: apply saved investigation order 2026-07-02 18:52:11 +05:30
0c85dddd43 Investigation profile: preserve select2 item order in edit panel 2026-07-02 18:43:34 +05:30
0a48fa6d2c OPD investigation list: order by id instead of name 2026-07-02 18:24:33 +05:30
6288c626fc mPDF: normalize numeric font-weights across template PDF renderers 2026-07-02 10:27:46 +05:30
1abf572a14 OPD letter: add HTML debug endpoint and placeholder style controls 2026-07-02 10:09:45 +05:30
71abebb3d4 OPD template builder: show opd fee amount/desc in usage panel 2026-07-02 09:47:09 +05:30
e85bfd85e1 OPD template: split opd fee into amount and description placeholders 2026-07-02 09:40:25 +05:30
0f8bd43e72 Fix ABDM M3 HIU ID mapping, polling guards, and migration compatibility 2026-07-02 00:55:05 +05:30
930 changed files with 509051 additions and 214546 deletions

13
.agents/mcp_config.json Normal file
View File

@ -0,0 +1,13 @@
{
"mcpServers": {
"abdm-docs": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://docs.abdm.gov.in/mcp"
],
"url": "https://docs.abdm.gov.in/mcp"
}
}
}

View File

@ -0,0 +1,49 @@
# ABDM Integration Rules & Standards
## Rule 1: Care Context & Patient Reference Formatting in ABDM Linking Payloads
### Background & PHR Table Display Behavior
In the ABDM PHR app (`phrsbx.abdm.gov.in` and official PHR apps), the records table renders the payload's `patient[].referenceNumber` field directly under the column header:
**`Patient reference` | `Health Document Type` | `Date`**
### Strict Constraint
1. **NEVER** set or overwrite `patient[].referenceNumber` with the internal hospital UHID or patient code (e.g. `P26081015350`).
2. **ALWAYS** set `patient[].referenceNumber` to the exact Care Context Reference (e.g. `PRESC-15350-S33765-20261023`, `OPD-15350-S33765-20261023`).
3. If linking multiple care contexts in a single request, provide each care context with its own item in the `patient[]` array so each record displays its unique reference number in the PHR app.
### Canonical Care Context Reference Standard
- **Prescription**: `PRESC-{patient_id}-S{session_id}-{YYYYMMDD}`
- **OPD Consultation**: `OPD-{patient_id}-S{session_id}-{YYYYMMDD}`
- **Discharge Summary**: `DISCHARGE-{ipd_id}-{YYYYMMDD}`
- **Diagnostic Lab**: `LAB-{patient_id}-{test_id}-{YYYYMMDD}`
- **Diagnostic Radiology**: `RAD-{patient_id}-{rad_id}-{YYYYMMDD}`
- **Invoice**: `INVOICE-OPD-{opd_id}-{YYYY-MM-DD}` or `INVOICE-CHG-{charge_id}-{YYYY-MM-DD}`
- **Wellness**: `WELLNESS-{patient_id}-{YYYYMMDD}`
- **Immunization**: `IMM-{patient_id}-{vaccine_id}-{YYYYMMDD}`
---
## Rule 2: Never Overwrite Structured References in Code
In `app/Controllers/AbdmGateway.php` and the bridge gateway:
- Do NOT use regex to detect `OPD-`, `PRESC-`, etc., and replace them with `p_code`.
- If a caller supplies a structured care context reference as `patient_ref`, keep it intact.
- Only fall back to `p_code` or `P-{id}` if no care context reference is provided or available.
---
## Rule 3: FHIR Document Generation Standards
- All clinical FHIR documents must conform to NRCeS FHIR R4 profiles.
- Entry[0] must always be the `Composition` resource.
- Use valid LOINC codes for composition type and section codes.
- Use SNOMED CT for clinical diagnoses, findings, and conditions.
- Refer to `docs/abdm/CARE_CONTEXT_AND_FHIR_STANDARDS.md` for full implementation specifications.
---
## Rule 4: Patient Name Handling (`patient_master.p_fname`)
- Patient full name is stored strictly in `patient_master.p_fname`.
- The column `patient_master.p_lname` has been permanently dropped and deleted from `patient_master` in all databases.
- NEVER query, select, join, insert, or reference `patient_master.p_lname` in any controllers, models, queries, or FHIR generators.
- When generating FHIR Patient or Composition resources, map the patient's full name directly from `patient_master.p_fname`.
- Note: Doctors in `doctor_master` continue to use `p_fname`, `p_mname`, and `p_lname`.

View File

@ -0,0 +1,51 @@
# HMS Billing & Revenue Standards
This document defines the architectural and database rules for all OPD, IPD, Diagnostics, and Pharmacy billing in the E-Atria HMS.
---
## 1. Core Billing Table Schema & Roles
| Table Name | Primary Role | Key Columns |
| :--- | :--- | :--- |
| `invoice_master` | Master bill/invoice record for OPD, IPD, and Lab visits | `id`, `invoice_no`, `patient_id`, `doctor_id`, `total_amount`, `discount_amount`, `tax_amount`, `net_amount`, `paid_amount`, `balance_amount`, `status`, `payment_mode`, `created_date` |
| `invoice_item` | Line items for services, doctor visits, procedures, lab investigations | `id`, `invoice_id`, `item_type`, `item_id`, `item_name`, `item_rate`, `qty`, `amount`, `discount`, `net_amount`, `doctor_id`, `created_at` |
| `payment_history` | Multi-tender transaction log (Cash, UPI, Card, NetBanking, Cheque) | `id`, `invoice_id`, `patient_id`, `amount`, `payment_mode`, `transaction_ref`, `bank_source_id`, `received_by`, `payment_date` |
| `ipd_invoice_item` | Dynamic daily IPD charges (room rent, nursing, doctor rounds, procedures) | `id`, `ipd_id`, `item_type`, `item_id`, `item_name`, `item_rate`, `item_qty`, `item_amount`, `doc_id`, `doc_name`, `date_item` |
| `doc_opd_fee` | OPD consultation fee slab configured per doctor | `id`, `doc_id`, `doc_fee_type`, `doc_fee_desc`, `amount` |
| `doc_ipd_fee` | IPD visit fee slab configured per doctor | `id`, `doc_id`, `doc_fee_type`, `doc_fee_desc`, `amount`, `isdelete` |
| `sales_master` | Pharmacy sales invoice master | `id`, `bill_no`, `patient_id`, `opd_id`, `ipd_id`, `total`, `discount`, `net_amount`, `paid_amount`, `created_at` |
---
## 2. Inviolable Financial Integrity Rules
1. **Balance Equation Strictness**:
For every invoice in `invoice_master`:
$$\text{net\_amount} = \text{total\_amount} - \text{discount\_amount} + \text{tax\_amount}$$
$$\text{balance\_amount} = \text{net\_amount} - \text{paid\_amount}$$
- Any transaction modifying line items or applying discounts MUST atomically update `invoice_master.net_amount` and `invoice_master.balance_amount`.
2. **Every Receipt Must Have a Ledger Entry**:
- Whenever money is collected (cash, UPI, card, bank transfer, advance), an entry MUST be inserted into `payment_history`.
- Never update `invoice_master.paid_amount` without inserting a corresponding row in `payment_history`.
- The sum of payments in `payment_history` for an `invoice_id` must always equal `invoice_master.paid_amount`.
3. **Status Transitions**:
- `UNPAID`: $\text{paid\_amount} = 0$
- `PARTIAL`: $0 < \text{paid\_amount} < \text{net\_amount}$
- `PAID`: $\text{paid\_amount} \ge \text{net\_amount}$
- `CANCELLED`: Only permitted when reversed with reason log and audit user ID.
4. **IPD Running Charges to Final Invoice**:
- IPD patients accumulate daily charges in `ipd_invoice_item` (room tariff, daily doctor rounds, medication, nursing care).
- Upon discharge billing, all unbilled items from `ipd_invoice_item` and approved advances from `payment_history` are aggregated into the final settlement invoice in `invoice_master`.
- Once finalized, items in `ipd_invoice_item` must be marked as billed/settled to prevent double billing.
5. **Discount Governance**:
- Any discount greater than zero requires `discount_reason` and must be authorized by an authorized user (`discount_approved_by`).
- Doctors or cashiers cannot grant unauthorized ad-hoc discounts without an audit trail.
6. **Patient Full Name Standard**:
- In invoices and receipts, the patient's name MUST be fetched from `patient_master.p_fname`.
- Never query or write to `patient_master.p_lname` (permanently dropped).

View File

@ -0,0 +1,53 @@
# HMS Clinical & Medical Record Standards
This document defines the clinical data model, doctor naming conventions, laboratory reporting, radiology reporting, and electronic medical record (EMR) rules for the E-Atria HMS.
---
## 1. Demographic & Clinical Name Rules
1. **Patient Full Name Standard (`patient_master.p_fname`)**:
- The patient's full name is stored strictly and exclusively in `patient_master.p_fname`.
- The column `patient_master.p_lname` has been permanently dropped from the database.
- **NEVER** use, select, insert, update, or reference `patient_master.p_lname` anywhere in controllers, models, views, or queries.
2. **Doctor Name Standard (`doctor_master`)**:
- For doctors, the database retains multi-part names: `p_title`, `p_fname`, `p_mname`, `p_lname`.
- When displaying a doctor's full name on UI, prescription prints, or reports:
```php
$doctorFullName = trim(($doctor->p_title ?? 'Dr.') . ' ' . trim(($doctor->p_fname ?? '') . ' ' . ($doctor->p_mname ?? '') . ' ' . ($doctor->p_lname ?? '')));
```
- Always display qualification (`doc_sign`) and medical council registration number (`doctor_reg_no`) on all prescription and diagnostic report footers.
---
## 2. Clinical Terminology & Code Mappings
1. **SNOMED CT Coding**:
- All chief complaints, physical findings, and diagnoses recorded in OPD consultation must link to SNOMED CT Concept IDs whenever available.
- The local CSNOTK bridge is configured at `snomed.csnotk.baseUrl` in `.env`.
2. **LOINC Coding for Pathology**:
- All tests in `lab_tests` should have corresponding LOINC codes mapped in `lab_tests.loinc_num` or `lab_tests.loinc_code`.
- When generating NRCeS FHIR Document Bundles (DiagnosticReport), LOINC is the mandatory primary coding system.
3. **Ayushman Bharat & TPA Packages**:
- Standard package procedures must map to `ayushman_package_master` (1,401 standardized PM-JAY packages).
---
## 3. Diagnostic & Imaging Workflow Integrity
1. **Pathology Lifecycle**:
$$\text{Test Prescribed} \longrightarrow \text{Sample Collected} \longrightarrow \text{Accession/Barcode} \longrightarrow \text{Result Entry} \longrightarrow \text{Doctor Verification} \longrightarrow \text{Published Report}$$
- No diagnostic report can be released to a patient portal or ABDM bridge without formal verification (`verified_by` / `doctor_sign`).
- Out-of-range critical/panic values must be visually highlighted in bold red with critical alert indicators.
2. **Radiology Lifecycle**:
$$\text{Scan Ordered} \longrightarrow \text{Procedure Completed} \longrightarrow \text{Drafting Findings} \longrightarrow \text{Impression} \longrightarrow \text{Radiologist Sign-off}$$
- Templates stored in `doc_print_templates` / `radiology_ultrasound_template` must preserve standardized headings:
1. Clinical Indication / History
2. Modality & Protocol
3. Observations / Findings
4. Impression / Conclusion
5. Advice / Recommendations

View File

@ -0,0 +1,56 @@
# NABH Hospital Accreditation Compliance Rules
This document specifies the NABH (National Accreditation Board for Hospitals & Healthcare Providers, 5th Edition) standards embedded in the E-Atria HMS architecture.
---
## 1. 13 Mandatory Statutory Consent Forms
All IPD admissions and specialized clinical procedures must record explicit, informed patient consent before interventions:
| Consent Form ID | Title | Key Mandatory Requirement |
| :--- | :--- | :--- |
| `NABH-IPD-01` | Admission Request & Initial Assessment Form | Demographics, provisional diagnosis, treating consultant, signature within 24h |
| `NABH-IPD-02` | General Informed Consent for Medical Treatment | Risks, benefits, hospital policies, patient/attendant signature |
| `NABH-IPD-03` | Informed Consent for Surgical Procedure / Operation | Operating surgeon, specific procedure name, alternatives, anesthesia type |
| `NABH-IPD-04` | Informed Consent for Administration of Anesthesia | General / Spinal / Epidural / Regional, fasting status, ASA grade |
| `NABH-IPD-05` | High-Risk Informed Consent | Explicit documentation of mortality risk, ICU requirement, signed by 2 attendants |
| `NABH-IPD-06` | Blood & Blood Component Transfusion Consent | PRBC, FFP, Platelets, adverse reaction warning, refusal rights |
| `NABH-IPD-07` | ICU / HDU Admission Informed Consent | Critical care protocols, invasive monitoring, ventilator consent |
| `NABH-IPD-08` | Discharge Against Medical Advice (DAMA / LAMA) | Declaration of voluntary discharge against advice, liability waiver |
| `NABH-IPD-09` | Consent for Invasive Diagnostic / Bedside Procedure | Endoscopy, Lumbar puncture, CVC, Pleural tap |
| `NABH-IPD-10` | Refusal of Medical Treatment / Procedure Consent | Explicit informed refusal documenting medical risks of refusal |
| `NABH-IPD-11` | Chemotherapy / Dialysis Specialized Consent | Specific drug protocols, cumulative toxicity risks |
| `NABH-IPD-12` | Restraint Application Consent | Physical/chemical restraint reason, alternative trials, periodic review |
| `NABH-IPD-13` | Release of Medical Records / Photography Consent | Confidentiality waiver, medico-legal or insurance release |
---
## 2. Inpatient Clinical Timelines & Standards
1. **Initial Assessment Timeline**:
- Initial Medical Assessment by doctor must be completed within **24 hours of admission** (or immediately for emergency/ICU admissions).
- Initial Nursing Assessment must be completed within **2 to 4 hours of admission**.
2. **Daily Clinical Progress Notes (SOAP Format)**:
- Every inpatient must have daily dated and timed notes adhering to:
- **S (Subjective)**: Patient complaints, comfort, pain score (1-10).
- **O (Objective)**: Vitals (BP, PR, RR, SpO2, Temp), systemic physical examination, lab/imaging review.
- **A (Assessment)**: Current clinical status and diagnosis evolution.
- **P (Plan)**: Medication changes, investigations ordered, diet, discharge planning.
3. **Discharge Summary Mandatory Criteria**:
- Under NABH, a discharge summary MUST contain:
1. Admission & Discharge Dates & Times.
2. Primary & Secondary Final Diagnoses (with ICD-10 codes).
3. Significant Clinical History & Physical Findings on admission.
4. Results of Significant Diagnostic Tests & Interventions.
5. Summary of Hospital Course & Treatment Provided.
6. Condition of the Patient at Discharge.
7. Discharge Medications (generic name, strength, dosage, route, frequency, duration).
8. Urgent Warning Signs / Red Flags necessitating immediate emergency return.
9. Specific Follow-up Date and Consulting Doctor Name.
4. **Digital Scanning & Retention (`nabh_ipd_scans`)**:
- Physical paper consent forms and bedside charts scanned into the system are stored in `nabh_ipd_scans` with proper categorization (`NABH-IPD-01` to `13`).
- Scanned records must be retained in accordance with the hospital's medico-legal retention period (minimum 3 years for adult IPD, till age of majority + 3 years for pediatric cases).

View File

@ -0,0 +1,66 @@
---
name: abdm-fhir
description: Use when producing or checking FHIR for ABDM: building NRCES compliant document bundle generation into a codebase, or auditing the bundles an existing FHIR store already emits. Covers the resource profiles ABDM requires, the Composition rules, and the validator to check against.
type: skill
domain: fhir
agent_consumers:
- abdm-integration-agent
- abdm-call-debugger
- fhir-compliance-agent
requires:
- abdm-docs-mcp
produces:
- nrces-document-bundle
can_execute: true
can_orchestrate: false
---
# ABDM FHIR
Generated from the ABDM Developer Portal on 2026-09-16, catalogue version 2026.09.16.
This file is a snapshot. Re-download the whole folder from https://docs.abdm.gov.in/skills/abdm-fhir/ when it is older than the work you are doing: this router and every file under references/ that it links to. Fetching this file alone leaves those links pointing at files you do not have.
## What this skill covers
- **Design.** What a generator gets wrong before it reaches a profile table. [references/design.md](references/design.md)
- **Generate.** Build NRCES compliant bundle generation into a codebase. [references/generate.md](references/generate.md)
- **Audit.** Check an existing FHIR store's output against the same profiles. [references/audit.md](references/audit.md)
Open one when the work calls for it. This file is the map, not the material.
## Try asking
- "Add ABDM compliant FHIR bundle generation to this codebase"
- "Audit the FHIR bundles this codebase already emits"
Loaded with no task? Say in three lines what this skill does. Offer the prompts above. Then ask what the person is building, and whether the code for it exists yet.
## Before anything else
- Treat every request and response shape in this skill as unconfirmed until the sandbox has answered you. Check a response before you rely on its shape.
- The design section is different in kind. Its rules come from building a working front desk against the sandbox, and each atom it cites names what was observed and the date it was seen.
- A bundle that validates is not a bundle ABDM accepts. The NRCES profiles are the floor, and the milestone the bundle travels under adds its own rules on top.
## Practices that hold across every call
- Read the body, not only the status. A refusal often names the field in its body while the status says nothing useful.
- When ABDM publishes a value, read it rather than hard coding what it currently says. That covers a parameter, such as the encryption algorithm the certificate endpoints return beside the key, and it covers an enumeration. The registries publish theirs as master data calls: councils, courses, colleges, states and districts on the HPR, and facility types and LGD codes on the HFR. A table typed into your source goes stale silently. Purposes and HI types have no master data call: take them from the enumeration in the specification of the call you are making. Refuse to act on a published value you do not recognise rather than falling back to a default.
- Read every field in a response, not the one you came for. The M1 certificate call returns the encryption algorithm next to the key.
- Prove an assumption against a call that is able to disagree with you. A call that refuses every input with one message cannot tell you which input was right.
- Suspect the transport before the data. When a call refuses a value you believe in, check the encryption, the headers and the clock before you doubt the value.
- Do not carry an encryption path from one module to another. Read the certificate and the algorithm from the registry you are calling.
- Never log a sensitive value before you encrypt it, and never send one to a remote service to be encrypted. Both move the leak rather than removing it.
- Generate a fresh REQUEST-ID for every call and log it before sending. Once a call has failed it is the only handle on it.
- Check the host on any sample before you copy it. A request copied whole can be correct in every respect except where it is pointed, and that failure looks like credentials.
- Do not validate an identifier more strictly than the platform does. A schema that types a field as a UUID is not a promise that every value is one. Refusing a value ABDM would have accepted turns your own client into the thing that broke.
- Read a plural response as plural. A verification returns an accounts array and a consent request can produce more than one artefact. Store the collection and decide from its length.
- A documented callback path is not a documented callback payload. Log the whole body on arrival before you parse it, so a handler written against an assumed shape fails where you can see it.
- Decode a token before you use it. A call that hands you a token has not necessarily handed you the token the next call wants, and the claims are base64 that need no library to read.
- When a journey carries the same parameter through two calls, check what each call's specification asks for rather than carrying the first value forward.
- Do not infer which path an identifier belongs to from where that identifier is most discussed. Send every identifier to the lookup first and let the answer pick the path, so nobody who already holds an account is sent to create a second.
- Do not match an error code with string equality. A code may come back bare, as `ABDM-1001`, or with a trailing `: ` separator, as `ABDM-1001: `. Match on the code itself and tolerate the separator.
- Handle a failure that carries no body. Check for an empty body before you parse, or your client throws on the simplest failure there is.
- Back off on an authentication failure rather than retrying, and never loop a credential check.
- Send TIMESTAMP in UTC, ISO-8601 with milliseconds and a trailing Z, as in `2022-10-06T15:10:00.587Z`.
- Cache a public certificate with a validity window rather than forever. A rotation fails every encrypted call at once, and a cache with no expiry cannot recover on its own.

View File

@ -0,0 +1,91 @@
# fhir-audit
Audit an existing FHIR store's output against ABDM's NRCES profiles,
and fix the generation pipeline where it falls short. The store stays
authoritative: this skill patches what emits from it, it does not
replace it.
## 1. Collect representative output
From the integrator, get one real (or realistic test) document bundle
per record type their store produces, saved as local `.json` files.
Do not synthesize bundles yourself for this step; the point of the
audit is what the store actually emits, not what a correctly built
bundle would look like.
## 2. Tier 1 pass
Run `validate` with `kind: fhir` on each bundle, passing its `record_type`. Collect
every finding across every bundle into one gap report, grouped by
finding (the shape of the defect, for example "`Composition.author`
missing" or "`Composition.meta.profile` does not include ..."), not by
which bundle it came from. The same defect usually repeats across every
bundle the store produces, because it comes from one place in the
pipeline; grouping by bundle would make the same root cause look like
many separate problems.
## 3. Interpret with the knowledge surface
For each finding, use its Ref to read what NRCES actually demands and
why ABDM checks it. Ref names the NRCES profile the rule came from
(for example `OPConsultRecord` or `DocumentBundle`), not an atom id
directly; map it to the record type's mapping atom via `get`:
`shared.fhir.document-bundles` for envelope-level findings (Ref
`DocumentBundle`), or the type's mapping atom
(`shared.fhir.map-opconsultation`, `shared.fhir.map-prescription`,
`shared.fhir.map-diagnosticreport`, `shared.fhir.map-dischargesummary`,
`shared.fhir.map-immunizationrecord`,
`shared.fhir.map-healthdocumentrecord`, or
`shared.fhir.map-wellnessrecord`) for a Composition-element or
section-level finding. Four record types (Prescription,
DiagnosticReport, HealthDocumentRecord, ImmunizationRecord) have no
NRCES section slices: do not expect or ask for section-by-section
findings on these four, only Composition-element and entry-level ones.
Sort each finding into one of two buckets:
- **Generation-time fix.** The store already captures the data; the
pipeline just emits the wrong shape (wrong or missing
`meta.profile`, a malformed reference, a missing `Bundle.identifier`
field). This is fixable in code, in this session.
- **Mapping gap.** The store never captures the data a required
element needs at all (no encounter record to populate
`Composition.encounter`, no coded allergy list to populate an
`AllergyIntolerance` entry). This is not a code fix; it is a
conversation with the integrator about what their store needs to
start capturing, and it belongs in the gap report as an open item,
not a silent workaround.
## 4. Patch, do not replace
For every generation-time fix, amend the integrator's existing
generation pipeline directly, or add a thin adapter that post-processes
the store's output into the compliant shape if the pipeline itself is
not reasonably editable. Either way the store keeps producing its own
output; this skill's job is the layer between that output and what
ABDM requires, not a replacement generator.
## 5. Tier 2 pass
Follow `shared.fhir.hl7-validator-recipe` against the patched output
for each record type: download the pinned `validator_cli.jar`, run it
with `-ig ndhm.in#6.5.0` (the recipe atom is the authoritative source
for the pinned version, defer to it if this ever looks stale), and
iterate the same way as tier 1, fix, re-run, until the report lists no
errors. A warning is not the same as a pass; read each one and decide
deliberately whether it is acceptable.
## 6. Done means
The gap report shows every original finding either resolved (with the
fix that resolved it) or explicitly accepted by the integrator (mapping
gaps they have chosen to defer, named as such, not silently dropped).
Tier 1 and tier 2 are both clean against every collected bundle, and
the exact commands to re-run both checks are recorded in the
integrator's repo (a make target or script) so the checks outlive this
session.
Never invent clinical codes: where the integrator's data lacks a coded
value, surface the gap to the human rather than fabricating a SNOMED
code (tier 1 will not catch a wrong code; tier 2 may not either without
a terminology server).

View File

@ -0,0 +1,115 @@
# fhir-generate
Scaffold FHIR document bundle generation for one or more ABDM record
types, directly into the integrator's own codebase, and drive it to a
clean bill of health against both validation tiers.
## 1. Establish scope
Call `search` with `kind: fhir_profile` to get the full list of ABDM record types
(the seven `hiType` values: OPConsultation, Prescription,
DiagnosticReport, DischargeSummary, ImmunizationRecord,
HealthDocumentRecord, WellnessRecord). Confirm with the integrator
which of these seven their system must produce; do not build all seven
speculatively if only one or two are needed.
Identify the language and the repository (or the path within a
monorepo) where the generation module will live. If the integrator
already has a FHIR-adjacent module (a `fhir/`, `hie-cm/`, or similar
directory), that is where this work belongs.
## 2. Learn the target shape
For each in-scope record type:
- Call `get` with `fhir:<that type>`, and once with `fhir:DocumentBundle`
(the shared envelope profile every record type rides on top of).
- Call `get` with `fhir-example:<that type>`, to see a concrete, valid
bundle.
- Read `shared.fhir.document-bundles` via `get` for the envelope
rules that apply to every record type (`Bundle.type`, `Bundle.meta`,
`Bundle.identifier`, `Bundle.timestamp`).
- Read that type's mapping atom via `get`
(`shared.fhir.map-opconsultation`, `shared.fhir.map-prescription`,
`shared.fhir.map-diagnosticreport`, `shared.fhir.map-dischargesummary`,
`shared.fhir.map-immunizationrecord`,
`shared.fhir.map-healthdocumentrecord`, or
`shared.fhir.map-wellnessrecord`) for the Composition's required
elements and, where NRCES defines them, its section slices.
Four record types (Prescription, DiagnosticReport, HealthDocumentRecord,
ImmunizationRecord) have no NRCES section slices: their Composition
carries one unnamed, required section whose `entry` array is what is
actually constrained. Do not scaffold section-by-section guidance for
these four; scaffold the required entry resource types their mapping
atom names instead. OPConsultation, DischargeSummary and WellnessRecord
do have named section slices; use the mapping atom's section table for
those.
## 3. Scaffold in the integrator's stack
For each in-scope record type, write a builder function that:
- Takes the integrator's own domain data as input (their patient,
encounter, order, or report model, whatever they call it).
- Produces a document bundle matching the digest returned by
`get` with `fhir:<type>`: the correct `meta.profile` URL on the
Composition, every required top-level element the digest lists, and
the section shape the mapping atom describes for that type.
- Resolves every reference internally: any resource a section entry or
the Composition points at must be added to the bundle as its own
entry, not left dangling.
Then write one bundle-level wrapper, shared across all in-scope
builders, that applies the `DocumentBundle` envelope constraints:
`Bundle.type` fixed to `"document"`, `Bundle.meta` and
`Bundle.meta.versionId` set, `Bundle.identifier` (`.system` and
`.value`) set, `Bundle.timestamp` set. The Composition must be the
bundle's first entry.
Follow the repository's existing conventions for module layout, error
handling, and naming. If the integrator's stack already has a FHIR
library (a typed resource model, a bundle builder), build on it rather
than duplicating it. If it has none, plain JSON construction (maps or
structs marshaled to JSON) is fine; do not introduce a new FHIR library
dependency just for this.
## 4. Iterate against tier 1
Run each builder's output bundle through `validate` with `kind: fhir`, passing the
bundle and its `record_type`. For every finding returned:
- Read the finding's Fix text.
- Apply exactly that fix to the builder (not a workaround in the test
data).
- Re-run `validate` with `kind: fhir`.
Repeat until `validate` returns no findings for that record type,
then move to the next in-scope type.
## 5. Finish with tier 2
Tier 1 is structural and fast; it does not check nested cardinalities,
terminology bindings, or section slice discriminators. Follow
`shared.fhir.hl7-validator-recipe` end to end, in the integrator's own
environment: download the pinned `validator_cli.jar`, run it against
each builder's output bundle with `-ig ndhm.in#6.5.0` (the recipe atom
is the authoritative source for the pinned version, defer to it if
this ever looks stale), and resolve every error the report lists. A
warning is not an error; read each one and decide deliberately whether
it is acceptable, rather than treating a warning-only run as clean.
## 6. Done means
For every in-scope record type: tier 1 (`validate`, `kind: fhir`) returns no
findings, and tier 2 (the official HL7 validator) exits 0 with no
errors, against IG 6.5.0. Record the exact commands to re-run both
checks (a make target, an npm script, or a shell script committed to
the integrator's repo) so the checks outlive this session and the next
person who touches this module can re-verify without re-deriving the
commands.
Never invent clinical codes: where the integrator's data lacks a coded
value, surface the gap to the human rather than fabricating a SNOMED
code (tier 1 will not catch a wrong code; tier 2 may not either without
a terminology server).

View File

@ -0,0 +1,79 @@
---
name: abdm-gateway
description: Use when building, debugging or testing the ABDM gateway: the gateway session and bridge registry.
type: skill
domain: gateway
agent_consumers:
- abdm-integration-agent
- abdm-call-debugger
requires:
- sandbox-client-credentials
produces:
- gateway-session-token
- bridge-url
can_execute: true
can_orchestrate: false
---
# ABDM Gateway, sessions and the bridge registry
Generated from the ABDM Developer Portal on 2026-09-16, catalogue version 2026.09.16. Every fact below comes from a page in that portal, which is the place to look when this file does not carry enough.
This file is a snapshot. Re-download the whole folder from https://docs.abdm.gov.in/skills/abdm-gateway/ when it is older than the work you are doing: this router and every file under references/ that it links to. Fetching this file alone leaves those links pointing at files you do not have.
If the abdm-docs MCP server is connected, trust its answers over this file: it serves the current catalogue and stamps every response with its catalogue_version, which you can compare against the version above.
## What you can do with Gateway
- Bridge
- Session
What it cannot do yet matters as much. Read **Before anything else** below before assuming a capability is one endpoint away.
## Try asking
- "Get a gateway access token and register this bridge"
- "What has to be in place before my first Gateway call?"
- "My Gateway call failed. Here is the response: what is wrong, and how do I fix it?"
Loaded with no task? Say in three lines what this skill does. Offer the prompts above. Then ask what the person is building, and whether the code for it exists yet.
## What is in this folder
- **Scaffold.** Survey the codebase first when one exists, then build it flow by flow against the sandbox, as a loop that ends when the step's exit condition holds rather than on a call returning 200. [references/scaffold.md](references/scaffold.md)
- **Integrate.** 4 operations, with their hosts and headers. [references/integrate.md](references/integrate.md)
- **Debug.** The specification's examples return no error code for this module. [references/debug.md](references/debug.md)
This file is the map. Each line above is a file beside it, opened one at a time rather than read through.
## Before anything else
- Treat every request and response shape in this skill as unconfirmed until the sandbox has answered you. Check a response before you rely on its shape.
## Practices that hold across every call
- Read the body, not only the status. A refusal often names the field in its body while the status says nothing useful.
- When ABDM publishes a value, read it rather than hard coding what it currently says. That covers a parameter, such as the encryption algorithm the certificate endpoints return beside the key, and it covers an enumeration. The registries publish theirs as master data calls: councils, courses, colleges, states and districts on the HPR, and facility types and LGD codes on the HFR. A table typed into your source goes stale silently. Purposes and HI types have no master data call: take them from the enumeration in the specification of the call you are making. Refuse to act on a published value you do not recognise rather than falling back to a default.
- Read every field in a response, not the one you came for. The M1 certificate call returns the encryption algorithm next to the key.
- Prove an assumption against a call that is able to disagree with you. A call that refuses every input with one message cannot tell you which input was right.
- Suspect the transport before the data. When a call refuses a value you believe in, check the encryption, the headers and the clock before you doubt the value.
- Do not carry an encryption path from one module to another. Read the certificate and the algorithm from the registry you are calling.
- Never log a sensitive value before you encrypt it, and never send one to a remote service to be encrypted. Both move the leak rather than removing it.
- Generate a fresh REQUEST-ID for every call and log it before sending. Once a call has failed it is the only handle on it.
- Check the host on any sample before you copy it. A request copied whole can be correct in every respect except where it is pointed, and that failure looks like credentials.
- Do not validate an identifier more strictly than the platform does. A schema that types a field as a UUID is not a promise that every value is one. Refusing a value ABDM would have accepted turns your own client into the thing that broke.
- Read a plural response as plural. A verification returns an accounts array and a consent request can produce more than one artefact. Store the collection and decide from its length.
- A documented callback path is not a documented callback payload. Log the whole body on arrival before you parse it, so a handler written against an assumed shape fails where you can see it.
- Decode a token before you use it. A call that hands you a token has not necessarily handed you the token the next call wants, and the claims are base64 that need no library to read.
- When a journey carries the same parameter through two calls, check what each call's specification asks for rather than carrying the first value forward.
- Do not infer which path an identifier belongs to from where that identifier is most discussed. Send every identifier to the lookup first and let the answer pick the path, so nobody who already holds an account is sent to create a second.
- Do not match an error code with string equality. A code may come back bare, as `ABDM-1001`, or with a trailing `: ` separator, as `ABDM-1001: `. Match on the code itself and tolerate the separator.
- Handle a failure that carries no body. Check for an empty body before you parse, or your client throws on the simplest failure there is.
- Back off on an authentication failure rather than retrying, and never loop a credential check.
- Send TIMESTAMP in UTC, ISO-8601 with milliseconds and a trailing Z, as in `2022-10-06T15:10:00.587Z`.
- Cache a public certificate with a validity window rather than forever. A rotation fails every encrypted call at once, and a cache with no expiry cannot recover on its own.
## Where the detail is
- Every endpoint, with its body fields and responses: /docs/hiecm/v3/api/gateway
- Every error code across modules: /docs/hiecm/v3/reference/error-codes
- Terms: /docs/hiecm/v3/getting-started/glossary

View File

@ -0,0 +1,9 @@
# Debug Gateway, sessions and the bridge registry
The codes this module can return, with the message and the operation that returns each.
## Errors
The Gateway, sessions and the bridge registry specification's examples return no error code yet. That is a gap in the specification, not a promise that this module cannot fail.
A code you meet that is not above is one the specifications do not carry yet. Read the code together with the message: a code can appear twice with different meanings.

View File

@ -0,0 +1,37 @@
# Integrate Gateway, sessions and the bridge registry
The calls themselves: where they live, what they need in their headers, and one request written out in full.
## Hosts
- `https://dev.abdm.gov.in` ABDM gateway, sandbox
- `https://apis.abdm.gov.in` ABDM gateway, production
## Endpoints
4 operations, grouped by the journey they belong to.
### Other operations
| Method | Path | What it does |
| --- | --- | --- |
| `GET` | `/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id}` | Fetch the details of a service ID. |
| `GET` | `/api/hiecm/gateway/v3/bridge-services` | Fetch the service ids registered against a bridge. |
| `PATCH` | `/api/hiecm/gateway/v3/bridge/url` | Update the bridge URL. |
| `POST` | `/api/hiecm/gateway/v3/sessions` | Generate access token. |
## Headers
| Header | What it is |
| --- | --- |
| `REQUEST-ID` | Unique UUID for track the end to end request transaction |
| `TIMESTAMP` | Actual time of the request was initiated, ISO 8601 represents date and time by starting with the year, follow… |
| `X-CM-ID` | Suffix of the consent manager to which the request was intended |
## A request, in full
```bash
curl --request GET \
--url https://dev.abdm.gov.in/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id} \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx'
```

View File

@ -0,0 +1,208 @@
# HIE-CM gateway build
Scaffolds an ABDM gateway integration one journey at a time. It covers the gateway session and bridge registry.
## How this skill runs
Every journey below is an OODA loop, not a recipe: observe the actual state (last response, last error), orient against the step matched below, decide the cheapest next action, act, and return to observe. A step is done only when its exit condition is observed against the sandbox, never because it "should have worked."
Loop limit: 8 passes per step. Hitting the limit is an escalation: state what was observed, what was tried, and which operation page to read, then ask one question.
## Before the first journey, when the codebase already exists
Skip this section only for a system that does not exist yet. Otherwise it runs first, and its exit condition is a written plan, not a call.
### In plain words
Most ABDM integrations are not new systems. They are a hospital management
system, a laboratory system or a clinic application that already has patients,
visits, records, a login, an HTTP client and a way of keeping secrets. Every
ABDM journey has to land somewhere inside that, and a journey built before the
codebase has been read lands in the wrong place: a second HTTP client beside the
first, an ABHA column on the wrong table, a callback route the reverse proxy
never forwards.
So the first loop is not a journey. It is a survey of the system as it is, and
its exit condition is a written plan that names, for every ABDM touchpoint, the
file it will live in. The journeys then build against that plan rather than
against the specification's idea of a fresh codebase.
### Before you start
- The repository, checked out, with permission to read all of it. A survey of
half a codebase produces a plan for half a system.
- The answers to the deployment interview. The
code says what the system is. Only the integrator can say what the
deployment is, and the two together decide which journeys are built at all.
- The practices that hold across every call, which
the plan has to leave room for.
### What happens
This is one loop with a limit of eight passes over the codebase. Each pass
reads live state only, which here means the files themselves, never a README's
description of them and never an assumption carried from a similar system.
**Observe.** Inventory the system from its manifests and its tree, not from its
documentation. Record file paths for each of these, or record that none exists:
| Find | Where it usually shows | Why ABDM needs it |
|---|---|---|
| Languages and runtime versions | package manifests, lock files, toolchain files | Every generated call has to be idiomatic here |
| Build, run and test commands | manifests, CI configuration, a Makefile | Each journey's exit condition becomes a test that runs the same way |
| The frontend and backend split, and how they talk | the top level tree, an API client in the frontend, route definitions in the backend | The counter screens go in the frontend; every ABDM call goes through the backend |
| The outbound HTTP client the backend already uses | the dependency list, a shared client module | ABDM calls reuse it, or a second one appears and the two drift |
| How secrets and configuration reach the process | environment loading, a vault client, a config file | The client id, the secret and the access token travel the same way |
| The patient model, and the identifier fields it already carries | the schema, the ORM models, the migrations | The ABHA number and address become columns beside the existing identifiers, not a new table |
| The visit, encounter or record model | the same places | A care context maps to one of these, and the plan has to say which |
| Where inbound HTTP is routed and authenticated, and whether the deployment has a public URL | the router, the middleware, the reverse proxy configuration, the deployment manifests | ABDM calls back, and a callback route that nothing forwards is silence nobody notices |
| Existing cryptography helpers | a security or crypto module, the dependency list | The RSA encryption of identifiers reuses them |
| Where errors are shown to a user, and where they are logged | the frontend's error surface, the logging setup | A refused call has to land on the screen the person is looking at, and never log a token |
**Orient.** Map each ABDM touchpoint onto that inventory. Where the map is
exact, write the file path. Where it is not, write two candidates and say what
would decide between them. The common ambiguities: two places that could hold
the patient identifier, an HTTP client in the frontend and none in the backend,
a monorepo with several services and no obvious owner for callbacks.
Then read the interview answers against the inventory. A government integrator
gets the demographic route; a facility with no public URL gets no callback
driven journey until it has one; a desk with a fingerprint reader gets the
biometric method. The route set is the intersection of what the deployment
allows and what the code can host.
**Decide.** Order the journeys. The token comes first because every other call
needs it: the gateway session token, or for M4 the bearer token the registry calls
carry. Then the journey whose exit condition can be observed with
the least new code, usually a profile read for a patient who already holds an
ABHA. Creation and linking come after, because each depends on state the earlier
ones produce. For each journey, name the files it will touch and the test that
proves its exit condition.
**Act.** Write the plan. It is a file in the repository, at the path the
integrator names or at the root as `abdm-integration-plan.md`, and it is the
only output of this loop. Then return to observe once, reading the plan against
the tree, to confirm every path in it exists or is marked as new.
If the limit is reached with questions still open, escalate: name what was
found, name the two candidates that could not be separated, point at this
atom, and ask one question.
### How you know it worked
The plan exists and answers every row of the inventory table with a file path,
or with the words none, add at, followed by a path. No row is blank and no row
says to be decided.
Every ABDM touchpoint in the plan names one file, or names two candidates and
the observation that would choose between them. Every journey in the plan names
the test that proves its exit condition and the command that runs it.
Open the plan beside the tree. Every path it names resolves, or is marked as
new. That is the observation that ends this loop, and the first journey does
not start until it has been made.
### When it goes wrong
- **The plan puts the HTTP client in the frontend.** The survey found the
frontend's API client and stopped. Every ABDM call carries a secret, so it
goes through the backend, and the plan has to say which backend module.
- **Two patient tables, and the plan picked one.** Orient produced one
hypothesis where it needed two. Name both, and name the query that shows
which one the visit model points at.
- **The plan has a callback route and the deployment has no public URL.** The
inventory row on inbound routing was answered from the router rather than
from the deployment. Mark every callback driven journey as blocked on a URL,
and build the ones that are not.
- **The survey read the README and not the tree.** A README describes the
system somebody meant to build. The plan is for the one that exists.
- **Eight passes and the plan is still incomplete.** Escalate with the rows
that are answered, the rows that are not, this atom, and one question about
the row that blocks the most journeys.
From `shared.concept.survey-an-existing-codebase`.
## Journeys
### Bridge (`gateway-abdm-gateway`)
**Act: the calls in this journey, in order**
#### 1. Fetch the service ids registered against a bridge (`gateway_get_gateway_v3_bridge_services`)
```bash
curl --request GET \
--url https://dev.abdm.gov.in/api/hiecm/gateway/v3/bridge-services \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx'
```
#### 2. Fetch the details of a service ID (`gateway_get_gateway_v3_bridge_service_serviceid_service_id`)
```bash
curl --request GET \
--url https://dev.abdm.gov.in/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id} \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx'
```
#### 3. Update the bridge URL (`gateway_patch_gateway_v3_bridge_url`)
```bash
curl --request PATCH \
--url https://dev.abdm.gov.in/api/hiecm/gateway/v3/bridge/url \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"url": "<YOUR_CALLBACK_URL>"
}'
```
**Exit condition (Observe until this is true)**
A 202 response. The specification gives no body for it, so read what comes back.
### Session (`gateway-abdm-sessions`)
**Act: the calls in this journey, in order**
#### 1. Generate access token (`gateway_post_gateway_v3_sessions`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/gateway/v3/sessions \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"clientId": "SBX_0000",
"clientSecret": "0******-***-***-***-a****",
"grantType": "client_credentials"
}'
```
**Exit condition (Observe until this is true)**
A 202 whose body matches:
```json
{
"accessToken": "<TOKEN>",
"expiresIn": 1200,
"refreshExpiresIn": 1800,
"refreshToken": "<TOKEN>",
"tokenType": "bearer"
}
```
## Where the detail is
- Every operation, with its body fields and responses: /docs/hiecm/v3/api/gateway

View File

@ -0,0 +1,102 @@
---
name: abdm-m1
description: Use when building, debugging or testing ABDM Milestone 1: creating an ABHA number or address, ABHA login, profile management, or the gateway session token. Carries the endpoints, the required headers, the two token rule, the encryption rule and the error codes its specification's examples return. Also carries the scaffolding loop that builds it flow by flow and the loop from a failed call to a named fix, in references/.
type: skill
domain: m1
agent_consumers:
- abdm-integration-agent
- abdm-call-debugger
requires:
- gateway-session-token
produces:
- abha-number
- abha-address
- user-token
- abha-profile
can_execute: true
can_orchestrate: false
---
# ABDM M1, create and verify ABHA
Generated from the ABDM Developer Portal on 2026-09-16, catalogue version 2026.09.16. Every fact below comes from a page in that portal, which is the place to look when this file does not carry enough.
This file is a snapshot. Re-download the whole folder from https://docs.abdm.gov.in/skills/abdm-m1/ when it is older than the work you are doing: this router and every file under references/ that it links to. Fetching this file alone leaves those links pointing at files you do not have.
If the abdm-docs MCP server is connected, trust its answers over this file: it serves the current catalogue and stamps every response with its catalogue_version, which you can compare against the version above.
## What you can do with M1
- Create an ABHA for somebody who has none: by Aadhaar OTP, by demographic authentication, by face or fingerprint, or under a parent for a child.
- Log in somebody who already has one, by Aadhaar, mobile, ABHA number or ABHA address.
- Read their profile, which carries the whole registration form: names, date of birth, gender, mobile, address with its codes, and a photograph.
- Find an ABHA somebody has forgotten, and pick the right account when one mobile holds several.
- Show the ABHA card and QR code, and take a profile a patient shares by QR at your counter.
- Update a profile and change a mobile.
What it cannot do yet matters as much. Read **Before anything else** below before assuming a capability is one endpoint away.
## Try asking
- "Add ABHA creation by Aadhaar OTP to this codebase"
- "What has to be in place before my first M1 call?"
- "My M1 call returned ABDM-1017. What is wrong, and how do I fix it?"
- "Walk me through the M1 test cases before go-live"
Loaded with no task? Say in three lines what this skill does. Offer the prompts above. Then ask what the person is building, and whether the code for it exists yet.
## What is in this folder
- **Scaffold.** Survey the codebase first when one exists, then build it flow by flow against the sandbox, as a loop that ends when the step's exit condition holds rather than on a call returning 200. [references/scaffold.md](references/scaffold.md)
- **Design.** What the journey around the calls has to do, and what a screen is forbidden to claim. [references/design.md](references/design.md)
- **Integrate.** 123 operations, with their hosts and headers. [references/integrate.md](references/integrate.md)
- **Debug.** The loop from a failed call to a named fix, and 17 error codes from the specification's examples. [references/debug.md](references/debug.md)
- **Test.** The functional test cases, one loop each, with the evidence the sandbox can vouch for and the manifest that replaces a screenshot report. [references/test.md](references/test.md)
This file is the map. Each line above is a file beside it, opened one at a time rather than read through.
## Before anything else
- Treat every request and response shape in this skill as unconfirmed until the sandbox has answered you. Check a response before you rely on its shape.
- The design section is different in kind. Its rules come from building a working front desk against the sandbox, and each atom it cites names what was observed and the date it was seen.
- ABDM publishes operations, not a user experience. The journey is the integrator's to design, so offer the shape below as a suggestion and build what they ask for instead when they have a view of their own counter.
- The ABHA step comes before the registration form and fills it. A verified profile carries the whole form, so a journey that registers the patient first and offers ABHA afterwards has already spent the keystrokes it existed to save.
- Two ways the profile reaches the desk. The patient scans a QR and consents in their own app, and ABDM posts the profile to your callback, so nobody types or asks anything. Or the desk runs the identifier journey. The filled form is the destination either way.
- Decide deliberately whether a journey can complete without an ABHA. A record keyed by the facility's own number does not need one, and a journey that cannot finish without one blocks care for anyone who has none.
- An identifier and an auth method are two different questions, and listing them together is what makes M1 look like five choices. Ask which identifier first, then offer auth methods underneath it, and only where there is more than one.
- Every identifier starts on the login path, Aadhaar included. A verified login already returns the accounts, and only ABDM-1114 on a refusal means nobody holds one. Create on any other answer and the patient ends up with two numbers, which nothing merges.
- Get an access token first, from the gateway session endpoint. Every other call needs it in `Authorization: Bearer <token>`.
- Two tokens exist and they are not interchangeable. The gateway access token goes in `Authorization`. The user token from an enrolment or a login goes in `X-token`. Profile endpoints need both.
- Sensitive fields travel encrypted. Aadhaar numbers, mobile numbers, email addresses, OTP values and passwords are encrypted before they go in the body, then base64 encoded.
- The certificate response tells you the padding. `GET /v3/profile/public/certificate` returns `{"publicKey", "encryptionAlgorithm"}`. Read that field and translate it for your language. Do not hard code a padding: a constant is right until it is not, and the failure then looks like a bad value rather than a stale constant.
- One path serves several jobs. The `scope` array in the body picks which one, so read it before assuming an endpoint does one thing.
- The accounts array on a login verification already carries ABHANumber, preferredAbhaAddress, name, gender, dob, profilePhoto and kycVerified, so a registration form can fill the moment the OTP verifies and before any profile call.
## Practices that hold across every call
- Read the body, not only the status. A refusal often names the field in its body while the status says nothing useful.
- When ABDM publishes a value, read it rather than hard coding what it currently says. That covers a parameter, such as the encryption algorithm the certificate endpoints return beside the key, and it covers an enumeration. The registries publish theirs as master data calls: councils, courses, colleges, states and districts on the HPR, and facility types and LGD codes on the HFR. A table typed into your source goes stale silently. Purposes and HI types have no master data call: take them from the enumeration in the specification of the call you are making. Refuse to act on a published value you do not recognise rather than falling back to a default.
- Read every field in a response, not the one you came for. The M1 certificate call returns the encryption algorithm next to the key.
- Prove an assumption against a call that is able to disagree with you. A call that refuses every input with one message cannot tell you which input was right.
- Suspect the transport before the data. When a call refuses a value you believe in, check the encryption, the headers and the clock before you doubt the value.
- Do not carry an encryption path from one module to another. Read the certificate and the algorithm from the registry you are calling.
- Never log a sensitive value before you encrypt it, and never send one to a remote service to be encrypted. Both move the leak rather than removing it.
- Generate a fresh REQUEST-ID for every call and log it before sending. Once a call has failed it is the only handle on it.
- Check the host on any sample before you copy it. A request copied whole can be correct in every respect except where it is pointed, and that failure looks like credentials.
- Do not validate an identifier more strictly than the platform does. A schema that types a field as a UUID is not a promise that every value is one. Refusing a value ABDM would have accepted turns your own client into the thing that broke.
- Read a plural response as plural. A verification returns an accounts array and a consent request can produce more than one artefact. Store the collection and decide from its length.
- A documented callback path is not a documented callback payload. Log the whole body on arrival before you parse it, so a handler written against an assumed shape fails where you can see it.
- Decode a token before you use it. A call that hands you a token has not necessarily handed you the token the next call wants, and the claims are base64 that need no library to read.
- When a journey carries the same parameter through two calls, check what each call's specification asks for rather than carrying the first value forward.
- Do not infer which path an identifier belongs to from where that identifier is most discussed. Send every identifier to the lookup first and let the answer pick the path, so nobody who already holds an account is sent to create a second.
- Do not match an error code with string equality. A code may come back bare, as `ABDM-1001`, or with a trailing `: ` separator, as `ABDM-1001: `. Match on the code itself and tolerate the separator.
- Handle a failure that carries no body. Check for an empty body before you parse, or your client throws on the simplest failure there is.
- Back off on an authentication failure rather than retrying, and never loop a credential check.
- Send TIMESTAMP in UTC, ISO-8601 with milliseconds and a trailing Z, as in `2022-10-06T15:10:00.587Z`.
- Cache a public certificate with a validity window rather than forever. A rotation fails every encrypted call at once, and a cache with no expiry cannot recover on its own.
## Where the detail is
- Every endpoint, with its body fields and responses: /docs/hiecm/v3/api/m1
- The flows as diagrams: /docs/hiecm/v3/milestones/m1
- Every error code across modules: /docs/hiecm/v3/reference/error-codes
- Terms: /docs/hiecm/v3/getting-started/glossary

View File

@ -0,0 +1,139 @@
# HIE-CM m1 debug
Every error below is an OODA loop: observe the error code and last request id, orient against the matched code, decide the fix, act, and observe whether the original step now succeeds. Applying a fix is not the exit condition; the original step succeeding is.
Loop limit: 5 passes per error.
## Errors
### 404
**Specification example:** HTTP 404, `Runtime Error`, on `m1_post_v3_profile_login_verify_find_abha_face`.
**Exit condition: the original call now succeeds.**
### 900900
**Specification example:** HTTP 500, `Unclassified Authentication Failure`, on `m1_post_v3_enrollment_auth_byabdm_mobile_verify_create_ab_091285`.
**Exit condition: the original call now succeeds.**
### 900901
**Specification example:** HTTP 401, `Invalid Credentials`, on `m1_post_v3_enrollment_request_otp_aadhaar_otp`.
**Exit condition: the original call now succeeds.**
### 900902
**Specification example:** HTTP 401, `Missing Credentials`, on `m1_post_v3_profile_benefit_search_xmluid`.
**Exit condition: the original call now succeeds.**
### ABDM-1017
**Specification example:** HTTP 401, `Invalid Transaction Id`, on `m1_get_v3_enrollment_enrol_suggestion_create_abha_aadhaar_otp`.
**Exit condition: the original call now succeeds.**
### ABDM-1021
**Specification example:** HTTP 401, `Lack of required priviledges`, on `m1_post_v3_enrollment_enrol_byaadhaar_child_child_abha`.
**Exit condition: the original call now succeeds.**
### ABDM-1094
**Specification example:** HTTP 401, `X-token expired`, on `m1_post_v3_enrollment_enrol_byaadhaar_child_child_abha`.
**Exit condition: the original call now succeeds.**
### ABDM-1114
**Specification example:** HTTP 404, `User not found`, on `m1_patch_v3_profile_account_child_child_abha`.
**Exit condition: the original call now succeeds.**
### ABDM-1124
**Specification example:** HTTP 422, `The mobile number provided by you is already linked to 6 ABHA Numbers. Please provide a different Mobile Number.`, on `m1_post_v3_enrollment_enrol_byaadhaar_demo_auth_create_ab_81107d`.
**Exit condition: the original call now succeeds.**
### ABDM-1138
**Specification example:** HTTP 400, `The benefit record has already been de-linked`, on `m1_post_v3_profile_benefit_linkanddelink_x_token`.
**Exit condition: the original call now succeeds.**
### ABDM-1140
**Specification example:** HTTP 400, `The benefit record has already been linked`, on `m1_post_v3_profile_benefit_linkanddelink_x_token`.
**Exit condition: the original call now succeeds.**
### ABDM-1157
**Specification example:** HTTP 422, `Child ABHA’s account limit has been exceeded for the requested Abha ID number ‘<ABHA_NUMBER>`, on `m1_post_v3_enrollment_enrol_byaadhaar_child_child_abha`.
**Exit condition: the original call now succeeds.**
### ABDM-1160
**Specification example:** HTTP 422, `Non KYC CHILD ABHA is allowed to update their profile only once`, on `m1_patch_v3_profile_account_child_child_abha`.
**Exit condition: the original call now succeeds.**
### ABDM-1204
**Specification example:** HTTP 422, `UIDAI Error code : 400 : Invalid Aadhaar OTP value.`, on `m1_post_v3_enrollment_enrol_byaadhaar_otp`.
**Exit condition: the original call now succeeds.**
### ABDM-1207
**Specification example:** HTTP 422, `The information you provided does not match the details on record with Aadhaar. Please verify and provide accurate information.`, on `m1_post_v3_enrollment_enrol_byaadhaar_demo_auth_create_ab_81107d`.
**Exit condition: the original call now succeeds.**
### ABDM-1211
**Specification example:** HTTP 400, `User not found.`, on `m1_post_v3_phr_web_login_abha_search_abha_address_login_m_27a20f`.
**Exit condition: the original call now succeeds.**
### ABDM-1224
**Specification example:** HTTP 401, `Login via Biometric is not allowed.`, on `m1_post_v3_profile_login_request_otp_find_abha_face`.
**Exit condition: the original call now succeeds.**
## Where the detail is
- The operation that returns each code: /docs/hiecm/v3/api/m1
## Every code in the specification
### Codes
| Code | HTTP | Message | Returned by |
| --- | --- | --- | --- |
| `404` | 404 | Runtime Error | `m1_post_v3_profile_login_verify_find_abha_face` |
| `900900` | 500 | Unclassified Authentication Failure | `m1_post_v3_enrollment_auth_byabdm_mobile_verify_create_ab_091285` |
| `900901` | 401 | Invalid Credentials | `m1_post_v3_enrollment_request_otp_aadhaar_otp` |
| `900902` | 401 | Missing Credentials | `m1_post_v3_profile_benefit_search_xmluid` |
| `ABDM-1017` | 401 | Invalid Transaction Id | `m1_get_v3_enrollment_enrol_suggestion_create_abha_aadhaar_otp` |
| `ABDM-1021` | 401 | Lack of required priviledges | `m1_post_v3_enrollment_enrol_byaadhaar_child_child_abha` |
| `ABDM-1094` | 401 | X-token expired | `m1_post_v3_enrollment_enrol_byaadhaar_child_child_abha` |
| `ABDM-1114` | 404 | User not found | `m1_patch_v3_profile_account_child_child_abha` |
| `ABDM-1124` | 422 | The mobile number provided by you is already linked to 6 ABHA Numbers. Please provide a different Mobile Numb… | `m1_post_v3_enrollment_enrol_byaadhaar_demo_auth_create_ab_81107d` |
| `ABDM-1138` | 400 | The benefit record has already been de-linked | `m1_post_v3_profile_benefit_linkanddelink_x_token` |
| `ABDM-1140` | 400 | The benefit record has already been linked | `m1_post_v3_profile_benefit_linkanddelink_x_token` |
| `ABDM-1157` | 422 | Child ABHA’s account limit has been exceeded for the requested Abha ID number ‘<ABHA_NUMBER> | `m1_post_v3_enrollment_enrol_byaadhaar_child_child_abha` |
| `ABDM-1160` | 422 | Non KYC CHILD ABHA is allowed to update their profile only once | `m1_patch_v3_profile_account_child_child_abha` |
| `ABDM-1204` | 422 | UIDAI Error code : 400 : Invalid Aadhaar OTP value. | `m1_post_v3_enrollment_enrol_byaadhaar_otp` |
| `ABDM-1207` | 422 | The information you provided does not match the details on record with Aadhaar. Please verify and provide acc… | `m1_post_v3_enrollment_enrol_byaadhaar_demo_auth_create_ab_81107d` |
| `ABDM-1211` | 400 | User not found. | `m1_post_v3_phr_web_login_abha_search_abha_address_login_m_27a20f` |
| `ABDM-1224` | 401 | Login via Biometric is not allowed. | `m1_post_v3_profile_login_request_otp_find_abha_face` |
A code you meet that is not above is one the specifications do not carry yet. Read the code together with the message: a code can appear twice with different meanings.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,178 @@
# Integrate M1, create and verify ABHA
The calls themselves: where they live, what they need in their headers, and one request written out in full.
## Hosts
- `https://abhasbx.abdm.gov.in` ABHA service, sandbox
- `https://dev.abdm.gov.in` ABDM gateway, sandbox
- `https://apis.abdm.gov.in` ABDM gateway, production
## Endpoints
123 operations, grouped by the journey they belong to.
### Other operations
| Method | Path | What it does |
| --- | --- | --- |
| `POST` | `/abha/api/v3.1/profile/login/verify` | Login via Face Auth (QR) - verify |
| `POST` | `/abha/api/v3.1/profile/login/verify` | Login via Biometric (Fingerprint) - v3.1 single step |
| `POST` | `/abha/api/v3.1/profile/login/verify` | Login via Biometric (Iris) - v3.1 single step |
| `POST` | `/abha/api/v3/enrollment/auth/byAbdm` | After ABHA creation - verify email OTP (optional) |
| `POST` | `/abha/api/v3/enrollment/auth/byAbdm` | After ABHA creation - verify email OTP (optional) |
| `POST` | `/abha/api/v3/enrollment/auth/byAbdm` | After ABHA creation - verify email OTP (optional) |
| `POST` | `/abha/api/v3/enrollment/auth/byAbdm` | After ABHA creation - verify email OTP (optional) |
| `POST` | `/abha/api/v3/enrollment/auth/byAbdm` | After ABHA creation - verify mobile OTP (optional) |
| `POST` | `/abha/api/v3/enrollment/auth/byAbdm` | After ABHA creation - verify mobile OTP (optional) |
| `POST` | `/abha/api/v3/enrollment/auth/byAbdm` | After ABHA creation - verify mobile OTP (optional) |
| `POST` | `/abha/api/v3/enrollment/auth/byAbdm` | After ABHA creation - verify mobile OTP (optional) |
| `POST` | `/abha/api/v3/enrollment/enrol/abha-address` | After ABHA creation - create ABHA address |
| `POST` | `/abha/api/v3/enrollment/enrol/abha-address` | After ABHA creation - create ABHA address |
| `POST` | `/abha/api/v3/enrollment/enrol/abha-address` | After ABHA creation - create ABHA address |
| `POST` | `/abha/api/v3/enrollment/enrol/abha-address` | After ABHA creation - create ABHA address |
| `POST` | `/abha/api/v3/enrollment/enrol/auth/init` | Face auth - generate transaction ID (init) |
| `POST` | `/abha/api/v3/enrollment/enrol/auth/init` | Face auth - generate transaction ID (init) |
| `POST` | `/abha/api/v3/enrollment/enrol/byAadhaar` | Create Child ABHA |
| `POST` | `/abha/api/v3/enrollment/enrol/byAadhaar` | Create Child ABHA |
| `POST` | `/abha/api/v3/enrollment/enrol/byAadhaar` | Create ABHA - Demographic authentication (Demo Auth) |
| `POST` | `/abha/api/v3/enrollment/enrol/byAadhaar` | Create ABHA - Demographic authentication (Demo Auth) |
| `POST` | `/abha/api/v3/enrollment/enrol/byAadhaar` | Create ABHA - Aadhaar face authentication |
| `POST` | `/abha/api/v3/enrollment/enrol/byAadhaar` | Create ABHA - Aadhaar fingerprint (bio) |
| `POST` | `/abha/api/v3/enrollment/enrol/byAadhaar` | Create ABHA - Aadhaar IRIS |
| `POST` | `/abha/api/v3/enrollment/enrol/byAadhaar` | Create ABHA - verify Aadhaar OTP |
| `POST` | `/abha/api/v3/enrollment/enrol/capturePID` | Face auth - capture PID / track status |
| `POST` | `/abha/api/v3/enrollment/enrol/capturePID` | Face auth - capture PID / track status |
| `POST` | `/abha/api/v3/enrollment/enrol/capturePID` | Face auth - capture PID / track status |
| `GET` | `/abha/api/v3/enrollment/enrol/suggestion` | After ABHA creation - get ABHA address suggestions |
| `GET` | `/abha/api/v3/enrollment/enrol/suggestion` | After ABHA creation - get ABHA address suggestions |
| `GET` | `/abha/api/v3/enrollment/enrol/suggestion` | After ABHA creation - get ABHA address suggestions |
| `GET` | `/abha/api/v3/enrollment/enrol/suggestion` | After ABHA creation - get ABHA address suggestions |
| `GET` | `/abha/api/v3/enrollment/profile/children` | Get Child ABHA list of the parent |
| `GET` | `/abha/api/v3/enrollment/profile/children` | Get Child ABHA list of the parent |
| `POST` | `/abha/api/v3/enrollment/request/otp` | Send Aadhaar OTP for ABHA enrolment |
| `POST` | `/abha/api/v3/enrollment/request/otp` | After ABHA creation - send OTP to verify email (optional) |
| `POST` | `/abha/api/v3/enrollment/request/otp` | After ABHA creation - send OTP to verify email (optional) |
| `POST` | `/abha/api/v3/enrollment/request/otp` | After ABHA creation - send OTP to verify email (optional) |
| `POST` | `/abha/api/v3/enrollment/request/otp` | After ABHA creation - send OTP to verify email (optional) |
| `POST` | `/abha/api/v3/enrollment/request/otp` | After ABHA creation - send OTP to verify mobile (optional) |
| `POST` | `/abha/api/v3/enrollment/request/otp` | After ABHA creation - send OTP to verify mobile (optional) |
| `POST` | `/abha/api/v3/enrollment/request/otp` | After ABHA creation - send OTP to verify mobile (optional) |
| `POST` | `/abha/api/v3/enrollment/request/otp` | After ABHA creation - send OTP to verify mobile (optional) |
| `POST` | `/abha/api/v3/phr/web/login/abha/request/otp` | ABHA address login via Aadhaar OTP - send OTP |
| `POST` | `/abha/api/v3/phr/web/login/abha/request/otp` | ABHA address login via Fingerprint - send authentication request |
| `POST` | `/abha/api/v3/phr/web/login/abha/request/otp` | ABHA address login via IRIS - send authentication request |
| `POST` | `/abha/api/v3/phr/web/login/abha/request/otp` | ABHA address login via Mobile OTP - send OTP |
| `POST` | `/abha/api/v3/phr/web/login/abha/search` | Search ABHA address (auth methods) |
| `POST` | `/abha/api/v3/phr/web/login/abha/search` | Search ABHA address (auth methods) |
| `POST` | `/abha/api/v3/phr/web/login/abha/verify` | ABHA address login via Aadhaar OTP - verify |
| `POST` | `/abha/api/v3/phr/web/login/abha/verify` | ABHA address login via Fingerprint - verify |
| `POST` | `/abha/api/v3/phr/web/login/abha/verify` | ABHA address login via IRIS - verify |
| `POST` | `/abha/api/v3/phr/web/login/abha/verify` | ABHA address login via Mobile OTP - verify |
| `GET` | `/abha/api/v3/phr/web/login/profile/abha-profile` | Get ABHA-address profile |
| `GET` | `/abha/api/v3/phr/web/login/profile/abha-profile` | Get ABHA-address profile |
| `GET` | `/abha/api/v3/phr/web/login/profile/abha-profile` | Get ABHA-address profile |
| `GET` | `/abha/api/v3/phr/web/login/profile/abha-profile` | Get ABHA-address profile |
| `GET` | `/abha/api/v3/phr/web/login/profile/abha/phr-card` | Get PHR card |
| `GET` | `/abha/api/v3/phr/web/login/profile/abha/phr-card` | Get PHR card |
| `GET` | `/abha/api/v3/phr/web/login/profile/abha/phr-card` | Get PHR card |
| `GET` | `/abha/api/v3/phr/web/login/profile/abha/phr-card` | Get PHR card |
| `GET` | `/abha/api/v3/phr/web/login/profile/abha/qr-code` | Get ABHA-address QR code |
| `GET` | `/abha/api/v3/phr/web/login/profile/abha/qr-code` | Get ABHA-address QR code |
| `GET` | `/abha/api/v3/phr/web/login/profile/abha/qr-code` | Get ABHA-address QR code |
| `GET` | `/abha/api/v3/phr/web/login/profile/abha/qr-code` | Get ABHA-address QR code |
| `GET` | `/abha/api/v3/profile/account` | Get ABHA profile |
| `PATCH` | `/abha/api/v3/profile/account` | Update Child ABHA profile |
| `PATCH` | `/abha/api/v3/profile/account` | Update Child ABHA profile |
| `GET` | `/abha/api/v3/profile/account/abha-card` | Retrieve ABHA card image |
| `POST` | `/abha/api/v3/profile/account/abha/search` | Search ABHA by mobile |
| `POST` | `/abha/api/v3/profile/account/abha/search` | Search ABHA by mobile |
| `POST` | `/abha/api/v3/profile/account/abha/search` | Search ABHA by mobile |
| `POST` | `/abha/api/v3/profile/account/abha/search` | Search ABHA by mobile |
| `POST` | `/abha/api/v3/profile/account/abha/search` | Search ABHA by mobile |
| `GET` | `/abha/api/v3/profile/account/download-abha-card` | Download ABHA card |
| `GET` | `/abha/api/v3/profile/account/qrCode` | Get ABHA QR code |
| `POST` | `/abha/api/v3/profile/account/request/otp` | Child ABHA KYC - send Aadhaar OTP |
| `POST` | `/abha/api/v3/profile/account/request/otp` | Child ABHA KYC - send Aadhaar OTP |
| `POST` | `/abha/api/v3/profile/account/request/otp` | Re-KYC - send Aadhaar OTP |
| `POST` | `/abha/api/v3/profile/account/request/otp` | Update mobile - send OTP |
| `GET` | `/abha/api/v3/profile/account/request/token` | Refresh user token |
| `POST` | `/abha/api/v3/profile/account/verify` | Child ABHA KYC - verify Aadhaar OTP |
| `POST` | `/abha/api/v3/profile/account/verify` | Child ABHA KYC - verify Aadhaar OTP |
| `POST` | `/abha/api/v3/profile/account/verify` | Re-KYC - verify Aadhaar OTP |
| `POST` | `/abha/api/v3/profile/account/verify` | Update mobile - verify OTP |
| `GET` | `/abha/api/v3/profile/benefit/abha/{abhanumber}` | Get benefits linked to an ABHA number |
| `POST` | `/abha/api/v3/profile/benefit/linkAndDelink` | Link / De-link benefit using ABHA number |
| `POST` | `/abha/api/v3/profile/benefit/linkAndDelink` | Link / De-link benefit using X-token |
| `POST` | `/abha/api/v3/profile/benefit/linkAndDelink` | Link / De-link benefit using xmlUid |
| `POST` | `/abha/api/v3/profile/benefit/search` | Benefit search by ABHA number |
| `POST` | `/abha/api/v3/profile/benefit/search` | Benefit search by xmlUid |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Login via Aadhaar number - send Aadhaar OTP |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Login via ABHA number - send Aadhaar OTP |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Login via ABHA number - send ABHA (mobile) OTP |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Login via Biometric (Fingerprint) - send authentication request |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Login via Biometric (Iris) - send authentication request |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Find ABHA via Aadhaar OTP - send OTP |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Find ABHA via Face - send authentication request |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Find ABHA via Fingerprint - send authentication request |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Find ABHA via IRIS - send authentication request |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Find ABHA via Mobile - send OTP |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Forgot ABHA via Aadhaar - send OTP |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Forgot ABHA via Mobile - send OTP |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Login via Mobile number - send OTP |
| `POST` | `/abha/api/v3/profile/login/verify` | Login via Aadhaar number - verify Aadhaar OTP |
| `POST` | `/abha/api/v3/profile/login/verify` | Login via ABHA number - verify Aadhaar OTP |
| `POST` | `/abha/api/v3/profile/login/verify` | Login via ABHA number - verify ABHA (mobile) OTP |
| `POST` | `/abha/api/v3/profile/login/verify` | Login via Biometric (Fingerprint) - verify |
| `POST` | `/abha/api/v3/profile/login/verify` | Login via Biometric (Iris) - verify |
| `POST` | `/abha/api/v3/profile/login/verify` | Find ABHA via Aadhaar OTP - verify OTP |
| `POST` | `/abha/api/v3/profile/login/verify` | Find ABHA via Face - verify |
| `POST` | `/abha/api/v3/profile/login/verify` | Find ABHA via Fingerprint - verify |
| `POST` | `/abha/api/v3/profile/login/verify` | Find ABHA via IRIS - verify |
| `POST` | `/abha/api/v3/profile/login/verify` | Find ABHA via Mobile - verify OTP |
| `POST` | `/abha/api/v3/profile/login/verify` | Forgot ABHA via Aadhaar - verify OTP |
| `POST` | `/abha/api/v3/profile/login/verify` | Forgot ABHA via Mobile - verify OTP |
| `POST` | `/abha/api/v3/profile/login/verify` | Login via Mobile number - verify OTP |
| `POST` | `/abha/api/v3/profile/login/verify/user` | Login via Mobile number - verify user (select ABHA) |
| `GET` | `/abha/api/v3/profile/public/certificate` | Get public certificate (RSA encryption key) |
| `GET` | `/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id}` | Fetch the details of a service ID. |
| `GET` | `/api/hiecm/gateway/v3/bridge-services` | Fetch the service ids registered against a bridge. |
| `PATCH` | `/api/hiecm/gateway/v3/bridge/url` | Update the bridge URL. |
| `POST` | `/api/hiecm/gateway/v3/sessions` | Generate access token. |
## Headers
| Header | What it is |
| --- | --- |
| `REQUEST-ID` | Unique UUID for every request. |
| `TIMESTAMP` | Current UTC timestamp in ISO-8601 format. |
| `BENEFIT_NAME` | **Applicable for user who is enrolling via Benefit Program.** |
| `X-token` | **Applicable for child abha creation. X-token of Parent user, user can get X-token after login to the system** |
| `TRANSACTION_ID` | Transaction ID from the ABHA creation response. |
| `Content-Type` | `application/json`. |
| `R-token` | Refresh token (`Bearer <refreshToken>`) received at login. |
| `T-token` | Short-lived token (`Bearer <token>`) returned by *Login via Mobile number - verify OTP*. |
| `X-CM-ID` | Suffix of the consent manager to which the request was intended |
## A request, in full
```bash
curl --request POST \
--url https://abhasbx.abdm.gov.in/abha/api/v3.1/profile/login/verify \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'Content-Type: application/json' \
--data '{
"scope": [
"abha-login",
"aadhaar-face-login-verify"
],
"authData": {
"authMethods": [
"face_auth"
],
"face_login": {
"txnId": "8220299c-40ad-40b6-bc52-13a7d46a69d0",
"aadhaar": "{{encrypted aadhaar number}}"
}
}
}'
```

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,401 @@
# HIE-CM m1 test
Walks the ABDM M1 functional test cases, ABHA creation and verification, against the system you built and the sandbox. Each case ends in one of four recorded outcomes, never in an opinion.
## What this skill does
- Runs every M1 test case in the ABHA creation and verification set against your system and the sandbox, one case at a time
- Records, for each case, the sandbox response and REQUEST-ID that prove it, or the screen that has to be attested, or the human step it stopped at
- Writes a manifest of case ids to request ids at the end, which is the evidence a reviewer checks against the gateway rather than a folder of screenshots
## What it needs from you
| Need | Where it comes from |
|---|---|
| Sandbox client id and secret | The ABDM sandbox portal, under your registered application |
| Your system running against the sandbox hosts | Your deployment or a local build. The skill drives your system, not the sandbox directly |
| A way to trigger each journey in your system | A screen, an API or a script. Say which at the start |
| A person with an Aadhaar linked mobile, for OTP cases | Present at the desk for the run. Every OTP is a human step and the skill stops for it |
| A fingerprint or face device, for the biometric cases | Only if you claim those cases. Without one they are recorded as not run |
| Whether you are a government or a private integrator | The set marks some cases mandatory for one and optional for the other |
## Say one of these
- "Walk the M1 test cases against my sandbox and log each one."
- "Run only the ABHA verification cases, VRFY_ABHA_101 to 405."
- "Re-run CRT_ABHA_112, the address suggestion case failed yesterday."
- "Write a terminal script that runs the M1 test cases and asks me for the Aadhaar number and each OTP."
## What happens first
One question: which cases. All of them, one function group, or a list of ids. Then the preconditions for the first case are checked before anything is sent. Nothing else is asked until a case needs a human.
## How this skill runs
Every case is an observe, orient, decide, act loop. Observe the live state: the last response, the last REQUEST-ID, what your screen shows. Orient against the case below. Decide the cheapest action that produces a new observation. Act, paste the raw result, return to observe. A case is done only when its exit condition is observed, never because the step should have worked.
Loop limit: 3 passes per test case. Hitting the limit is an escalation: state what was observed with request ids, what was tried, name one section of this skill or one operation page to read, and ask one question.
### The four outcomes
| Outcome | Record it when | Never when |
|---|---|---|
| `passed` | The exit condition is observed and the observation is pasted verbatim | The response was not pasted. A pass with no output is a fail |
| `failed` | Three passes and the exit condition was not observed, or the sandbox returned the refusal the case expects you to handle and your system did not handle it | A human step was missing. That is `needs-human` |
| `needs-human` | The case reached an OTP, a biometric scan, an operator's document check, or a person who was not there | Ever as a substitute for a fail you can see |
| `not-run` | The case does not apply to your entity, you do not claim the optional capability, or ABDM publishes no operation for it | To skip a mandatory case that applies to you |
### The three kinds of evidence
Every case names one of these. It decides what the manifest carries.
- **sandbox.** A call the gateway sees. Evidence is the HTTP status, the body and the REQUEST-ID, pasted. The exit condition is a literal in the body. A reviewer can check this against the gateway's own record, which is why it outranks the other two.
- **screen.** A rule about what your system shows or stores, which no call proves. Evidence is one screenshot or a short recording and the design rule it satisfies. A screen case is attested, not observed, and the manifest marks it so.
- **human.** A step only a person can do. Evidence is the observation just before it and the outcome `needs-human` when nobody was there.
### Rules that hold for every case
- Search before create. Every identifier goes to the login path first, and only ABDM-1114 on the verify says nobody holds an account. Creating on any other answer gives the patient two numbers, which nothing merges. `hiecm.concept.m1-avoiding-duplicate-abha`
- Never ask twice. A value the transaction already holds, the Aadhaar number, the mobile, the txnId, is carried, not re-entered. `hiecm.concept.m1-never-ask-twice`
- Two tokens. The gateway access token goes in `Authorization`. The user token an enrolment or a login returns goes in `X-token`. Profile calls need both.
- Fresh `REQUEST-ID` on every call, logged before sending. A reused id is refused, and after a failure the id is the only handle on the call.
- Paste the response. A step with no pasted output is not done.
- Sensitive values travel encrypted: Aadhaar, mobile, email, OTP. Read the algorithm from the certificate call rather than hard coding a padding.
- One question when you escalate. The person is being interrupted.
### The run record
Append one block per loop pass. It is the raw material for the manifest.
```text
case: CRT_ABHA_101 pass: 1 of 3 at: 2026-09-29T10:14:02Z
observed: POST /abha/api/v3/enrollment/enrol/byAadhaar REQUEST-ID 6f1c... HTTP 200
body: {"message":"Account created successfully","txnId":"...","tokens":{"token":"<X-token>",...},"ABHAProfile":{"ABHANumber":"91-...",...}}
matched: exit condition for CRT_ABHA_101, step 2
next: CRT_ABHA_113
```
### When the run is a script
Asked for a test script, a test command or automated tests, build one interactive terminal runner that walks the cases below. It does the typing. Every rule above still holds.
| Rule | Why |
|---|---|
| Name every check by its case id from this skill, such as `CRT_ABHA_101`. Never invent a numbering such as `TC01` | The functional testing report quotes these ids. A check with no case id answers nothing a reviewer asks |
| At each `human` step, stop and prompt in the terminal for the value: Aadhaar number, mobile, OTP, the chosen address. Read it from stdin, encrypt it, send it | Every M1 success path passes through an OTP. A runner that never asks never reaches one |
| Never write a typed value to disk, a log or the manifest, and never hard code one | An Aadhaar number and an OTP belong to the person, not the run |
| Run each `sandbox` case's success path and the refusal its exit condition names, as separate checks | The case passes only when both are observed |
| Compare the status and the body literal the exit condition names, such as `200` with `tokens.token` present, or `422` with `error.code` `ABDM-1204` | A status alone never passes a check |
| A `4xx` passes only where the case's exit condition names that refusal | A `400` on a success path step is `failed` |
| A blank answer at a prompt records the case `needs-human` and moves to the next case | Nobody present is neither a pass nor a fail |
| A `screen` case prints its check, then asks `passed? y/n` and the evidence file name | No call proves a screen, so the case is attested |
| At the end, print one line per case id with its outcome and request ids, then write the manifest in the last section | The person reads outcomes by case id, not by script step |
A run reads like this. The person's values are typed at the prompts and never echoed back.
```text
CRT_ABHA_105 POST /v3/enrollment/request/otp REQUEST-ID 3b9e... HTTP 200 txnId present matched
Enter the OTP sent to the mobile ending 1234, or leave blank if nobody is here:
CRT_ABHA_107 wrong OTP REQUEST-ID 7c02... HTTP 422 error.code ABDM-1204 matched
CRT_ABHA_107 right OTP REQUEST-ID 9a41... HTTP 200 tokens.token present matched
CRT_ABHA_107 passed
```
Nudge: calls with a bad `scope`, a bad `loginHint` or a made up `txnId` test your client, not a case. Run them first if you want them, label them `preflight`, and keep them out of the case counts.
## Test cases
The ids, the mandatory marks and the wording of each check are ABDM's, from the M1 ABHA creation and verification set. The sections are grouped as the set groups them. Where the set names an operation, the operation id here is the one in `references/integrate.md`, which carries the host, the headers and a full request.
### CRT_ABHA_101 to 115: create an ABHA by Aadhaar OTP
Applies to every integrator. Mandatory unless marked. This is the group every other creation group repeats with a different authentication step, so it is written in full and the others state only what differs.
Loop limit: 3 passes per test case.
**Preconditions.** A gateway access token less than 30 minutes old. A person present with an Aadhaar linked mobile. Their Aadhaar number searched first on the login path and not found, so the run creates rather than duplicates.
#### CRT_ABHA_101, the option exists. `sandbox`
Your system offers ABHA creation by Aadhaar OTP, and the journey completes. Drive it end to end through your screen or API.
Calls, in order: `m1_post_v3_enrollment_request_otp_aadhaar_otp`, `m1_post_v3_enrollment_enrol_byaadhaar_otp`, the optional mobile and email verifications, `m1_get_v3_enrollment_enrol_suggestion_create_abha_aadhaar_otp`, `m1_post_v3_enrollment_enrol_abha_address_create_abha_aadhaar_otp`, then `m1_get_v3_profile_account` and `m1_get_v3_profile_account_abha_card`.
Exit condition: three literals, all pasted.
1. `m1_post_v3_enrollment_enrol_byaadhaar_otp` returns 200 with `tokens.token` present and `ABHAProfile.ABHANumber` present.
2. `m1_post_v3_enrollment_enrol_abha_address_create_abha_aadhaar_otp` returns 200 with `healthIdNumber` and `preferredAbhaAddress`.
3. `m1_get_v3_profile_account`, sent with that `X-token`, returns 200 with the same `ABHANumber`.
Nudge: read `message` on step 1. `Account created successfully` is a new account. `This account already exist` is a 200 too, and it means the search-first rule was skipped or the sandbox person already holds one. Record which, because the second is a screen failure on CRT_ABHA_101 even though the API passed.
#### CRT_ABHA_102, consent is shown and recorded. `screen`
Your system shows the published ABDM consent text before the Aadhaar number is asked for, and stores that the person agreed, with when. Evidence: the consent screen, and the stored record for this run. `hiecm.concept.m1-screen-contract`
#### CRT_ABHA_103, consent in another language. `screen`, optional
The same consent offered in at least one language other than English. Evidence: the screen in that language. Record `not-run` if you do not claim it.
#### CRT_ABHA_104, an invalid Aadhaar number is refused before any call. `screen`
Enter an 11 digit and a 13 digit value. Your system refuses each with a message that says the number is not valid, and sends nothing. Evidence: the refusal on screen and an empty call log for that attempt. Your own check has to be the strict one here; the sandbox's refusal for a bad number is not the one this case is about. `hiecm.concept.m1-honest-screen-states`
#### CRT_ABHA_105, the Aadhaar OTP is requested and can be entered. `sandbox`, then `human`
Exit condition: `m1_post_v3_enrollment_request_otp_aadhaar_otp` returns 200 with a `txnId` and a `message` that names the masked mobile. Paste it. Then stop: the OTP arrives on the person's phone and only they enter it. If they are not there, record `needs-human` and the txnId, and do not mark the case passed or failed.
Screen check alongside: the prompt tells the person the OTP went to the mobile linked with Aadhaar and shows the last digits, which the `message` carries.
#### CRT_ABHA_106, resend OTP. `screen`
The resend control is disabled for 60 seconds after each send and works at most twice. Evidence: a recording or three timestamped screenshots: disabled at send, enabled after 60 seconds, disabled after the second resend. A resend that works reuses the `txnId`; a fresh `txnId` is a new request, not a resend.
#### CRT_ABHA_107, the OTP is verified, and a wrong OTP is refused. `sandbox`, `human`
Two observations, both needed.
1. A wrong OTP: `m1_post_v3_enrollment_enrol_byaadhaar_otp` returns 422 with `error.code` `ABDM-1204` and a message naming an invalid Aadhaar OTP value, and your screen says the OTP was wrong and lets the person retry without re-entering the Aadhaar number.
2. The right OTP: the 200 from CRT_ABHA_101 step 1.
The person enters both OTPs. Stop for each.
#### CRT_ABHA_108, the communication mobile is the Aadhaar mobile. `sandbox`, optional
If your system checks whether the mobile the person gave is the Aadhaar linked one and skips the second OTP when it is, drive that path. Exit condition: the journey reaches the ABHA address step with no `mobile-verify` call in the log. Record `not-run` if you always verify, which CRT_ABHA_109 then covers.
#### CRT_ABHA_109, a different communication mobile is verified. `sandbox`, `human`
Give a mobile that is not the Aadhaar linked one. Exit condition: `m1_post_v3_enrollment_request_otp_mobile_verify_create_ab_1b66bb` returns 200 with a `txnId`, the person enters the OTP, and `m1_post_v3_enrollment_auth_byabdm_mobile_verify_create_ab_091285` returns 200. A wrong OTP here is refused on screen and the person can retry.
#### CRT_ABHA_112, the ABHA address is suggested and validated. `sandbox` and `screen`
Mandatory for private and government integrators. Optional for a programme that creates a default address by demographic authentication.
Exit condition: `m1_get_v3_enrollment_enrol_suggestion_create_abha_aadhaar_otp` returns 200 with `abhaAddressList` holding at least three entries, and `m1_post_v3_enrollment_enrol_abha_address_create_abha_aadhaar_otp` returns 200 with `preferredAbhaAddress` equal to the one chosen.
Screen check: at least three suggestions are shown, or a free field with these rules printed beside it, and an address already taken is refused with a message that says so and offers the suggestions.
```text
length 8 to 18
letters, digits, or both
at most one dot and at most one underscore, neither first nor last
```
#### CRT_ABHA_113, the ABHA number is displayed. `screen`
The 14 digit ABHA number and the ABHA address from CRT_ABHA_112 are shown together after creation. Evidence: the screen, with the number matching `healthIdNumber` from the pasted response.
#### CRT_ABHA_114, the ABHA card can be viewed and downloaded. `sandbox` and `screen`
Mandatory for private integrators that generate the card. Exit condition: `m1_get_v3_profile_account_abha_card` returns 200 with content type `image/png`, sent with the `X-token` from creation. Screen check: the card shown carries the ABHA number, the QR code, date of birth, gender and the ABHA address. The photo is optional.
#### CRT_ABHA_115, your own card carries the ABHA details. `screen`
For an integrator that prints its own programme card instead. Mandatory for government where CRT_ABHA_114 is not done. The card shows the ABHA number and address, and your system stores both against your own patient id. Evidence: the card and the stored record.
### CRT_ABHA_201 to 210: create an ABHA by Aadhaar biometric
Applies to every integrator. Optional, except that CRT_ABHA_209 is mandatory for a private integrator that generates the card and one of 209 or 210 is mandatory for government.
Loop limit: 3 passes per test case.
Same cases as 101 to 115 with these differences. Run each as its counterpart above and record the counterpart's evidence.
| Case | Counterpart | What differs |
|---|---|---|
| CRT_ABHA_201 | 101 | The creation call is `m1_post_v3_enrollment_enrol_byaadhaar_fingerprint` or `m1_post_v3_enrollment_enrol_byaadhaar_face`. Exit condition is the same 200 with `tokens.token` and `ABHAProfile.ABHANumber` |
| CRT_ABHA_205 | 105 and 107 | `human`: the person scans. A failed scan is refused on screen and can be retried. Face runs `m1_post_v3_enrollment_enrol_auth_init_create_abha_face_au_4dea33` then the capture call first |
| CRT_ABHA_206, 207 | 108, 109 | Unchanged |
| CRT_ABHA_208 | 113 | Unchanged |
| CRT_ABHA_209, 210 | 114, 115 | Unchanged |
| CRT_ABHA_202, 203, 204 | 102, 103, 104 | Unchanged |
Without a registered device the whole group is `not-run`, with that reason.
### CRT_ABHA_301 to 309: create an ABHA by demographic authentication
Government entities only. Mandatory for them. A private integrator records the group `not-run`.
Loop limit: 3 passes per test case.
#### CRT_ABHA_301 and 305, the demographic call creates the account. `sandbox`
One call, `m1_post_v3_enrollment_enrol_byaadhaar_demo_auth_create_ab_81107d`, with the name, date of birth, gender, Aadhaar number, mobile, address, state and district as they read on the Aadhaar card. Exit condition: 200 with `healthIdNumber`, `healthId` and `kycVerified` `true`.
Then the mismatch: send the same call with the date of birth changed. Exit condition: a 422 whose message says the information does not match the details on record with Aadhaar, and your screen says so without creating anything. Both observations, both pasted.
Nudge: the same mobile on a seventh account is refused with ABDM-1124. That is a mobile limit, not a demographic mismatch. Read `error.message`.
#### CRT_ABHA_305 address, the three cases. `sandbox` and `screen`
The address on the card and the profile is the same one in all three cases: the existing address when the person had one, the address they chose when they chose one, and the default `<ABHA number>@sbx` when neither. Evidence: `healthId` in the creation response and the address on `m1_get_v3_profile_account`, equal, for whichever case the run hit. Record which.
#### CRT_ABHA_306, the profile is filled from the response, not typed. `screen`
Name, date of birth and gender are shown filled and not editable. Address, mobile and email are editable. Evidence: the form after creation. `hiecm.concept.m1-confirm-the-filled-form`
#### CRT_ABHA_302, 303, 304, 307, 308, 309
As 102, 103, 104, 113, 114 and 115.
### CRT_ABHA_401 to 411: create an ABHA by driving licence or PAN
ABDM's M1 specification publishes no enrolment by document operation. Record every case in this group `not-run` with that reason, whatever your entity type, until an operation is published. Do not improvise a call.
### VRFY_ABHA_101 and 102: verify an ABHA number or address by Aadhaar OTP
Applies to every integrator. Mandatory.
Loop limit: 3 passes per test case.
**Preconditions.** A person present with an ABHA and the Aadhaar linked mobile.
#### VRFY_ABHA_101, by ABHA number. `sandbox`, `human`
Calls: `m1_post_v3_profile_login_request_otp_abha_number_aadhaar_otp`, the OTP, `m1_post_v3_profile_login_verify_abha_number_aadhaar_otp`, then `m1_get_v3_profile_account` with the returned token as `X-token`.
Exit condition: the verify returns 200 with `authResult` `success` and `accounts[0].ABHANumber`, and the profile call returns 200 with the same `ABHANumber`. A wrong OTP returns 400 with `otpValue` naming an invalid OTP value, and your screen says the verification failed.
Screen checks alongside: resend as in CRT_ABHA_106; name, date of birth and gender shown not editable; the profile stored against your own patient id after verification.
Nudge: the accounts array already carries the whole registration form. Fill the form from it before the profile call, so the person reads back rather than types.
#### VRFY_ABHA_102, by ABHA address. `sandbox`, `human`
Calls: `m1_post_v3_phr_web_login_abha_search_abha_address_login_a_de8184`, `m1_post_v3_phr_web_login_abha_request_otp_aadhaar_otp`, the OTP, `m1_post_v3_phr_web_login_abha_verify_aadhaar_otp`, then `m1_get_v3_phr_web_login_profile_abha_profile_abha_address_c04e83`.
Exit condition: the verify returns 200 with a token, and the profile call returns 200 carrying the ABHA number and the address searched for. Paste both.
### VRFY_ABHA_201 and 202: verify by the ABHA linked mobile OTP
Mandatory. As VRFY_ABHA_101 and 102 with the mobile OTP operations: `m1_post_v3_profile_login_request_otp_abha_number_abha_otp` and `m1_post_v3_profile_login_verify_abha_number_abha_otp` for the number, `m1_post_v3_phr_web_login_abha_request_otp_mobile_otp` and `m1_post_v3_phr_web_login_abha_verify_mobile_otp` for the address. Same exit conditions, same screen checks.
Loop limit: 3 passes per test case.
### VRFY_ABHA_301 to 305: fetch ABHA details by the communication mobile
Mandatory. This is the lookup that costs no Aadhaar OTP, so it is the one your desk should run first.
Loop limit: 3 passes per test case.
#### VRFY_ABHA_301, an invalid mobile is refused. `screen`
A nine digit and an eleven digit value are refused on screen with a message asking for a valid mobile, and nothing is sent.
#### VRFY_ABHA_302, no ABHA on this mobile. `sandbox`, `human`
Calls: `m1_post_v3_profile_login_request_otp_mobile`, the OTP, `m1_post_v3_profile_login_verify_mobile_otp`.
Exit condition: the verify returns 404 with `error.code` `ABDM-1114`. Your screen says no ABHA number is linked to this mobile, and offers to create one. The create offer is the point of the case; a dead end fails it. `hiecm.concept.m1-journey-completes-without-abha`
#### VRFY_ABHA_303, one or more ABHAs on this mobile. `sandbox`, `human`
Same two calls with a mobile that holds accounts, then `m1_post_v3_profile_login_verify_user` with the chosen `ABHANumber` and the first verify's token as `T-token`, then `m1_get_v3_profile_account`.
Exit condition: the first verify returns 200 with `accounts` holding at least one entry with `ABHANumber`, `preferredAbhaAddress`, `name` and `profilePhoto`; the user verify returns 200 with `token`; the profile call returns 200 with the chosen `ABHANumber`.
Screen checks: every account in the array is listed with name, number, address and photo; choosing one already linked to a patient in your system says so and names your patient id; choosing one not yet linked registers and links it. `hiecm.concept.m1-two-routes-to-the-profile`
Nudge: read the array as plural. One mobile can hold up to six accounts, and a screen that shows the first one silently links the wrong person.
#### VRFY_ABHA_304, a wrong OTP. `sandbox`, `human`
Exit condition: `m1_post_v3_profile_login_verify_mobile_otp` returns 400 with `otpValue` naming an invalid OTP value, and your screen says so and allows a retry without re-entering the mobile.
#### VRFY_ABHA_305, resend. `screen`
As CRT_ABHA_106.
### VRFY_ABHA_401 to 405: fetch ABHA details by Aadhaar number
Mandatory.
Loop limit: 3 passes per test case.
#### VRFY_ABHA_401, an invalid Aadhaar is refused. `screen`
As CRT_ABHA_104, on the verification screen.
#### VRFY_ABHA_403, no ABHA on this Aadhaar. `sandbox`, `human`
Calls: `m1_post_v3_profile_login_request_otp_aadhaar`, the OTP, `m1_post_v3_profile_login_verify_aadhaar_otp`.
Exit condition: the request returns 200 with a `message` naming the masked Aadhaar mobile, the person enters the OTP, and the verify returns 404 with `error.code` `ABDM-1114` and a message that no ABHA user is registered with this Aadhaar number. Your screen says so and offers creation, and the creation path does not ask for the Aadhaar number again. `hiecm.concept.m1-never-ask-twice`
#### VRFY_ABHA_404, an ABHA exists on this Aadhaar. `sandbox`, `human`
Same calls with an Aadhaar that holds an account, then `m1_get_v3_profile_account`.
Exit condition: the verify returns 200 with `authResult` `success` and `accounts[0].ABHANumber`; the profile call returns 200 with the same number. Screen checks: the profile is shown, the card can be downloaded as in CRT_ABHA_114, and the account is registered and linked to your patient id if it was not already.
#### VRFY_ABHA_402 and 405
A wrong OTP and resend, as VRFY_ABHA_304 and 305.
### VRFY_ABHA_501 and 502: verify by fingerprint, government entities
Optional. `human`. Calls: `m1_post_v3_1_profile_login_verify_fingerprint` for a number. The set names no operation for an address by fingerprint; record VRFY_ABHA_502 `not-run` with that reason. Exit condition for 501: 200 with `accounts[0].ABHANumber`, then the profile call as VRFY_ABHA_101. Without a device, `not-run`.
Loop limit: 3 passes per test case.
### Reading the ABHA QR code, optional
The set numbers this row VRFY_ABHA_501 as well. Record it as `QR-read` so the two are told apart in the manifest.
`screen`. No call. Your system scans a person's ABHA QR code and fills name, date of birth, gender and mobile into registration from it. Evidence: the filled form after a scan, with nothing typed. `hiecm.concept.m1-two-routes-to-the-profile`
Loop limit: 3 passes per test case.
### PROF_ABHA_601 to 605: profile update
Optional. Each is `sandbox` and `human`, since every change is confirmed by an OTP.
Loop limit: 3 passes per test case.
| Case | Calls | Exit condition |
|---|---|---|
| PROF_ABHA_601, mobile | `m1_post_v3_profile_account_request_otp_update_mobile`, the OTP, `m1_post_v3_profile_account_verify_update_mobile` | The verify returns 200 with `authResult` `success` and a message that the mobile number was linked; `m1_get_v3_profile_account` then shows the new masked `mobile` |
| PROF_ABHA_602, photo | `m1_patch_v3_profile_account_profile_photo` | 200, and `m1_get_v3_profile_account` returns the new `profilePhoto` |
| PROF_ABHA_603, email | The request and verify calls above with the email scope | 200 on the verify, and the profile shows the new email |
| PROF_ABHA_604, re-KYC | `m1_post_v3_profile_account_request_otp_re_kyc`, the OTP, `m1_post_v3_profile_account_verify_re_kyc` | 200 on the verify, and the profile shows `kycVerified` `true` |
| PROF_ABHA_605, delete or deactivate | ABDM's M1 specification publishes no delete or deactivate operation | `not-run`, with that reason |
### TAGGING_UNIQUEPATIENTID_UNIQUEABHANUMBER: one ABHA per patient id
Mandatory. `screen`. Your system checks whether an ABHA number already exists in its database before it creates a patient id, on both the creation and the verification paths, so one ABHA never maps to two of your patients and one of your patients never holds two ABHAs.
Evidence: verify the same ABHA twice in a run. The second time, the screen says the record is already linked and names your patient id, and the database holds one row. `hiecm.concept.m1-avoiding-duplicate-abha`
Loop limit: 3 passes per test case.
### SHARE_PATIENT_PROFILE_701: share a profile by scanning the facility QR
This case is run from the person's ABHA app, and the call that proves it lands on your side as the `on-share` webhook. It belongs to the scan and register skill, `abdm-scan-and-register`, which carries the webhook and the token reply. Record it there. In this manifest, write `see abdm-scan-and-register`.
## When the last case is recorded
Write the manifest. It is the whole report. Case ids to request ids, nothing else, so a reviewer checks it against the gateway's own record rather than reading screenshots. Secrets never appear in it: no tokens, no OTPs, no Aadhaar numbers, no client secret.
```json
{
"skill": "abdm-m1",
"set": "M1 ABHA creation and verification, NHA, version 1.1",
"entity": "private",
"run_started": "2026-09-29T10:12:40Z",
"run_finished": "2026-09-29T11:48:03Z",
"client_id": "<your sandbox client id>",
"cases": [
{"id": "CRT_ABHA_101", "outcome": "passed", "evidence": "sandbox",
"request_ids": ["6f1c...", "a02d...", "c9e4..."],
"observed": ["byAadhaar 200 message=Account created successfully", "abha-address 200 healthIdNumber", "profile/account 200 ABHANumber"]},
{"id": "CRT_ABHA_102", "outcome": "passed", "evidence": "screen",
"attachment": "consent-2026-09-29.png", "rule": "hiecm.concept.m1-screen-contract"},
{"id": "CRT_ABHA_105", "outcome": "needs-human", "evidence": "human",
"request_ids": ["b7a1..."], "reason": "OTP arrives on the person's phone; nobody present"},
{"id": "CRT_ABHA_401", "outcome": "not-run", "reason": "no enrolment by document operation in the M1 specification"}
]
}
```
Then say, in three lines: how many cases passed, failed, need a human and were not run; which mandatory cases for your entity are not `passed`; and the one case to fix first.

View File

@ -0,0 +1,92 @@
---
name: abdm-m2
description: Use when building, debugging or testing ABDM Milestone 2: care contexts, HIP initiated linking, discovery, and pushing encrypted health records to a requester. Carries the endpoints and the encryption parameters. Also carries the scaffolding loop that builds it flow by flow and the loop from a failed call to a named fix, in references/.
type: skill
domain: m2
agent_consumers:
- abdm-integration-agent
- abdm-call-debugger
requires:
- gateway-session-token
- hip-registration
- callback-url
- nrces-document-bundle
produces:
- care-context
- link-token
- health-information-push
can_execute: true
can_orchestrate: false
---
# ABDM M2, create and link records
Generated from the ABDM Developer Portal on 2026-09-16, catalogue version 2026.09.16. Every fact below comes from a page in that portal, which is the place to look when this file does not carry enough.
This file is a snapshot. Re-download the whole folder from https://docs.abdm.gov.in/skills/abdm-m2/ when it is older than the work you are doing: this router and every file under references/ that it links to. Fetching this file alone leaves those links pointing at files you do not have.
If the abdm-docs MCP server is connected, trust its answers over this file: it serves the current catalogue and stamps every response with its catalogue_version, which you can compare against the version above.
## What you can do with M2
- Tell ABDM a patient had a visit with you, so their records can be found later.
- Answer a discovery request when somebody looks for that patient.
- Send records out encrypted when a consent says you must.
- Get the link token the linking calls need.
What it cannot do yet matters as much. Read **Before anything else** below before assuming a capability is one endpoint away.
## Try asking
- "Link a care context for this patient"
- "What has to be in place before my first M2 call?"
- "My M2 call returned ABDM-1000. What is wrong, and how do I fix it?"
Loaded with no task? Say in three lines what this skill does. Offer the prompts above. Then ask what the person is building, and whether the code for it exists yet.
## What is in this folder
- **Scaffold.** Survey the codebase first when one exists, then build it flow by flow against the sandbox, as a loop that ends when the step's exit condition holds rather than on a call returning 200. [references/scaffold.md](references/scaffold.md)
- **Design.** What the journey around the calls has to do, and what a screen is forbidden to claim. [references/design.md](references/design.md)
- **Integrate.** 24 operations, with their hosts and headers. [references/integrate.md](references/integrate.md)
- **Debug.** The loop from a failed call to a named fix, and 120 error codes from the specification's examples. [references/debug.md](references/debug.md)
This file is the map. Each line above is a file beside it, opened one at a time rather than read through.
## Before anything else
- Treat every request and response shape in this skill as unconfirmed until the sandbox has answered you. Check a response before you rely on its shape.
- The design section is different in kind. Its rules come from building a working front desk against the sandbox, and each atom it cites names what was observed and the date it was seen.
- You act as the HIP.
- Before M2, three things must hold: the facility is registered in the HFR with a valid HFR ID, that HIP ID is linked to your client ID (through the NHPR portal or the M4 software linkage APIs), and a callback URL is set for the client ID with the Update Bridge API.
- You are the side that encrypts, and the parameters arrive from the requester rather than from you. The health information request carries `keyMaterial` with `cryptoAlg`, `curve: Curve25519`, the requester's `dhPublicKey` and a `nonce`. Generate your own Curve25519 pair and your own nonce, and send your public key and nonce back with the data so the requester can derive the same secret.
- The key derivation and the symmetric cipher applied over that shared secret are not in the specification. The data flow page (/docs/hiecm/v3/concepts/data-flow) and the Fidelius reference (shared.concept.fidelius-ecdh-interop) give the scheme: HKDF over the shared secret, and AES-GCM for the payload. Build from those, not from a sample.
## Practices that hold across every call
- Read the body, not only the status. A refusal often names the field in its body while the status says nothing useful.
- When ABDM publishes a value, read it rather than hard coding what it currently says. That covers a parameter, such as the encryption algorithm the certificate endpoints return beside the key, and it covers an enumeration. The registries publish theirs as master data calls: councils, courses, colleges, states and districts on the HPR, and facility types and LGD codes on the HFR. A table typed into your source goes stale silently. Purposes and HI types have no master data call: take them from the enumeration in the specification of the call you are making. Refuse to act on a published value you do not recognise rather than falling back to a default.
- Read every field in a response, not the one you came for. The M1 certificate call returns the encryption algorithm next to the key.
- Prove an assumption against a call that is able to disagree with you. A call that refuses every input with one message cannot tell you which input was right.
- Suspect the transport before the data. When a call refuses a value you believe in, check the encryption, the headers and the clock before you doubt the value.
- Do not carry an encryption path from one module to another. Read the certificate and the algorithm from the registry you are calling.
- Never log a sensitive value before you encrypt it, and never send one to a remote service to be encrypted. Both move the leak rather than removing it.
- Generate a fresh REQUEST-ID for every call and log it before sending. Once a call has failed it is the only handle on it.
- Check the host on any sample before you copy it. A request copied whole can be correct in every respect except where it is pointed, and that failure looks like credentials.
- Do not validate an identifier more strictly than the platform does. A schema that types a field as a UUID is not a promise that every value is one. Refusing a value ABDM would have accepted turns your own client into the thing that broke.
- Read a plural response as plural. A verification returns an accounts array and a consent request can produce more than one artefact. Store the collection and decide from its length.
- A documented callback path is not a documented callback payload. Log the whole body on arrival before you parse it, so a handler written against an assumed shape fails where you can see it.
- Decode a token before you use it. A call that hands you a token has not necessarily handed you the token the next call wants, and the claims are base64 that need no library to read.
- When a journey carries the same parameter through two calls, check what each call's specification asks for rather than carrying the first value forward.
- Do not infer which path an identifier belongs to from where that identifier is most discussed. Send every identifier to the lookup first and let the answer pick the path, so nobody who already holds an account is sent to create a second.
- Do not match an error code with string equality. A code may come back bare, as `ABDM-1001`, or with a trailing `: ` separator, as `ABDM-1001: `. Match on the code itself and tolerate the separator.
- Handle a failure that carries no body. Check for an empty body before you parse, or your client throws on the simplest failure there is.
- Back off on an authentication failure rather than retrying, and never loop a credential check.
- Send TIMESTAMP in UTC, ISO-8601 with milliseconds and a trailing Z, as in `2022-10-06T15:10:00.587Z`.
- Cache a public certificate with a validity window rather than forever. A rotation fails every encrypted call at once, and a cache with no expiry cannot recover on its own.
## Where the detail is
- Every endpoint, with its body fields and responses: /docs/hiecm/v3/api/m2
- The flows as diagrams: /docs/hiecm/v3/milestones/m2
- Every error code across modules: /docs/hiecm/v3/reference/error-codes
- Terms: /docs/hiecm/v3/getting-started/glossary

View File

@ -0,0 +1,860 @@
# HIE-CM m2 debug
Every error below is an OODA loop: observe the error code and last request id, orient against the matched code, decide the fix, act, and observe whether the original step now succeeds. Applying a fix is not the exit condition; the original step succeeding is.
Loop limit: 5 passes per error.
## Errors
### ABDM-1000
**NHA's list for the module:** `Unable to connect the database`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1001
**NHA's list for the module:** `No data found`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1004
**NHA's list for the module:** `SMS Gateway is unavailable`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1006
**NHA's list for the module:** `Bad Request, invalid request Body`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1007
**NHA's list for the module:** `Connection failed due to timeout`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1008
**NHA's list for the module:** `SMS service currently disabled`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1010
**NHA's list for the module:** `Validation failed`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1011
**NHA's list for the module:** `Gateway database unavailable`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1012
**NHA's list for the module:** `No records found against the ABHA Address`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1013
**NHA's list for the module:** `Invalid ABHA Number`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1015
**NHA's list for the module:** `Invalid Response`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1016
**NHA's list for the module:** `Invalid TimeStamp`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1017
**NHA's list for the module:** `Invalid TransactionId`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1018
**NHA's list for the module:** `Share Profile database unavailable`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1019
**NHA's list for the module:** `Dependent Service Unavailable`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1020
**NHA's list for the module:** `Unknown database`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1022
**NHA's list for the module:** `Too many requests`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1023
**NHA's list for the module:** `Invalid User`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1024
**NHA's list for the module:** `Dependent service unavailable`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1025
**NHA's list for the module:** `Invalid ServiceId`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1026
**NHA's list for the module:** `Invalid Link Token`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1027
**NHA's list for the module:** `You are blocked. Please try again after 24 hours.`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1028
**NHA's list for the module:** `HIP is unavailable`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1029
**NHA's list for the module:** `Redis server is unavailable`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1030
**NHA's list for the module:** `Invalid request ID`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1031
**NHA's list for the module:** `Invalid request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1032
**NHA's list for the module:** `Invalid header`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1033
**NHA's list for the module:** `HIU is unavailable`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1034
**NHA's list for the module:** `Notification service unavailable`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1035
**NHA's list for the module:** `Invalid HIP ID`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1036
**NHA's list for the module:** `Data does not matched`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1037
**NHA's list for the module:** `Counter and Care context count mismatch`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1038
**NHA's list for the module:** `ABHA address and Link token mismatch`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1040
**NHA's list for the module:** `Invalid HIU ID`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1041
**NHA's list for the module:** `Invalid Acknowledgement`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1042
**NHA's list for the module:** `Provider Mandatory`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1043
**NHA's list for the module:** `ABHA Address does not match with KYC details.`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1044
**NHA's list for the module:** `Broadcast Failed`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1045
**NHA's list for the module:** `Database Access is restricted`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1046
**NHA's list for the module:** `Invalid Purpose`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1047
**NHA's list for the module:** `Purpose does not exist`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1048
**NHA's list for the module:** `Timeout`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1049
**NHA's list for the module:** `Invalid Profile Share Intent Keys`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1050
**NHA's list for the module:** `Invalid Profile Share Metadata Keys`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1051
**NHA's list for the module:** `Invalid ABHA Number or ABHA Address`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1052
**NHA's list for the module:** `Invalid TransactionId or response's requestId`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1401
**NHA's list for the module:** `HIP is not available`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1061
**NHA's list for the module:** `Consent artefact expired`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1062
**NHA's list for the module:** `Consent Not granted`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1063
**NHA's list for the module:** `Date Range given is invalid`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1064
**NHA's list for the module:** `request with this request id already exists`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1109
**NHA's list for the module:** `ABHA DB service unavailable`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1108
**NHA's list for the module:** `Notification DB service unavailable`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1201
**NHA's list for the module:** `IDP Gateway is unavailable`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-9999
**NHA's list for the module:** `Unknown exception`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1006
**NHA's list for the module:** `Invalid combinations of scopes`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1056
**NHA's list for the module:** `This care contexts has been already linked`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1055
**NHA's list for the module:** `Invalid HIP Id or PHR Id`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1056
**NHA's list for the module:** `Invalid Link Reference Number`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1057
**NHA's list for the module:** `Invalid Care Contexts`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1059
**NHA's list for the module:** `Invalid Care Contexts count`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1060
**NHA's list for the module:** `Invalid Patient Reference Number`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1061
**NHA's list for the module:** `Invalid Patient Display`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1062
**NHA's list for the module:** `ABHA number mismatch with Link token`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1063
**NHA's list for the module:** `HIP Id mismatch with Link token`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1064
**NHA's list for the module:** `Request body was missing`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1065
**NHA's list for the module:** `Invalid X Auth token`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1066
**NHA's list for the module:** `Invalid JWT token`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1067
**NHA's list for the module:** `Request body not required`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1170
**NHA's list for the module:** `Invalid ABHA address`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1084
**NHA's list for the module:** `ABHA address mismatch with X Auth token`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1085
**NHA's list for the module:** `ABHA number mismatch with X Auth token`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1086
**NHA's list for the module:** `Patient profile mismatch with X Auth token`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1087
**NHA's list for the module:** `Duplicate patient share request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1090
**NHA's list for the module:** `Duplicate HIP link request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1091
**NHA's list for the module:** `Duplicate Get links request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1092
**NHA's list for the module:** `Duplicate Link token request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1093
**NHA's list for the module:** `Duplicate Bridge request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1094
**NHA's list for the module:** `Duplicate bridge patch request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1095
**NHA's list for the module:** `Duplicate Bridge service request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1102
**NHA's list for the module:** `Profile information cannot be null`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1103
**NHA's list for the module:** `Duplicate Discovery request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1104
**NHA's list for the module:** `Duplicate Init request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1105
**NHA's list for the module:** `Duplicate Confirm request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1106
**NHA's list for the module:** `Duplicate On discovery request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1107
**NHA's list for the module:** `Duplicate On init request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1108
**NHA's list for the module:** `Duplicate On confirm request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1109
**NHA's list for the module:** `Invalid On discovery response`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1110
**NHA's list for the module:** `Invalid On init response`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1111
**NHA's list for the module:** `Invalid On confirm response`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1112
**NHA's list for the module:** `Invalid or already expired consent artefact id`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1113
**NHA's list for the module:** `Duplicate health information provider data flow response`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1149
**NHA's list for the module:** `Intent type is not supported at HIP end`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1150
**NHA's list for the module:** `Bridge API version cannot be null`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1402
**NHA's list for the module:** `Acknowledgement is not received from HIP`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-9999
**NHA's list for the module:** `HIP is unable to generate a token at this time. Please try again later.`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-9999
**NHA's list for the module:** `HIP is unable to process at this time. Please try again later.`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1030
**NHA's list for the module:** `Request id not found`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-2500
**NHA's list for the module:** `No mapping found for`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-2401
**NHA's list for the module:** `The X Auth token is invalid.`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-2402
**NHA's list for the module:** `Invalid Timestamp`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-2404
**NHA's list for the module:** `Invalid Request Id`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-2429
**NHA's list for the module:** `Too many requests found`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-2501
**NHA's list for the module:** `Payment status should be : SUCCESS,CANCELED,PENDING,FAIL,REFUND_INITIATED,REFUND_SUCCESS`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-2500
**NHA's list for the module:** `Authorization header is missing`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-2403
**NHA's list for the module:** `Invalid X-CM-ID`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-2406
**NHA's list for the module:** `Invalid API sequence flow, please follow logical flow`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-2406
**NHA's list for the module:** `The status is invalid. Please follow the logical status flow or transition.`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-9999
**NHA's list for the module:** `User not found`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-9999
**NHA's list for the module:** `Cannot process the request at the moment, please try later.`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-9001
**NHA's list for the module:** `No open order against ABHA. Please ensure a minimum of one open order`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-9002
**NHA's list for the module:** `No registration found at <<hospital name>>. Contact counter support`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-9003
**NHA's list for the module:** `Hospital services temporarily unavailable. Please try again after some time.`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-9004
**NHA's list for the module:** `Services disrupted, please try again.`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-9005
**NHA's list for the module:** `Bank server not responding. Please try again later`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-9006
**NHA's list for the module:** `Service details mismatch. Please ensure original service ID from HMIS`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-9007
**NHA's list for the module:** `The Scan and Pay functionality is not enabled at this facility. Kindly contact the hospital administration.`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1006
**NHA's list for the module:** `Invalid count, must be 2 digit and ranges between 1 to 20`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1407
**NHA's list for the module:** `The ABHA Number associated with this ABHA Address is currently deactivated. Please reactivate it.`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1006
**NHA's list for the module:** `Invalid HIType, it must be in Prescription,DiagnosticReport,OPConsultation,DischargeSummary,ImmunizationRecord,HealthDocumentRecord,WellnessRecord,Invoice`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
## Where the detail is
- The operation that returns each code: /docs/hiecm/v3/api/m2
## Every code in the specification
### Codes
| Code | HTTP | Message | Returned by |
| --- | --- | --- | --- |
| `ABDM-1000` | | Unable to connect the database | NHA's list for the module |
| `ABDM-1001` | | No data found | NHA's list for the module |
| `ABDM-1004` | | SMS Gateway is unavailable | NHA's list for the module |
| `ABDM-1006` | | Bad Request, invalid request Body | NHA's list for the module |
| `ABDM-1007` | | Connection failed due to timeout | NHA's list for the module |
| `ABDM-1008` | | SMS service currently disabled | NHA's list for the module |
| `ABDM-1010` | | Validation failed | NHA's list for the module |
| `ABDM-1011` | | Gateway database unavailable | NHA's list for the module |
| `ABDM-1012` | | No records found against the ABHA Address | NHA's list for the module |
| `ABDM-1013` | | Invalid ABHA Number | NHA's list for the module |
| `ABDM-1015` | | Invalid Response | NHA's list for the module |
| `ABDM-1016` | | Invalid TimeStamp | NHA's list for the module |
| `ABDM-1017` | | Invalid TransactionId | NHA's list for the module |
| `ABDM-1018` | | Share Profile database unavailable | NHA's list for the module |
| `ABDM-1019` | | Dependent Service Unavailable | NHA's list for the module |
| `ABDM-1020` | | Unknown database | NHA's list for the module |
| `ABDM-1022` | | Too many requests | NHA's list for the module |
| `ABDM-1023` | | Invalid User | NHA's list for the module |
| `ABDM-1024` | | Dependent service unavailable | NHA's list for the module |
| `ABDM-1025` | | Invalid ServiceId | NHA's list for the module |
| `ABDM-1026` | | Invalid Link Token | NHA's list for the module |
| `ABDM-1027` | | You are blocked. Please try again after 24 hours. | NHA's list for the module |
| `ABDM-1028` | | HIP is unavailable | NHA's list for the module |
| `ABDM-1029` | | Redis server is unavailable | NHA's list for the module |
| `ABDM-1030` | | Invalid request ID | NHA's list for the module |
| `ABDM-1031` | | Invalid request | NHA's list for the module |
| `ABDM-1032` | | Invalid header | NHA's list for the module |
| `ABDM-1033` | | HIU is unavailable | NHA's list for the module |
| `ABDM-1034` | | Notification service unavailable | NHA's list for the module |
| `ABDM-1035` | | Invalid HIP ID | NHA's list for the module |
| `ABDM-1036` | | Data does not matched | NHA's list for the module |
| `ABDM-1037` | | Counter and Care context count mismatch | NHA's list for the module |
| `ABDM-1038` | | ABHA address and Link token mismatch | NHA's list for the module |
| `ABDM-1040` | | Invalid HIU ID | NHA's list for the module |
| `ABDM-1041` | | Invalid Acknowledgement | NHA's list for the module |
| `ABDM-1042` | | Provider Mandatory | NHA's list for the module |
| `ABDM-1043` | | ABHA Address does not match with KYC details. | NHA's list for the module |
| `ABDM-1044` | | Broadcast Failed | NHA's list for the module |
| `ABDM-1045` | | Database Access is restricted | NHA's list for the module |
| `ABDM-1046` | | Invalid Purpose | NHA's list for the module |
| `ABDM-1047` | | Purpose does not exist | NHA's list for the module |
| `ABDM-1048` | | Timeout | NHA's list for the module |
| `ABDM-1049` | | Invalid Profile Share Intent Keys | NHA's list for the module |
| `ABDM-1050` | | Invalid Profile Share Metadata Keys | NHA's list for the module |
| `ABDM-1051` | | Invalid ABHA Number or ABHA Address | NHA's list for the module |
| `ABDM-1052` | | Invalid TransactionId or response's requestId | NHA's list for the module |
| `ABDM-1401` | | HIP is not available | NHA's list for the module |
| `ABDM-1061` | | Consent artefact expired | NHA's list for the module |
| `ABDM-1062` | | Consent Not granted | NHA's list for the module |
| `ABDM-1063` | | Date Range given is invalid | NHA's list for the module |
| `ABDM-1064` | | request with this request id already exists | NHA's list for the module |
| `ABDM-1109` | | ABHA DB service unavailable | NHA's list for the module |
| `ABDM-1108` | | Notification DB service unavailable | NHA's list for the module |
| `ABDM-1201` | | IDP Gateway is unavailable | NHA's list for the module |
| `ABDM-9999` | | Unknown exception | NHA's list for the module |
| `ABDM-1006` | | Invalid combinations of scopes | NHA's list for the module |
| `ABDM-1056` | | This care contexts has been already linked | NHA's list for the module |
| `ABDM-1055` | | Invalid HIP Id or PHR Id | NHA's list for the module |
| `ABDM-1056` | | Invalid Link Reference Number | NHA's list for the module |
| `ABDM-1057` | | Invalid Care Contexts | NHA's list for the module |
| `ABDM-1059` | | Invalid Care Contexts count | NHA's list for the module |
| `ABDM-1060` | | Invalid Patient Reference Number | NHA's list for the module |
| `ABDM-1061` | | Invalid Patient Display | NHA's list for the module |
| `ABDM-1062` | | ABHA number mismatch with Link token | NHA's list for the module |
| `ABDM-1063` | | HIP Id mismatch with Link token | NHA's list for the module |
| `ABDM-1064` | | Request body was missing | NHA's list for the module |
| `ABDM-1065` | | Invalid X Auth token | NHA's list for the module |
| `ABDM-1066` | | Invalid JWT token | NHA's list for the module |
| `ABDM-1067` | | Request body not required | NHA's list for the module |
| `ABDM-1170` | | Invalid ABHA address | NHA's list for the module |
| `ABDM-1084` | | ABHA address mismatch with X Auth token | NHA's list for the module |
| `ABDM-1085` | | ABHA number mismatch with X Auth token | NHA's list for the module |
| `ABDM-1086` | | Patient profile mismatch with X Auth token | NHA's list for the module |
| `ABDM-1087` | | Duplicate patient share request | NHA's list for the module |
| `ABDM-1090` | | Duplicate HIP link request | NHA's list for the module |
| `ABDM-1091` | | Duplicate Get links request | NHA's list for the module |
| `ABDM-1092` | | Duplicate Link token request | NHA's list for the module |
| `ABDM-1093` | | Duplicate Bridge request | NHA's list for the module |
| `ABDM-1094` | | Duplicate bridge patch request | NHA's list for the module |
| `ABDM-1095` | | Duplicate Bridge service request | NHA's list for the module |
| `ABDM-1102` | | Profile information cannot be null | NHA's list for the module |
| `ABDM-1103` | | Duplicate Discovery request | NHA's list for the module |
| `ABDM-1104` | | Duplicate Init request | NHA's list for the module |
| `ABDM-1105` | | Duplicate Confirm request | NHA's list for the module |
| `ABDM-1106` | | Duplicate On discovery request | NHA's list for the module |
| `ABDM-1107` | | Duplicate On init request | NHA's list for the module |
| `ABDM-1108` | | Duplicate On confirm request | NHA's list for the module |
| `ABDM-1109` | | Invalid On discovery response | NHA's list for the module |
| `ABDM-1110` | | Invalid On init response | NHA's list for the module |
| `ABDM-1111` | | Invalid On confirm response | NHA's list for the module |
| `ABDM-1112` | | Invalid or already expired consent artefact id | NHA's list for the module |
| `ABDM-1113` | | Duplicate health information provider data flow response | NHA's list for the module |
| `ABDM-1149` | | Intent type is not supported at HIP end | NHA's list for the module |
| `ABDM-1150` | | Bridge API version cannot be null | NHA's list for the module |
| `ABDM-1402` | | Acknowledgement is not received from HIP | NHA's list for the module |
| `ABDM-9999` | | HIP is unable to generate a token at this time. Please try again later. | NHA's list for the module |
| `ABDM-9999` | | HIP is unable to process at this time. Please try again later. | NHA's list for the module |
| `ABDM-1030` | | Request id not found | NHA's list for the module |
| `ABDM-2500` | | No mapping found for | NHA's list for the module |
| `ABDM-2401` | | The X Auth token is invalid. | NHA's list for the module |
| `ABDM-2402` | | Invalid Timestamp | NHA's list for the module |
| `ABDM-2404` | | Invalid Request Id | NHA's list for the module |
| `ABDM-2429` | | Too many requests found | NHA's list for the module |
| `ABDM-2501` | | Payment status should be : SUCCESS,CANCELED,PENDING,FAIL,REFUND_INITIATED,REFUND_SUCCESS | NHA's list for the module |
| `ABDM-2500` | | Authorization header is missing | NHA's list for the module |
| `ABDM-2403` | | Invalid X-CM-ID | NHA's list for the module |
| `ABDM-2406` | | Invalid API sequence flow, please follow logical flow | NHA's list for the module |
| `ABDM-2406` | | The status is invalid. Please follow the logical status flow or transition. | NHA's list for the module |
| `ABDM-9999` | | User not found | NHA's list for the module |
| `ABDM-9999` | | Cannot process the request at the moment, please try later. | NHA's list for the module |
| `ABDM-9001` | | No open order against ABHA. Please ensure a minimum of one open order | NHA's list for the module |
| `ABDM-9002` | | No registration found at <<hospital name>>. Contact counter support | NHA's list for the module |
| `ABDM-9003` | | Hospital services temporarily unavailable. Please try again after some time. | NHA's list for the module |
| `ABDM-9004` | | Services disrupted, please try again. | NHA's list for the module |
| `ABDM-9005` | | Bank server not responding. Please try again later | NHA's list for the module |
| `ABDM-9006` | | Service details mismatch. Please ensure original service ID from HMIS | NHA's list for the module |
| `ABDM-9007` | | The Scan and Pay functionality is not enabled at this facility. Kindly contact the hospital administration. | NHA's list for the module |
| `ABDM-1006` | | Invalid count, must be 2 digit and ranges between 1 to 20 | NHA's list for the module |
| `ABDM-1407` | | The ABHA Number associated with this ABHA Address is currently deactivated. Please reactivate it. | NHA's list for the module |
| `ABDM-1006` | | Invalid HIType, it must be in Prescription,DiagnosticReport,OPConsultation,DischargeSummary,ImmunizationRecor… | NHA's list for the module |
A code you meet that is not above is one the specifications do not carry yet. Read the code together with the message: a code can appear twice with different meanings.

View File

@ -0,0 +1,639 @@
# Design M2, create and link records
What the integration has to do to the journey around the calls: how many questions a patient is asked, where a failure is shown, and what a screen is forbidden to claim. Every rule below comes from a Catalogue atom, cited at the end.
## The unit of work is an exchange, not a call
### In plain words
Every M2 and M3 call answers twice. Once straight away, saying the request was
accepted, and later on a callback to your own bridge, saying what actually
happened. Do not treat the first as success. It says the request was accepted,
not that anything was linked.
So the request id stops being a log handle and becomes the join key. An
outbound call, the wait, and the callback that answers it are one exchange, and
they should read as one row with a timeline. Shown as three separate lines they
read as noise, and the difference between accepted and done stays invisible,
which is the one thing the interface exists to show.
### What happens
Register the waiter before sending. A callback that arrives before the HTTP
response returns is a race the sandbox eventually wins.
Then hold five outcomes apart. These must not look alike:
| State | Means | Observed |
|---|---|---|
| sent | in the air | |
| accepted, waiting | `202`, nothing back yet | real patient, 340 ms |
| answered | the callback arrived | |
| refused before waiting | a synchronous `400`, nothing was ever pending | fictional patient, 91 ms |
| no answer in the window | accepted, then silence | real patient, 60,000 ms |
The fourth and fifth are the ones implementations collapse into each other. A
refused call closing its waiter through the same function as an answered one
renders a synchronous `400` as a green callback arrived. Fix that in the shared
function rather than at the call sites that reach it.
The fourth outcome is also useful. Generate link token validates the patient
before accepting the request, so an identity nobody holds is refused at once
with `400` and `ABDM-9999`, while a recognised one is accepted with `202` and
answers later. The two are distinguishable at the first response, so only a
recognised patient is worth waiting for. Note the code: `ABDM-9999` is the catch
all, and the message is the only part naming the cause.
No timeout is published for any of these, so the honest words for the fifth
outcome are that nothing arrived in the window you chose.
### How you know it worked
Send one linking call and read one row. It carries the request id, the outbound
call, the elapsed wait, and the callback when it lands, in one timeline.
Send a call for an identity nobody holds. The row shows refused within a few
hundred milliseconds, never shows waiting, and no waiter is left open.
### When it goes wrong
- A synchronous refusal shows as a completed exchange. The refusal path and the
callback path share the function that closes the waiter.
- A callback cannot be matched to its call. The waiter was registered after
sending, and the callback won the race.
- Every call is accepted and nothing ever answers. No callback URL is registered
against the facility id, which is a configuration cause for a runtime symptom.
## Nobody is standing there, so never block and never lose the state
### In plain words
M1's rules do not carry over to M2. There is no patient to spare a question, no
one time password to save, and no screen anybody is looking at. The patient has
left. What there is instead is a call that was accepted and then went quiet, and
a callback that may arrive tomorrow or never.
Two consequences follow, and they are the opposite of how an M1 journey is
built.
### What happens
**Never block.** Linking is several calls, each answered on a callback that may
be a minute away. A button that waits for the outcome is a button that hangs for
sixty seconds and then says nothing useful. Start the work, return at once, and
point at where it can be watched. The desk gets on with the next patient.
**State outlives the session.** Where a link has got to belongs on the record,
not in a page's memory. Reopening the application must show where everything
stands without re-running anything. This is the reverse of M1, where the whole
journey lives and dies inside one person's visit.
**Name the step, not the spinner.** Linking tells a receptionist nothing. These
do:
- Asking ABDM for a link token.
- Asking ABDM for a link token: ABDM accepted it and no answer came back. This
client has no callback URL registered, so the answer has nowhere to go.
- Asking ABDM for a link token: refused. `ABDM-9999`, user not found.
The second is the interesting one. It names a configuration cause for a runtime
symptom, which is the difference between a receptionist raising a ticket and an
integrator fixing one line of configuration.
### How you know it worked
Start a link and close the page. Reopen the application and the record shows
which step the link reached, and when, without any call being made again.
Press the button that starts linking. It returns immediately and points at where
progress can be watched. It does not sit waiting for a callback.
### When it goes wrong
- The interface hangs for sixty seconds and then reports nothing. Something is
waiting on the callback inside the request that started the work.
- Reopening the application shows a link as not started when it was started
yesterday. The state was held in the page rather than on the record.
- A receptionist raises a ticket for what turns out to be a missing callback
URL. The message named the symptom without naming the configuration cause.
## A refused request is still remembered, so a retry is a duplicate
### In plain words
ABDM records a link token request even when it refuses the patient, and
deduplicates the next identical request against the one it refused. So a retry
inside that window cannot succeed, and its refusal no longer names the original
cause.
The second message says duplicate, which reads as though the first attempt had
worked. It had not.
### What happens
The same request for the same unknown address, sent twice:
| When | Result |
|---|---|
| 14:17:42 | `400`, `ABDM-9999`, user not found |
| 14:18:51, 69 seconds later | `400`, `ABDM-1092`, duplicate link token request |
The length of the deduplication window is not published. It is at least sixty
nine seconds.
So do not offer a button that cannot work. Where a duplicate is the answer,
explain it, and say that the earlier refusal is the one that names the cause.
Point the reader back at the first exchange rather than at the second.
This is the reason the first refusal has to be kept rather than replaced. An
interface that overwrites the last error with the newest one destroys the only
message that explained anything.
### How you know it worked
Send a request that is refused, then send it again inside the window. The
interface shows `ABDM-1092`, does not present it as a new failure, and links
back to the first exchange and its `ABDM-9999`.
The retry control is absent or disabled while the window is open, rather than
present and failing.
### When it goes wrong
- A retry loop runs and every attempt after the first says duplicate. Nothing is
checking whether a retry can succeed.
- The cause of a failure cannot be found because the newest message replaced it.
Keep every exchange, and treat the first refusal as the authoritative one.
- A duplicate refusal is read as evidence that the first request succeeded.
It is not. The first was refused, and ABDM remembered the refusal.
## What the integrator needs on screen, separately from the patient
### In plain words
A desk that talks to ABDM asynchronously cannot be debugged without a view built
for the integrator rather than the receptionist. It is cheap to build and it is
the difference between a fix that takes a minute and one that takes a day.
### What happens
**A live view of every call and callback, grouped by request id**, so an
outbound call, its wait, and the callback answering it read as one exchange with
a timeline.
**Redact by name and length, never by value.** Show that an `Authorization`
header was sent and how long it was. Never its contents. The panel is a browser.
**Show what would be sent, before sending it.** A request preview or a bundle
inspector turns it failed at the far end into something checkable at the desk.
**A readiness check that names what is missing**, and this is where two
configuration failures have to be told apart:
| Missing | Effect | Treat as |
|---|---|---|
| Facility id | the call cannot be sent | blocker, refuse locally |
| Callback URL | the call sends and is accepted, and the answer has nowhere to go | warning, send anyway |
Treating both as blockers is the tempting mistake. Refusing to send when no
callback URL is registered hides exactly the behaviour the panel exists to make
visible. Send, accept, wait, time out, and say why.
Refuse the first locally and name the value. An invented facility id comes back
from ABDM as an entitlement error that reads like a credentials problem, and
sends the integrator to the console instead of to one line of configuration.
Presence is not validity. `X-HIU-ID` is checked for presence rather than
against any registry: absent is refused `401`, and an invented id is accepted
`202`. Anyone testing with a made up id sees acknowledgements that look like
progress, which is why the local check has to be the strict one.
### How you know it worked
Clear the facility id and press the button. The call is refused before anything
is sent, and the message names the configuration value that is absent.
Clear the callback URL and press the same button. The call is sent, accepted,
waits the window, and reports that nothing arrived and why.
Open the panel during a linking run. Each exchange is one row, headers are shown
by name and length, and no header value appears anywhere.
### When it goes wrong
- A token appears in the panel. Redaction is by value rather than by name and
length. This is a credential leak, not a display bug.
- An integrator is sent to the developer console by an entitlement error. The
facility id was not checked locally before the call went out.
- Calls are accepted and nothing ever answers, and the panel says only waiting.
Name the missing callback URL as the cause, rather than leaving the reader
with a timeout.
## Inbound is a surface, and silence there is a failure state
### In plain words
M2 and M3 are not only things your desk asks ABDM. ABDM asks your desk things
and waits: a discovery request, a link initiation, a link confirmation, a
request for the records a consent covers, and a consent notification.
Four of those five carry no documented payload in the published sources. A
handler written against an assumed shape fails on the first real delivery,
asynchronously, where nobody is watching. And a handler that only logs leaves a
patient's records undiscoverable while appearing to work.
### What happens
Answer the transport quickly and reason afterwards. ABDM is waiting on a `2xx`,
and a handler that thinks before it replies is a handler that times out.
Then give the interface a state for ABDM asked and this desk has not replied.
Not an empty list, and not silence. A named, visible condition, saying what a
correct reply would have been.
Where the payload is undocumented, record the entire body and the entire header
set on the first delivery of each path, before anything tries to read it.
Record header names and lengths, never values. The name is the finding. The
value is a credential.
Every inbound callback carries a bearer token in the `Authorization` header, as
`Bearer <token>`. Verify it before your handler does any work. See
[proving a callback came from ABDM](/docs/hiecm/v3/concepts/callback-authenticity).
The security rule underneath: a URL reachable by ABDM is reachable by everyone.
A presented signature that fails verification is refused everywhere. An absent
one may be tolerated on a sandbox, and where it is, the record has to be marked
as unverified rather than passed off as genuine.
### How you know it worked
Trigger a discovery against your bridge. The transport is acknowledged inside
the window, and the interface shows the delivery, the reply, and the time
between them.
Take a path you have never received before. The whole body and the whole header
name set are recorded before any code reads a field, so the shape can be learned
from the record rather than guessed.
Leave an inbound request unanswered on purpose. The interface names it as
unanswered rather than showing nothing.
### When it goes wrong
- A patient's records cannot be found from another facility, and nothing looks
broken. A discovery handler is logging and not replying.
- Deliveries time out under load. Work is being done before the acknowledgement
rather than after it.
- A handler throws on the first real delivery. It was written against an assumed
payload, and the body was never recorded whole.
## A care context and its records are one thing
### In plain words
A care context is the visit. The records are what happened at it. Neither is
useful alone.
A bundle nobody can name a care context for cannot be sent. A care context with
nothing behind it is a promise the next discovery cannot keep: another facility
finds the visit, asks for the records, and there are none.
So store them together and show them together.
### What happens
Show the counts that matter to a patient rather than the ones that are easy to
compute: visits opened, documents attached, and visits not yet findable
elsewhere. The third is the one worth surfacing, because it means a record
exists that no other facility can reach.
Validate before storing, not before sending. Refusing to store a bundle the
receiver could not read is cheap. Discovering it after a consent has been served
is not.
Let the desk inspect a bundle before it goes: the profile it claims, the
resources inside it, the attachment type, and whether every reference resolves
within the bundle. The upload itself wants a drop target, a title prefilled from
the filename but editable, and named refusals for type and for size. Show a hash
and a size so a file is identifiable in a list without keeping a second copy of
it.
Write the title for the patient. They read it in their own application months
later, not the receptionist filing it today.
Never log the attachment. It is a patient's record, and it belongs in the bundle
and in the encrypted payload built from it, nowhere else.
### How you know it worked
Open a visit and attach nothing. The interface counts it as a visit not yet
findable elsewhere, rather than as a completed link.
Attach a document and the same count falls by one.
Try to store a bundle whose references do not resolve inside it. Storing is
refused, and the refusal names the reference that pointed outward.
### When it goes wrong
- Another facility discovers a visit and receives nothing. A care context was
linked with no records behind it.
- A bundle is refused at the far end, asynchronously, with no explanation
reaching the desk. It was validated before sending rather than before storing.
- A list of visits becomes slow to open. Bundles are being held in the list
rather than stored separately and read when needed.
## Asynchronous calls and callbacks, why a 200 means very little
### In plain words
Nothing goes participant to participant. Every request is addressed to the gateway, which forwards it. Two things follow.
- **You get an acknowledgement, not an answer.** In the [M3](/docs/hiecm/v3/getting-started/glossary#m3) consent flow the [HIU](/docs/hiecm/v3/getting-started/glossary#hiu) asks, the HIE-CM returns the consent request id on a callback, and the patient's decision comes back later. Each call's page in the [API reference](/docs/hiecm/v3/api) names the callback it produces.
- **You have to be reachable.** Half of [M2](/docs/hiecm/v3/getting-started/glossary#m2) is endpoints the gateway calls on your system.
One exception. In the health information flow the HIU supplies a data push URL, and the HIP encrypts the records and pushes them there. That URL may differ from the HIU's registered gateway URL, to improve privacy. The permission came through the gateway. The bytes do not.
Match each callback to the call that caused it by `response.requestId`, which carries the `REQUEST-ID` you sent. Callbacks do not arrive in the order you sent the requests, and the same one can arrive twice, so a repeat must change nothing. Each callback is described in [the API reference](/docs/hiecm/v3/api).
### What happens
Send the call with a fresh `REQUEST-ID`, treat the 202 as receipt only, and wait for the callback. Key the handler on `response.requestId`, answer it quickly, and make a second delivery of the same request id a no-op.
### How you know it worked
A callback reaches your URL whose `response.requestId` equals the `REQUEST-ID` you sent. Given three calls and two callbacks, the call whose request id has no callback is the one outstanding.
### When it goes wrong
Nothing arrives: work through [the callback never arrives](/docs/hiecm/v3/troubleshooting/callback-never-arrives). A retry is appended as a new event: key on the request id. The code waits on the response body for the result: it never comes there, so the integration hangs.
## Proving a callback really came from ABDM
### In plain words
Every callback in the specifications declares bearer authentication. The token
arrives in the `Authorization` header as `Bearer <token>`. Check three things
before your handler does any work:
1. **A bearer token is present.** Reject a callback without one, and log the
rejection.
2. **An answer answers a call you made.** Its `response.requestId` matches the
`REQUEST-ID` of a request you sent. A callback that answers nothing you sent
is not yours to act on.
3. **It is for a facility you serve.** `X-HIP-ID` or `X-HIU-ID` names one of
your own facilities. This is the only check that covers a callback that
answers nothing, such as a discovery request, a link init or a consent
notification. A bridge can receive callbacks for services that are not
yours: on a shared sandbox bridge, another organisation's consent
notifications and link callbacks have arrived at an integrator's URL.
Storing one keeps another organisation's patient data, and answering one
acts on its behalf.
The keys that verify the token's signature are not among the published gateway
calls. Confirm at onboarding how to verify the token, and meanwhile hold the
three checks above.
The signature inside a consent artefact is a different thing. It signs the
artefact's contents and proves the artefact was not altered. Checking the
delivery does not check the artefact, and checking the artefact does not check
the delivery.
### How you know it worked
A callback carrying a bearer token and a request id you sent is processed. The
same body with the `Authorization` header removed is rejected before your
handler reads the payload, and the rejection is logged. The second is the test
worth writing, because it is the only one that fails loudly when the check is
silently skipped.
### When it goes wrong
**The check is skipped under load.** A handler that checks inside a try block
and continues on failure is worse than one that never checked, because it reads
as safe. Fail closed.
**Nothing arrives at all**, which is a different problem. See
[the callback never arrives](/docs/hiecm/v3/troubleshooting/callback-never-arrives).
### What happens
In the handler, before parsing the body for action: require the `Authorization` header with a bearer token; require that `X-HIP-ID` or `X-HIU-ID` names one of your facilities; and, on a callback that answers a call, require that `response.requestId` matches a `REQUEST-ID` your system sent and has not already handled. Reject otherwise. Do not invent a signature check against a key source the specifications do not publish.
### How you know it worked
A test posts a valid callback body without `Authorization` and sees it rejected and logged before any handler work.
### When it goes wrong
Never fall back to processing a callback that failed a check while you investigate. A callback whose request id is unknown to you, or whose facility header names a facility you do not serve, is logged and dropped, not stored, answered or retried.
## Care contexts, how records are grouped so they can be found
### In plain words
Each care context contains only two pieces of information:
- **Reference ID.** A unique internal identifier assigned by the
[HRP](/docs/hiecm/v3/getting-started/glossary#hrp) (HMIS/LMIS). Used to link
and retrieve the associated health records.
- **Display Name.** A user-friendly description to help identify the group of
records. Must not include any sensitive or confidential information such as
test results or diagnoses. Example: "OPD records (X-Ray, Prescription) from
3rd March 2023".
### Recommended approach for structuring care contexts
To ensure clarity and usability, it is recommended to organise patient data as
follows:
- Create one care context per outpatient visit (OPD)
- Create one care context per inpatient admission (IPD)
This approach provides a clear and event-based grouping of health records.
### JSON structure of care contexts
```json
{
"patient": {
"referenceNumber": "TMH-PUID-001",
"display": "TMH records for Kiran Kumar",
"careContexts": [
{
"referenceNumber": "2375639",
"display": "OPD records for 03 Oct 2022"
}
]
}
}
```
### What happens
Give each care context a `referenceNumber` your own system resolves to the records behind it, and a `display` a person recognises months later. Group by encounter: one per outpatient visit, one per inpatient admission, not one per test or document.
### How you know it worked
Three tests in one visit are one care context. A display name reads like "OPD records for 03 Oct 2022" and carries no diagnosis or result.
### When it goes wrong
A diagnosis or result in `display` leaks clinical information into a system built never to hold it, visible to anyone who can list the patient's care contexts. One care context per record produces a list no person can navigate.
## How a health record is encrypted between HIP and HIU
### In plain words
The scheme is [Elliptic Curve Diffie-Hellman](/docs/hiecm/v3/getting-started/glossary#ecdh) key exchange on Curve25519, with AES-GCM for the payload and HKDF to derive the session key. Only the HIU holding valid consent can read the data, and the design gives perfect forward secrecy: key material compromised later does not expose data exchanged earlier.
### Who holds which key
| Key material | Generated by | Where it goes |
| --- | --- | --- |
| Short term private key, DHSK(U) | HIU | Never leaves the HIU |
| Short term public key, DHPK(U) | HIU | Sent with the request |
| Nonce, RAND(U), 32 bytes | HIU | Sent with the request |
| Short term private key, DHSK(P) | HIP | Never leaves the HIP |
| Short term public key, DHPK(P) | HIP | Sent with the encrypted data |
| Nonce, RAND(P), 32 bytes | HIP | Sent with the encrypted data |
| Shared key, DHK(U,P) | Computed independently by both | Never transmitted |
| Session key, SK(U,P), 256 bit AES-GCM | Derived independently by both | Never transmitted |
| Long term private key | HIP | Never leaves the HIP. Signs the encrypted payload. |
A new key pair per exchange is what buys forward secrecy.
### What the HIP does, step by step
Six steps, once consent has validated.
1. Generate a key pair, DHSK(P) and DHPK(P), in the group the HIU specified.
2. Generate a 32 byte random value, RAND(P).
3. Compute the shared key DHK(U,P) from the HIU's public key DHPK(U) and the HIP's own private key DHSK(P).
4. Derive the salt and IV by XOR of RAND(P) and RAND(U). The first 20 bytes are the salt for HKDF, the last 12 bytes the IV.
5. Compute a 256 bit AES-GCM session key SK(U,P) with HKDF-SHA256, from the x coordinate of the shared key and that salt. The HKDF `info` is empty.
6. Encrypt the data with AES-256-GCM, that key and that IV, with no additional authenticated data. Append the 16 byte authentication tag to the ciphertext and base64 encode the result.
The HIP then sends DHPK(P), RAND(P) and the encrypted data. The HIU derives the same session key from its own private key DHSK(U) and the HIP's public key DHPK(P), with salt and IV from the same XOR.
Build the shared key from the HIU's public key and the HIP's private key. That is the pairing that makes the Diffie-Hellman exchange work.
### Do not write this yourself
Two reference implementations exist. Fidelius, at [github.com/sukreet/fidelius](https://github.com/sukreet/fidelius), and the Fidelius CLI, which is Java, with worked examples for Node.js, Python, Ruby and PHP at [github.com/mgrmtech/fidelius-cli](https://github.com/mgrmtech/fidelius-cli/tree/main/examples) that run the binary as a subprocess. A webinar covers the CLI from both sides, at [youtu.be/rSir2gbkEmk](https://youtu.be/rSir2gbkEmk?t=9232) from 2:33:52.
### What happens
Generate a fresh key pair and nonce per transfer. XOR the two nonces: the first 20 bytes are the HKDF salt, the last 12 the IV. Derive the key with HKDF-SHA256 over the x coordinate of the ECDH result, with an empty `info`, for 32 bytes. Encrypt with AES-256-GCM, no additional authenticated data, and append the 16 byte tag before base64 encoding.
### How you know it worked
The HIU decrypts every entry and its tag check passes. Before any peer is involved, round trip a record through the Fidelius CLI and compare bytes.
### When it goes wrong
Every tag check fails: compare the salt and IV split, the HKDF input (the x coordinate, not the whole shared secret) and an `info` or additional data that should be empty. One HIP fails while others work: compare how its public key is encoded.
## Reading an ABDM error code
### In plain words
ABDM returns [several different error shapes](/docs/hiecm/v3/api/m1/errors), and
only some of them carry a code. Parse for all of them before you write any handling,
because the shape tells you where the failure came from.
Every code in the [error code reference](/docs/hiecm/v3/reference/error-codes)
carries an action. Key your handling to that column rather than to a list of
codes you maintain by hand.
| Action | What your code does |
| --- | --- |
| Fix request | Do not retry. Something you sent is wrong, and sending it again will not help |
| Fix auth | Fetch a fresh token, then retry once |
| New request id | Generate a new `REQUEST-ID`, then retry once |
| Retry | Back off and retry, with a ceiling on attempts |
| Cannot proceed | Stop, and tell the person why in their own terms |
| Ask support | Stop, and collect the ids before the context is lost |
| Unclassified | Treat as Cannot proceed until you have seen it once and know better |
Symptom first debugging, for the failures that produce no useful code at all, is
in [troubleshooting](/docs/hiecm/v3/troubleshooting).
Read the code in the body before the HTTP status. A 404 can carry `ABDM-1016`,
Invalid Timestamp: the route exists and the request was refused. A 404 whose
body carries `Status report` and no code means no route matched the request. A
code can arrive bare or with a trailing colon and space, as in `ABDM-1016: `, so
match on the code itself.
### What happens
Parse the body for an error code before acting on the status. Strip a trailing colon and space from the code, then key the handling on the action column of the [error code reference](/docs/hiecm/v3/reference/error-codes), not on a list maintained by hand.
### How you know it worked
Given a code, you can say what it means and which header or field it concerns: `ABDM-2403` is Invalid X-CM-ID, the consent manager header.
### When it goes wrong
A one line message is read as a diagnosis: Invalid header covers many causes. A code that is not in the reference is handled as Unclassified, not guessed at. A 404 is treated as a wrong path when its body carries a code.
## Roles, which entity your software acts for and which way the record moves
### In plain words
There are two integrator roles on HIE-CM, and your product is one of them for its
whole life. What decides it is which entity your software acts for.
| Role | It acts for | What you build |
| --- | --- | --- |
| [IMS](/docs/hiecm/v3/getting-started/glossary#ims) | A care provider. An HMIS in a hospital, an EMR in a clinic, a LIMS in a laboratory, a PMS in a pharmacy | [M1](/docs/hiecm/v3/milestones/m1) to [M4](/docs/hiecm/v3/milestones/m4) |
| [PHR](/docs/hiecm/v3/getting-started/glossary#phr) | A care seeker, who holds their own records and gives consent | [P1](/docs/hiecm/v3/milestones/p1) to [P3](/docs/hiecm/v3/milestones/p3) |
[HIP](/docs/hiecm/v3/getting-started/glossary#hip) and
[HIU](/docs/hiecm/v3/getting-started/glossary#hiu) are not a third and a fourth
role, and they are not something you register as. They are the two ends of one
record moving: whoever publishes it is the HIP for that exchange, and whoever
asks to read one they did not create is the HIU.
Both roles are both, and it changes call by call:
- A hospital is the HIP when it shares a discharge summary, and the HIU when it pulls an earlier prescription, through the same IMS.
- A citizen is the HIP when they push a record from their PHR application, and the HIU when they fetch one.
Neither is a thing you can build once and be. See
[HIP and HIU](/docs/hiecm/v3/concepts/hip-hiu).
So the milestones you build follow the direction your records move, not the kind
of product you sell. A PHR app that lets a citizen push a record publishes as
the HIP, and builds the M2 linking and transfer calls as well. See
[where the citizen is the HIP](/docs/hiecm/v3/milestones/p2#where-the-citizen-is-the-hip).
Records never pass through the consent manager: it routes the request and holds
the consent, and the record goes from the system that holds it to the system
that asked.
### What happens
Decide the role once, IMS or PHR, from the entity. Then list every direction a record moves through the product: publishing a record is HIP behaviour, fetching one it did not create is HIU behaviour. Build the milestones for each direction the product uses.
### How you know it worked
For a hospital system that also pulls a patient's history, you can name the role, IMS, both directions, and the milestones: M1, M2 and M3. For a PHR app that uploads a scanned prescription, you can say the citizen is the HIP for that record.
### When it goes wrong
HIP, HIU, health repository and health locker are chosen as though they were one list of company types: two are directions, one is custody, one is a product. A PHR app is built for P1 alone and then cannot publish the first record a citizen pushes. A fetch is designed against the consent manager, which holds no records.
## Where these came from
- `hiecm.concept.m2-exchange-not-call`
- `hiecm.concept.m2-never-block-the-desk`
- `hiecm.concept.m2-retry-is-a-duplicate`
- `hiecm.concept.m2-integrator-call-panel`
- `hiecm.concept.m2-inbound-is-a-surface`
- `hiecm.concept.m2-care-context-and-records`
- `hiecm.concept.asynchronous-callbacks`
- `hiecm.concept.callback-authenticity`
- `hiecm.concept.care-context`
- `hiecm.concept.data-flow-encryption`
- `hiecm.concept.error-codes`
- `hiecm.concept.roles`

View File

@ -0,0 +1,70 @@
# Integrate M2, create and link records
The calls themselves: where they live, what they need in their headers, and one request written out in full.
## Hosts
- `https://dev.abdm.gov.in` ABDM gateway, sandbox
- `https://apis.abdm.gov.in` ABDM gateway, production
## Endpoints
24 operations, grouped by the journey they belong to.
### Other operations
| Method | Path | What it does |
| --- | --- | --- |
| `POST` | `/api/hiecm/consent/v3/request/hip/on-notify` | Acknowledge the notification sent when a consent request is approved/revoked/ex… |
| `POST` | `/api/hiecm/data-flow/v3/health-information/hip/on-request` | Health information data request acknowledgement from HIP. |
| `POST` | `/api/hiecm/data-flow/v3/health-information/notify` | Notifications corresponding to events during data flow |
| `GET` | `/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id}` | Fetch the details of a service ID. |
| `GET` | `/api/hiecm/gateway/v3/bridge-services` | Fetch the service ids registered against a bridge. |
| `PATCH` | `/api/hiecm/gateway/v3/bridge/url` | Update the bridge URL. |
| `POST` | `/api/hiecm/gateway/v3/sessions` | Generate access token. |
| `POST` | `/api/hiecm/hip/v3/link/carecontext` | Perform HIP initiated linking. |
| `POST` | `/api/hiecm/hip/v3/link/context/notify` | Notify CM about any update on the already linked care context for a patient. |
| `POST` | `/api/hiecm/hip/v3/link/patient/links/sms/notify2` | Send SMS notification to patient that a care context is linked. |
| `POST` | `/api/hiecm/user-initiated-linking/v3/link/care-context/on-confirm` | Sharing the response of /api/hiecm/user-initiated-linking/v3/link/care-context/… |
| `POST` | `/api/hiecm/user-initiated-linking/v3/link/care-context/on-init` | As a result of the initialization, HIP has to generate a unique reference-numbe… |
| `POST` | `/api/hiecm/user-initiated-linking/v3/patient/care-context/on-discover` | HMIS/LIMS/HIP has to ensure that only unlinked records of the patient has to be… |
| `POST` | `/api/hiecm/v3/token/generate-token` | Generate link token to link the health records |
| `POST` | `/api/v3/consent/request/hip/notify` | This is a callback API to notify HIP when consent is APPROVED or REVOKED. |
| `POST` | `/api/v3/hip/health-information/request` | Health information data request to HIP. |
| `POST` | `/api/v3/hip/link/care-context/confirm` | Confirm the linking of care contexts for a patient. It allows healthcare inform… |
| `POST` | `/api/v3/hip/link/care-context/init` | Initiate the linking of care contexts for a patient. It allows healthcare infor… |
| `POST` | `/api/v3/hip/patient/care-context/discover` | Discover care contexts associated with a patient. It allows healthcare informat… |
| `POST` | `/api/v3/hip/token/on-generate-token` | This is a call back API of [/api/hiecm/v3/token/generate-token]. |
| `POST` | `/api/v3/link/on_carecontext` | Is a callback API that will be called by HIE-CM. The response will be received … |
| `POST` | `/api/v3/links/context/on-notify` | This API endpoint is a call back API for /api/hiecm/hip/v3/link/context/notify … |
| `POST` | `/api/v3/patients/sms/on-notify` | This API endpoint is a call back API for /api/hiecm/hip/v3/link/patient/links/s… |
| `POST` | `/health-information/transfer` | health information transfer API |
## Headers
| Header | What it is |
| --- | --- |
| `REQUEST-ID` | Unique UUID for track the end to end request transaction |
| `TIMESTAMP` | Actual time of the request was initiated, ISO 8601 represents date and time by starting with the year, follow… |
| `X-CM-ID` | Suffix of the consent manager to which the request was intended |
| `X-HIP-ID` | Identifier of the health information provider to which the request was intended |
| `X-LINK-TOKEN` | JWT Authentication token which was issued by ABDM after successful validation of username and password |
| `X-HIU-ID` | Identifier of the health information user to which the request was intended |
## A request, in full
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/consent/v3/request/hip/on-notify \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"acknowledgement": {
"status": "OK",
"consentId": "e3c74829-3f82-4f94-959e-e10f57bcd57b"
},
"response": {
"requestId": "6f0b4665-a915-4c92-aa36-65afb4a2cd71"
}
}'
```

View File

@ -0,0 +1,562 @@
# HIE-CM m2 build
Scaffolds an ABDM m2 integration one journey at a time. It covers care contexts, HIP initiated linking, discovery, and pushing encrypted records to a requester.
## How this skill runs
Every journey below is an OODA loop, not a recipe: observe the actual state (last response, last error), orient against the step matched below, decide the cheapest next action, act, and return to observe. A step is done only when its exit condition is observed against the sandbox, never because it "should have worked."
Loop limit: 8 passes per step. Hitting the limit is an escalation: state what was observed, what was tried, and which operation page to read, then ask one question.
## Before the first journey, when the codebase already exists
Skip this section only for a system that does not exist yet. Otherwise it runs first, and its exit condition is a written plan, not a call.
### In plain words
Most ABDM integrations are not new systems. They are a hospital management
system, a laboratory system or a clinic application that already has patients,
visits, records, a login, an HTTP client and a way of keeping secrets. Every
ABDM journey has to land somewhere inside that, and a journey built before the
codebase has been read lands in the wrong place: a second HTTP client beside the
first, an ABHA column on the wrong table, a callback route the reverse proxy
never forwards.
So the first loop is not a journey. It is a survey of the system as it is, and
its exit condition is a written plan that names, for every ABDM touchpoint, the
file it will live in. The journeys then build against that plan rather than
against the specification's idea of a fresh codebase.
### Before you start
- The repository, checked out, with permission to read all of it. A survey of
half a codebase produces a plan for half a system.
- The answers to the deployment interview. The
code says what the system is. Only the integrator can say what the
deployment is, and the two together decide which journeys are built at all.
- The practices that hold across every call, which
the plan has to leave room for.
### What happens
This is one loop with a limit of eight passes over the codebase. Each pass
reads live state only, which here means the files themselves, never a README's
description of them and never an assumption carried from a similar system.
**Observe.** Inventory the system from its manifests and its tree, not from its
documentation. Record file paths for each of these, or record that none exists:
| Find | Where it usually shows | Why ABDM needs it |
|---|---|---|
| Languages and runtime versions | package manifests, lock files, toolchain files | Every generated call has to be idiomatic here |
| Build, run and test commands | manifests, CI configuration, a Makefile | Each journey's exit condition becomes a test that runs the same way |
| The frontend and backend split, and how they talk | the top level tree, an API client in the frontend, route definitions in the backend | The counter screens go in the frontend; every ABDM call goes through the backend |
| The outbound HTTP client the backend already uses | the dependency list, a shared client module | ABDM calls reuse it, or a second one appears and the two drift |
| How secrets and configuration reach the process | environment loading, a vault client, a config file | The client id, the secret and the access token travel the same way |
| The patient model, and the identifier fields it already carries | the schema, the ORM models, the migrations | The ABHA number and address become columns beside the existing identifiers, not a new table |
| The visit, encounter or record model | the same places | A care context maps to one of these, and the plan has to say which |
| Where inbound HTTP is routed and authenticated, and whether the deployment has a public URL | the router, the middleware, the reverse proxy configuration, the deployment manifests | ABDM calls back, and a callback route that nothing forwards is silence nobody notices |
| Existing cryptography helpers | a security or crypto module, the dependency list | The RSA encryption of identifiers reuses them |
| Where errors are shown to a user, and where they are logged | the frontend's error surface, the logging setup | A refused call has to land on the screen the person is looking at, and never log a token |
**Orient.** Map each ABDM touchpoint onto that inventory. Where the map is
exact, write the file path. Where it is not, write two candidates and say what
would decide between them. The common ambiguities: two places that could hold
the patient identifier, an HTTP client in the frontend and none in the backend,
a monorepo with several services and no obvious owner for callbacks.
Then read the interview answers against the inventory. A government integrator
gets the demographic route; a facility with no public URL gets no callback
driven journey until it has one; a desk with a fingerprint reader gets the
biometric method. The route set is the intersection of what the deployment
allows and what the code can host.
**Decide.** Order the journeys. The token comes first because every other call
needs it: the gateway session token, or for M4 the bearer token the registry calls
carry. Then the journey whose exit condition can be observed with
the least new code, usually a profile read for a patient who already holds an
ABHA. Creation and linking come after, because each depends on state the earlier
ones produce. For each journey, name the files it will touch and the test that
proves its exit condition.
**Act.** Write the plan. It is a file in the repository, at the path the
integrator names or at the root as `abdm-integration-plan.md`, and it is the
only output of this loop. Then return to observe once, reading the plan against
the tree, to confirm every path in it exists or is marked as new.
If the limit is reached with questions still open, escalate: name what was
found, name the two candidates that could not be separated, point at this
atom, and ask one question.
### How you know it worked
The plan exists and answers every row of the inventory table with a file path,
or with the words none, add at, followed by a path. No row is blank and no row
says to be decided.
Every ABDM touchpoint in the plan names one file, or names two candidates and
the observation that would choose between them. Every journey in the plan names
the test that proves its exit condition and the command that runs it.
Open the plan beside the tree. Every path it names resolves, or is marked as
new. That is the observation that ends this loop, and the first journey does
not start until it has been made.
### When it goes wrong
- **The plan puts the HTTP client in the frontend.** The survey found the
frontend's API client and stopped. Every ABDM call carries a secret, so it
goes through the backend, and the plan has to say which backend module.
- **Two patient tables, and the plan picked one.** Orient produced one
hypothesis where it needed two. Name both, and name the query that shows
which one the visit model points at.
- **The plan has a callback route and the deployment has no public URL.** The
inventory row on inbound routing was answered from the router rather than
from the deployment. Mark every callback driven journey as blocked on a URL,
and build the ones that are not.
- **The survey read the README and not the tree.** A README describes the
system somebody meant to build. The plan is for the one that exists.
- **Eight passes and the plan is still incomplete.** Escalate with the rows
that are answered, the rows that are not, this atom, and one question about
the row that blocks the most journeys.
From `shared.concept.survey-an-existing-codebase`.
## Journeys
### Link token (`m2-abdm-link-token-hip`)
**Act: the calls in this journey, in order**
#### 1. Generate link token to link the health records (`m2_post_v3_token_generate_token`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/v3/token/generate-token \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-HIP-ID: IN2810014366' \
--header 'Content-Type: application/json' \
--data '{
"abhaNumber": 12345678901234,
"abhaAddress": "<ABHA_ADDRESS>",
"name": "first_name + middle_name + last_name",
"gender": "M",
"yearOfBirth": 9999
}'
```
**Exit condition (Observe until this is true)**
Each call you made in this journey answered by its callback, with `response.requestId` equal to the `REQUEST-ID` you sent on that call. The 202 on a call is receipt, not the outcome: the outcome is in the callback's body.
- `POST /api/hiecm/v3/token/generate-token` is answered by `POST /api/v3/hip/token/on-generate-token` on your bridge.
### HIP initiated linking (`m2-abdm-hip-initiated-linking-hip`)
**Act: the calls in this journey, in order**
#### 1. Perform HIP initiated linking (`m2_post_hip_v3_link_carecontext`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/hip/v3/link/carecontext \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-HIP-ID: IN2810014366' \
--header 'X-LINK-TOKEN: <TOKEN>' \
--header 'Content-Type: application/json' \
--data '{
"abhaNumber": 12345678901234,
"abhaAddress": "<ABHA_ADDRESS>",
"patient": [
{
"referenceNumber": "TMH-PUID-001",
"display": "String",
"careContexts": [
{
"referenceNumber": "TMH-PUID-001",
"display": "display 1"
}
],
"hiType": "DiagnosticReport",
"count": 1
}
]
}'
```
#### 2. Notify a change to a linked care context (`m2_post_hip_v3_link_context_notify`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/hip/v3/link/context/notify \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-HIP-ID: IN2810014366' \
--header 'Content-Type: application/json' \
--data '{
"notification": {
"patient": {
"id": "<ABHA_ADDRESS>"
},
"careContext": {
"patientReference": "<ABHA_ADDRESS>",
"careContextReference": "b009a970-8b04-4779-abd1-b50f113245bf"
},
"hiTypes": [
"DiagnosticReport"
],
"date": "2024-05-09T10:34:00.387Z",
"hip": {
"id": "ABDM_HIP"
}
}
}'
```
#### 3. Send SMS notification to patient that a care context is linked (`m2_post_hip_v3_link_patient_links_sms_notify2`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/hip/v3/link/patient/links/sms/notify2 \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"notification": {
"phoneNo": "986543***",
"hip": {
"id": "ABDM_HIP",
"name": "ABC Hospital"
}
}
}'
```
**Exit condition (Observe until this is true)**
Each call you made in this journey answered by its callback, with `response.requestId` equal to the `REQUEST-ID` you sent on that call. The 202 on a call is receipt, not the outcome: the outcome is in the callback's body.
- `POST /api/hiecm/hip/v3/link/carecontext` is answered by `POST /api/v3/link/on_carecontext` on your bridge.
- `POST /api/hiecm/hip/v3/link/context/notify` is answered by `POST /api/v3/links/context/on-notify` on your bridge.
- `POST /api/hiecm/hip/v3/link/patient/links/sms/notify2` is answered by `POST /api/v3/patients/sms/on-notify` on your bridge.
### User initiated linking (`m2-abdm-user-initiated-linking-hip`)
**Act: the calls in this journey, in order**
#### 1. Answer the care context discovery (`m2_post_user_initiated_linking_v3_patient_care_context_on_8c9340`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/user-initiated-linking/v3/patient/care-context/on-discover \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-HIU-ID: IN2810014366' \
--header 'Content-Type: application/json' \
--data '{
"transactionId": "f901b782-bfdf-4224-9f8d-da2cadc20c0d",
"patient": [
{
"referenceNumber": "<ABHA_ADDRESS>",
"display": "12345",
"careContexts": [
{
"referenceNumber": "abc123",
"display": "12345"
}
],
"hiType": "Prescription",
"count": 1
}
],
"matchedBy": [
"MR"
],
"response": {
"requestId": "f29f0e59-8388-4698-9fe6-05db67aeac46"
}
}'
```
#### 2. Link care context on init (`m2_post_user_initiated_linking_v3_link_care_context_on_init`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/user-initiated-linking/v3/link/care-context/on-init \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"transactionId": "f901b782-bfdf-4224-9f8d-da2cadc20c0d",
"link": {
"referenceNumber": "d353b782-bfdf-4224-9f8d-da2cadc20c0d",
"authenticationType": "DIRECT",
"meta": {
"communicationMedium": "MOBILE",
"communicationHint": "OTP",
"communicationExpiry": "2024-05-01T05:22:34.123Z"
}
},
"response": {
"requestId": "f29f0e59-8388-4698-9fe6-05db67aeac46"
}
}'
```
#### 3. Link care context on confirm (`m2_post_user_initiated_linking_v3_link_care_context_on_confirm`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/user-initiated-linking/v3/link/care-context/on-confirm \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"patient": [
{
"referenceNumber": "<ABHA_ADDRESS>",
"display": "12345",
"careContexts": [
{
"referenceNumber": "abc123",
"display": "12345"
}
],
"hiType": "Prescription",
"count": 1
}
],
"response": {
"requestId": "f29f0e59-8388-4698-9fe6-05db67aeac46"
}
}'
```
**Exit condition (Observe until this is true)**
A 202 on this reply, sent with `response.requestId` set to the `REQUEST-ID` of the `POST /api/v3/hip/link/care-context/confirm` request it answers. A reply without that id answers nothing.
### Consent and data flow (`m2-consent-management-data-flow-hip`)
**Act: the calls in this journey, in order**
#### 1. Acknowledge the consent notification (`m2_post_consent_v3_request_hip_on_notify`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/consent/v3/request/hip/on-notify \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"acknowledgement": {
"status": "OK",
"consentId": "e3c74829-3f82-4f94-959e-e10f57bcd57b"
},
"response": {
"requestId": "6f0b4665-a915-4c92-aa36-65afb4a2cd71"
}
}'
```
#### 2. Submit the health information data request acknowledgement from HIP (`m2_post_data_flow_v3_health_information_hip_on_request`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/data-flow/v3/health-information/hip/on-request \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"hiRequest": {
"transactionId": "18235d89-cb13-479d-ad71-7a57d5f669a8",
"sessionStatus": "ACKNOWLEDGED"
},
"response": {
"requestId": "6f0b4665-a915-4c92-aa36-65afb4a2cd71"
}
}'
```
#### 3. Submit the notifications corresponding to events during data flow (`m2_post_data_flow_v3_health_information_notify`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/data-flow/v3/health-information/notify \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"notification": {
"consentId": "18235d89-cb13-479d-ad71-7a57d5f669a8",
"transactionId": "18235d89-cb13-479d-ad71-7a57d5f669a8",
"doneAt": "2023-01-24T06:35:44.167Z",
"notifier": {
"type": "HIP",
"id": "IN2810014366"
},
"statusNotification": {
"sessionStatus": "TRANSFERRED",
"hipId": "IN2810014366",
"statusResponses": [
{
"careContextReference": "10004-20200001768-1",
"hiStatus": "DELIVERED",
"description": "Data sent successfully"
}
]
}
}
}'
```
**Exit condition (Observe until this is true)**
A 202 response. The specification gives no body for it, so read what comes back.
### Callbacks (`m2-callbacks`)
**Act: the calls in this journey, in order**
#### 1. Receive the HIP token on generate token (`m2_post_v3_hip_token_on_generate_token`)
Inbound to your bridge at `/api/v3/hip/token/on-generate-token`. Acknowledge it and continue.
#### 2. Link on carecontext (`m2_post_v3_link_on_carecontext`)
Inbound to your bridge at `/api/v3/link/on_carecontext`. Acknowledge it and continue.
#### 3. Receive the links context on notify (`m2_post_v3_links_context_on_notify`)
Inbound to your bridge at `/api/v3/links/context/on-notify`. Acknowledge it and continue.
#### 4. Receive the patients SMS on notify (`m2_post_v3_patients_sms_on_notify`)
Inbound to your bridge at `/api/v3/patients/sms/on-notify`. Acknowledge it and continue.
#### 5. Discover care contexts associated with a patient (`m2_post_v3_hip_patient_care_context_discover`)
Inbound to your bridge at `/api/v3/hip/patient/care-context/discover`. Acknowledge it and continue.
#### 6. Initiate the linking of care contexts for a patient (`m2_post_v3_hip_link_care_context_init`)
Inbound to your bridge at `/api/v3/hip/link/care-context/init`. Acknowledge it and continue.
#### 7. Confirm the linking of care contexts for a patient (`m2_post_v3_hip_link_care_context_confirm`)
Inbound to your bridge at `/api/v3/hip/link/care-context/confirm`. Acknowledge it and continue.
#### 8. Receive the consent decision (`m2_post_v3_consent_request_hip_notify`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/v3/consent/request/hip/notify \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-HIP-ID: IN2810014366' \
--header 'Content-Type: application/json' \
--data '{
"notification": {
"status": "GRANTED",
"consentId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"consentDetail": {
"schemaVersion": "v3",
"consentId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"createdAt": "2024-05-01T05:10:20.123Z",
"patient": {
"id": "<ABHA_ADDRESS>"
},
"careContexts": [
{
"patientReference": "batman@tmh",
"careContextReference": "Episode1"
}
],
"purpose": {
"text": "Care Management",
"code": "CAREMGT",
"refUri": "www.abc.com"
},
"hip": {
"id": "cowin_hip_01",
"name": "Cowin",
"type": "HIP"
},
"hiu": {
"id": "cowin_hiu_01",
"name": "Cowin",
"type": "HIU"
},
"consentManager": {
"id": "abdm"
},
"requester": {
"name": "<ABHA_ADDRESS>",
"identifier": {
"value": "REG1",
"type": "MH1001",
"system": "https://www.sample.com"
}
},
"hiTypes": [
"Prescription"
],
"permission": {
"accessMode": "VIEW",
"dateRange": {
"from": "2021-09-28T12:30:08.573Z",
"to": "2021-09-28T12:30:08.573Z"
},
"dataEraseAt": "2021-09-28T12:30:08.573Z",
"frequency": {
"unit": "HOUR",
"value": 1,
"repeats": 0
}
}
},
"signature": "e8nY601CYDsC0FKoDjSp+7GeQ2s2R8oZncLCz5ce+pEuDOr5bZV0aaHjwJg4b9S9V+twjt4hbojx3fl7egrt8+0c+lfPTi5/bBUAQXCABTfFmtFU7jn65HlTt8kgkiONx26ZBhJ0wX3xjYI72PPtzYIiT5Q08YtDoILA62KceioV7lwuKssw7wC4ECbBAvRuXT121TmtrPhf+0myJATSnaajS06S6OthrKfZLNTUFf3pFiJzqouSTrjNblOX6DT2+JuO3rom1Szz/03c0HQG+wWASv+PO3J6uRs0UI4JvKmM/4tP+Z+/HPKM15K5U5K+4pqf6czKrbIDpkT/kP8bGg==",
"grantAcknowledgement": false
}
}'
```
#### 9. Receive the health information data request to HIP (`m2_post_v3_hip_health_information_request`)
Inbound to your bridge at `/api/v3/hip/health-information/request`. Acknowledge it and continue.
#### 10. Push the encrypted records to the HIU's data push URL (`m2_post_health_information_transfer`)
Outbound from your bridge. POST each page of encrypted records to the `dataPushUrl` in the health information request of step 9. The call goes straight to the HIU, not through the gateway. The HIU answers 202 for each page.
**Exit condition (Observe until this is true)**
A 202 response. The specification gives no body for it, so read what comes back.
## Where the detail is
- Every operation, with its body fields and responses: /docs/hiecm/v3/api/m2
- Error codes: /docs/hiecm/v3/api/m2/errors

View File

@ -0,0 +1,91 @@
---
name: abdm-m3
description: Use when building, debugging or testing ABDM Milestone 3: raising a consent request, tracking its status, reading consent artefacts, and fetching encrypted health records as an HIU. Carries the endpoints and the consent rules. Also carries the scaffolding loop that builds it flow by flow and the loop from a failed call to a named fix, in references/.
type: skill
domain: m3
agent_consumers:
- abdm-integration-agent
- abdm-call-debugger
requires:
- gateway-session-token
- hiu-registration
- callback-url
- abha-address
produces:
- consent-request-id
- consent-artefact
can_execute: true
can_orchestrate: false
---
# ABDM M3, fetch data with consent
Generated from the ABDM Developer Portal on 2026-09-16, catalogue version 2026.09.16. Every fact below comes from a page in that portal, which is the place to look when this file does not carry enough.
This file is a snapshot. Re-download the whole folder from https://docs.abdm.gov.in/skills/abdm-m3/ when it is older than the work you are doing: this router and every file under references/ that it links to. Fetching this file alone leaves those links pointing at files you do not have.
If the abdm-docs MCP server is connected, trust its answers over this file: it serves the current catalogue and stamps every response with its catalogue_version, which you can compare against the version above.
## What you can do with M3
- Ask a patient, through their consent manager, for records another provider holds.
- Track that request through a grant, a denial, a revocation and an expiry.
- Receive the encrypted records at your data push URL and decrypt them.
- Handle one request that produces several consent artefacts.
What it cannot do yet matters as much. Read **Before anything else** below before assuming a capability is one endpoint away.
## Try asking
- "Raise a consent request and fetch the records it covers"
- "What has to be in place before my first M3 call?"
- "My M3 call failed. Here is the response: what is wrong, and how do I fix it?"
Loaded with no task? Say in three lines what this skill does. Offer the prompts above. Then ask what the person is building, and whether the code for it exists yet.
## What is in this folder
- **Scaffold.** Survey the codebase first when one exists, then build it flow by flow against the sandbox, as a loop that ends when the step's exit condition holds rather than on a call returning 200. [references/scaffold.md](references/scaffold.md)
- **Design.** What the journey around the calls has to do, and what a screen is forbidden to claim. [references/design.md](references/design.md)
- **Integrate.** 16 operations, with their hosts and headers. [references/integrate.md](references/integrate.md)
- **Debug.** The specification's examples return no error code for this module. [references/debug.md](references/debug.md)
This file is the map. Each line above is a file beside it, opened one at a time rather than read through.
## Before anything else
- Treat every request and response shape in this skill as unconfirmed until the sandbox has answered you. Check a response before you rely on its shape.
- The design section is different in kind. Its rules come from building a working front desk against the sandbox, and each atom it cites names what was observed and the date it was seen.
- One consent request produces one artefact per HIP, so store the request id and every artefact id. Taking the first element is the bug that silently drops half a fetch.
- You act as the HIU. The HIE-CM holds the consent and asks the patient on your behalf. No artefact, no records.
- The patient must be known to you by ABHA address before you can raise a request.
- Records arrive encrypted at the `dataPushUrl` the health information request names. Decrypt them with the key material that request carries.
## Practices that hold across every call
- Read the body, not only the status. A refusal often names the field in its body while the status says nothing useful.
- When ABDM publishes a value, read it rather than hard coding what it currently says. That covers a parameter, such as the encryption algorithm the certificate endpoints return beside the key, and it covers an enumeration. The registries publish theirs as master data calls: councils, courses, colleges, states and districts on the HPR, and facility types and LGD codes on the HFR. A table typed into your source goes stale silently. Purposes and HI types have no master data call: take them from the enumeration in the specification of the call you are making. Refuse to act on a published value you do not recognise rather than falling back to a default.
- Read every field in a response, not the one you came for. The M1 certificate call returns the encryption algorithm next to the key.
- Prove an assumption against a call that is able to disagree with you. A call that refuses every input with one message cannot tell you which input was right.
- Suspect the transport before the data. When a call refuses a value you believe in, check the encryption, the headers and the clock before you doubt the value.
- Do not carry an encryption path from one module to another. Read the certificate and the algorithm from the registry you are calling.
- Never log a sensitive value before you encrypt it, and never send one to a remote service to be encrypted. Both move the leak rather than removing it.
- Generate a fresh REQUEST-ID for every call and log it before sending. Once a call has failed it is the only handle on it.
- Check the host on any sample before you copy it. A request copied whole can be correct in every respect except where it is pointed, and that failure looks like credentials.
- Do not validate an identifier more strictly than the platform does. A schema that types a field as a UUID is not a promise that every value is one. Refusing a value ABDM would have accepted turns your own client into the thing that broke.
- Read a plural response as plural. A verification returns an accounts array and a consent request can produce more than one artefact. Store the collection and decide from its length.
- A documented callback path is not a documented callback payload. Log the whole body on arrival before you parse it, so a handler written against an assumed shape fails where you can see it.
- Decode a token before you use it. A call that hands you a token has not necessarily handed you the token the next call wants, and the claims are base64 that need no library to read.
- When a journey carries the same parameter through two calls, check what each call's specification asks for rather than carrying the first value forward.
- Do not infer which path an identifier belongs to from where that identifier is most discussed. Send every identifier to the lookup first and let the answer pick the path, so nobody who already holds an account is sent to create a second.
- Do not match an error code with string equality. A code may come back bare, as `ABDM-1001`, or with a trailing `: ` separator, as `ABDM-1001: `. Match on the code itself and tolerate the separator.
- Handle a failure that carries no body. Check for an empty body before you parse, or your client throws on the simplest failure there is.
- Back off on an authentication failure rather than retrying, and never loop a credential check.
- Send TIMESTAMP in UTC, ISO-8601 with milliseconds and a trailing Z, as in `2022-10-06T15:10:00.587Z`.
- Cache a public certificate with a validity window rather than forever. A rotation fails every encrypted call at once, and a cache with no expiry cannot recover on its own.
## Where the detail is
- Every endpoint, with its body fields and responses: /docs/hiecm/v3/api/m3
- The flows as diagrams: /docs/hiecm/v3/milestones/m3
- Every error code across modules: /docs/hiecm/v3/reference/error-codes
- Terms: /docs/hiecm/v3/getting-started/glossary

View File

@ -0,0 +1,9 @@
# Debug M3, fetch data with consent
The codes this module can return, with the message and the operation that returns each.
## Errors
The M3, fetch data with consent specification's examples return no error code yet. That is a gap in the specification, not a promise that this module cannot fail.
A code you meet that is not above is one the specifications do not carry yet. Read the code together with the message: a code can appear twice with different meanings.

View File

@ -0,0 +1,156 @@
# Design M3, fetch data with consent
What the integration has to do to the journey around the calls: how many questions a patient is asked, where a failure is shown, and what a screen is forbidden to claim. Every rule below comes from a Catalogue atom, cited at the end.
## Read plural as plural, and never translate a code into a meaning
### In plain words
Two habits cause most of the avoidable failures on the consent side, and both
are about reading what came back rather than what you expected.
A consent request produces one artefact per HIP, so a request that spans
facilities returns several. Taking the first element is
the bug that silently drops half a fetch.
And the same error code means different things in different modules, so a code
alone is not a meaning.
### What happens
Hold the collection. A length of one is a case, not the normal case. It is worth
having a function whose existence prevents any call site from reaching for the
first element, because the failure is silent: half the records simply never
arrive, and nothing reports an error.
Carry ABDM's message through to the screen and never translate a code into words
of your own. `ABDM-1112` is an unusable consent in one place and a DigiLocker
gender mismatch in a module error table. `ABDM-1062` is a withheld consent in
one and a link token mismatch in another. Whichever you choose to display, you
will be wrong for the other module, and the message ABDM sent is the only part
that names the actual cause.
Handle two answers from consent status and consent fetch. The specification
documents them as synchronous responses carrying a status and an artefact
array. One run against ids that did not exist returned `202` with an empty
body instead. That single observation is not a rule: check the status before
you read the body, treat a `200` as the documented answer, treat a `202` with
no body as an acknowledgement whose answer arrives on the callback, and confirm
which you get on your own data before building on either.
### How you know it worked
Raise a consent covering care contexts at two HIPs. The number of artefacts you
hold matches the number ABDM returned, and a fetch runs for each one.
Trigger a refusal. The screen shows ABDM's own message text alongside the code,
and no wording of your own has replaced it.
### When it goes wrong
- A fetch returns fewer records than the consent covers, and nothing errors.
Something took the first artefact and discarded the rest.
- A displayed explanation contradicts what ABDM sent. A code was translated
locally instead of the message being carried through.
- A `202` with an empty body is read as a failure, or a `200` with a body is
parsed as if it were empty. The status decides which answer you hold.
## Refuse to guess an undocumented step, and say so before the work starts
### In plain words
M3's data transfer needs a key derivation and a symmetric cipher over the shared
secret. Neither is in the specification. The
[data flow page](/docs/hiecm/v3/concepts/data-flow) and the
Fidelius reference give the
scheme: HKDF over the shared secret, and AES-GCM for the payload. Build the step
from those. A desk that reads only the specification cannot complete it, and no
amount of care in the code around it changes that.
What matters is where the integrator finds out. A desk that discovers it cannot
decrypt at the moment records arrive has discovered it in the worst place
available: asynchronously, after a consent has been served, with a patient's
records in hand and nothing to do with them.
### What happens
Build every step from what is documented. Where a step is documented nowhere,
throw on it with a message naming exactly what is missing. Not a generic
failure. The name of the step, and what would have to be published for it to
work.
Then report it in the readiness check up front, rather than at the moment the
first encrypted bundle arrives.
The rule generalises past encryption. Where a capability cannot work, say so
before somebody depends on it, in the place they would act on it. A capability
that is going to fail should fail in the readiness check, where an integrator is
already looking for problems, not in a flow where they are looking for records.
Do not add a dependency to paper over a scheme nobody has written down. A guess
with a package name on it is still a guess, and it is harder to find later
because it looks like a decision somebody made deliberately.
### How you know it worked
Open the readiness check before running anything. It names any step that is
documented nowhere as unavailable, and says which part is missing.
Run the flow anyway. Where a step is missing, it fails at that step with a
message naming it, rather than at a later point with a decoding error.
### When it goes wrong
- Records arrive and cannot be read, and the failure reads as a corrupt payload.
The undocumented step failed quietly somewhere earlier.
- A library appeared in the dependency list to solve the cipher, chosen from a
sample rather than from the data flow page. Check it implements HKDF and
AES-GCM as that page gives them.
- The readiness check is green and the capability does not work. The check is
testing configuration rather than capability.
## Consent, what it authorises and how it ends
### In plain words
There are five states, in the two sections a PHR app shows: Requests holds Requested, Denied and Expired; Approved holds Granted and Revoked.
```mermaid
stateDiagram-v2
[*] --> Requested: HIU raises a consent request
Requested --> Granted: Patient approves
Requested --> Denied: Patient refuses
Requested --> Expired: Patient does not act in time
Granted --> Revoked: Patient withdraws access
Granted --> [*]: Validity period ends
```
| State | What it means | What your system does |
| --- | --- | --- |
| Requested | The patient has not acted yet. | Wait. Poll the request status if you need to show progress. |
| Granted | The patient approved, and set how long the access lasts. | Fetch the artefact ids, then request the data. |
| Denied | The patient refused. | Stop. There is no partial result and no retry that changes the answer. |
| Expired | The patient did not act inside the window the HIU set on the request. | Raise a new request if the clinical need is still there. |
| Revoked | The patient withdrew a consent they had already granted. | Stop fetching under that artefact from that moment. |
Two clocks run here. The **request window** is how long the patient has to answer, set by the HIU, and running out produces Expired. The **consent validity period** is how long access lasts once granted, set by the patient as they grant, with a defined expiry date and time. Neither is the **date range**, which says which records are in scope by when the care happened: a consent granted today can cover records from 2019.
Granted is not permanent. Revoked and Expired are ordinary destinations, not faults, and your system will meet both in production.
### What happens
Store the consent request id from the init callback, then every consent artefact id a grant returns. Before each fetch, check the artefact is still usable: the patient can revoke at any time, and the validity period ends on its own.
### How you know it worked
A granted request returns at least one artefact id, and a fetch under it is accepted while the artefact is within its validity period and not revoked.
### When it goes wrong
A fetch that worked last week fails today because the patient revoked or the validity period ended; that is the system working. `ABDM-1062` is consent not granted, and `ABDM-1112` is an artefact id that is invalid or already expired. Records kept past the consent window are a legal problem, not a technical one.
## Where these came from
- `hiecm.concept.m3-plural-artefacts-and-codes`
- `hiecm.concept.m3-refuse-to-guess`
- `hiecm.concept.consent-artefact`

View File

@ -0,0 +1,55 @@
# Integrate M3, fetch data with consent
The calls themselves: where they live, what they need in their headers, and one request written out in full.
## Hosts
- `https://dev.abdm.gov.in` ABDM gateway, sandbox
- `https://apis.abdm.gov.in` ABDM gateway, production
## Endpoints
16 operations, grouped by the journey they belong to.
### Other operations
| Method | Path | What it does |
| --- | --- | --- |
| `POST` | `/api/hiecm/consent/v3/fetch` | Fetch the consent details |
| `POST` | `/api/hiecm/consent/v3/request/hiu/on-notify` | Acknowledge the notification sent when a consent request is approved/denied/rev… |
| `POST` | `/api/hiecm/consent/v3/request/init` | Initiate the consent request |
| `POST` | `/api/hiecm/consent/v3/request/status` | Get consent request status |
| `POST` | `/api/hiecm/data-flow/v3/health-information/notify` | Notifications corresponding to events during data flow |
| `POST` | `/api/hiecm/data-flow/v3/health-information/request` | Health information data request from HIU. |
| `GET` | `/api/hiecm/data-flow/v3/health-information/request/status/{transaction-id}` | Get the current status of the Health Information Request. |
| `GET` | `/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id}` | Fetch the details of a service ID. |
| `GET` | `/api/hiecm/gateway/v3/bridge-services` | Fetch the service ids registered against a bridge. |
| `PATCH` | `/api/hiecm/gateway/v3/bridge/url` | Update the bridge URL. |
| `POST` | `/api/hiecm/gateway/v3/sessions` | Generate access token. |
| `POST` | `/api/v3/hiu/consent/on-fetch` | This is a callback API called by CM to provide fetched consent artefact details… |
| `POST` | `/api/v3/hiu/consent/request/notify` | This is a callback API to notify HIU when consent is APPROVED, DENIED or REVOKE… |
| `POST` | `/api/v3/hiu/consent/request/on-init` | Callback API of consent request for patient HIU. |
| `POST` | `/api/v3/hiu/consent/request/on-status` | Callback API of consent status request. |
| `POST` | `/api/v3/hiu/health-information/on-request` | Health information data request acknowledgement to HIU. |
## Headers
| Header | What it is |
| --- | --- |
| `REQUEST-ID` | Unique UUID for track the end to end request transaction |
| `TIMESTAMP` | Actual time of the request was initiated, ISO 8601 represents date and time by starting with the year, follow… |
| `X-CM-ID` | Suffix of the consent manager to which the request was intended |
| `X-HIU-ID` | Identifier of the health information user to which the request was intended |
## A request, in full
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/consent/v3/fetch \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-HIU-ID: IN2810014366' \
--header 'Content-Type: application/json' \
--data '{
"consentId": "5f7a535d-a3fd-416b-b069-c97d021fbacd"
}'
```

View File

@ -0,0 +1,377 @@
# HIE-CM m3 build
Scaffolds an ABDM m3 integration one journey at a time. It covers raising a consent request, tracking it, and fetching the records it covers as an HIU.
## How this skill runs
Every journey below is an OODA loop, not a recipe: observe the actual state (last response, last error), orient against the step matched below, decide the cheapest next action, act, and return to observe. A step is done only when its exit condition is observed against the sandbox, never because it "should have worked."
Loop limit: 8 passes per step. Hitting the limit is an escalation: state what was observed, what was tried, and which operation page to read, then ask one question.
## Before the first journey, when the codebase already exists
Skip this section only for a system that does not exist yet. Otherwise it runs first, and its exit condition is a written plan, not a call.
### In plain words
Most ABDM integrations are not new systems. They are a hospital management
system, a laboratory system or a clinic application that already has patients,
visits, records, a login, an HTTP client and a way of keeping secrets. Every
ABDM journey has to land somewhere inside that, and a journey built before the
codebase has been read lands in the wrong place: a second HTTP client beside the
first, an ABHA column on the wrong table, a callback route the reverse proxy
never forwards.
So the first loop is not a journey. It is a survey of the system as it is, and
its exit condition is a written plan that names, for every ABDM touchpoint, the
file it will live in. The journeys then build against that plan rather than
against the specification's idea of a fresh codebase.
### Before you start
- The repository, checked out, with permission to read all of it. A survey of
half a codebase produces a plan for half a system.
- The answers to the deployment interview. The
code says what the system is. Only the integrator can say what the
deployment is, and the two together decide which journeys are built at all.
- The practices that hold across every call, which
the plan has to leave room for.
### What happens
This is one loop with a limit of eight passes over the codebase. Each pass
reads live state only, which here means the files themselves, never a README's
description of them and never an assumption carried from a similar system.
**Observe.** Inventory the system from its manifests and its tree, not from its
documentation. Record file paths for each of these, or record that none exists:
| Find | Where it usually shows | Why ABDM needs it |
|---|---|---|
| Languages and runtime versions | package manifests, lock files, toolchain files | Every generated call has to be idiomatic here |
| Build, run and test commands | manifests, CI configuration, a Makefile | Each journey's exit condition becomes a test that runs the same way |
| The frontend and backend split, and how they talk | the top level tree, an API client in the frontend, route definitions in the backend | The counter screens go in the frontend; every ABDM call goes through the backend |
| The outbound HTTP client the backend already uses | the dependency list, a shared client module | ABDM calls reuse it, or a second one appears and the two drift |
| How secrets and configuration reach the process | environment loading, a vault client, a config file | The client id, the secret and the access token travel the same way |
| The patient model, and the identifier fields it already carries | the schema, the ORM models, the migrations | The ABHA number and address become columns beside the existing identifiers, not a new table |
| The visit, encounter or record model | the same places | A care context maps to one of these, and the plan has to say which |
| Where inbound HTTP is routed and authenticated, and whether the deployment has a public URL | the router, the middleware, the reverse proxy configuration, the deployment manifests | ABDM calls back, and a callback route that nothing forwards is silence nobody notices |
| Existing cryptography helpers | a security or crypto module, the dependency list | The RSA encryption of identifiers reuses them |
| Where errors are shown to a user, and where they are logged | the frontend's error surface, the logging setup | A refused call has to land on the screen the person is looking at, and never log a token |
**Orient.** Map each ABDM touchpoint onto that inventory. Where the map is
exact, write the file path. Where it is not, write two candidates and say what
would decide between them. The common ambiguities: two places that could hold
the patient identifier, an HTTP client in the frontend and none in the backend,
a monorepo with several services and no obvious owner for callbacks.
Then read the interview answers against the inventory. A government integrator
gets the demographic route; a facility with no public URL gets no callback
driven journey until it has one; a desk with a fingerprint reader gets the
biometric method. The route set is the intersection of what the deployment
allows and what the code can host.
**Decide.** Order the journeys. The token comes first because every other call
needs it: the gateway session token, or for M4 the bearer token the registry calls
carry. Then the journey whose exit condition can be observed with
the least new code, usually a profile read for a patient who already holds an
ABHA. Creation and linking come after, because each depends on state the earlier
ones produce. For each journey, name the files it will touch and the test that
proves its exit condition.
**Act.** Write the plan. It is a file in the repository, at the path the
integrator names or at the root as `abdm-integration-plan.md`, and it is the
only output of this loop. Then return to observe once, reading the plan against
the tree, to confirm every path in it exists or is marked as new.
If the limit is reached with questions still open, escalate: name what was
found, name the two candidates that could not be separated, point at this
atom, and ask one question.
### How you know it worked
The plan exists and answers every row of the inventory table with a file path,
or with the words none, add at, followed by a path. No row is blank and no row
says to be decided.
Every ABDM touchpoint in the plan names one file, or names two candidates and
the observation that would choose between them. Every journey in the plan names
the test that proves its exit condition and the command that runs it.
Open the plan beside the tree. Every path it names resolves, or is marked as
new. That is the observation that ends this loop, and the first journey does
not start until it has been made.
### When it goes wrong
- **The plan puts the HTTP client in the frontend.** The survey found the
frontend's API client and stopped. Every ABDM call carries a secret, so it
goes through the backend, and the plan has to say which backend module.
- **Two patient tables, and the plan picked one.** Orient produced one
hypothesis where it needed two. Name both, and name the query that shows
which one the visit model points at.
- **The plan has a callback route and the deployment has no public URL.** The
inventory row on inbound routing was answered from the router rather than
from the deployment. Mark every callback driven journey as blocked on a URL,
and build the ones that are not.
- **The survey read the README and not the tree.** A README describes the
system somebody meant to build. The plan is for the one that exists.
- **Eight passes and the plan is still incomplete.** Escalate with the rows
that are answered, the rows that are not, this atom, and one question about
the row that blocks the most journeys.
From `shared.concept.survey-an-existing-codebase`.
## Journeys
### Consent and data flow (`m3-consent-management-data-flow-hiu`)
**Act: the calls in this journey, in order**
#### 1. Initiate the consent request (`m3_post_consent_v3_request_init`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/consent/v3/request/init \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"consent": {
"purpose": {
"text": "Care Management",
"code": "CAREMGT",
"refUri": "www.abc.com"
},
"patient": {
"id": "<ABHA_ADDRESS>"
},
"hip": null,
"hiu": {
"id": "cowin_hiu_01"
},
"careContexts": [
{
"patientReference": "batman@tmh",
"careContextReference": "Episode1"
}
],
"requester": {
"name": "<ABHA_ADDRESS>",
"identifier": {
"value": "REG1",
"type": "MH1001",
"system": "https://www.sample.com"
}
},
"hiTypes": [
"Prescription"
],
"permission": {
"accessMode": "VIEW",
"dateRange": {
"from": "2021-09-28T12:30:08.573Z",
"to": "2021-09-28T12:30:08.573Z"
},
"dataEraseAt": "2021-09-28T12:30:08.573Z",
"frequency": {
"unit": "HOUR",
"value": 1,
"repeats": 0
}
}
}
}'
```
#### 2. Get consent request status (`m3_post_consent_v3_request_status`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/consent/v3/request/status \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-HIU-ID: IN2810014366' \
--header 'Content-Type: application/json' \
--data '{
"consentRequestId": "5f7a535d-a3fd-416b-b069-c97d021fbacd"
}'
```
#### 3. Acknowledge the consent notification (`m3_post_consent_v3_request_hiu_on_notify`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/consent/v3/request/hiu/on-notify \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"acknowledgement": [
{
"status": "OK",
"consentId": "e3c74829-3f82-4f94-959e-e10f57bcd57b"
}
],
"error": {
"code": "ABDM-1001",
"message": "unable to connect database"
},
"response": {
"requestId": "6f0b4665-a915-4c92-aa36-65afb4a2cd71"
}
}'
```
#### 4. Fetch the consent details (`m3_post_consent_v3_fetch`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/consent/v3/fetch \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-HIU-ID: IN2810014366' \
--header 'Content-Type: application/json' \
--data '{
"consentId": "5f7a535d-a3fd-416b-b069-c97d021fbacd"
}'
```
#### 5. Submit the health information data request from HIU (`m3_post_data_flow_v3_health_information_request`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/data-flow/v3/health-information/request \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-HIU-ID: IN2810014366' \
--header 'Content-Type: application/json' \
--data '{
"hiRequest": {
"consent": {
"id": "18235d89-cb13-479d-ad71-7a57d5f669a8"
},
"dateRange": {
"from": "2022-10-06T15:10:00.587Z",
"to": "2022-11-06T15:10:00.587Z"
},
"dataPushUrl": "https://live.ndhm.gov.in/api-hiu/data/notification",
"keyMaterial": {
"cryptoAlg": "ECDH",
"curve": "curve25519",
"dhPublicKey": {
"expiry": "2022-12-28T13:18:20.742Z",
"parameters": "Ephemeral public key",
"keyValue": "BFN7KTdOT0jIAExG2A8Jg+01wMPWxptiGqwHRVvtiVEsUq2FR7P2UdqZxJyPJSeR6muai21iQhasNxnhh8I5M+g="
},
"nonce": "28236d89-cb13-479d-ad71-7a57d5f669a9"
}
}
}'
```
#### 6. Submit the notifications corresponding to events during data flow (`m3_post_data_flow_v3_health_information_notify`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/data-flow/v3/health-information/notify \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"notification": {
"consentId": "18235d89-cb13-479d-ad71-7a57d5f669a8",
"transactionId": "18235d89-cb13-479d-ad71-7a57d5f669a8",
"doneAt": "2023-01-24T06:35:44.167Z",
"notifier": {
"type": "HIU",
"id": "100005"
},
"statusNotification": {
"sessionStatus": "RECEIVED",
"hipId": "IN2810014366",
"statusResponses": [
{
"careContextReference": "10004-20200001768-1",
"hiStatus": "OK",
"description": "Data received successfully"
}
]
}
}
}'
```
#### 7. Get the current status of the health information request (`m3_get_data_flow_v3_health_information_request_status_tra_550104`)
```bash
curl --request GET \
--url https://dev.abdm.gov.in/api/hiecm/data-flow/v3/health-information/request/status/{transaction-id} \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx'
```
**Exit condition (Observe until this is true)**
Each call you made in this journey answered by its callback, with `response.requestId` equal to the `REQUEST-ID` you sent on that call. The 202 on a call is receipt, not the outcome: the outcome is in the callback's body.
- `POST /api/hiecm/consent/v3/request/init` is answered by `POST /api/v3/hiu/consent/request/on-init` on your bridge.
- `POST /api/hiecm/consent/v3/request/status` is answered by `POST /api/v3/hiu/consent/request/on-status` on your bridge.
- `POST /api/hiecm/consent/v3/fetch` is answered by `POST /api/v3/hiu/consent/on-fetch` on your bridge.
- `POST /api/hiecm/data-flow/v3/health-information/request` is answered by `POST /api/v3/hiu/health-information/on-request` on your bridge.
Then `GET /api/hiecm/data-flow/v3/health-information/request/status/{transaction-id}` returns a 200 whose body matches:
```json
{
"transactionId": "18235d89-cb13-479d-ad71-7a57d5f669a8",
"status": "TRANSFERRED"
}
```
### Callbacks (`m3-callbacks`)
**Act: the calls in this journey, in order**
#### 1. Receive the consent request for patient HIU (`m3_post_v3_hiu_consent_request_on_init`)
Inbound to your bridge at `/api/v3/hiu/consent/request/on-init`. Acknowledge it and continue.
#### 2. Receive the consent status request (`m3_post_v3_hiu_consent_request_on_status`)
Inbound to your bridge at `/api/v3/hiu/consent/request/on-status`. Acknowledge it and continue.
#### 3. Notify HIU when consent is APPROVED, DENIED or REVOKED (`m3_post_v3_hiu_consent_request_notify`)
Inbound to your bridge at `/api/v3/hiu/consent/request/notify`. Acknowledge it and continue.
#### 4. Receive the provide fetched consent artefact details to HIU (`m3_post_v3_hiu_consent_on_fetch`)
Inbound to your bridge at `/api/v3/hiu/consent/on-fetch`. Acknowledge it and continue.
#### 5. Receive the health information data request acknowledgement to HIU (`m3_post_v3_hiu_health_information_on_request`)
Inbound to your bridge at `/api/v3/hiu/health-information/on-request`. Acknowledge it and continue.
**Exit condition (Observe until this is true)**
A 200 response. The specification gives no body for it, so read what comes back.
## Where the detail is
- Every operation, with its body fields and responses: /docs/hiecm/v3/api/m3
- Error codes: /docs/hiecm/v3/api/m3/errors

View File

@ -0,0 +1,88 @@
---
name: abdm-m4
description: Use when building, debugging or testing ABDM Milestone 4, the NHPR: creating an HPID, registering a healthcare professional on the HPR, onboarding a facility to the HFR, and linking that facility to a bridge. Carries the operations, their hosts and headers.
type: skill
domain: m4
agent_consumers:
- abdm-integration-agent
- abdm-call-debugger
requires:
- gateway-session-token
produces:
- hpid
- facility-id
- bridge-facility-link
can_execute: true
can_orchestrate: false
---
# ABDM M4, register facilities and professionals
Generated from the ABDM Developer Portal on 2026-09-16, catalogue version 2026.09.16. Every fact below comes from a page in that portal, which is the place to look when this file does not carry enough.
This file is a snapshot. Re-download the whole folder from https://docs.abdm.gov.in/skills/abdm-m4/ when it is older than the work you are doing: this router and every file under references/ that it links to. Fetching this file alone leaves those links pointing at files you do not have.
If the abdm-docs MCP server is connected, trust its answers over this file: it serves the current catalogue and stamps every response with its catalogue_version, which you can compare against the version above.
## What you can do with M4
- Create an HPID for a professional and register them in the HPR.
- Register a facility in the HFR and carry it through to submission.
- Link a facility to a bridge and set the type of each link.
- Fetch the council, course, college, university and geography codes these calls take instead of names.
What it cannot do yet matters as much. Read **Before anything else** below before assuming a capability is one endpoint away.
## Try asking
- "Onboard this facility to the HFR and link its HIP bridge"
- "What has to be in place before my first M4 call?"
- "My M4 call failed. Here is the response: what is wrong, and how do I fix it?"
Loaded with no task? Say in three lines what this skill does. Offer the prompts above. Then ask what the person is building, and whether the code for it exists yet.
## What is in this folder
- **Scaffold.** Survey the codebase first when one exists, then build it flow by flow against the sandbox, as a loop that ends when the step's exit condition holds rather than on a call returning 200. [references/scaffold.md](references/scaffold.md)
- **Integrate.** 91 operations, with their hosts and headers. [references/integrate.md](references/integrate.md)
- **Debug.** The specification's examples return no error code for this module. [references/debug.md](references/debug.md)
This file is the map. Each line above is a file beside it, opened one at a time rather than read through.
## Before anything else
- Treat every request and response shape in this skill as unconfirmed until the sandbox has answered you. Check a response before you rely on its shape.
- Neither registry moves a health record. M4 establishes who the professional is and what the facility is, so every record flow has a verified provider behind it.
- The register professional call carries an `hprToken` in its payload, beside the practitioner.
- The facility calls are keyed to a `trackingId`, and the facility status values in the examples include `Draft` and `Submitted`. Read the status rather than assuming a facility is complete.
- Register professional takes codes, not names. Fetch council, course, college, university, state, district and language from the master data APIs first.
- `POST /v1/bridges/MutipleHRPAddUpdateServices` links a facility to a bridge. Each entry names a `bridgeId`, a `hipName`, a `type` such as `HIP`, and whether it is `active`.
## Practices that hold across every call
- Read the body, not only the status. A refusal often names the field in its body while the status says nothing useful.
- When ABDM publishes a value, read it rather than hard coding what it currently says. That covers a parameter, such as the encryption algorithm the certificate endpoints return beside the key, and it covers an enumeration. The registries publish theirs as master data calls: councils, courses, colleges, states and districts on the HPR, and facility types and LGD codes on the HFR. A table typed into your source goes stale silently. Purposes and HI types have no master data call: take them from the enumeration in the specification of the call you are making. Refuse to act on a published value you do not recognise rather than falling back to a default.
- Read every field in a response, not the one you came for. The M1 certificate call returns the encryption algorithm next to the key.
- Prove an assumption against a call that is able to disagree with you. A call that refuses every input with one message cannot tell you which input was right.
- Suspect the transport before the data. When a call refuses a value you believe in, check the encryption, the headers and the clock before you doubt the value.
- Do not carry an encryption path from one module to another. Read the certificate and the algorithm from the registry you are calling.
- Never log a sensitive value before you encrypt it, and never send one to a remote service to be encrypted. Both move the leak rather than removing it.
- Generate a fresh REQUEST-ID for every call and log it before sending. Once a call has failed it is the only handle on it.
- Check the host on any sample before you copy it. A request copied whole can be correct in every respect except where it is pointed, and that failure looks like credentials.
- Do not validate an identifier more strictly than the platform does. A schema that types a field as a UUID is not a promise that every value is one. Refusing a value ABDM would have accepted turns your own client into the thing that broke.
- Read a plural response as plural. A verification returns an accounts array and a consent request can produce more than one artefact. Store the collection and decide from its length.
- A documented callback path is not a documented callback payload. Log the whole body on arrival before you parse it, so a handler written against an assumed shape fails where you can see it.
- Decode a token before you use it. A call that hands you a token has not necessarily handed you the token the next call wants, and the claims are base64 that need no library to read.
- When a journey carries the same parameter through two calls, check what each call's specification asks for rather than carrying the first value forward.
- Do not infer which path an identifier belongs to from where that identifier is most discussed. Send every identifier to the lookup first and let the answer pick the path, so nobody who already holds an account is sent to create a second.
- Do not match an error code with string equality. A code may come back bare, as `ABDM-1001`, or with a trailing `: ` separator, as `ABDM-1001: `. Match on the code itself and tolerate the separator.
- Handle a failure that carries no body. Check for an empty body before you parse, or your client throws on the simplest failure there is.
- Back off on an authentication failure rather than retrying, and never loop a credential check.
- Send TIMESTAMP in UTC, ISO-8601 with milliseconds and a trailing Z, as in `2022-10-06T15:10:00.587Z`.
- Cache a public certificate with a validity window rather than forever. A rotation fails every encrypted call at once, and a cache with no expiry cannot recover on its own.
## Where the detail is
- Every endpoint, with its body fields and responses: /docs/hiecm/v3/api/m4
- The flows as diagrams: /docs/hiecm/v3/milestones/m4
- Every error code across modules: /docs/hiecm/v3/reference/error-codes
- Terms: /docs/hiecm/v3/getting-started/glossary

View File

@ -0,0 +1,9 @@
# Debug M4, register facilities and professionals
The codes this module can return, with the message and the operation that returns each.
## Errors
The M4, register facilities and professionals specification's examples return no error code yet. That is a gap in the specification, not a promise that this module cannot fail.
A code you meet that is not above is one the specifications do not carry yet. Read the code together with the message: a code can appear twice with different meanings.

View File

@ -0,0 +1,133 @@
# Integrate M4, register facilities and professionals
The calls themselves: where they live, what they need in their headers, and one request written out in full.
## Hosts
- `https://apihspsbx.abdm.gov.in/v4/int` NHPR, sandbox
- `https://dev.abdm.gov.in` ABDM gateway, sandbox
- `https://apis.abdm.gov.in` ABDM gateway, production
## Endpoints
91 operations, grouped by the journey they belong to.
### Other operations
| Method | Path | What it does |
| --- | --- | --- |
| `POST` | `/aadhaar/generateLink` | Generate Aadhaar Link |
| `POST` | `/aadhaar/isAuthenticated` | Is Aadhaar Authenticated |
| `GET` | `/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id}` | Fetch the details of a service ID. |
| `GET` | `/api/hiecm/gateway/v3/bridge-services` | Fetch the service ids registered against a bridge. |
| `PATCH` | `/api/hiecm/gateway/v3/bridge/url` | Update the bridge URL. |
| `POST` | `/api/hiecm/gateway/v3/sessions` | Generate access token. |
| `POST` | `/api/v1/auth/authPassword` | Login Via Password |
| `GET` | `/api/v1/auth/cert` | Get Public Certificate |
| `POST` | `/api/v1/auth/confirmWithAadhaarOtp` | Verify Aadhaar OTP |
| `POST` | `/api/v1/auth/init` | Send Via Aadhaar OTP |
| `POST` | `/api/v2/auth/loginViaMobileSendOTP` | Send Verify OTP |
| `POST` | `/apis/v1/doctors/fetch-documents-list` | Fetch Documents |
| `POST` | `/apis/v1/doctors/fetch-professional-info` | Get Professional Info |
| `POST` | `/apis/v1/doctors/generate-mobile-otp` | Generate Mobile OTP 2 |
| `POST` | `/apis/v1/doctors/generate-verification-email` | Send Verification Email |
| `POST` | `/apis/v1/doctors/regenerate-mobile-otp` | Regenerate Mobile OTP |
| `POST` | `/apis/v1/doctors/register-professional-new` | Register Professional |
| `POST` | `/apis/v1/doctors/resent-verify-email` | Resend Verification Email |
| `POST` | `/apis/v1/doctors/update-professional-new` | Update Professional |
| `POST` | `/apis/v1/doctors/verify-email-otp` | Verify Email OTP |
| `POST` | `/apis/v1/doctors/verify-mobile-otp` | Verify Mobile OTP |
| `GET` | `/apis/v1/masters/affiliated-board` | Get All Affiliated Board |
| `GET` | `/apis/v1/masters/affiliated-board/{id}` | Get Affiliated Board By ID |
| `GET` | `/apis/v1/masters/affiliated-board/states/{id}` | Get Affiliated Board By State ID |
| `GET` | `/apis/v1/masters/colleges/{id}` | Get College By State |
| `GET` | `/apis/v1/masters/colleges/{stateId}/{medicineId}` | Get College By State And Medicine ID |
| `GET` | `/apis/v1/masters/countries` | Get All Countries |
| `GET` | `/apis/v1/masters/countries/{id}` | Get Countries By ID |
| `POST` | `/apis/v1/masters/courses` | List Courses |
| `GET` | `/apis/v1/masters/district` | Get All Districts |
| `GET` | `/apis/v1/masters/district/{id}` | Get Districts By State |
| `GET` | `/apis/v1/masters/languages` | List Government Health Programmes |
| `GET` | `/apis/v1/masters/languages/{id}` | Get Pi Languages By ID |
| `GET` | `/apis/v1/masters/medical-councils` | Get All Medical Council |
| `GET` | `/apis/v1/masters/medical-councils/name` | Get Medical Council By System Of Medicine Name |
| `GET` | `/apis/v1/masters/nurse-councils` | Get All Nurse Councils |
| `GET` | `/apis/v1/masters/states` | Get All States |
| `GET` | `/apis/v1/masters/states/{id}` | Get Status |
| `GET` | `/apis/v1/masters/sub-districts` | Get All Sub Districts |
| `GET` | `/apis/v1/masters/sub-districts/{id}` | Get All Sub Districts 1 |
| `GET` | `/apis/v1/masters/system-of-medicines` | Get All Medical System |
| `GET` | `/apis/v1/masters/universites` | List All University |
| `GET` | `/apis/v1/masters/universites/{id}` | Get University By College |
| `POST` | `/apis/v1/uploads/upload-document` | Upload Documents |
| `POST` | `/FacilityManagement/v1.5/facility/bygeoLocation/searchWithinRadiusWithFilter` | Get Facility Within Radius With Filter |
| `POST` | `/FacilityManagement/v1.5/facility/search` | Search Facility 1 |
| `GET` | `/getPsuDetailsByMinistry` | Get Psu Data |
| `GET` | `/hpid/get/categories` | Fetch HPID Categories |
| `GET` | `/hpid/get/subCategories` | Fetch HPID Sub Categories From Category |
| `POST` | `/password/change/byPassword` | Change Password |
| `POST` | `/password/recover/byAadhaar` | Recover Password Via Aadhaar |
| `POST` | `/password/recover/byMobile/sendMobileOTP` | Generate Mobile OTP 1 |
| `POST` | `/password/recover/byMobile/verifyMobileOTP` | Verify Mobile OTP 1 |
| `POST` | `/password/recover/confirmByAadhaar` | Recover Password Confirm By Aadhaar |
| `POST` | `/password/reset/password` | Reset Password And Session |
| `POST` | `/password/resetPassword` | Reset Password |
| `POST` | `/search/address/filter/deduplicate` | Get Filtered Address Post |
| `POST` | `/v1.0/facility/search-facilities` | Search Facility |
| `POST` | `/v1.5/facility/additional-information` | V15Facility Additional Information |
| `POST` | `/v1.5/facility/basic-information` | V15Basic Facility Information |
| `POST` | `/v1.5/facility/detailed-information` | V15Facility Detailed Information |
| `POST` | `/v1.5/facility/fetch-facility-Sub-type` | Get All Facility Sub Type By Facility Type |
| `POST` | `/v1.5/facility/fetch-facility-type` | Get All Facility Type By Ownership And Sys Of Med |
| `GET` | `/v1.5/facility/get-master-data` | Get Master Data |
| `GET` | `/v1.5/facility/get-master-types` | Get All Master Type |
| `POST` | `/v1.5/facility/get-owner-subtype` | Get All Sub Types By Owner Ship Type And Sub Type |
| `POST` | `/v1.5/facility/get-specialities` | Get All Specialities By System Of Medicine Code |
| `GET` | `/v1.5/facility/lgd/districts` | Get All District By State ID |
| `GET` | `/v1.5/facility/lgd/states` | Get All States By LGD |
| `GET` | `/v1.5/facility/lgd/subdistricts` | Get All Sub District By District Code |
| `POST` | `/v1.5/facility/sendOtpToContact` | Send OTP To Contact |
| `POST` | `/v1.5/facility/submit-facility` | V15Submit Facility Details |
| `POST` | `/v1.5/facility/validateOtp` | Validate OTP |
| `GET` | `/v1/account/getIdCard` | Get Account Png Card |
| `GET` | `/v1/account/information` | Get User Profile By JWT |
| `GET` | `/v1/account/user-details/{hprId}` | Get User Details |
| `POST` | `/v1/bridges/MutipleHRPAddUpdateServices` | Facility Add And Update |
| `POST` | `/v1/forgot/hprId/aadhaar` | Retrieval Health ID By Aadhaar |
| `POST` | `/v1/forgot/hprId/mobile` | Retrieval Health ID By Mobile |
| `POST` | `/v1/forgot/hprId/mobile/generateOtp` | Generate Mobile OTP |
| `POST` | `/v1/registration/aadhaar/checkHpIdAccountExist` | Account Exist |
| `POST` | `/v1/registration/aadhaar/generateMobileOTP` | Generate Mobile OTP |
| `POST` | `/v1/registration/aadhaar/hpid/suggestion` | Get Suggesstion |
| `POST` | `/v1/registration/aadhaar/verifyMobileOTP` | Verify Mobile OTP |
| `GET` | `/v1/search/existsByHprId/{hprId}` | Exists By HPR ID |
| `GET` | `/v1/search/searchByHprId/{hprId}` | Search User By HPR ID |
| `GET` | `/v1/search/searchByMobile/{mobile}` | Search User By Mobile No |
| `POST` | `/v2/registration/aadhaar/createHprIdWithPreVerified` | Create HPR ID V2 |
| `POST` | `/v2/registration/aadhaar/demographicAuthViaMobile` | Demographic Auth Via Mobile |
| `POST` | `/v2/registration/aadhaar/verifyOTP` | Verify OTP |
| `GET` | `/v4/auth/logout` | Logout |
## Headers
| Header | What it is |
| --- | --- |
| `Authorization` | |
| `REQUEST-ID` | Unique UUID for track the end to end request transaction |
| `TIMESTAMP` | Actual time of the request was initiated, ISO 8601 represents date and time by starting with the year, follow… |
| `X-CM-ID` | Suffix of the consent manager to which the request was intended |
| `x-hprid-auth` | The HPR token of the signed-in professional, from the HPR login. |
| `x-hprid-auth-verifier` | The HPR token of the professional verifying the facility submission. |
| `X-Token` | The HPR token of the signed-in professional, from the HPR login. |
## A request, in full
```bash
curl --request POST \
--url https://apihspsbx.abdm.gov.in/v4/int/aadhaar/generateLink \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'Content-Type: application/json' \
--data '{
"scopes": [
"nhpr-register"
],
"source": "NHPR"
}'
```

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,88 @@
---
name: abdm-p1
description: Use when building, debugging or testing ABDM P1 in a PHR app: creating an ABHA address and logging in to it.
type: skill
domain: p1
agent_consumers:
- abdm-integration-agent
- abdm-call-debugger
requires:
- gateway-session-token
produces:
- phr-login
- abha-profile
can_execute: true
can_orchestrate: false
---
# ABDM P1, PHR registration and login
Generated from the ABDM Developer Portal on 2026-09-16, catalogue version 2026.09.16. Every fact below comes from a page in that portal, which is the place to look when this file does not carry enough.
This file is a snapshot. Re-download the whole folder from https://docs.abdm.gov.in/skills/abdm-p1/ when it is older than the work you are doing: this router and every file under references/ that it links to. Fetching this file alone leaves those links pointing at files you do not have.
If the abdm-docs MCP server is connected, trust its answers over this file: it serves the current catalogue and stamps every response with its catalogue_version, which you can compare against the version above.
## What you can do with P1
- PHR certificate and session token
- Create ABHA number, Aadhaar OTP
- Create ABHA address, mobile number
- Create ABHA address, ABHA number with ABHA OTP
- Create ABHA address, ABHA number with Aadhaar OTP
- PHR login, mobile number
- PHR login, ABHA address with mobile OTP
- PHR login, ABHA number with Aadhaar OTP
- PHR login, ABHA number with ABHA OTP
- PHR login, ABHA address with password
- PHR login, Aadhaar OTP
What it cannot do yet matters as much. Read **Before anything else** below before assuming a capability is one endpoint away.
## Try asking
- "Register a new user in this PHR app and log them in"
- "What has to be in place before my first P1 call?"
- "My P1 call returned ABDM-1107. What is wrong, and how do I fix it?"
Loaded with no task? Say in three lines what this skill does. Offer the prompts above. Then ask what the person is building, and whether the code for it exists yet.
## What is in this folder
- **Scaffold.** Survey the codebase first when one exists, then build it flow by flow against the sandbox, as a loop that ends when the step's exit condition holds rather than on a call returning 200. [references/scaffold.md](references/scaffold.md)
- **Integrate.** 15 operations, with their hosts and headers. [references/integrate.md](references/integrate.md)
- **Debug.** The loop from a failed call to a named fix, and 4 error codes from the specification's examples. [references/debug.md](references/debug.md)
This file is the map. Each line above is a file beside it, opened one at a time rather than read through.
## Before anything else
- Treat every request and response shape in this skill as unconfirmed until the sandbox has answered you. Check a response before you rely on its shape.
## Practices that hold across every call
- Read the body, not only the status. A refusal often names the field in its body while the status says nothing useful.
- When ABDM publishes a value, read it rather than hard coding what it currently says. That covers a parameter, such as the encryption algorithm the certificate endpoints return beside the key, and it covers an enumeration. The registries publish theirs as master data calls: councils, courses, colleges, states and districts on the HPR, and facility types and LGD codes on the HFR. A table typed into your source goes stale silently. Purposes and HI types have no master data call: take them from the enumeration in the specification of the call you are making. Refuse to act on a published value you do not recognise rather than falling back to a default.
- Read every field in a response, not the one you came for. The M1 certificate call returns the encryption algorithm next to the key.
- Prove an assumption against a call that is able to disagree with you. A call that refuses every input with one message cannot tell you which input was right.
- Suspect the transport before the data. When a call refuses a value you believe in, check the encryption, the headers and the clock before you doubt the value.
- Do not carry an encryption path from one module to another. Read the certificate and the algorithm from the registry you are calling.
- Never log a sensitive value before you encrypt it, and never send one to a remote service to be encrypted. Both move the leak rather than removing it.
- Generate a fresh REQUEST-ID for every call and log it before sending. Once a call has failed it is the only handle on it.
- Check the host on any sample before you copy it. A request copied whole can be correct in every respect except where it is pointed, and that failure looks like credentials.
- Do not validate an identifier more strictly than the platform does. A schema that types a field as a UUID is not a promise that every value is one. Refusing a value ABDM would have accepted turns your own client into the thing that broke.
- Read a plural response as plural. A verification returns an accounts array and a consent request can produce more than one artefact. Store the collection and decide from its length.
- A documented callback path is not a documented callback payload. Log the whole body on arrival before you parse it, so a handler written against an assumed shape fails where you can see it.
- Decode a token before you use it. A call that hands you a token has not necessarily handed you the token the next call wants, and the claims are base64 that need no library to read.
- When a journey carries the same parameter through two calls, check what each call's specification asks for rather than carrying the first value forward.
- Do not infer which path an identifier belongs to from where that identifier is most discussed. Send every identifier to the lookup first and let the answer pick the path, so nobody who already holds an account is sent to create a second.
- Do not match an error code with string equality. A code may come back bare, as `ABDM-1001`, or with a trailing `: ` separator, as `ABDM-1001: `. Match on the code itself and tolerate the separator.
- Handle a failure that carries no body. Check for an empty body before you parse, or your client throws on the simplest failure there is.
- Back off on an authentication failure rather than retrying, and never loop a credential check.
- Send TIMESTAMP in UTC, ISO-8601 with milliseconds and a trailing Z, as in `2022-10-06T15:10:00.587Z`.
- Cache a public certificate with a validity window rather than forever. A rotation fails every encrypted call at once, and a cache with no expiry cannot recover on its own.
## Where the detail is
- Every endpoint, with its body fields and responses: /docs/hiecm/v3/api/p1
- Every error code across modules: /docs/hiecm/v3/reference/error-codes
- Terms: /docs/hiecm/v3/getting-started/glossary

View File

@ -0,0 +1,48 @@
# HIE-CM p1 debug
Every error below is an OODA loop: observe the error code and last request id, orient against the matched code, decide the fix, act, and observe whether the original step now succeeds. Applying a fix is not the exit condition; the original step succeeding is.
Loop limit: 5 passes per error.
## Errors
### 900902
**Specification example:** HTTP 401, `Missing Credentials`, on `p1_get_v3_phr_app_enrollment_isexists`.
**Exit condition: the original call now succeeds.**
### ABDM-1107
**Specification example:** HTTP 400, `Invalid combinations of scopes`, on `p1_post_v3_phr_app_login_verify`.
**Exit condition: the original call now succeeds.**
### ABDM-1211
**Specification example:** HTTP 400, `User not found.`, on `p1_post_v3_phr_app_login_search`.
**Exit condition: the original call now succeeds.**
### ABDM-9999
**Specification example:** HTTP 400, `Invalid LoginId`, on `p1_post_v3_phr_app_enrollment_request_otp`.
**Exit condition: the original call now succeeds.**
## Where the detail is
- The operation that returns each code: /docs/hiecm/v3/api/p1
## Every code in the specification
### Codes
| Code | HTTP | Message | Returned by |
| --- | --- | --- | --- |
| `900902` | 401 | Missing Credentials | `p1_get_v3_phr_app_enrollment_isexists` |
| `ABDM-1107` | 400 | Invalid combinations of scopes | `p1_post_v3_phr_app_login_verify` |
| `ABDM-1211` | 400 | User not found. | `p1_post_v3_phr_app_login_search` |
| `ABDM-9999` | 400 | Invalid LoginId | `p1_post_v3_phr_app_enrollment_request_otp` |
A code you meet that is not above is one the specifications do not carry yet. Read the code together with the message: a code can appear twice with different meanings.

View File

@ -0,0 +1,74 @@
# Integrate P1, PHR registration and login
The calls themselves: where they live, what they need in their headers, and one request written out in full.
## Hosts
- `https://abhasbx.abdm.gov.in` ABHA service, sandbox
- `https://dev.abdm.gov.in` ABDM gateway, sandbox
- `https://apis.abdm.gov.in` ABDM gateway, production
## Endpoints
15 operations, grouped by the journey they belong to.
### Other operations
| Method | Path | What it does |
| --- | --- | --- |
| `POST` | `/abha/api/v3/phr/app/enrollment/enrol` | 3 flows: Enrol ABHA Address |
| `GET` | `/abha/api/v3/phr/app/enrollment/isExists` | 3 flows: isExists API, isExists API Copy |
| `POST` | `/abha/api/v3/phr/app/enrollment/request/otp` | 3 flows: OTP Request - Mobile, OTP Request - ABHA OTP, OTP Request - AADHAR OTP |
| `POST` | `/abha/api/v3/phr/app/enrollment/suggestion` | 3 flows: Suggestion API |
| `POST` | `/abha/api/v3/phr/app/enrollment/verify` | 3 flows: OTP Verify - Mobile, OTP Verify - ABHA OTP, OTP Verify - AADHAR OTP |
| `GET` | `/abha/api/v3/phr/app/login/public/certificate` | PHR Certificate |
| `POST` | `/abha/api/v3/phr/app/login/request/otp` | 5 flows: OTP Request - Mobile, OTP Request - ABHAADDRES Mobile, OTP Request - A… |
| `POST` | `/abha/api/v3/phr/app/login/search` | Search Auth Methods - ABHAAddress |
| `POST` | `/abha/api/v3/phr/app/login/verify` | 6 flows: Login OTP Verify - Mobile, Login OTP Verify - ABHAADDRES Mobile, Login… |
| `POST` | `/abha/api/v3/phr/app/login/verify/user` | 5 flows: Verify User, Verify - User |
| `POST` | `/abha/api/v3/profile/account/request/emailVerificationLink` | Email Verification Link |
| `GET` | `/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id}` | Fetch the details of a service ID. |
| `GET` | `/api/hiecm/gateway/v3/bridge-services` | Fetch the service ids registered against a bridge. |
| `PATCH` | `/api/hiecm/gateway/v3/bridge/url` | Update the bridge URL. |
| `POST` | `/api/hiecm/gateway/v3/sessions` | Generate access token. |
## Headers
| Header | What it is |
| --- | --- |
| `REQUEST-ID` | Unique UUID for each request. |
| `TIMESTAMP` | Request timestamp in UTC, ISO-8601 with Z. |
| `T-token` | The transaction token from the preceding login step, sent with a `Bearer ` prefix. It is valid only for that … |
| `X-token` | The user token from a login or enrolment response, sent with a `Bearer ` prefix. It acts for that ABHA holder. |
| `X-CM-ID` | Suffix of the consent manager to which the request was intended |
## A request, in full
```bash
curl --request POST \
--url https://abhasbx.abdm.gov.in/abha/api/v3/phr/app/enrollment/enrol \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'Content-Type: application/json' \
--data '{
"txnId": "27d444b7-2a3d-46d8-bf67-e5590b6c46b6",
"phrDetails": {
"mobile": "<ENCRYPTED_MOBILE>",
"firstName": "John",
"middleName": "",
"lastName": "Doe",
"yearOfBirth": "<DOB>",
"dayOfBirth": "",
"monthOfBirth": "<DOB>",
"gender": "M",
"email": "",
"profilePhoto": "",
"address": "<ADDRESS>",
"stateName": "Maharashtra",
"stateCode": "27",
"districtName": "<ADDRESS>",
"districtCode": "123",
"pinCode": "<PINCODE>",
"abhaAddress": "<ABHA_ADDRESS>",
"password": "<ENCRYPTED_PASSWORD>"
}
}'
```

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
---
name: abdm-p2
description: Use when building, debugging or testing ABDM P2 in a PHR app: the PHR profile, linking an ABHA number, switching profiles, and linking, sharing and consent for the patient.
type: skill
domain: p2
agent_consumers:
- abdm-integration-agent
- abdm-call-debugger
requires:
- phr-login
produces:
- consent-decision
can_execute: true
can_orchestrate: false
---
# ABDM P2, Consents Management
Generated from the ABDM Developer Portal on 2026-09-16, catalogue version 2026.09.16. Every fact below comes from a page in that portal, which is the place to look when this file does not carry enough.
This file is a snapshot. Re-download the whole folder from https://docs.abdm.gov.in/skills/abdm-p2/ when it is older than the work you are doing: this router and every file under references/ that it links to. Fetching this file alone leaves those links pointing at files you do not have.
If the abdm-docs MCP server is connected, trust its answers over this file: it serves the current catalogue and stamps every response with its catalogue_version, which you can compare against the version above.
## What you can do with P2
- PHR profile, update mobile
- PHR profile, update password
- Link ABHA number, ABHA OTP
- Link ABHA number, Aadhaar OTP
- PHR profile, switch profile
- PHR profile, card, QR code and session
- Quick OPD Registration
- User initiated linking
- Consent manager, HIU and HIP
- Consent manager, fetch and manage consent requests
What it cannot do yet matters as much. Read **Before anything else** below before assuming a capability is one endpoint away.
## Try asking
- "Link this user's records to their ABHA address from the PHR app"
- "What has to be in place before my first P2 call?"
- "My P2 call returned ABDM-9999. What is wrong, and how do I fix it?"
Loaded with no task? Say in three lines what this skill does. Offer the prompts above. Then ask what the person is building, and whether the code for it exists yet.
## What is in this folder
- **Scaffold.** Survey the codebase first when one exists, then build it flow by flow against the sandbox, as a loop that ends when the step's exit condition holds rather than on a call returning 200. [references/scaffold.md](references/scaffold.md)
- **Integrate.** 39 operations, with their hosts and headers. [references/integrate.md](references/integrate.md)
- **Debug.** The loop from a failed call to a named fix, and 2 error codes from the specification's examples. [references/debug.md](references/debug.md)
This file is the map. Each line above is a file beside it, opened one at a time rather than read through.
## Before anything else
- Treat every request and response shape in this skill as unconfirmed until the sandbox has answered you. Check a response before you rely on its shape.
## Practices that hold across every call
- Read the body, not only the status. A refusal often names the field in its body while the status says nothing useful.
- When ABDM publishes a value, read it rather than hard coding what it currently says. That covers a parameter, such as the encryption algorithm the certificate endpoints return beside the key, and it covers an enumeration. The registries publish theirs as master data calls: councils, courses, colleges, states and districts on the HPR, and facility types and LGD codes on the HFR. A table typed into your source goes stale silently. Purposes and HI types have no master data call: take them from the enumeration in the specification of the call you are making. Refuse to act on a published value you do not recognise rather than falling back to a default.
- Read every field in a response, not the one you came for. The M1 certificate call returns the encryption algorithm next to the key.
- Prove an assumption against a call that is able to disagree with you. A call that refuses every input with one message cannot tell you which input was right.
- Suspect the transport before the data. When a call refuses a value you believe in, check the encryption, the headers and the clock before you doubt the value.
- Do not carry an encryption path from one module to another. Read the certificate and the algorithm from the registry you are calling.
- Never log a sensitive value before you encrypt it, and never send one to a remote service to be encrypted. Both move the leak rather than removing it.
- Generate a fresh REQUEST-ID for every call and log it before sending. Once a call has failed it is the only handle on it.
- Check the host on any sample before you copy it. A request copied whole can be correct in every respect except where it is pointed, and that failure looks like credentials.
- Do not validate an identifier more strictly than the platform does. A schema that types a field as a UUID is not a promise that every value is one. Refusing a value ABDM would have accepted turns your own client into the thing that broke.
- Read a plural response as plural. A verification returns an accounts array and a consent request can produce more than one artefact. Store the collection and decide from its length.
- A documented callback path is not a documented callback payload. Log the whole body on arrival before you parse it, so a handler written against an assumed shape fails where you can see it.
- Decode a token before you use it. A call that hands you a token has not necessarily handed you the token the next call wants, and the claims are base64 that need no library to read.
- When a journey carries the same parameter through two calls, check what each call's specification asks for rather than carrying the first value forward.
- Do not infer which path an identifier belongs to from where that identifier is most discussed. Send every identifier to the lookup first and let the answer pick the path, so nobody who already holds an account is sent to create a second.
- Do not match an error code with string equality. A code may come back bare, as `ABDM-1001`, or with a trailing `: ` separator, as `ABDM-1001: `. Match on the code itself and tolerate the separator.
- Handle a failure that carries no body. Check for an empty body before you parse, or your client throws on the simplest failure there is.
- Back off on an authentication failure rather than retrying, and never loop a credential check.
- Send TIMESTAMP in UTC, ISO-8601 with milliseconds and a trailing Z, as in `2022-10-06T15:10:00.587Z`.
- Cache a public certificate with a validity window rather than forever. A rotation fails every encrypted call at once, and a cache with no expiry cannot recover on its own.
## Where the detail is
- Every endpoint, with its body fields and responses: /docs/hiecm/v3/api/p2
- Every error code across modules: /docs/hiecm/v3/reference/error-codes
- Terms: /docs/hiecm/v3/getting-started/glossary

View File

@ -0,0 +1,34 @@
# HIE-CM p2 debug
Every error below is an OODA loop: observe the error code and last request id, orient against the matched code, decide the fix, act, and observe whether the original step now succeeds. Applying a fix is not the exit condition; the original step succeeding is.
Loop limit: 5 passes per error.
## Errors
### 900902
**Specification example:** HTTP 401, `Missing Credentials`, on `p2_get_v3_phr_app_login_profile`.
**Exit condition: the original call now succeeds.**
### ABDM-9999
**Specification example:** HTTP 400, `Invalid LoginId`, on `p2_post_v3_phr_app_login_profile_request_otp`.
**Exit condition: the original call now succeeds.**
## Where the detail is
- The operation that returns each code: /docs/hiecm/v3/api/p2
## Every code in the specification
### Codes
| Code | HTTP | Message | Returned by |
| --- | --- | --- | --- |
| `900902` | 401 | Missing Credentials | `p2_get_v3_phr_app_login_profile` |
| `ABDM-9999` | 400 | Invalid LoginId | `p2_post_v3_phr_app_login_profile_request_otp` |
A code you meet that is not above is one the specifications do not carry yet. Read the code together with the message: a code can appear twice with different meanings.

View File

@ -0,0 +1,79 @@
# Integrate P2, Consents Management
The calls themselves: where they live, what they need in their headers, and one request written out in full.
## Hosts
- `https://abhasbx.abdm.gov.in` PHR application service, sandbox
- `https://dev.abdm.gov.in` ABDM gateway, sandbox
- `https://apis.abdm.gov.in` ABDM gateway, production
## Endpoints
39 operations, grouped by the journey they belong to.
### Other operations
| Method | Path | What it does |
| --- | --- | --- |
| `GET` | `/abha/api/v3/phr/app/login/profile` | Get Profile |
| `POST` | `/abha/api/v3/phr/app/login/profile/link` | 2 flows: Link Request |
| `GET` | `/abha/api/v3/phr/app/login/profile/phrCard` | Get PHR Card |
| `GET` | `/abha/api/v3/phr/app/login/profile/qrCode` | Get QR Code |
| `GET` | `/abha/api/v3/phr/app/login/profile/request/logout` | Logout |
| `POST` | `/abha/api/v3/phr/app/login/profile/request/otp` | 3 flows: Send OTP - Update Mobile, Send ABHA OTP - Link-DeLink, Send Aadhaar OT… |
| `GET` | `/abha/api/v3/phr/app/login/profile/request/token` | Refresh Token |
| `GET` | `/abha/api/v3/phr/app/login/profile/switch-profile` | Switch Profile |
| `POST` | `/abha/api/v3/phr/app/login/profile/updateProfile` | Update Profile |
| `POST` | `/abha/api/v3/phr/app/login/profile/verify` | 4 flows: Verify OTP - Update Mobile, Verify Password - Update Password, Verify … |
| `POST` | `/abha/api/v3/phr/app/login/profile/verify/switch-profile/user` | Verify User Switch Profile |
| `GET` | `/api/hiecm/consent/v3/artefact` | Fetch all the consent artefact details of a patient. |
| `GET` | `/api/hiecm/consent/v3/artefact/{consentId}` | Fetch the consent artefact details associated with the artefact-ID. |
| `GET` | `/api/hiecm/consent/v3/artefact/request/{consentRequestId}` | Fetch all the consent artefact details associated with a consent request REQUES… |
| `POST` | `/api/hiecm/consent/v3/auto/approve` | Setup an auto-approval policy for given HIU. |
| `POST` | `/api/hiecm/consent/v3/auto/approve/{consentId}/disable` | Disable the auto-approval policy. |
| `POST` | `/api/hiecm/consent/v3/auto/approve/{consentId}/enable` | Enable the auto-approval policy. |
| `GET` | `/api/hiecm/consent/v3/request` | Fetch all the consent request details of a patient. |
| `GET` | `/api/hiecm/consent/v3/request/{consentRequestId}` | Get the consent request details by REQUEST-ID. |
| `POST` | `/api/hiecm/consent/v3/request/{consentRequestId}/approve` | Approve the consent request raised by HIU from PHR/mobile application. |
| `POST` | `/api/hiecm/consent/v3/request/{consentRequestId}/deny` | Deny the consent request raised by HIU from PHR/mobile application. |
| `POST` | `/api/hiecm/consent/v3/revoke` | Revoke the granted consent from PHR/mobile application. |
| `GET` | `/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id}` | Fetch the details of a service ID. |
| `GET` | `/api/hiecm/gateway/v3/bridge-services` | Fetch the service ids registered against a bridge. |
| `PATCH` | `/api/hiecm/gateway/v3/bridge/url` | Update the bridge URL. |
| `GET` | `/api/hiecm/gateway/v3/govt-programs` | Fetch the list of govt programmes. |
| `GET` | `/api/hiecm/gateway/v3/providers` | Fetch the list of providers filtered by name. |
| `GET` | `/api/hiecm/gateway/v3/providers/{hip-id}` | Fetch the record for provider details for requested provider ID. |
| `POST` | `/api/hiecm/gateway/v3/sessions` | Generate access token. |
| `GET` | `/api/hiecm/hip/v3/link/patient/links` | This is the PHR APP API, this API will used to fetch all link care-context for … |
| `GET` | `/api/hiecm/patient-share/v3/profile/getTokenDetails` | OPD Token History |
| `POST` | `/api/hiecm/patient-share/v3/share` | OPD token generation |
| `POST` | `/api/hiecm/user-initiated-linking/v3/link/care-context/confirm` | Confirm his/her health records. |
| `POST` | `/api/hiecm/user-initiated-linking/v3/link/care-context/init` | Link his/her health records. |
| `POST` | `/api/hiecm/user-initiated-linking/v3/patient/care-context/discover` | Discover his/her health records. |
| `POST` | `/api/v3/hiu/patient/care-context/on-confirm` | Receive confirmation of the linked care contexts for a patient. It provides det… |
| `POST` | `/api/v3/hiu/patient/care-context/on-discover` | Receive the discovered care contexts of a patient. It provides detailed informa… |
| `POST` | `/api/v3/hiu/patient/care-context/on-init` | Receive the initial linking of care contexts for a patient. It provides detaile… |
| `POST` | `/api/v3/hiu/patient/on-share` | This API will be invoked to the HIU for sharing the response of HIECM's /api/hi… |
## Headers
| Header | What it is |
| --- | --- |
| `X-token` | The user token from a login or enrolment response, sent with a `Bearer ` prefix. It acts for that ABHA holder. |
| `REQUEST-ID` | Unique UUID for each request. |
| `TIMESTAMP` | Request timestamp in UTC, ISO-8601 with Z. |
| `X-AUTH-TOKEN` | The user token issued at login. Send it beside X-token. |
| `R-token` | The refresh token from a login response, sent with a `Bearer ` prefix, exchanged for a new user token. |
| `T-token` | The transaction token from the preceding login step, sent with a `Bearer ` prefix. It is valid only for that … |
| `X-CM-ID` | Suffix of the consent manager to which the request was intended |
| `X-HIU-ID` | Identifier of the health information user to which the request was intended |
## A request, in full
```bash
curl --request GET \
--url https://abhasbx.abdm.gov.in/abha/api/v3/phr/app/login/profile \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'X-token: Bearer <JWT TOKEN>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-AUTH-TOKEN: <X_AUTH_TOKEN>'
```

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,80 @@
---
name: abdm-p3
description: Use when building, debugging or testing ABDM P3 in a PHR app: reading, approving, denying, enabling, disabling and updating the patient's subscriptions and subscription requests, and the subscription request and notifications on the health locker side.
type: skill
domain: p3
agent_consumers:
- abdm-integration-agent
- abdm-call-debugger
requires:
- phr-login
produces:
- subscription
can_execute: true
can_orchestrate: false
---
# ABDM P3, PHR subscriptions
Generated from the ABDM Developer Portal on 2026-09-16, catalogue version 2026.09.16. Every fact below comes from a page in that portal, which is the place to look when this file does not carry enough.
This file is a snapshot. Re-download the whole folder from https://docs.abdm.gov.in/skills/abdm-p3/ when it is older than the work you are doing: this router and every file under references/ that it links to. Fetching this file alone leaves those links pointing at files you do not have.
If the abdm-docs MCP server is connected, trust its answers over this file: it serves the current catalogue and stamps every response with its catalogue_version, which you can compare against the version above.
## What you can do with P3
- Subscription request and notifications, HIU side
- Subscription approval and management, PHR side
What it cannot do yet matters as much. Read **Before anything else** below before assuming a capability is one endpoint away.
## Try asking
- "Let this user approve or deny a subscription request"
- "What has to be in place before my first P3 call?"
- "My P3 call failed. Here is the response: what is wrong, and how do I fix it?"
Loaded with no task? Say in three lines what this skill does. Offer the prompts above. Then ask what the person is building, and whether the code for it exists yet.
## What is in this folder
- **Scaffold.** Survey the codebase first when one exists, then build it flow by flow against the sandbox, as a loop that ends when the step's exit condition holds rather than on a call returning 200. [references/scaffold.md](references/scaffold.md)
- **Design.** What the journey around the calls has to do, and what a screen is forbidden to claim. [references/design.md](references/design.md)
- **Integrate.** 18 operations, with their hosts and headers. [references/integrate.md](references/integrate.md)
- **Debug.** The specification's examples return no error code for this module. [references/debug.md](references/debug.md)
This file is the map. Each line above is a file beside it, opened one at a time rather than read through.
## Before anything else
- Treat every request and response shape in this skill as unconfirmed until the sandbox has answered you. Check a response before you rely on its shape.
- The design section is different in kind. Its rules come from building a working front desk against the sandbox, and each atom it cites names what was observed and the date it was seen.
## Practices that hold across every call
- Read the body, not only the status. A refusal often names the field in its body while the status says nothing useful.
- When ABDM publishes a value, read it rather than hard coding what it currently says. That covers a parameter, such as the encryption algorithm the certificate endpoints return beside the key, and it covers an enumeration. The registries publish theirs as master data calls: councils, courses, colleges, states and districts on the HPR, and facility types and LGD codes on the HFR. A table typed into your source goes stale silently. Purposes and HI types have no master data call: take them from the enumeration in the specification of the call you are making. Refuse to act on a published value you do not recognise rather than falling back to a default.
- Read every field in a response, not the one you came for. The M1 certificate call returns the encryption algorithm next to the key.
- Prove an assumption against a call that is able to disagree with you. A call that refuses every input with one message cannot tell you which input was right.
- Suspect the transport before the data. When a call refuses a value you believe in, check the encryption, the headers and the clock before you doubt the value.
- Do not carry an encryption path from one module to another. Read the certificate and the algorithm from the registry you are calling.
- Never log a sensitive value before you encrypt it, and never send one to a remote service to be encrypted. Both move the leak rather than removing it.
- Generate a fresh REQUEST-ID for every call and log it before sending. Once a call has failed it is the only handle on it.
- Check the host on any sample before you copy it. A request copied whole can be correct in every respect except where it is pointed, and that failure looks like credentials.
- Do not validate an identifier more strictly than the platform does. A schema that types a field as a UUID is not a promise that every value is one. Refusing a value ABDM would have accepted turns your own client into the thing that broke.
- Read a plural response as plural. A verification returns an accounts array and a consent request can produce more than one artefact. Store the collection and decide from its length.
- A documented callback path is not a documented callback payload. Log the whole body on arrival before you parse it, so a handler written against an assumed shape fails where you can see it.
- Decode a token before you use it. A call that hands you a token has not necessarily handed you the token the next call wants, and the claims are base64 that need no library to read.
- When a journey carries the same parameter through two calls, check what each call's specification asks for rather than carrying the first value forward.
- Do not infer which path an identifier belongs to from where that identifier is most discussed. Send every identifier to the lookup first and let the answer pick the path, so nobody who already holds an account is sent to create a second.
- Do not match an error code with string equality. A code may come back bare, as `ABDM-1001`, or with a trailing `: ` separator, as `ABDM-1001: `. Match on the code itself and tolerate the separator.
- Handle a failure that carries no body. Check for an empty body before you parse, or your client throws on the simplest failure there is.
- Back off on an authentication failure rather than retrying, and never loop a credential check.
- Send TIMESTAMP in UTC, ISO-8601 with milliseconds and a trailing Z, as in `2022-10-06T15:10:00.587Z`.
- Cache a public certificate with a validity window rather than forever. A rotation fails every encrypted call at once, and a cache with no expiry cannot recover on its own.
## Where the detail is
- Every endpoint, with its body fields and responses: /docs/hiecm/v3/api/p3
- Every error code across modules: /docs/hiecm/v3/reference/error-codes
- Terms: /docs/hiecm/v3/getting-started/glossary

View File

@ -0,0 +1,9 @@
# Debug P3, PHR subscriptions
The codes this module can return, with the message and the operation that returns each.
## Errors
The P3, PHR subscriptions specification's examples return no error code yet. That is a gap in the specification, not a promise that this module cannot fail.
A code you meet that is not above is one the specifications do not carry yet. Read the code together with the message: a code can appear twice with different meanings.

View File

@ -0,0 +1,71 @@
# Design P3, PHR subscriptions
What the integration has to do to the journey around the calls: how many questions a patient is asked, where a failure is shown, and what a screen is forbidden to claim. Every rule below comes from a Catalogue atom, cited at the end.
## The five things a personal health record application must let a person do with consent
### In plain words
Consent is granted by a person, and the PHR app is where they do it. There is
a floor of five capabilities, and an app missing one leaves a person able to
give access they cannot inspect, change or withdraw.
1. **See the request**, with the HIU asking, the purpose, the record types,
the date range of records, how long the consent would last, and its status.
2. **Change it before allowing it**, where the request permits: the access
duration, the record date range, the categories shared, and the validity
period. This is the one most often left out, and the one that turns a
consent screen into a negotiation rather than a demand.
3. **Allow or refuse it.** The consent flow has three outcomes, not two:
approve, reject and ignore. An ignored request expires on the requester's
window, and the interface has to show that state.
4. **See what is already allowed**, so the person can tell which
organisations hold access right now. A list of past decisions is not the
same thing.
5. **Take it back** at any time. Two things follow: the status updates at the
consent manager, and sharing under that consent stops immediately, not at
the end of the period.
### What happens
Build a screen for each of the five. Approving posts to `/api/hiecm/consent/v3/request/{consentRequestId}/approve`, denying to `/api/hiecm/consent/v3/request/{consentRequestId}/deny`, and revoking a granted consent to `/api/hiecm/consent/v3/revoke`. Show Expired as its own state, never as Denied, because the person refused nothing.
### How you know it worked
One request goes through the whole arc in the app: seen, its date range narrowed, allowed, found in the list of live consents, and revoked. A fetch attempted under it afterwards fails.
### When it goes wrong
A screen that lists requests but not live consents leaves the person unable to revoke what they cannot see. Revocation shown as expiry hides a decision the person made. Leaving out modification turns consent into a notice.
## Subscriptions, and why a personal health record application needs one
### In plain words
Ask the user for consent before you create a subscription. An approved
subscription notifies your app when a care context is linked or updated. Surface these as device
notifications.
You need screens to list subscriptions, approve them, deny them and edit them.
Editing covers health information types, purpose, categories and the time period.
A subscription tells you a record exists. It is not consent, and it gives nobody
the record: reading it still needs a consent request, which is why a
subscription usually runs beside an auto approval policy.
### What happens
Raise the subscription with `/api/hiecm/subscription-requests/v3/init`; the request id arrives on `/api/v3/hiu/hiecm/subscription-requests/on-init`. The person approves it with `/api/hiecm/subscription-requests/v3/{subscriptionRequestId}/approve` or denies it. Once approved, notifications arrive on `/api/v3/hiu/subscription/notify`, in the categories `LINK` and `DATA`, and you acknowledge each with `/api/hiecm/subscription-requests/v3/hiu/care-context/on-notify`. Set one up when you create an address and when a person signs in with an address the install has not seen.
### How you know it worked
The subscription shows as approved, and linking a care context to that address from a facility produces a notification on your callback without any call from you.
### When it goes wrong
Nothing arrives: the checks are those for any callback, see [the callback never arrives](/docs/hiecm/v3/troubleshooting/callback-never-arrives). A subscription created without asking the person is a consent failure that certification looks for. A notification acted on as though it were permission reads a record with no consent behind it.
## Where these came from
- `hiecm.concept.consent-in-a-phr-app`
- `hiecm.concept.phr-subscriptions`

View File

@ -0,0 +1,53 @@
# Integrate P3, PHR subscriptions
The calls themselves: where they live, what they need in their headers, and one request written out in full.
## Hosts
- `https://dev.abdm.gov.in` ABDM gateway, sandbox
- `https://apis.abdm.gov.in` ABDM gateway, production
## Endpoints
18 operations, grouped by the journey they belong to.
### Other operations
| Method | Path | What it does |
| --- | --- | --- |
| `GET` | `/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id}` | Fetch the details of a service ID. |
| `GET` | `/api/hiecm/gateway/v3/bridge-services` | Fetch the service ids registered against a bridge. |
| `PATCH` | `/api/hiecm/gateway/v3/bridge/url` | Update the bridge URL. |
| `POST` | `/api/hiecm/gateway/v3/sessions` | Generate access token. |
| `GET` | `/api/hiecm/subscription-requests/v3/{subscriptionID}` | Fetch his/her subscription details by subscription ID. |
| `POST` | `/api/hiecm/subscription-requests/v3/{subscriptionRequestId}/approve` | Approve subscription request. |
| `POST` | `/api/hiecm/subscription-requests/v3/{subscriptionRequestId}/deny` | Deny subscription request. |
| `POST` | `/api/hiecm/subscription-requests/v3/disable/{subscriptionID}` | Disable the subscription by subscription ID. |
| `POST` | `/api/hiecm/subscription-requests/v3/enable/{subscriptionID}` | Enable the subscription by subscription ID. |
| `POST` | `/api/hiecm/subscription-requests/v3/hiu/care-context/on-notify` | Respond to /api/v3/hiu/subscription/notify. |
| `POST` | `/api/hiecm/subscription-requests/v3/hiu/on-notify` | Respond to /subscription-requests/hiu/notify. |
| `POST` | `/api/hiecm/subscription-requests/v3/init` | Initiate subscription request. |
| `PUT` | `/api/hiecm/subscription-requests/v3/patients/{subscriptionID}` | Edit the subscription details. |
| `GET` | `/api/hiecm/subscription-requests/v3/request/{subscriptionRequestId}` | Fetch his/her subscription details by subscription REQUEST-ID. |
| `GET` | `/api/hiecm/subscription-requests/v3/requests` | Fetch his/her subscription requests details. |
| `POST` | `/api/v3/hiu/hiecm/subscription-requests/on-init` | This is a callback API for /api/hiecm/subscription-requests/v3/init. |
| `POST` | `/api/v3/hiu/subscription-requests/hiu/notify` | This is a callback API when a subscription request is approved or denied. |
| `POST` | `/api/v3/hiu/subscription/notify` | This is a callback API to notify the subscribed HIU when a care context is link… |
## Headers
| Header | What it is |
| --- | --- |
| `REQUEST-ID` | Unique UUID for track the end to end request transaction |
| `TIMESTAMP` | Actual time of the request was initiated, ISO 8601 represents date and time by starting with the year, follow… |
| `X-CM-ID` | Suffix of the consent manager to which the request was intended |
| `X-AUTH-TOKEN` | JWT Authentication token which was issued by ABDM after successful validation of username and password |
| `X-HIU-ID` | Identifier of the health information user to which the request was intended |
## A request, in full
```bash
curl --request GET \
--url https://dev.abdm.gov.in/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id} \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx'
```

View File

@ -0,0 +1,484 @@
# HIE-CM p3 build
Scaffolds an ABDM p3 integration one journey at a time. It covers reading, approving, denying, enabling, disabling and updating the patient's subscriptions and subscription requests, and the subscription request and notifications on the health locker side.
## How this skill runs
Every journey below is an OODA loop, not a recipe: observe the actual state (last response, last error), orient against the step matched below, decide the cheapest next action, act, and return to observe. A step is done only when its exit condition is observed against the sandbox, never because it "should have worked."
Loop limit: 8 passes per step. Hitting the limit is an escalation: state what was observed, what was tried, and which operation page to read, then ask one question.
## Before the first journey, when the codebase already exists
Skip this section only for a system that does not exist yet. Otherwise it runs first, and its exit condition is a written plan, not a call.
### In plain words
Most ABDM integrations are not new systems. They are a hospital management
system, a laboratory system or a clinic application that already has patients,
visits, records, a login, an HTTP client and a way of keeping secrets. Every
ABDM journey has to land somewhere inside that, and a journey built before the
codebase has been read lands in the wrong place: a second HTTP client beside the
first, an ABHA column on the wrong table, a callback route the reverse proxy
never forwards.
So the first loop is not a journey. It is a survey of the system as it is, and
its exit condition is a written plan that names, for every ABDM touchpoint, the
file it will live in. The journeys then build against that plan rather than
against the specification's idea of a fresh codebase.
### Before you start
- The repository, checked out, with permission to read all of it. A survey of
half a codebase produces a plan for half a system.
- The answers to the deployment interview. The
code says what the system is. Only the integrator can say what the
deployment is, and the two together decide which journeys are built at all.
- The practices that hold across every call, which
the plan has to leave room for.
### What happens
This is one loop with a limit of eight passes over the codebase. Each pass
reads live state only, which here means the files themselves, never a README's
description of them and never an assumption carried from a similar system.
**Observe.** Inventory the system from its manifests and its tree, not from its
documentation. Record file paths for each of these, or record that none exists:
| Find | Where it usually shows | Why ABDM needs it |
|---|---|---|
| Languages and runtime versions | package manifests, lock files, toolchain files | Every generated call has to be idiomatic here |
| Build, run and test commands | manifests, CI configuration, a Makefile | Each journey's exit condition becomes a test that runs the same way |
| The frontend and backend split, and how they talk | the top level tree, an API client in the frontend, route definitions in the backend | The counter screens go in the frontend; every ABDM call goes through the backend |
| The outbound HTTP client the backend already uses | the dependency list, a shared client module | ABDM calls reuse it, or a second one appears and the two drift |
| How secrets and configuration reach the process | environment loading, a vault client, a config file | The client id, the secret and the access token travel the same way |
| The patient model, and the identifier fields it already carries | the schema, the ORM models, the migrations | The ABHA number and address become columns beside the existing identifiers, not a new table |
| The visit, encounter or record model | the same places | A care context maps to one of these, and the plan has to say which |
| Where inbound HTTP is routed and authenticated, and whether the deployment has a public URL | the router, the middleware, the reverse proxy configuration, the deployment manifests | ABDM calls back, and a callback route that nothing forwards is silence nobody notices |
| Existing cryptography helpers | a security or crypto module, the dependency list | The RSA encryption of identifiers reuses them |
| Where errors are shown to a user, and where they are logged | the frontend's error surface, the logging setup | A refused call has to land on the screen the person is looking at, and never log a token |
**Orient.** Map each ABDM touchpoint onto that inventory. Where the map is
exact, write the file path. Where it is not, write two candidates and say what
would decide between them. The common ambiguities: two places that could hold
the patient identifier, an HTTP client in the frontend and none in the backend,
a monorepo with several services and no obvious owner for callbacks.
Then read the interview answers against the inventory. A government integrator
gets the demographic route; a facility with no public URL gets no callback
driven journey until it has one; a desk with a fingerprint reader gets the
biometric method. The route set is the intersection of what the deployment
allows and what the code can host.
**Decide.** Order the journeys. The token comes first because every other call
needs it: the gateway session token, or for M4 the bearer token the registry calls
carry. Then the journey whose exit condition can be observed with
the least new code, usually a profile read for a patient who already holds an
ABHA. Creation and linking come after, because each depends on state the earlier
ones produce. For each journey, name the files it will touch and the test that
proves its exit condition.
**Act.** Write the plan. It is a file in the repository, at the path the
integrator names or at the root as `abdm-integration-plan.md`, and it is the
only output of this loop. Then return to observe once, reading the plan against
the tree, to confirm every path in it exists or is marked as new.
If the limit is reached with questions still open, escalate: name what was
found, name the two candidates that could not be separated, point at this
atom, and ask one question.
### How you know it worked
The plan exists and answers every row of the inventory table with a file path,
or with the words none, add at, followed by a path. No row is blank and no row
says to be decided.
Every ABDM touchpoint in the plan names one file, or names two candidates and
the observation that would choose between them. Every journey in the plan names
the test that proves its exit condition and the command that runs it.
Open the plan beside the tree. Every path it names resolves, or is marked as
new. That is the observation that ends this loop, and the first journey does
not start until it has been made.
### When it goes wrong
- **The plan puts the HTTP client in the frontend.** The survey found the
frontend's API client and stopped. Every ABDM call carries a secret, so it
goes through the backend, and the plan has to say which backend module.
- **Two patient tables, and the plan picked one.** Orient produced one
hypothesis where it needed two. Name both, and name the query that shows
which one the visit model points at.
- **The plan has a callback route and the deployment has no public URL.** The
inventory row on inbound routing was answered from the router rather than
from the deployment. Mark every callback driven journey as blocked on a URL,
and build the ones that are not.
- **The survey read the README and not the tree.** A README describes the
system somebody meant to build. The plan is for the one that exists.
- **Eight passes and the plan is still incomplete.** Escalate with the rows
that are answered, the rows that are not, this atom, and one question about
the row that blocks the most journeys.
From `shared.concept.survey-an-existing-codebase`.
## Journeys
### Subscription request and notifications, HIU side (`p3-subscription-hiu`)
**Act: the calls in this journey, in order**
#### 1. Initiate subscription request (`p3_post_subscription_requests_v3_init`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/subscription-requests/v3/init \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"subscription": {
"purpose": {
"text": "Care Management",
"code": "CAREMGT",
"refUri": "https://abc.def.in"
},
"patient": {
"id": "<ABHA_ADDRESS>"
},
"hiu": {
"id": "INDIA_HIU",
"name": "INDIA HIU",
"type": "HIU"
},
"hips": [
{
"id": "INDIA_HIP",
"name": "INDIA HIP",
"type": "HIP"
}
],
"categories": [
"LINK"
],
"period": {
"from": "2024-05-09T10:34:00.389Z",
"to": "2024-05-09T10:34:00.389Z"
}
}
}'
```
#### 2. Receive the HIU subscription requests on init (`p3_post_v3_hiu_hiecm_subscription_requests_on_init`)
Inbound to your bridge at `/api/v3/hiu/hiecm/subscription-requests/on-init`. Acknowledge it and continue.
#### 3. Notify subscription requests HIU (`p3_post_v3_hiu_subscription_requests_hiu_notify`)
Inbound to your bridge at `/api/v3/hiu/subscription-requests/hiu/notify`. Acknowledge it and continue.
#### 4. Answer the subscription request notification (`p3_post_subscription_requests_v3_hiu_on_notify`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/subscription-requests/v3/hiu/on-notify \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"acknowledgement": {
"status": "OK",
"subscriptionRequestId": "f29f0e59-8388-4698-9fe6-05db67aeac46"
},
"error": {
"code": "ABDM-1001",
"message": "No data found"
},
"response": {
"requestId": "f29f0e59-8388-4698-9fe6-05db67aeac46"
}
}'
```
#### 5. Notify HIU subscription (`p3_post_v3_hiu_subscription_notify`)
Inbound to your bridge at `/api/v3/hiu/subscription/notify`. Acknowledge it and continue.
#### 6. Answer the care context subscription notification (`p3_post_subscription_requests_v3_hiu_care_context_on_notify`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/subscription-requests/v3/hiu/care-context/on-notify \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"acknowledgement": {
"status": "OK",
"eventId": "3c2f0e59-8388-4698-9fe6-05db67aeac46"
},
"error": {
"code": "ABDM-1001",
"message": "No data found"
},
"response": {
"requestId": "f29f0e59-8388-4698-9fe6-05db67aeac46"
}
}'
```
**Exit condition (Observe until this is true)**
Each call you made in this journey answered by its callback, with `response.requestId` equal to the `REQUEST-ID` you sent on that call. The 202 on a call is receipt, not the outcome: the outcome is in the callback's body.
- `POST /api/hiecm/subscription-requests/v3/init` is answered by `POST /api/v3/hiu/hiecm/subscription-requests/on-init` on your bridge.
### Subscription approval and management, PHR side (`p3-subscription-phr`)
**Act: the calls in this journey, in order**
#### 1. Approve subscription request (`p3_post_subscription_requests_v3_request_id_approve`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/subscription-requests/v3/{subscriptionRequestId}/approve \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-AUTH-TOKEN: <TOKEN>' \
--header 'Content-Type: application/json' \
--data '{
"isApplicableForAllHIPs": true,
"includedSources": [
{
"hiTypes": [
"Prescription",
"DiagnosticReport",
"OPConsultation",
"DischargeSummary",
"ImmunizationRecord",
"HealthDocumentRecord",
"WellnessRecord",
"Invoice"
],
"purpose": {
"text": "Care Management",
"code": "CAREMGT",
"refUri": "www.abdm.gov.in"
},
"categories": [
"LINK",
"DATA"
],
"period": {
"from": "2025-01-09T09:00:00.000Z",
"to": "2124-12-31T09:00:00.000Z"
}
}
],
"excludedSources": []
}'
```
#### 2. Deny subscription request (`p3_post_subscription_requests_v3_request_id_deny`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/subscription-requests/v3/{subscriptionRequestId}/deny \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-AUTH-TOKEN: <TOKEN>' \
--header 'Content-Type: application/json' \
--data '{
"reason": "Subscription denied."
}'
```
#### 3. Fetch his/her subscription requests details (`p3_get_subscription_requests_v3_requests`)
```bash
curl --request GET \
--url "https://dev.abdm.gov.in/api/hiecm/subscription-requests/v3/requests?limit=5&offset=5&status=ALL" \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-AUTH-TOKEN: <TOKEN>'
```
#### 4. Edit the subscription details (`p3_put_subscription_requests_v3_patients_subscription_id`)
```bash
curl --request PUT \
--url https://dev.abdm.gov.in/api/hiecm/subscription-requests/v3/patients/{subscriptionID} \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-AUTH-TOKEN: <TOKEN>' \
--header 'Content-Type: application/json' \
--data '{
"hiuId": "INDIA_HIU",
"subscriptionEditAndApprovalRequest": {
"isApplicableForAllHIPs": true,
"includedSources": [
{
"hiTypes": [
"Prescription"
],
"purpose": {
"text": "Care Management",
"code": "CAREMGT",
"refUri": "https://abc.def.in"
},
"hip": {
"id": "INDIA_HIP",
"name": "INDIA HIP",
"type": "HIP"
},
"categories": [
"LINK"
],
"period": {
"from": "2024-05-09T10:34:00.389Z",
"to": "2024-05-09T10:34:00.389Z"
},
"status": "SUCCESS"
}
],
"excludedSources": [
{
"hiTypes": [
"Prescription"
],
"purpose": {
"text": "Care Management",
"code": "CAREMGT",
"refUri": "https://abc.def.in"
},
"hip": {
"id": "INDIA_HIP",
"name": "INDIA HIP",
"type": "HIP"
},
"categories": [
"LINK"
],
"period": {
"from": "2024-05-09T10:34:00.389Z",
"to": "2024-05-09T10:34:00.389Z"
},
"status": "SUCCESS"
}
]
}
}'
```
#### 5. Disable the subscription by subscription ID (`p3_post_subscription_requests_v3_disable_subscription_id`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/subscription-requests/v3/disable/{subscriptionID} \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-AUTH-TOKEN: <TOKEN>'
```
#### 6. Enable the subscription by subscription ID (`p3_post_subscription_requests_v3_enable_subscription_id`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/subscription-requests/v3/enable/{subscriptionID} \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-AUTH-TOKEN: <TOKEN>'
```
#### 7. Fetch his/her subscription details by subscription REQUEST-ID (`p3_get_subscription_requests_v3_request_request_id`)
```bash
curl --request GET \
--url https://dev.abdm.gov.in/api/hiecm/subscription-requests/v3/request/{subscriptionRequestId} \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-AUTH-TOKEN: <TOKEN>'
```
#### 8. Fetch his/her subscription details by subscription ID (`p3_get_subscription_requests_v3_subscription_id`)
```bash
curl --request GET \
--url https://dev.abdm.gov.in/api/hiecm/subscription-requests/v3/{subscriptionID} \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-AUTH-TOKEN: <TOKEN>'
```
**Exit condition (Observe until this is true)**
A 200 whose body matches:
```json
{
"subscriptionId": "f29f0e59-8388-4698-9fe6-05db67aeac46",
"purpose": {
"text": "Care Management",
"code": "CAREMGT",
"refUri": "https://abc.def.in"
},
"dateCreated": "2021-09-28T12:30:08.573Z",
"status": "GRANTED",
"dateGranted": "2021-09-28T12:30:08.573Z",
"patient": {
"id": "<ABHA_ADDRESS>"
},
"requester": {
"id": "<ABHA_ADDRESS>",
"name": "ABDM_HIU",
"type": "HIU"
},
"includedSources": [
{
"hip": {
"id": "INDIA_HIP",
"name": "INDIA HIP",
"type": "HIP"
},
"categories": [
"LINK"
],
"hiTypes": [
"Prescription"
],
"period": {
"from": "2024-05-09T10:34:00.389Z",
"to": "2024-05-09T10:34:00.389Z"
},
"status": "GRANTED"
}
]
}
```
## Where the detail is
- Every operation, with its body fields and responses: /docs/hiecm/v3/api/p3
- Error codes: /docs/hiecm/v3/api/p3/errors

View File

@ -0,0 +1,77 @@
---
name: abdm-p4
description: Use when building, debugging or testing ABDM P4, health lockers: setting up a locker and listing the lockers and requests on an ABHA address.
type: skill
domain: p4
agent_consumers:
- abdm-integration-agent
- abdm-call-debugger
requires:
- phr-login
produces:
- locker-record
can_execute: true
can_orchestrate: false
---
# ABDM P4, health lockers
Generated from the ABDM Developer Portal on 2026-09-16, catalogue version 2026.09.16. Every fact below comes from a page in that portal, which is the place to look when this file does not carry enough.
This file is a snapshot. Re-download the whole folder from https://docs.abdm.gov.in/skills/abdm-p4/ when it is older than the work you are doing: this router and every file under references/ that it links to. Fetching this file alone leaves those links pointing at files you do not have.
If the abdm-docs MCP server is connected, trust its answers over this file: it serves the current catalogue and stamps every response with its catalogue_version, which you can compare against the version above.
## What you can do with P4
- Locker
What it cannot do yet matters as much. Read **Before anything else** below before assuming a capability is one endpoint away.
## Try asking
- "Set up a health locker for this user"
- "What has to be in place before my first P4 call?"
- "My P4 call failed. Here is the response: what is wrong, and how do I fix it?"
Loaded with no task? Say in three lines what this skill does. Offer the prompts above. Then ask what the person is building, and whether the code for it exists yet.
## What is in this folder
- **Scaffold.** Survey the codebase first when one exists, then build it flow by flow against the sandbox, as a loop that ends when the step's exit condition holds rather than on a call returning 200. [references/scaffold.md](references/scaffold.md)
- **Integrate.** 9 operations, with their hosts and headers. [references/integrate.md](references/integrate.md)
- **Debug.** The specification's examples return no error code for this module. [references/debug.md](references/debug.md)
This file is the map. Each line above is a file beside it, opened one at a time rather than read through.
## Before anything else
- Treat every request and response shape in this skill as unconfirmed until the sandbox has answered you. Check a response before you rely on its shape.
## Practices that hold across every call
- Read the body, not only the status. A refusal often names the field in its body while the status says nothing useful.
- When ABDM publishes a value, read it rather than hard coding what it currently says. That covers a parameter, such as the encryption algorithm the certificate endpoints return beside the key, and it covers an enumeration. The registries publish theirs as master data calls: councils, courses, colleges, states and districts on the HPR, and facility types and LGD codes on the HFR. A table typed into your source goes stale silently. Purposes and HI types have no master data call: take them from the enumeration in the specification of the call you are making. Refuse to act on a published value you do not recognise rather than falling back to a default.
- Read every field in a response, not the one you came for. The M1 certificate call returns the encryption algorithm next to the key.
- Prove an assumption against a call that is able to disagree with you. A call that refuses every input with one message cannot tell you which input was right.
- Suspect the transport before the data. When a call refuses a value you believe in, check the encryption, the headers and the clock before you doubt the value.
- Do not carry an encryption path from one module to another. Read the certificate and the algorithm from the registry you are calling.
- Never log a sensitive value before you encrypt it, and never send one to a remote service to be encrypted. Both move the leak rather than removing it.
- Generate a fresh REQUEST-ID for every call and log it before sending. Once a call has failed it is the only handle on it.
- Check the host on any sample before you copy it. A request copied whole can be correct in every respect except where it is pointed, and that failure looks like credentials.
- Do not validate an identifier more strictly than the platform does. A schema that types a field as a UUID is not a promise that every value is one. Refusing a value ABDM would have accepted turns your own client into the thing that broke.
- Read a plural response as plural. A verification returns an accounts array and a consent request can produce more than one artefact. Store the collection and decide from its length.
- A documented callback path is not a documented callback payload. Log the whole body on arrival before you parse it, so a handler written against an assumed shape fails where you can see it.
- Decode a token before you use it. A call that hands you a token has not necessarily handed you the token the next call wants, and the claims are base64 that need no library to read.
- When a journey carries the same parameter through two calls, check what each call's specification asks for rather than carrying the first value forward.
- Do not infer which path an identifier belongs to from where that identifier is most discussed. Send every identifier to the lookup first and let the answer pick the path, so nobody who already holds an account is sent to create a second.
- Do not match an error code with string equality. A code may come back bare, as `ABDM-1001`, or with a trailing `: ` separator, as `ABDM-1001: `. Match on the code itself and tolerate the separator.
- Handle a failure that carries no body. Check for an empty body before you parse, or your client throws on the simplest failure there is.
- Back off on an authentication failure rather than retrying, and never loop a credential check.
- Send TIMESTAMP in UTC, ISO-8601 with milliseconds and a trailing Z, as in `2022-10-06T15:10:00.587Z`.
- Cache a public certificate with a validity window rather than forever. A rotation fails every encrypted call at once, and a cache with no expiry cannot recover on its own.
## Where the detail is
- Every endpoint, with its body fields and responses: /docs/hiecm/v3/api/p4
- Every error code across modules: /docs/hiecm/v3/reference/error-codes
- Terms: /docs/hiecm/v3/getting-started/glossary

View File

@ -0,0 +1,9 @@
# Debug P4, health lockers
The codes this module can return, with the message and the operation that returns each.
## Errors
The P4, health lockers specification's examples return no error code yet. That is a gap in the specification, not a promise that this module cannot fail.
A code you meet that is not above is one the specifications do not carry yet. Read the code together with the message: a code can appear twice with different meanings.

View File

@ -0,0 +1,44 @@
# Integrate P4, health lockers
The calls themselves: where they live, what they need in their headers, and one request written out in full.
## Hosts
- `https://dev.abdm.gov.in` ABDM gateway, sandbox
- `https://apis.abdm.gov.in` ABDM gateway, production
## Endpoints
9 operations, grouped by the journey they belong to.
### Other operations
| Method | Path | What it does |
| --- | --- | --- |
| `GET` | `/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id}` | Fetch the details of a service ID. |
| `GET` | `/api/hiecm/gateway/v3/bridge-services` | Fetch the service ids registered against a bridge. |
| `PATCH` | `/api/hiecm/gateway/v3/bridge/url` | Update the bridge URL. |
| `GET` | `/api/hiecm/gateway/v3/health-lockers` | Fetch the record with health locker enabled provider details. |
| `POST` | `/api/hiecm/gateway/v3/sessions` | Generate access token. |
| `GET` | `/api/hiecm/subscription-requests/v3/patients/lockers` | The API provides the list of health locker that the ABHA address is subscribed … |
| `GET` | `/api/hiecm/subscription-requests/v3/patients/lockers/{locker-id}` | Get health locker settings of a patient by locker ID. |
| `GET` | `/api/hiecm/subscription-requests/v3/patients/requests` | Get all the consent and subscription requests with given filters. |
| `POST` | `/api/hiecm/subscription-requests/v3/setup-locker` | Setup health locker for a patient. |
## Headers
| Header | What it is |
| --- | --- |
| `REQUEST-ID` | Unique UUID for track the end to end request transaction |
| `TIMESTAMP` | Actual time of the request was initiated, ISO 8601 represents date and time by starting with the year, follow… |
| `X-CM-ID` | Suffix of the consent manager to which the request was intended |
| `X-AUTH-TOKEN` | JWT Authentication token issued by ABDM after successful validation of username and password |
| `X-LOCKER-ID` | The locker id |
## A request, in full
```bash
curl --request GET \
--url https://dev.abdm.gov.in/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id} \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx'
```

View File

@ -0,0 +1,222 @@
# HIE-CM p4 build
Scaffolds an ABDM p4 integration one journey at a time. It covers setting up a health locker and listing the lockers and requests on an ABHA address.
## How this skill runs
Every journey below is an OODA loop, not a recipe: observe the actual state (last response, last error), orient against the step matched below, decide the cheapest next action, act, and return to observe. A step is done only when its exit condition is observed against the sandbox, never because it "should have worked."
Loop limit: 8 passes per step. Hitting the limit is an escalation: state what was observed, what was tried, and which operation page to read, then ask one question.
## Before the first journey, when the codebase already exists
Skip this section only for a system that does not exist yet. Otherwise it runs first, and its exit condition is a written plan, not a call.
### In plain words
Most ABDM integrations are not new systems. They are a hospital management
system, a laboratory system or a clinic application that already has patients,
visits, records, a login, an HTTP client and a way of keeping secrets. Every
ABDM journey has to land somewhere inside that, and a journey built before the
codebase has been read lands in the wrong place: a second HTTP client beside the
first, an ABHA column on the wrong table, a callback route the reverse proxy
never forwards.
So the first loop is not a journey. It is a survey of the system as it is, and
its exit condition is a written plan that names, for every ABDM touchpoint, the
file it will live in. The journeys then build against that plan rather than
against the specification's idea of a fresh codebase.
### Before you start
- The repository, checked out, with permission to read all of it. A survey of
half a codebase produces a plan for half a system.
- The answers to the deployment interview. The
code says what the system is. Only the integrator can say what the
deployment is, and the two together decide which journeys are built at all.
- The practices that hold across every call, which
the plan has to leave room for.
### What happens
This is one loop with a limit of eight passes over the codebase. Each pass
reads live state only, which here means the files themselves, never a README's
description of them and never an assumption carried from a similar system.
**Observe.** Inventory the system from its manifests and its tree, not from its
documentation. Record file paths for each of these, or record that none exists:
| Find | Where it usually shows | Why ABDM needs it |
|---|---|---|
| Languages and runtime versions | package manifests, lock files, toolchain files | Every generated call has to be idiomatic here |
| Build, run and test commands | manifests, CI configuration, a Makefile | Each journey's exit condition becomes a test that runs the same way |
| The frontend and backend split, and how they talk | the top level tree, an API client in the frontend, route definitions in the backend | The counter screens go in the frontend; every ABDM call goes through the backend |
| The outbound HTTP client the backend already uses | the dependency list, a shared client module | ABDM calls reuse it, or a second one appears and the two drift |
| How secrets and configuration reach the process | environment loading, a vault client, a config file | The client id, the secret and the access token travel the same way |
| The patient model, and the identifier fields it already carries | the schema, the ORM models, the migrations | The ABHA number and address become columns beside the existing identifiers, not a new table |
| The visit, encounter or record model | the same places | A care context maps to one of these, and the plan has to say which |
| Where inbound HTTP is routed and authenticated, and whether the deployment has a public URL | the router, the middleware, the reverse proxy configuration, the deployment manifests | ABDM calls back, and a callback route that nothing forwards is silence nobody notices |
| Existing cryptography helpers | a security or crypto module, the dependency list | The RSA encryption of identifiers reuses them |
| Where errors are shown to a user, and where they are logged | the frontend's error surface, the logging setup | A refused call has to land on the screen the person is looking at, and never log a token |
**Orient.** Map each ABDM touchpoint onto that inventory. Where the map is
exact, write the file path. Where it is not, write two candidates and say what
would decide between them. The common ambiguities: two places that could hold
the patient identifier, an HTTP client in the frontend and none in the backend,
a monorepo with several services and no obvious owner for callbacks.
Then read the interview answers against the inventory. A government integrator
gets the demographic route; a facility with no public URL gets no callback
driven journey until it has one; a desk with a fingerprint reader gets the
biometric method. The route set is the intersection of what the deployment
allows and what the code can host.
**Decide.** Order the journeys. The token comes first because every other call
needs it: the gateway session token, or for M4 the bearer token the registry calls
carry. Then the journey whose exit condition can be observed with
the least new code, usually a profile read for a patient who already holds an
ABHA. Creation and linking come after, because each depends on state the earlier
ones produce. For each journey, name the files it will touch and the test that
proves its exit condition.
**Act.** Write the plan. It is a file in the repository, at the path the
integrator names or at the root as `abdm-integration-plan.md`, and it is the
only output of this loop. Then return to observe once, reading the plan against
the tree, to confirm every path in it exists or is marked as new.
If the limit is reached with questions still open, escalate: name what was
found, name the two candidates that could not be separated, point at this
atom, and ask one question.
### How you know it worked
The plan exists and answers every row of the inventory table with a file path,
or with the words none, add at, followed by a path. No row is blank and no row
says to be decided.
Every ABDM touchpoint in the plan names one file, or names two candidates and
the observation that would choose between them. Every journey in the plan names
the test that proves its exit condition and the command that runs it.
Open the plan beside the tree. Every path it names resolves, or is marked as
new. That is the observation that ends this loop, and the first journey does
not start until it has been made.
### When it goes wrong
- **The plan puts the HTTP client in the frontend.** The survey found the
frontend's API client and stopped. Every ABDM call carries a secret, so it
goes through the backend, and the plan has to say which backend module.
- **Two patient tables, and the plan picked one.** Orient produced one
hypothesis where it needed two. Name both, and name the query that shows
which one the visit model points at.
- **The plan has a callback route and the deployment has no public URL.** The
inventory row on inbound routing was answered from the router rather than
from the deployment. Mark every callback driven journey as blocked on a URL,
and build the ones that are not.
- **The survey read the README and not the tree.** A README describes the
system somebody meant to build. The plan is for the one that exists.
- **Eight passes and the plan is still incomplete.** Escalate with the rows
that are answered, the rows that are not, this atom, and one question about
the row that blocks the most journeys.
From `shared.concept.survey-an-existing-codebase`.
## Journeys
### Locker (`p4-locker`)
**Act: the calls in this journey, in order**
#### 1. Setup health locker for a patient (`p4_post_subscription_requests_v3_setup_locker`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/subscription-requests/v3/setup-locker \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-AUTH-TOKEN: <TOKEN>' \
--header 'X-LOCKER-ID: <X_LOCKER_ID>'
```
#### 2. Get the subscription requests patients lockers (`p4_get_subscription_requests_v3_patients_lockers`)
```bash
curl --request GET \
--url "https://dev.abdm.gov.in/api/hiecm/subscription-requests/v3/patients/lockers?includeInactive=true" \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-AUTH-TOKEN: <TOKEN>'
```
#### 3. Get health locker settings of a patient by locker ID (`p4_get_subscription_requests_v3_patients_lockers_lockerid`)
```bash
curl --request GET \
--url https://dev.abdm.gov.in/api/hiecm/subscription-requests/v3/patients/lockers/{locker-id} \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-AUTH-TOKEN: <TOKEN>'
```
#### 4. Get all the consent and subscription requests with given filters (`p4_get_subscription_requests_v3_patients_requests`)
```bash
curl --request GET \
--url "https://dev.abdm.gov.in/api/hiecm/subscription-requests/v3/patients/requests?consentLimit=<CONSENTLIMIT>&consentOffset=<CONSENTOFFSET>&subscriptionLimit=<SUBSCRIPTIONLIMIT>&subscriptionOffset=<SUBSCRIPTIONOFFSET>&status=ALL" \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-AUTH-TOKEN: <TOKEN>'
```
#### 5. Fetch the record with health locker enabled provider details (`p4_get_gateway_v3_health_lockers`)
```bash
curl --request GET \
--url https://dev.abdm.gov.in/api/hiecm/gateway/v3/health-lockers \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx'
```
**Exit condition (Observe until this is true)**
A 200 whose body matches:
```json
[
{
"identifier": {
"name": "AB - PMJAY",
"id": "PMJAY"
},
"facilityType": [
"HIP"
],
"isHip": true,
"isGovtEntity": false,
"endpoints": {
"healthLockerEndpoints": [
{
"use": "registration",
"connectionType": "HTTPS",
"address": "https://abc.com/register"
}
]
}
}
]
```
## Where the detail is
- Every operation, with its body fields and responses: /docs/hiecm/v3/api/p4

View File

@ -0,0 +1,80 @@
---
name: abdm-record-share
description: Use when building, debugging or testing ABDM patient scan and record share: a PHR app shares chosen records with an HIU after scanning its QR code, on either side.
type: skill
domain: record-share
agent_consumers:
- abdm-integration-agent
- abdm-call-debugger
requires:
- gateway-session-token
- hip-registration
- callback-url
produces:
- shared-record
can_execute: true
can_orchestrate: false
---
# ABDM Patient scan and record share
Generated from the ABDM Developer Portal on 2026-09-16, catalogue version 2026.09.16. Every fact below comes from a page in that portal, which is the place to look when this file does not carry enough.
This file is a snapshot. Re-download the whole folder from https://docs.abdm.gov.in/skills/abdm-record-share/ when it is older than the work you are doing: this router and every file under references/ that it links to. Fetching this file alone leaves those links pointing at files you do not have.
If the abdm-docs MCP server is connected, trust its answers over this file: it serves the current catalogue and stamps every response with its catalogue_version, which you can compare against the version above.
## What you can do with Patient scan and record share
- Record share, PHR app side
- Record share, HIU side
What it cannot do yet matters as much. Read **Before anything else** below before assuming a capability is one endpoint away.
## Try asking
- "Receive the records a patient shares from a PHR app after scanning our QR code"
- "What has to be in place before my first Patient scan and record share call?"
- "My Patient scan and record share call failed. Here is the response: what is wrong, and how do I fix it?"
Loaded with no task? Say in three lines what this skill does. Offer the prompts above. Then ask what the person is building, and whether the code for it exists yet.
## What is in this folder
- **Scaffold.** Survey the codebase first when one exists, then build it flow by flow against the sandbox, as a loop that ends when the step's exit condition holds rather than on a call returning 200. [references/scaffold.md](references/scaffold.md)
- **Integrate.** 12 operations, with their hosts and headers. [references/integrate.md](references/integrate.md)
- **Debug.** The specification's examples return no error code for this module. [references/debug.md](references/debug.md)
This file is the map. Each line above is a file beside it, opened one at a time rather than read through.
## Before anything else
- Treat every request and response shape in this skill as unconfirmed until the sandbox has answered you. Check a response before you rely on its shape.
## Practices that hold across every call
- Read the body, not only the status. A refusal often names the field in its body while the status says nothing useful.
- When ABDM publishes a value, read it rather than hard coding what it currently says. That covers a parameter, such as the encryption algorithm the certificate endpoints return beside the key, and it covers an enumeration. The registries publish theirs as master data calls: councils, courses, colleges, states and districts on the HPR, and facility types and LGD codes on the HFR. A table typed into your source goes stale silently. Purposes and HI types have no master data call: take them from the enumeration in the specification of the call you are making. Refuse to act on a published value you do not recognise rather than falling back to a default.
- Read every field in a response, not the one you came for. The M1 certificate call returns the encryption algorithm next to the key.
- Prove an assumption against a call that is able to disagree with you. A call that refuses every input with one message cannot tell you which input was right.
- Suspect the transport before the data. When a call refuses a value you believe in, check the encryption, the headers and the clock before you doubt the value.
- Do not carry an encryption path from one module to another. Read the certificate and the algorithm from the registry you are calling.
- Never log a sensitive value before you encrypt it, and never send one to a remote service to be encrypted. Both move the leak rather than removing it.
- Generate a fresh REQUEST-ID for every call and log it before sending. Once a call has failed it is the only handle on it.
- Check the host on any sample before you copy it. A request copied whole can be correct in every respect except where it is pointed, and that failure looks like credentials.
- Do not validate an identifier more strictly than the platform does. A schema that types a field as a UUID is not a promise that every value is one. Refusing a value ABDM would have accepted turns your own client into the thing that broke.
- Read a plural response as plural. A verification returns an accounts array and a consent request can produce more than one artefact. Store the collection and decide from its length.
- A documented callback path is not a documented callback payload. Log the whole body on arrival before you parse it, so a handler written against an assumed shape fails where you can see it.
- Decode a token before you use it. A call that hands you a token has not necessarily handed you the token the next call wants, and the claims are base64 that need no library to read.
- When a journey carries the same parameter through two calls, check what each call's specification asks for rather than carrying the first value forward.
- Do not infer which path an identifier belongs to from where that identifier is most discussed. Send every identifier to the lookup first and let the answer pick the path, so nobody who already holds an account is sent to create a second.
- Do not match an error code with string equality. A code may come back bare, as `ABDM-1001`, or with a trailing `: ` separator, as `ABDM-1001: `. Match on the code itself and tolerate the separator.
- Handle a failure that carries no body. Check for an empty body before you parse, or your client throws on the simplest failure there is.
- Back off on an authentication failure rather than retrying, and never loop a credential check.
- Send TIMESTAMP in UTC, ISO-8601 with milliseconds and a trailing Z, as in `2022-10-06T15:10:00.587Z`.
- Cache a public certificate with a validity window rather than forever. A rotation fails every encrypted call at once, and a cache with no expiry cannot recover on its own.
## Where the detail is
- Every endpoint, with its body fields and responses: /docs/hiecm/v3/api/record-share
- Every error code across modules: /docs/hiecm/v3/reference/error-codes
- Terms: /docs/hiecm/v3/getting-started/glossary

View File

@ -0,0 +1,9 @@
# Debug Patient scan and record share
The codes this module can return, with the message and the operation that returns each.
## Errors
The Patient scan and record share specification's examples return no error code yet. That is a gap in the specification, not a promise that this module cannot fail.
A code you meet that is not above is one the specifications do not carry yet. Read the code together with the message: a code can appear twice with different meanings.

View File

@ -0,0 +1,50 @@
# Integrate Patient scan and record share
The calls themselves: where they live, what they need in their headers, and one request written out in full.
## Hosts
- `https://dev.abdm.gov.in` ABDM gateway, sandbox. X-CM-ID is sbx.
- `https://apis.abdm.gov.in` ABDM gateway, production. X-CM-ID is abdm.
## Endpoints
12 operations, grouped by the journey they belong to.
### Other operations
| Method | Path | What it does |
| --- | --- | --- |
| `GET` | `/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id}` | Fetch the details of a service ID. |
| `GET` | `/api/hiecm/gateway/v3/bridge-services` | Fetch the service ids registered against a bridge. |
| `PATCH` | `/api/hiecm/gateway/v3/bridge/url` | Update the bridge URL. |
| `POST` | `/api/hiecm/gateway/v3/sessions` | Generate access token. |
| `GET` | `/api/hiecm/patient-record/v3/audit-history` | List the record sharing history of the signed in user. |
| `POST` | `/api/hiecm/patient-record/v3/notify` | Notify the HIE-CM of the transfer status, once, after the data transfer complet… |
| `POST` | `/api/hiecm/patient-record/v3/on-share` | Reply to a share request with the data push URL and the encryption key. |
| `POST` | `/api/hiecm/patient-record/v3/share` | Share a patient's records with the HIU whose QR code was scanned. |
| `POST` | `/api/v3/patient-record/on-notify` | Receive the other side's transfer status. |
| `POST` | `/api/v3/patient-record/on-share` | Receive the HIU's data push URL and encryption key, as the PHR app. |
| `POST` | `/api/v3/patient-record/share` | Receive a patient's share request, as the HIU. |
| `POST` | `/health-information/transfer` | Receive the encrypted records at the data push URL, as the HIU. |
## Headers
| Header | What it is |
| --- | --- |
| `REQUEST-ID` | Unique UUID for track the end to end request transaction |
| `TIMESTAMP` | Actual time of the request was initiated, ISO 8601 represents date and time by starting with the year, follow… |
| `X-CM-ID` | Suffix of the consent manager to which the request was intended |
| `X-AUTH-TOKEN` | JWT access token issued by the PHR service after successful user authentication. If the HIP does not have any… |
| `X-HIU-ID` | Identifier of the health information user to which the request was intended. |
| `request-id` | Random UUID, a v4 style guid, unique per callback. |
| `timestamp` | ISO 8601 timestamp of when the callback was sent. |
| `x-hiu-id` | Identifier of the health information user to which the request was intended. |
## A request, in full
```bash
curl --request GET \
--url https://dev.abdm.gov.in/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id} \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx'
```

View File

@ -0,0 +1,379 @@
# HIE-CM record-share build
Scaffolds an ABDM record-share integration one journey at a time. It covers a patient sharing chosen records with an HIU from a PHR app after scanning its QR code.
## How this skill runs
Every journey below is an OODA loop, not a recipe: observe the actual state (last response, last error), orient against the step matched below, decide the cheapest next action, act, and return to observe. A step is done only when its exit condition is observed against the sandbox, never because it "should have worked."
Loop limit: 8 passes per step. Hitting the limit is an escalation: state what was observed, what was tried, and which operation page to read, then ask one question.
## Before the first journey, when the codebase already exists
Skip this section only for a system that does not exist yet. Otherwise it runs first, and its exit condition is a written plan, not a call.
### In plain words
Most ABDM integrations are not new systems. They are a hospital management
system, a laboratory system or a clinic application that already has patients,
visits, records, a login, an HTTP client and a way of keeping secrets. Every
ABDM journey has to land somewhere inside that, and a journey built before the
codebase has been read lands in the wrong place: a second HTTP client beside the
first, an ABHA column on the wrong table, a callback route the reverse proxy
never forwards.
So the first loop is not a journey. It is a survey of the system as it is, and
its exit condition is a written plan that names, for every ABDM touchpoint, the
file it will live in. The journeys then build against that plan rather than
against the specification's idea of a fresh codebase.
### Before you start
- The repository, checked out, with permission to read all of it. A survey of
half a codebase produces a plan for half a system.
- The answers to the deployment interview. The
code says what the system is. Only the integrator can say what the
deployment is, and the two together decide which journeys are built at all.
- The practices that hold across every call, which
the plan has to leave room for.
### What happens
This is one loop with a limit of eight passes over the codebase. Each pass
reads live state only, which here means the files themselves, never a README's
description of them and never an assumption carried from a similar system.
**Observe.** Inventory the system from its manifests and its tree, not from its
documentation. Record file paths for each of these, or record that none exists:
| Find | Where it usually shows | Why ABDM needs it |
|---|---|---|
| Languages and runtime versions | package manifests, lock files, toolchain files | Every generated call has to be idiomatic here |
| Build, run and test commands | manifests, CI configuration, a Makefile | Each journey's exit condition becomes a test that runs the same way |
| The frontend and backend split, and how they talk | the top level tree, an API client in the frontend, route definitions in the backend | The counter screens go in the frontend; every ABDM call goes through the backend |
| The outbound HTTP client the backend already uses | the dependency list, a shared client module | ABDM calls reuse it, or a second one appears and the two drift |
| How secrets and configuration reach the process | environment loading, a vault client, a config file | The client id, the secret and the access token travel the same way |
| The patient model, and the identifier fields it already carries | the schema, the ORM models, the migrations | The ABHA number and address become columns beside the existing identifiers, not a new table |
| The visit, encounter or record model | the same places | A care context maps to one of these, and the plan has to say which |
| Where inbound HTTP is routed and authenticated, and whether the deployment has a public URL | the router, the middleware, the reverse proxy configuration, the deployment manifests | ABDM calls back, and a callback route that nothing forwards is silence nobody notices |
| Existing cryptography helpers | a security or crypto module, the dependency list | The RSA encryption of identifiers reuses them |
| Where errors are shown to a user, and where they are logged | the frontend's error surface, the logging setup | A refused call has to land on the screen the person is looking at, and never log a token |
**Orient.** Map each ABDM touchpoint onto that inventory. Where the map is
exact, write the file path. Where it is not, write two candidates and say what
would decide between them. The common ambiguities: two places that could hold
the patient identifier, an HTTP client in the frontend and none in the backend,
a monorepo with several services and no obvious owner for callbacks.
Then read the interview answers against the inventory. A government integrator
gets the demographic route; a facility with no public URL gets no callback
driven journey until it has one; a desk with a fingerprint reader gets the
biometric method. The route set is the intersection of what the deployment
allows and what the code can host.
**Decide.** Order the journeys. The token comes first because every other call
needs it: the gateway session token, or for M4 the bearer token the registry calls
carry. Then the journey whose exit condition can be observed with
the least new code, usually a profile read for a patient who already holds an
ABHA. Creation and linking come after, because each depends on state the earlier
ones produce. For each journey, name the files it will touch and the test that
proves its exit condition.
**Act.** Write the plan. It is a file in the repository, at the path the
integrator names or at the root as `abdm-integration-plan.md`, and it is the
only output of this loop. Then return to observe once, reading the plan against
the tree, to confirm every path in it exists or is marked as new.
If the limit is reached with questions still open, escalate: name what was
found, name the two candidates that could not be separated, point at this
atom, and ask one question.
### How you know it worked
The plan exists and answers every row of the inventory table with a file path,
or with the words none, add at, followed by a path. No row is blank and no row
says to be decided.
Every ABDM touchpoint in the plan names one file, or names two candidates and
the observation that would choose between them. Every journey in the plan names
the test that proves its exit condition and the command that runs it.
Open the plan beside the tree. Every path it names resolves, or is marked as
new. That is the observation that ends this loop, and the first journey does
not start until it has been made.
### When it goes wrong
- **The plan puts the HTTP client in the frontend.** The survey found the
frontend's API client and stopped. Every ABDM call carries a secret, so it
goes through the backend, and the plan has to say which backend module.
- **Two patient tables, and the plan picked one.** Orient produced one
hypothesis where it needed two. Name both, and name the query that shows
which one the visit model points at.
- **The plan has a callback route and the deployment has no public URL.** The
inventory row on inbound routing was answered from the router rather than
from the deployment. Mark every callback driven journey as blocked on a URL,
and build the ones that are not.
- **The survey read the README and not the tree.** A README describes the
system somebody meant to build. The plan is for the one that exists.
- **Eight passes and the plan is still incomplete.** Escalate with the rows
that are answered, the rows that are not, this atom, and one question about
the row that blocks the most journeys.
From `shared.concept.survey-an-existing-codebase`.
## Journeys
### Record share, PHR app side (`record-share-phr`)
**Act: the calls in this journey, in order**
#### 1. Share a patient's records with the HIU whose QR code was scanned (`record-share_post_patient_record_v3_share`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/patient-record/v3/share \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-HIU-ID: HIU_ID' \
--header 'X-CM-ID: sbx' \
--header 'X-AUTH-TOKEN: Bearer <USER_TOKEN>' \
--header 'Content-Type: application/json' \
--data '{
"metaData": {
"hiuId": "MANISH_HIU",
"counterId": "IN081010313"
},
"profile": {
"patient": {
"abhaNumber": null,
"abhaAddress": "abhaAddress@sbx",
"name": "String",
"gender": "M",
"dayOfBirth": "18",
"monthOfBirth": "10",
"yearOfBirth": "1991",
"address": {
"line": "String",
"district": "String",
"state": "String",
"pincode": "XXXXXX"
},
"phoneNumber": "989141XXXX"
}
},
"sharedRecordCount": 2,
"consent": {
"careContexts": [
{
"patientReference": "manishk1991@sbx",
"careContextReference": "10004-20200001768-1"
},
{
"patientReference": "manishk1991@sbx",
"careContextReference": "10004-20200001768-2"
}
],
"permission": {
"accessMode": "VIEW"
},
"dataEraseAt": "2025-10-11T08:58:09.738Z"
}
}'
```
#### 2. Receive the HIU's data push URL and encryption key, as the PHR app (`record-share_post_v3_patient_record_on_share`)
Inbound to your bridge at `/api/v3/patient-record/on-share`. Acknowledge it and continue.
#### 3. Push the encrypted records to the HIU's data push URL, as the PHR app (`record-share_post_health_information_transfer`)
Outbound from your app. POST the encrypted records to the `dataPushUrl` the HIU sent in the on-share of step 2. The call goes straight to the HIU, not through the gateway. The HIU answers 202.
#### 4. Notify patient record (`record-share_post_patient_record_v3_notify`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/patient-record/v3/notify \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-HIU-ID: HIU_ID' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"notification": {
"transactionId": "a0e7bed4-ef98-4ea8-9077-f4a6192bfe2b",
"doneAt": "2026-03-19T08:01:11.090Z",
"statusNotification": {
"sessionStatus": "TRANSFERRED",
"statusResponses": [
{
"careContextReference": "COC497647c1-0627-48fa-8131-0dddc1b3e0b4",
"hiStatus": "DELIVERED",
"description": "Data sent successfully"
},
{
"careContextReference": "COC497647c1-0627-48fa-8131-0dddc1b3e0b5",
"hiStatus": "DELIVERED",
"description": "Data sent successfully"
}
]
}
}
}'
```
#### 5. Receive the other side's transfer status (`record-share_post_v3_patient_record_on_notify`)
Inbound to your bridge at `/api/v3/patient-record/on-notify`. Acknowledge it and continue.
#### 6. List the record sharing history of the signed in user (`record-share_get_patient_record_v3_audit_history`)
```bash
curl --request GET \
--url https://dev.abdm.gov.in/api/hiecm/patient-record/v3/audit-history \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-AUTH-TOKEN: Bearer <USER_TOKEN>'
```
**Exit condition (Observe until this is true)**
Each call you made in this journey answered by its callback, with `response.requestId` equal to the `REQUEST-ID` you sent on that call. The 202 on a call is receipt, not the outcome: the outcome is in the callback's body.
- `POST /api/hiecm/patient-record/v3/share` is answered by `POST /api/v3/patient-record/share` on your bridge.
- `POST /api/hiecm/patient-record/v3/notify` is answered by `POST /api/v3/patient-record/on-notify` on your bridge.
Then `GET /api/hiecm/patient-record/v3/audit-history` returns a 200 whose body matches:
```json
[
{
"requestId": "ed9f451d-9e07-484d-ab68-9972d6529d68",
"abhaAddress": "manishk1991@sbx",
"senderFacilityId": "MANISH_PHR_TEST",
"senderFacilityName": "MANISH-PHR-TEST",
"receiverFacilityId": "MANISH_HIU",
"receiverFacilityName": "MANISH_HIU",
"counterCode": "f4cd0d8e-25ec-465f-993c-01c91a56e0e4",
"transactionId": "f413b202-16b6-4d4a-9900-5cdcfb8baa50",
"status": "RECORD_SHARE_REQUESTED",
"sharedRecordCount": 2,
"consent": {
"accessMode": "VIEW",
"dataEraseAt": "2026-10-12T08:58:09.738Z",
"careContexts": [
{
"patientReference": "manikandanb87@sbx",
"careContextReference": "COC497647c1-0627-48fa-8131-0dddc1b3e0b4"
},
{
"patientReference": "manikandanb87@sbx",
"careContextReference": "COC497647c1-0627-48fa-8131-0dddc1b3e0b5"
}
]
},
"dateCreated": "2025-12-08T12:04:53.594Z",
"dateModified": "2025-12-08T12:04:53.594Z"
}
]
```
### Record share, HIU side (`record-share-hiu`)
**Act: the calls in this journey, in order**
#### 1. Receive a patient's share request, as the HIU (`record-share_post_v3_patient_record_share`)
Inbound to your bridge at `/api/v3/patient-record/share`. Acknowledge it and continue.
#### 2. Submit the reply to a share request with the data push URL and the encryption key (`record-share_post_patient_record_v3_on_share`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/patient-record/v3/on-share \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-HIU-ID: HIU_ID' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"hiRequest": {
"transactionId": "18235d89-cb13-479d-ad71-7a57d5f669a8",
"dataPushUrl": "https://webhook.site/a2477c41-2185-47eb-835a/health-information/transfer",
"keyMaterial": {
"cryptoAlg": "ECDH.",
"curve": "curve25519",
"dhPublicKey": {
"expiry": "2022-12-28T13:18:20.742Z",
"parameters": "Ephemeral public key.",
"keyValue": "BFN7KTdOT0jIAExG2A8Jg+01wMPWxptiGqwHRVvtiVEsUq2FR7P2UdqZxJyPJSeR6muai21iQhasNxnhh8I5M+g="
},
"nonce": "28236d89-cb13-479d-ad71-7a57d5f669a9"
}
},
"response": {
"requestId": "efd6964f-6893-4b66-9e4e-28afc164126b"
}
}'
```
#### 3. Receive the encrypted records at the data push URL, as the HIU (`record-share_post_health_information_transfer`)
Inbound to your bridge at `/health-information/transfer`. Acknowledge it and continue.
#### 4. Receive the other side's transfer status (`record-share_post_v3_patient_record_on_notify`)
Inbound to your bridge at `/api/v3/patient-record/on-notify`. Acknowledge it and continue.
#### 5. Notify patient record (`record-share_post_patient_record_v3_notify`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/patient-record/v3/notify \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-HIU-ID: HIU_ID' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"notification": {
"transactionId": "3acbbb52-6de0-441f-b452-3c9488462b25",
"doneAt": "2023-01-24T06:35:44.167Z",
"statusNotification": {
"sessionStatus": "RECEIVED",
"statusResponses": [
{
"careContextReference": "10004-20200001768-1",
"hiStatus": "VALID",
"description": "Data received successfully"
},
{
"careContextReference": "10004-20200001768-2",
"hiStatus": "ERRORED",
"description": "Data could not be decrypted"
}
]
}
}
}'
```
**Exit condition (Observe until this is true)**
Each call you made in this journey answered by its callback, with `response.requestId` equal to the `REQUEST-ID` you sent on that call. The 202 on a call is receipt, not the outcome: the outcome is in the callback's body.
- `POST /api/hiecm/patient-record/v3/on-share` is answered by `POST /api/v3/patient-record/on-share` on your bridge.
- `POST /api/hiecm/patient-record/v3/on-share` is answered by `POST /health-information/transfer` on your bridge.
- `POST /api/hiecm/patient-record/v3/notify` is answered by `POST /api/v3/patient-record/on-notify` on your bridge.
## Where the detail is
- Every operation, with its body fields and responses: /docs/hiecm/v3/api/record-share
- Error codes: /docs/hiecm/v3/api/record-share/errors

View File

@ -0,0 +1,82 @@
---
name: abdm-scan-and-pay
description: Use when building, debugging or testing ABDM scan and pay: open orders, patient selection and payment status between a facility and a PHR app.
type: skill
domain: scan-and-pay
agent_consumers:
- abdm-integration-agent
- abdm-call-debugger
requires:
- gateway-session-token
- facility-id
- callback-url
produces:
- order
- payment-status
can_execute: true
can_orchestrate: false
---
# ABDM Scan and pay
Generated from the ABDM Developer Portal on 2026-09-16, catalogue version 2026.09.16. Every fact below comes from a page in that portal, which is the place to look when this file does not carry enough.
This file is a snapshot. Re-download the whole folder from https://docs.abdm.gov.in/skills/abdm-scan-and-pay/ when it is older than the work you are doing: this router and every file under references/ that it links to. Fetching this file alone leaves those links pointing at files you do not have.
If the abdm-docs MCP server is connected, trust its answers over this file: it serves the current catalogue and stamps every response with its catalogue_version, which you can compare against the version above.
## What you can do with Scan and pay
- Scan and pay, HIP side
- Scan and pay, PHR side
- Scan and pay details and version update
What it cannot do yet matters as much. Read **Before anything else** below before assuming a capability is one endpoint away.
## Try asking
- "Open an order at this counter and take payment from a PHR app"
- "What has to be in place before my first Scan and pay call?"
- "My Scan and pay call failed. Here is the response: what is wrong, and how do I fix it?"
Loaded with no task? Say in three lines what this skill does. Offer the prompts above. Then ask what the person is building, and whether the code for it exists yet.
## What is in this folder
- **Scaffold.** Survey the codebase first when one exists, then build it flow by flow against the sandbox, as a loop that ends when the step's exit condition holds rather than on a call returning 200. [references/scaffold.md](references/scaffold.md)
- **Integrate.** 22 operations, with their hosts and headers. [references/integrate.md](references/integrate.md)
- **Debug.** The specification's examples return no error code for this module. [references/debug.md](references/debug.md)
This file is the map. Each line above is a file beside it, opened one at a time rather than read through.
## Before anything else
- Treat every request and response shape in this skill as unconfirmed until the sandbox has answered you. Check a response before you rely on its shape.
## Practices that hold across every call
- Read the body, not only the status. A refusal often names the field in its body while the status says nothing useful.
- When ABDM publishes a value, read it rather than hard coding what it currently says. That covers a parameter, such as the encryption algorithm the certificate endpoints return beside the key, and it covers an enumeration. The registries publish theirs as master data calls: councils, courses, colleges, states and districts on the HPR, and facility types and LGD codes on the HFR. A table typed into your source goes stale silently. Purposes and HI types have no master data call: take them from the enumeration in the specification of the call you are making. Refuse to act on a published value you do not recognise rather than falling back to a default.
- Read every field in a response, not the one you came for. The M1 certificate call returns the encryption algorithm next to the key.
- Prove an assumption against a call that is able to disagree with you. A call that refuses every input with one message cannot tell you which input was right.
- Suspect the transport before the data. When a call refuses a value you believe in, check the encryption, the headers and the clock before you doubt the value.
- Do not carry an encryption path from one module to another. Read the certificate and the algorithm from the registry you are calling.
- Never log a sensitive value before you encrypt it, and never send one to a remote service to be encrypted. Both move the leak rather than removing it.
- Generate a fresh REQUEST-ID for every call and log it before sending. Once a call has failed it is the only handle on it.
- Check the host on any sample before you copy it. A request copied whole can be correct in every respect except where it is pointed, and that failure looks like credentials.
- Do not validate an identifier more strictly than the platform does. A schema that types a field as a UUID is not a promise that every value is one. Refusing a value ABDM would have accepted turns your own client into the thing that broke.
- Read a plural response as plural. A verification returns an accounts array and a consent request can produce more than one artefact. Store the collection and decide from its length.
- A documented callback path is not a documented callback payload. Log the whole body on arrival before you parse it, so a handler written against an assumed shape fails where you can see it.
- Decode a token before you use it. A call that hands you a token has not necessarily handed you the token the next call wants, and the claims are base64 that need no library to read.
- When a journey carries the same parameter through two calls, check what each call's specification asks for rather than carrying the first value forward.
- Do not infer which path an identifier belongs to from where that identifier is most discussed. Send every identifier to the lookup first and let the answer pick the path, so nobody who already holds an account is sent to create a second.
- Do not match an error code with string equality. A code may come back bare, as `ABDM-1001`, or with a trailing `: ` separator, as `ABDM-1001: `. Match on the code itself and tolerate the separator.
- Handle a failure that carries no body. Check for an empty body before you parse, or your client throws on the simplest failure there is.
- Back off on an authentication failure rather than retrying, and never loop a credential check.
- Send TIMESTAMP in UTC, ISO-8601 with milliseconds and a trailing Z, as in `2022-10-06T15:10:00.587Z`.
- Cache a public certificate with a validity window rather than forever. A rotation fails every encrypted call at once, and a cache with no expiry cannot recover on its own.
## Where the detail is
- Every endpoint, with its body fields and responses: /docs/hiecm/v3/api/scan-and-pay
- Every error code across modules: /docs/hiecm/v3/reference/error-codes
- Terms: /docs/hiecm/v3/getting-started/glossary

View File

@ -0,0 +1,9 @@
# Debug Scan and pay
The codes this module can return, with the message and the operation that returns each.
## Errors
The Scan and pay specification's examples return no error code yet. That is a gap in the specification, not a promise that this module cannot fail.
A code you meet that is not above is one the specifications do not carry yet. Read the code together with the message: a code can appear twice with different meanings.

View File

@ -0,0 +1,58 @@
# Integrate Scan and pay
The calls themselves: where they live, what they need in their headers, and one request written out in full.
## Hosts
- `https://dev.abdm.gov.in` ABDM gateway, sandbox
- `https://apis.abdm.gov.in` ABDM gateway, production
## Endpoints
22 operations, grouped by the journey they belong to.
### Other operations
| Method | Path | What it does |
| --- | --- | --- |
| `GET` | `/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id}` | Fetch the details of a service ID. |
| `GET` | `/api/hiecm/gateway/v3/bridge-services` | Fetch the service ids registered against a bridge. |
| `PATCH` | `/api/hiecm/gateway/v3/bridge/url` | Update the bridge URL. |
| `PATCH` | `/api/hiecm/gateway/v3/scanPay/updateVersion` | Update version to the serviceId. |
| `POST` | `/api/hiecm/gateway/v3/sessions` | Generate access token. |
| `POST` | `/api/hiecm/scan-gateway/v3/patient/on-selection` | Share payment bundle alone with procedures of the patient. |
| `POST` | `/api/hiecm/scan-gateway/v3/patient/on-share/open-order` | HIE-CM to send all the open order for patient. |
| `GET` | `/api/hiecm/scan-gateway/v3/patient/scan-pay/details` | This is retrieve the all the details of the user. |
| `POST` | `/api/hiecm/scan-gateway/v3/patient/scan-pay/notify` | Send the payment status to HIU. |
| `POST` | `/api/hiecm/scan-gateway/v3/patient/scan-pay/on-notify` | Notify to HIP so that confirm that the HIU received the payment status. |
| `POST` | `/api/hiecm/scan-gateway/v3/patient/scan-pay/on-order-status` | Check the status of reports. |
| `POST` | `/api/hiecm/scan-gateway/v3/patient/scan-pay/order-status` | Check the status of reports. |
| `POST` | `/api/hiecm/scan-gateway/v3/patient/selection` | Select the all open-order and send to HIP for a payment request detail. |
| `POST` | `/api/hiecm/scan-gateway/v3/patient/share/open-order` | Be invoked from the integrator application (any PHR application, just like ABHA… |
| `POST` | `/v3/patient/on-selection` | This is callback API for the API. This API needs to implement by HIU to receive… |
| `POST` | `/v3/patient/on-share/open-order` | This is a callback API for patient on-share. This API needs to implement by HIU… |
| `POST` | `/v3/patient/scan-pay/notify` | This is callback API for the notify API. This API needs to implement by HIU to … |
| `POST` | `/v3/patient/scan-pay/on-notify` | This is an callback API for on-notify API need to implement by HIP to received … |
| `POST` | `/v3/patient/scan-pay/on-order-status` | This is callback for the on-order-status API. This API needs to implement by HI… |
| `POST` | `/v3/patient/scan-pay/order-status` | This is callback API for the order_status API. This API needs to implement by H… |
| `POST` | `/v3/patient/selection` | This is the call back API for the selection API. This API needs to implement by… |
| `POST` | `/v3/patient/share/open-order` | Check the status of reports. |
## Headers
| Header | What it is |
| --- | --- |
| `REQUEST-ID` | Unique UUID for track the end to end request transaction |
| `TIMESTAMP` | Actual time of the request was initiated, ISO 8601 represents date and time by starting with the year, follow… |
| `X-CM-ID` | Suffix of the consent manager to which the request was intended |
| `X-AUTH-TOKEN` | JWT Authentication token which was issued by ABDM after successful validation of username and password |
| `X-HIP-ID` | Identifier of the health information provider to which the request was intended |
| `X-HIU-ID` | Identifier of the health information user to which the request was intended |
## A request, in full
```bash
curl --request GET \
--url https://dev.abdm.gov.in/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id} \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx'
```

View File

@ -0,0 +1,543 @@
# HIE-CM scan-and-pay build
Scaffolds an ABDM scan-and-pay integration one journey at a time. It covers open orders, patient selection and payment status between a facility and a PHR app.
## How this skill runs
Every journey below is an OODA loop, not a recipe: observe the actual state (last response, last error), orient against the step matched below, decide the cheapest next action, act, and return to observe. A step is done only when its exit condition is observed against the sandbox, never because it "should have worked."
Loop limit: 8 passes per step. Hitting the limit is an escalation: state what was observed, what was tried, and which operation page to read, then ask one question.
## Before the first journey, when the codebase already exists
Skip this section only for a system that does not exist yet. Otherwise it runs first, and its exit condition is a written plan, not a call.
### In plain words
Most ABDM integrations are not new systems. They are a hospital management
system, a laboratory system or a clinic application that already has patients,
visits, records, a login, an HTTP client and a way of keeping secrets. Every
ABDM journey has to land somewhere inside that, and a journey built before the
codebase has been read lands in the wrong place: a second HTTP client beside the
first, an ABHA column on the wrong table, a callback route the reverse proxy
never forwards.
So the first loop is not a journey. It is a survey of the system as it is, and
its exit condition is a written plan that names, for every ABDM touchpoint, the
file it will live in. The journeys then build against that plan rather than
against the specification's idea of a fresh codebase.
### Before you start
- The repository, checked out, with permission to read all of it. A survey of
half a codebase produces a plan for half a system.
- The answers to the deployment interview. The
code says what the system is. Only the integrator can say what the
deployment is, and the two together decide which journeys are built at all.
- The practices that hold across every call, which
the plan has to leave room for.
### What happens
This is one loop with a limit of eight passes over the codebase. Each pass
reads live state only, which here means the files themselves, never a README's
description of them and never an assumption carried from a similar system.
**Observe.** Inventory the system from its manifests and its tree, not from its
documentation. Record file paths for each of these, or record that none exists:
| Find | Where it usually shows | Why ABDM needs it |
|---|---|---|
| Languages and runtime versions | package manifests, lock files, toolchain files | Every generated call has to be idiomatic here |
| Build, run and test commands | manifests, CI configuration, a Makefile | Each journey's exit condition becomes a test that runs the same way |
| The frontend and backend split, and how they talk | the top level tree, an API client in the frontend, route definitions in the backend | The counter screens go in the frontend; every ABDM call goes through the backend |
| The outbound HTTP client the backend already uses | the dependency list, a shared client module | ABDM calls reuse it, or a second one appears and the two drift |
| How secrets and configuration reach the process | environment loading, a vault client, a config file | The client id, the secret and the access token travel the same way |
| The patient model, and the identifier fields it already carries | the schema, the ORM models, the migrations | The ABHA number and address become columns beside the existing identifiers, not a new table |
| The visit, encounter or record model | the same places | A care context maps to one of these, and the plan has to say which |
| Where inbound HTTP is routed and authenticated, and whether the deployment has a public URL | the router, the middleware, the reverse proxy configuration, the deployment manifests | ABDM calls back, and a callback route that nothing forwards is silence nobody notices |
| Existing cryptography helpers | a security or crypto module, the dependency list | The RSA encryption of identifiers reuses them |
| Where errors are shown to a user, and where they are logged | the frontend's error surface, the logging setup | A refused call has to land on the screen the person is looking at, and never log a token |
**Orient.** Map each ABDM touchpoint onto that inventory. Where the map is
exact, write the file path. Where it is not, write two candidates and say what
would decide between them. The common ambiguities: two places that could hold
the patient identifier, an HTTP client in the frontend and none in the backend,
a monorepo with several services and no obvious owner for callbacks.
Then read the interview answers against the inventory. A government integrator
gets the demographic route; a facility with no public URL gets no callback
driven journey until it has one; a desk with a fingerprint reader gets the
biometric method. The route set is the intersection of what the deployment
allows and what the code can host.
**Decide.** Order the journeys. The token comes first because every other call
needs it: the gateway session token, or for M4 the bearer token the registry calls
carry. Then the journey whose exit condition can be observed with
the least new code, usually a profile read for a patient who already holds an
ABHA. Creation and linking come after, because each depends on state the earlier
ones produce. For each journey, name the files it will touch and the test that
proves its exit condition.
**Act.** Write the plan. It is a file in the repository, at the path the
integrator names or at the root as `abdm-integration-plan.md`, and it is the
only output of this loop. Then return to observe once, reading the plan against
the tree, to confirm every path in it exists or is marked as new.
If the limit is reached with questions still open, escalate: name what was
found, name the two candidates that could not be separated, point at this
atom, and ask one question.
### How you know it worked
The plan exists and answers every row of the inventory table with a file path,
or with the words none, add at, followed by a path. No row is blank and no row
says to be decided.
Every ABDM touchpoint in the plan names one file, or names two candidates and
the observation that would choose between them. Every journey in the plan names
the test that proves its exit condition and the command that runs it.
Open the plan beside the tree. Every path it names resolves, or is marked as
new. That is the observation that ends this loop, and the first journey does
not start until it has been made.
### When it goes wrong
- **The plan puts the HTTP client in the frontend.** The survey found the
frontend's API client and stopped. Every ABDM call carries a secret, so it
goes through the backend, and the plan has to say which backend module.
- **Two patient tables, and the plan picked one.** Orient produced one
hypothesis where it needed two. Name both, and name the query that shows
which one the visit model points at.
- **The plan has a callback route and the deployment has no public URL.** The
inventory row on inbound routing was answered from the router rather than
from the deployment. Mark every callback driven journey as blocked on a URL,
and build the ones that are not.
- **The survey read the README and not the tree.** A README describes the
system somebody meant to build. The plan is for the one that exists.
- **Eight passes and the plan is still incomplete.** Escalate with the rows
that are answered, the rows that are not, this atom, and one question about
the row that blocks the most journeys.
From `shared.concept.survey-an-existing-codebase`.
## Journeys
### Scan and pay, HIP side (`scan-and-pay-abdm-scan-pay-hip`)
**Act: the calls in this journey, in order**
#### 1. Check the status of reports (`scan-and-pay_post_v3_patient_share_open_order`)
Inbound to your bridge at `/v3/patient/share/open-order`. Acknowledge it and continue.
#### 2. Submit the HIE-CM to send all the open order for patient (`scan-and-pay_post_scan_gateway_v3_patient_on_share_open_order`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/scan-gateway/v3/patient/on-share/open-order \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"intent": "OPEN_PAYMENT_ORDER",
"abhaAddress": "<ABHA_ADDRESS>",
"patientUid": "string",
"procedures": [
{
"category": "OPD consultation",
"services": [
{
"name": "consultation",
"serviceId": "service-12345",
"description": "Albumin 24 hrs Urine",
"amount": 629.12
}
]
},
{
"category": "Laboratory and Diagnostics",
"services": [
{
"name": "Diagnostics",
"serviceId": "service-12345",
"description": "Albumin 24 hrs Urine",
"amount": 629.12
}
]
},
{
"category": "Pharmacy",
"services": [
{
"name": "Pharmacy",
"serviceId": "service-12345",
"description": "Albumin 24 hrs Urine",
"amount": 629.12
}
]
},
{
"category": "Miscellaneous/Other",
"services": [
{
"name": "Miscellaneous",
"serviceId": "service-12345",
"description": "Albumin 24 hrs Urine",
"amount": 629.12
}
]
}
],
"response": {
"requestId": "6c3d4e5c-09d1-****-817b-a0c82d130c53"
}
}'
```
#### 3. Receive the patient selection (`scan-and-pay_post_v3_patient_selection`)
Inbound to your bridge at `/v3/patient/selection`. Acknowledge it and continue.
#### 4. Share payment bundle alone with procedures of the patient (`scan-and-pay_post_scan_gateway_v3_patient_on_selection`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/scan-gateway/v3/patient/on-selection \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"intent": "PAYMENT_ORDER",
"openOrderRequestId": "b767614f-153a-4aa3-946f-1622596f0fab",
"abhaAddress": "<ABHA_ADDRESS>",
"procedures": [
{
"category": "OPD consultation",
"services": [
{
"name": "consultation",
"serviceId": "service-12345",
"description": "Albumin 24 hrs Urine",
"amount": 629.12
}
]
},
{
"category": "Laboratory and Diagnostics",
"services": [
{
"name": "Diagnostics",
"serviceId": "service-12345",
"description": "Albumin 24 hrs Urine",
"amount": 629.12
}
]
},
{
"category": "Pharmacy",
"services": [
{
"name": "Pharmacy",
"serviceId": "service-12345",
"description": "Albumin 24 hrs Urine",
"amount": 629.12
}
]
}
],
"paymentBundle": {
"paymentMode": "GATEWAY",
"paymentUrl": "string",
"orderNumber": "string",
"amount": 1250.55,
"merchantId": "123465",
"description": "Testing"
},
"response": {
"requestId": "6c3d4e5c-09d1-***-817b-a0c82d130c53"
}
}'
```
#### 5. Send the payment status to HIU (`scan-and-pay_post_scan_gateway_v3_patient_scan_pay_notify`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/scan-gateway/v3/patient/scan-pay/notify \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-HIP-ID: IN2810014366' \
--header 'Content-Type: application/json' \
--data '{
"acknowledgement": {
"status": "SUCCESS/ CANCELED/ PENDING/ FAIL/ REFUND_INITIATED/ REFUND_SUCCESS",
"abhaAddress": "<username>@sbx",
"transactionId": "string",
"orderNumber": "string",
"openOrderRequestId": "b767614f-153a-4aa3-946f-1622596f0fab",
"paymentDate": "2025-01-20T07:47:49.102Z",
"paymentRecipetLink": "PDF URL LINK of RECIPT"
}
}'
```
#### 6. Receive the patient scan pay on notify (`scan-and-pay_post_v3_patient_scan_pay_on_notify`)
Inbound to your bridge at `/v3/patient/scan-pay/on-notify`. Acknowledge it and continue.
#### 7. Receive the patient scan pay order status (`scan-and-pay_post_v3_patient_scan_pay_order_status`)
Inbound to your bridge at `/v3/patient/scan-pay/order-status`. Acknowledge it and continue.
#### 8. Check the status of reports (`scan-and-pay_post_scan_gateway_v3_patient_scan_pay_on_ord_21f376`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/scan-gateway/v3/patient/scan-pay/on-order-status \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"acknowledgement": {
"status": "SUCCESS/ CANCELED/ PENDING/ FAIL/ REFUND_INITIATED/ REFUND_SUCCESS",
"abhaAddress": "<username>@sbx",
"transactionId": "string",
"orderNumber": "string",
"openOrderRequestId": "Queried Request id",
"paymentDate": "Transaction Date UTC",
"paymentRecipetLink": "PDF URL LINK of RECIPT"
},
"response": {
"requestId": "b767614f-153a-***-946f-1622596f0fab"
}
}'
```
**Exit condition (Observe until this is true)**
Each call you made in this journey answered by its callback, with `response.requestId` equal to the `REQUEST-ID` you sent on that call. The 202 on a call is receipt, not the outcome: the outcome is in the callback's body.
- `POST /api/hiecm/scan-gateway/v3/patient/scan-pay/notify` is answered by `POST /v3/patient/scan-pay/on-notify` on your bridge.
### Scan and pay, PHR side (`scan-and-pay-abdm-hiecm-scan-pay-phr`)
**Act: the calls in this journey, in order**
#### 1. Share patient open order (`scan-and-pay_post_scan_gateway_v3_patient_share_open_order`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/scan-gateway/v3/patient/share/open-order \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-AUTH-TOKEN: <TOKEN>' \
--header 'X-HIU-ID: IN2810014366' \
--header 'Content-Type: application/json' \
--data '{
"intent": "OPEN_PAYMENT_ORDER",
"metaData": {
"hipId": "HIP_1",
"counterId": "123-456"
},
"profile": {
"patient": {
"abhaNumber": "91-7507-xxxx-xxxx",
"abhaAddress": "<ABHA_ADDRESS>",
"name": "name",
"gender": "M",
"dayOfBirth": "string",
"monthOfBirth": "string",
"yearOfBirth": "string",
"address": {
"line": "Address line 1",
"district": "XXXXXXX",
"state": "XXXXXX",
"pincode": "XXXXXX"
},
"phoneNumber": "987654xxxx"
}
}
}'
```
#### 2. Receive the patient on-share (`scan-and-pay_post_v3_patient_on_share_open_order`)
Inbound to your bridge at `/v3/patient/on-share/open-order`. Acknowledge it and continue.
#### 3. Select the all open-order and send to HIP for a payment request detail (`scan-and-pay_post_scan_gateway_v3_patient_selection`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/scan-gateway/v3/patient/selection \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-AUTH-TOKEN: <TOKEN>' \
--header 'X-HIU-ID: IN2810014366' \
--header 'Content-Type: application/json' \
--data '{
"intent": "PAYMENT_ORDER",
"openOrderRequestId": "b767614f-153a-***-946f-1622596f0fab",
"abhaAddress": "<ABHA_ADDRESS>",
"procedures": [
{
"category": "OPD consultation",
"services": [
{
"name": "consultation",
"serviceId": "service-12345",
"description": "Albumin 24 hrs Urine",
"amount": 629.12
}
]
},
{
"category": "Laboratory and Diagnostics",
"services": [
{
"name": "Diagnostics",
"serviceId": "service-12345",
"description": "Albumin 24 hrs Urine",
"amount": 629.12
}
]
},
{
"category": "Pharmacy",
"services": [
{
"name": "Pharmacy",
"serviceId": "service-12345",
"description": "Albumin 24 hrs Urine",
"amount": 629.12
}
]
}
]
}'
```
#### 4. Receive the patient on selection (`scan-and-pay_post_v3_patient_on_selection`)
Inbound to your bridge at `/v3/patient/on-selection`. Acknowledge it and continue.
#### 5. Notify patient scan pay (`scan-and-pay_post_v3_patient_scan_pay_notify`)
Inbound to your bridge at `/v3/patient/scan-pay/notify`. Acknowledge it and continue.
#### 6. Notify to HIP so that confirm that the HIU received the payment status (`scan-and-pay_post_scan_gateway_v3_patient_scan_pay_on_notify`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/scan-gateway/v3/patient/scan-pay/on-notify \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"acknowledgement": {
"status": "SUCCESS/ CANCELED/ PENDING/ FAIL/ REFUND_INITIATED/ REFUND_SUCCESS",
"abhaAddress": "<username>@sbx",
"transactionId": "string",
"orderNumber": "string",
"openOrderRequestId": "b767614f-153a-4aa3-946f-1622596f0fab",
"paymentDate": "2025-01-20T07:47:49.102Z",
"paymentRecipetLink": "PDF URL LINK of RECIPT"
},
"response": {
"requestId": "b767614f-153a-***-946f-1622596f0fab"
}
}'
```
#### 7. Check the status of reports (`scan-and-pay_post_scan_gateway_v3_patient_scan_pay_order_status`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/scan-gateway/v3/patient/scan-pay/order-status \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-AUTH-TOKEN: <TOKEN>' \
--header 'X-HIU-ID: IN2810014366' \
--header 'Content-Type: application/json' \
--data '{
"queryStatus": {
"orderNumber": "string",
"abhaAddress": "<ABHA_ADDRESS>",
"openOrderRequestId": "0d8bd16b-117c-4d07-9916-109fe3a9ab88"
}
}'
```
#### 8. Receive the patient scan pay on order status (`scan-and-pay_post_v3_patient_scan_pay_on_order_status`)
Inbound to your bridge at `/v3/patient/scan-pay/on-order-status`. Acknowledge it and continue.
**Exit condition (Observe until this is true)**
Each call you made in this journey answered by its callback, with `response.requestId` equal to the `REQUEST-ID` you sent on that call. The 202 on a call is receipt, not the outcome: the outcome is in the callback's body.
- `POST /api/hiecm/scan-gateway/v3/patient/share/open-order` is answered by `POST /v3/patient/on-share/open-order` on your bridge.
- `POST /api/hiecm/scan-gateway/v3/patient/selection` is answered by `POST /v3/patient/on-selection` on your bridge.
- `POST /api/hiecm/scan-gateway/v3/patient/scan-pay/order-status` is answered by `POST /v3/patient/scan-pay/on-order-status` on your bridge.
### Scan and pay details and version update (`scan-and-pay-utility`)
**Act: the calls in this journey, in order**
#### 1. Get the patient scan pay details (`scan-and-pay_get_scan_gateway_v3_patient_scan_pay_details`)
```bash
curl --request GET \
--url "https://dev.abdm.gov.in/api/hiecm/scan-gateway/v3/patient/scan-pay/details?status=SUCCESS&limit=10&startDate=2024-07-13T07:30:10.186Z&endDate=2025-02-18T08:30:50.189Z&offset=0" \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-AUTH-TOKEN: <TOKEN>'
```
#### 2. Update version to the serviceId (`scan-and-pay_patch_gateway_v3_scanpay_updateversion`)
```bash
curl --request PATCH \
--url https://dev.abdm.gov.in/api/hiecm/gateway/v3/scanPay/updateVersion \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"recordShareEnabled": true,
"scanPayEnabled": true,
"scanPayVersion": "v2",
"serviceId": [
"****_HIP, ***_HIU"
]
}'
```
**Exit condition (Observe until this is true)**
A 200 response. The specification gives no body for it, so read what comes back.
## Where the detail is
- Every operation, with its body fields and responses: /docs/hiecm/v3/api/scan-and-pay
- Error codes: /docs/hiecm/v3/api/scan-and-pay/errors

View File

@ -0,0 +1,79 @@
---
name: abdm-scan-and-register
description: Use when building, debugging or testing ABDM scan and register: receiving the profile a patient shares by QR code at a counter and answering with a queue token.
type: skill
domain: scan-and-register
agent_consumers:
- abdm-integration-agent
- abdm-call-debugger
requires:
- gateway-session-token
- facility-id
produces:
- abha-profile
- registration
can_execute: true
can_orchestrate: false
---
# ABDM Scan and register
Generated from the ABDM Developer Portal on 2026-09-16, catalogue version 2026.09.16. Every fact below comes from a page in that portal, which is the place to look when this file does not carry enough.
This file is a snapshot. Re-download the whole folder from https://docs.abdm.gov.in/skills/abdm-scan-and-register/ when it is older than the work you are doing: this router and every file under references/ that it links to. Fetching this file alone leaves those links pointing at files you do not have.
If the abdm-docs MCP server is connected, trust its answers over this file: it serves the current catalogue and stamps every response with its catalogue_version, which you can compare against the version above.
## What you can do with Scan and register
- Scan and register
What it cannot do yet matters as much. Read **Before anything else** below before assuming a capability is one endpoint away.
## Try asking
- "Register the patient who just scanned the counter QR code and hand them a token"
- "What has to be in place before my first Scan and register call?"
- "My Scan and register call failed. Here is the response: what is wrong, and how do I fix it?"
Loaded with no task? Say in three lines what this skill does. Offer the prompts above. Then ask what the person is building, and whether the code for it exists yet.
## What is in this folder
- **Scaffold.** Survey the codebase first when one exists, then build it flow by flow against the sandbox, as a loop that ends when the step's exit condition holds rather than on a call returning 200. [references/scaffold.md](references/scaffold.md)
- **Integrate.** 6 operations, with their hosts and headers. [references/integrate.md](references/integrate.md)
- **Debug.** The specification's examples return no error code for this module. [references/debug.md](references/debug.md)
This file is the map. Each line above is a file beside it, opened one at a time rather than read through.
## Before anything else
- Treat every request and response shape in this skill as unconfirmed until the sandbox has answered you. Check a response before you rely on its shape.
## Practices that hold across every call
- Read the body, not only the status. A refusal often names the field in its body while the status says nothing useful.
- When ABDM publishes a value, read it rather than hard coding what it currently says. That covers a parameter, such as the encryption algorithm the certificate endpoints return beside the key, and it covers an enumeration. The registries publish theirs as master data calls: councils, courses, colleges, states and districts on the HPR, and facility types and LGD codes on the HFR. A table typed into your source goes stale silently. Purposes and HI types have no master data call: take them from the enumeration in the specification of the call you are making. Refuse to act on a published value you do not recognise rather than falling back to a default.
- Read every field in a response, not the one you came for. The M1 certificate call returns the encryption algorithm next to the key.
- Prove an assumption against a call that is able to disagree with you. A call that refuses every input with one message cannot tell you which input was right.
- Suspect the transport before the data. When a call refuses a value you believe in, check the encryption, the headers and the clock before you doubt the value.
- Do not carry an encryption path from one module to another. Read the certificate and the algorithm from the registry you are calling.
- Never log a sensitive value before you encrypt it, and never send one to a remote service to be encrypted. Both move the leak rather than removing it.
- Generate a fresh REQUEST-ID for every call and log it before sending. Once a call has failed it is the only handle on it.
- Check the host on any sample before you copy it. A request copied whole can be correct in every respect except where it is pointed, and that failure looks like credentials.
- Do not validate an identifier more strictly than the platform does. A schema that types a field as a UUID is not a promise that every value is one. Refusing a value ABDM would have accepted turns your own client into the thing that broke.
- Read a plural response as plural. A verification returns an accounts array and a consent request can produce more than one artefact. Store the collection and decide from its length.
- A documented callback path is not a documented callback payload. Log the whole body on arrival before you parse it, so a handler written against an assumed shape fails where you can see it.
- Decode a token before you use it. A call that hands you a token has not necessarily handed you the token the next call wants, and the claims are base64 that need no library to read.
- When a journey carries the same parameter through two calls, check what each call's specification asks for rather than carrying the first value forward.
- Do not infer which path an identifier belongs to from where that identifier is most discussed. Send every identifier to the lookup first and let the answer pick the path, so nobody who already holds an account is sent to create a second.
- Do not match an error code with string equality. A code may come back bare, as `ABDM-1001`, or with a trailing `: ` separator, as `ABDM-1001: `. Match on the code itself and tolerate the separator.
- Handle a failure that carries no body. Check for an empty body before you parse, or your client throws on the simplest failure there is.
- Back off on an authentication failure rather than retrying, and never loop a credential check.
- Send TIMESTAMP in UTC, ISO-8601 with milliseconds and a trailing Z, as in `2022-10-06T15:10:00.587Z`.
- Cache a public certificate with a validity window rather than forever. A rotation fails every encrypted call at once, and a cache with no expiry cannot recover on its own.
## Where the detail is
- Every endpoint, with its body fields and responses: /docs/hiecm/v3/use-cases/scan-and-register
- Every error code across modules: /docs/hiecm/v3/reference/error-codes
- Terms: /docs/hiecm/v3/getting-started/glossary

View File

@ -0,0 +1,9 @@
# Debug Scan and register
The codes this module can return, with the message and the operation that returns each.
## Errors
The Scan and register specification's examples return no error code yet. That is a gap in the specification, not a promise that this module cannot fail.
A code you meet that is not above is one the specifications do not carry yet. Read the code together with the message: a code can appear twice with different meanings.

View File

@ -0,0 +1,40 @@
# Integrate Scan and register
The calls themselves: where they live, what they need in their headers, and one request written out in full.
## Hosts
- `https://dev.abdm.gov.in` ABDM gateway, sandbox
- `https://apis.abdm.gov.in` ABDM gateway, production
## Endpoints
6 operations, grouped by the journey they belong to.
### Other operations
| Method | Path | What it does |
| --- | --- | --- |
| `GET` | `/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id}` | Fetch the details of a service ID. |
| `GET` | `/api/hiecm/gateway/v3/bridge-services` | Fetch the service ids registered against a bridge. |
| `PATCH` | `/api/hiecm/gateway/v3/bridge/url` | Update the bridge URL. |
| `POST` | `/api/hiecm/gateway/v3/sessions` | Generate access token. |
| `POST` | `/api/hiecm/patient-share/v3/on-share` | Sharing the response of HIECM's /api/hiecm/patient-share/v3/on-share API |
| `POST` | `/api/v3/hip/patient/share` | This API will be invoked to the HIP for sharing the response of HIECM's /api/hi… |
## Headers
| Header | What it is |
| --- | --- |
| `REQUEST-ID` | Unique UUID for track the end to end request transaction |
| `TIMESTAMP` | Actual time of the request was initiated, ISO 8601 represents date and time by starting with the year, follow… |
| `X-CM-ID` | Suffix of the consent manager to which the request was intended |
| `X-HIP-ID` | Identifier of the health information provider to which the request was intended |
## A request, in full
```bash
curl --request GET \
--url https://dev.abdm.gov.in/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id} \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx'
```

View File

@ -0,0 +1,172 @@
# HIE-CM scan-and-register build
Scaffolds an ABDM scan-and-register integration one journey at a time. It covers receiving the profile a patient shares by QR code at a counter and answering with a queue token.
## How this skill runs
Every journey below is an OODA loop, not a recipe: observe the actual state (last response, last error), orient against the step matched below, decide the cheapest next action, act, and return to observe. A step is done only when its exit condition is observed against the sandbox, never because it "should have worked."
Loop limit: 8 passes per step. Hitting the limit is an escalation: state what was observed, what was tried, and which operation page to read, then ask one question.
## Before the first journey, when the codebase already exists
Skip this section only for a system that does not exist yet. Otherwise it runs first, and its exit condition is a written plan, not a call.
### In plain words
Most ABDM integrations are not new systems. They are a hospital management
system, a laboratory system or a clinic application that already has patients,
visits, records, a login, an HTTP client and a way of keeping secrets. Every
ABDM journey has to land somewhere inside that, and a journey built before the
codebase has been read lands in the wrong place: a second HTTP client beside the
first, an ABHA column on the wrong table, a callback route the reverse proxy
never forwards.
So the first loop is not a journey. It is a survey of the system as it is, and
its exit condition is a written plan that names, for every ABDM touchpoint, the
file it will live in. The journeys then build against that plan rather than
against the specification's idea of a fresh codebase.
### Before you start
- The repository, checked out, with permission to read all of it. A survey of
half a codebase produces a plan for half a system.
- The answers to the deployment interview. The
code says what the system is. Only the integrator can say what the
deployment is, and the two together decide which journeys are built at all.
- The practices that hold across every call, which
the plan has to leave room for.
### What happens
This is one loop with a limit of eight passes over the codebase. Each pass
reads live state only, which here means the files themselves, never a README's
description of them and never an assumption carried from a similar system.
**Observe.** Inventory the system from its manifests and its tree, not from its
documentation. Record file paths for each of these, or record that none exists:
| Find | Where it usually shows | Why ABDM needs it |
|---|---|---|
| Languages and runtime versions | package manifests, lock files, toolchain files | Every generated call has to be idiomatic here |
| Build, run and test commands | manifests, CI configuration, a Makefile | Each journey's exit condition becomes a test that runs the same way |
| The frontend and backend split, and how they talk | the top level tree, an API client in the frontend, route definitions in the backend | The counter screens go in the frontend; every ABDM call goes through the backend |
| The outbound HTTP client the backend already uses | the dependency list, a shared client module | ABDM calls reuse it, or a second one appears and the two drift |
| How secrets and configuration reach the process | environment loading, a vault client, a config file | The client id, the secret and the access token travel the same way |
| The patient model, and the identifier fields it already carries | the schema, the ORM models, the migrations | The ABHA number and address become columns beside the existing identifiers, not a new table |
| The visit, encounter or record model | the same places | A care context maps to one of these, and the plan has to say which |
| Where inbound HTTP is routed and authenticated, and whether the deployment has a public URL | the router, the middleware, the reverse proxy configuration, the deployment manifests | ABDM calls back, and a callback route that nothing forwards is silence nobody notices |
| Existing cryptography helpers | a security or crypto module, the dependency list | The RSA encryption of identifiers reuses them |
| Where errors are shown to a user, and where they are logged | the frontend's error surface, the logging setup | A refused call has to land on the screen the person is looking at, and never log a token |
**Orient.** Map each ABDM touchpoint onto that inventory. Where the map is
exact, write the file path. Where it is not, write two candidates and say what
would decide between them. The common ambiguities: two places that could hold
the patient identifier, an HTTP client in the frontend and none in the backend,
a monorepo with several services and no obvious owner for callbacks.
Then read the interview answers against the inventory. A government integrator
gets the demographic route; a facility with no public URL gets no callback
driven journey until it has one; a desk with a fingerprint reader gets the
biometric method. The route set is the intersection of what the deployment
allows and what the code can host.
**Decide.** Order the journeys. The token comes first because every other call
needs it: the gateway session token, or for M4 the bearer token the registry calls
carry. Then the journey whose exit condition can be observed with
the least new code, usually a profile read for a patient who already holds an
ABHA. Creation and linking come after, because each depends on state the earlier
ones produce. For each journey, name the files it will touch and the test that
proves its exit condition.
**Act.** Write the plan. It is a file in the repository, at the path the
integrator names or at the root as `abdm-integration-plan.md`, and it is the
only output of this loop. Then return to observe once, reading the plan against
the tree, to confirm every path in it exists or is marked as new.
If the limit is reached with questions still open, escalate: name what was
found, name the two candidates that could not be separated, point at this
atom, and ask one question.
### How you know it worked
The plan exists and answers every row of the inventory table with a file path,
or with the words none, add at, followed by a path. No row is blank and no row
says to be decided.
Every ABDM touchpoint in the plan names one file, or names two candidates and
the observation that would choose between them. Every journey in the plan names
the test that proves its exit condition and the command that runs it.
Open the plan beside the tree. Every path it names resolves, or is marked as
new. That is the observation that ends this loop, and the first journey does
not start until it has been made.
### When it goes wrong
- **The plan puts the HTTP client in the frontend.** The survey found the
frontend's API client and stopped. Every ABDM call carries a secret, so it
goes through the backend, and the plan has to say which backend module.
- **Two patient tables, and the plan picked one.** Orient produced one
hypothesis where it needed two. Name both, and name the query that shows
which one the visit model points at.
- **The plan has a callback route and the deployment has no public URL.** The
inventory row on inbound routing was answered from the router rather than
from the deployment. Mark every callback driven journey as blocked on a URL,
and build the ones that are not.
- **The survey read the README and not the tree.** A README describes the
system somebody meant to build. The plan is for the one that exists.
- **Eight passes and the plan is still incomplete.** Escalate with the rows
that are answered, the rows that are not, this atom, and one question about
the row that blocks the most journeys.
From `shared.concept.survey-an-existing-codebase`.
## Journeys
### Scan and register (`scan-and-register-abdm-patient-share-hip`)
**Act: the calls in this journey, in order**
#### 1. Share HIP patient (`scan-and-register_post_v3_hip_patient_share`)
Inbound to your bridge at `/api/v3/hip/patient/share`. Acknowledge it and continue.
#### 2. Answer the patient share request (`scan-and-register_post_patient_share_v3_on_share`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/patient-share/v3/on-share \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"acknowledgement": {
"status": "SUCCESS",
"abhaAddress": "<ABHA_ADDRESS>",
"profile": {
"context": "43",
"tokenNumber": "3",
"expiry": 180
}
},
"error": {
"code": "ABDM-9999",
"message": "Unknown exception"
},
"response": {
"requestId": "6f0b4665-a915-4c92-aa36-65afb4a2cd71"
}
}'
```
**Exit condition (Observe until this is true)**
A 202 on this reply, sent with `response.requestId` set to the `REQUEST-ID` of the `POST /api/v3/hip/patient/share` request it answers. A reply without that id answers nothing.
## Where the detail is
- Every operation, with its body fields and responses: /docs/hiecm/v3/api/scan-and-register
- Error codes: /docs/hiecm/v3/api/scan-and-register/errors

View File

@ -0,0 +1,78 @@
---
name: hms-billing
description: Use when building, debugging, modifying, or testing HMS billing workflows, including OPD consultation fees, IPD running charges, final discharge settlement, lab and radiology billing, pharmacy sales, multi-tender payments, and package management.
---
# HMS Billing & Financial Management Skill
This skill guides the agent through the complete billing workflows, ledger integrity, database structures, and calculation formulas in E-Atria HMS.
---
## 1. Overview of Billing Workflows
E-Atria HMS manages four distinct revenue streams:
1. **OPD Billing**: Doctor consultation fees, registration charges, minor OPD procedures, emergency day care.
2. **IPD Billing**: Bed charges, nursing fees, doctor daily rounds, ICU monitoring, OT/Surgery fees, package tariffs, final discharge settlement.
3. **Diagnostics Billing**: Laboratory pathology investigations, radiology imaging procedures.
4. **Pharmacy Sales**: Inpatient and outpatient drug dispensing, prescription fulfillment.
---
## 2. Key Database Tables
### Master & Transactional Tables
- `invoice_master`: Central invoice header containing patient reference, dates, totals, discounts, taxes, paid amount, and outstanding balance.
- `invoice_item`: Line items for services billed under an `invoice_master` record (`item_type`: 1=Consultation, 2=Procedure, 3=Lab, 4=Radiology, 5=Nursing, etc.).
- `payment_history`: Ledger recording every monetary transaction (Cash, UPI, Credit/Debit Card, NetBanking, Cheque, Advance Deposit).
- `ipd_invoice_item`: Running IPD ledger updated dynamically as daily nursing charges, doctor visits, and medications are consumed.
- `doc_opd_fee`: Doctor consultation fee schedule by fee type (`1`=New Patient, `2`=Revisit, `3`=Running, `4`=Emergency, `5`=Night/Off-time).
- `doc_ipd_fee`: Doctor IPD visit fee schedule (`1`=Regular Ward Visit, `2`=ICU Visit, etc.).
- `doc_fee_type`: Descriptive lookup for fee categories.
- `hospital_bank_payment_source`: Configured bank accounts / POS machines / UPI QR accounts for financial auditing.
- `ayushman_package_master`: Standard PM-JAY package procedure pricing.
---
## 3. OPD Consultation Billing Workflow
1. **Patient Lookup / Registration**:
- Check if patient exists via `patient_master.p_fname`, `mphone1`, or ABHA ID.
- If new, insert into `patient_master` (storing full name strictly in `p_fname`).
2. **Doctor & Fee Selection**:
- Select doctor from `doctor_master`.
- Fetch active consultation fee from `doc_opd_fee` for selected `doc_fee_type` (e.g. New Patient = ₹500, Revisit = ₹300).
3. **Invoice Generation**:
- Insert invoice in `invoice_master` with `status = 'PAID'` (or `'PARTIAL'`).
- Insert corresponding item row into `invoice_item`.
4. **Payment Recording**:
- Insert transaction row in `payment_history` with `payment_mode`, `amount`, and `received_by`.
5. **OPD Token / Receipt Printing**:
- Generate thermal or A4 receipt with hospital header, UHID, Doctor Name (`Dr. {p_fname}`), Token No, and QR code.
---
## 4. IPD Running Charges to Final Settlement
1. **Daily Accumulation**:
- Nursing staff and ward managers post daily items into `ipd_invoice_item`:
- Room/Bed tariff (based on `bed_master.bed_category_id`).
- Daily doctor visit charges (from `doc_ipd_fee`).
- Bedside monitoring, injections, consumables (`nursing_ipd_charges`).
2. **Advance Payments**:
- Inpatients make advance deposits during hospital stay.
- Advances are logged in `payment_history` linked to the patient's `ipd_id`.
3. **Discharge Settlement**:
- Upon discharge approval, the billing clerk generates the final settlement:
$$\text{Gross Total} = \sum \text{ipd\_invoice\_item.item\_amount}$$
$$\text{Net Due} = \text{Gross Total} - \text{Approved Discount} + \text{Taxes} - \sum \text{Advance Payments}$$
- The final invoice is created in `invoice_master`, and remaining balance is collected via `payment_history`.
- The `ipd_master.discharge_date` and `ipd_master.status = 'discharged'` are marked.
---
## 5. Safe Modification & Debugging Rules
- **Zero-Sum Balance Rule**: Never update `invoice_master.paid_amount` or `balance_amount` manually without validating that $\sum \text{payment\_history.amount} == \text{invoice\_master.paid\_amount}$.
- **Patient Name**: Always select `patient_master.p_fname`. Column `patient_master.p_lname` does not exist.
- **Doctor Share**: Doctor commission calculations must be derived from `invoice_item.doctor_id` and verified against active `finance_doctor_agreements`.

View File

@ -0,0 +1,73 @@
---
name: hms-ipd
description: Use when building, modifying, or testing Inpatient Department (IPD) features, including bed management, admission lifecycle, daily doctor rounds (SOAP), nursing care charting, vital signs monitoring, medication administration, OT/surgery documentation, and discharge workflows.
---
# HMS IPD (Inpatient Department) Management Skill
This skill guides the agent through the complete Inpatient care lifecycle from admission, ward/bed management, clinical care, nursing charts, to discharge processing in E-Atria HMS.
---
## 1. IPD Lifecycle Overview
```mermaid
graph TD
A[Patient Recommended for Admission in OPD/Emergency] --> B[IPD Registration: Bed Allocation & Category Selection]
B --> C[Initial Medical Assessment within 24h & Nursing Assessment within 4h]
C --> D[Daily Inpatient Care: Rounds, SOAP Notes, Nursing Vitals]
D --> E[Procedures / OT Surgery / Diagnostic Orders]
E --> F[Accumulation of Daily Inpatient Charges]
F --> G[Doctor Approves Discharge & Prepares Discharge Summary]
G --> H[Billing Settlement: Final Bill & Clearance]
H --> I[Bed Vacated & Cleaned for Next Admission]
```
---
## 2. IPD Database Architecture
| Table Name | Purpose | Key Columns |
| :--- | :--- | :--- |
| `ipd_master` | Inpatient admission record | `id`, `ipd_no`, `patient_id`, `admission_date`, `admission_time`, `r_doc_id` (admitting consultant), `bed_id`, `department_id`, `status` (`admitted`, `discharged`, `transferred`, `expired`), `discharge_date`, `discharge_time` |
| `bed_master` | Hospital bed master | `id`, `bed_name`, `bed_category_id`, `ward_id`, `is_occupied`, `daily_rate` |
| `ward_master` | Wards / departments | `id`, `ward_name`, `floor`, `total_beds` |
| `bed_assignment_history` | Bed allocation and transfer history | `id`, `ipd_id`, `patient_id`, `bed_id`, `assigned_at`, `released_at`, `transferred_reason` |
| `ipd_master_doc_list` | Multiple attending / visiting doctors assigned to an IPD case | `id`, `ipd_id`, `doc_id`, `doc_type` (`primary`, `surgeon`, `anesthetist`, `consultant`) |
| `ipd_nursing_entries` | Bedside nursing charts, TPR (Temp, Pulse, Resp), BP, SpO2, I/O chart | `id`, `ipd_id`, `nurse_id`, `entry_time`, `temp`, `pulse`, `resp_rate`, `bp_systolic`, `bp_diastolic`, `spo2`, `blood_sugar`, `intake_oral`, `intake_iv`, `output_urine`, `remarks` |
| `nursing_ipd_charges` | Inpatient consumables, nursing procedures, injections, dressing charges | `id`, `ipd_id`, `charge_name`, `qty`, `rate`, `amount`, `charged_at` |
| `ipd_discharge` | Master discharge document and final condition | `id`, `ipd_id`, `patient_id`, `discharge_type` (`normal`, `lama`, `referred`, `expired`), `discharge_status`, `follow_up_date` |
| `ipd_discharge_templates` | 7 NABH Specialty discharge summary narratives | `id`, `template_name`, `specialty`, `content_structure` |
---
## 3. Daily Clinical Rounds & Documentation (SOAP Notes)
- Every admitted patient requires at least one daily progress note by the attending doctor using the **SOAP Format**:
- **S (Subjective)**: Patient symptoms, pain score, oral intake tolerance, night sleep.
- **O (Objective)**: Vitals review, physical examination, wound inspection, drain output, lab results.
- **A (Assessment)**: Clinical progress (improving, stable, deteriorating), revised differential diagnosis.
- **P (Plan)**: Medication orders, IV fluids, lab investigation advice, discharge timeline.
- Stored in `ipd_document_templates` / `ipd_discharge_course`.
---
## 4. Bed Allocation & Ward Transfers
- **Atomic Status**: When a bed is assigned in `ipd_master`, `bed_master.is_occupied = 1` must be updated atomically within a database transaction.
- **Transfers**: When transferring a patient to another ward/bed (e.g. Ward -> ICU -> Post-Op):
- Record release time in `bed_assignment_history` for the old bed (`bed_master.is_occupied = 0`).
- Create a new row in `bed_assignment_history` for the new bed (`bed_master.is_occupied = 1`).
- Update `ipd_master.bed_id` to the new bed.
- Update room tariff in `ipd_invoice_item` starting from the transfer timestamp.
---
## 5. Discharge Workflow & Clearance
1. **Medical Discharge**: Treating doctor drafts and approves the Discharge Summary in `ipd_discharge`.
2. **Medication on Discharge**: Prescribe discharge medications with duration and explicit timing.
3. **Nursing Clearance**: Removal of IV lines, catheter, surgical dressings, return of unused pharmacy items.
4. **Billing Settlement**: Final bill audit, advance adjustment, receipt issuance (`invoice_master`).
5. **Gate Pass / Discharge Slip**: Printed with follow-up instructions and emergency contact numbers.
6. **Bed Release**: Bed marked as `is_occupied = 0` and flagged for housekeeping sanitization.

View File

@ -0,0 +1,75 @@
---
name: hms-nabh-compliance
description: Use when building, testing, or auditing hospital workflows for NABH (National Accreditation Board for Hospitals & Healthcare Providers) compliance, including the 13 statutory informed consent forms, initial medical/nursing assessments, clinical audit criteria, SBAR nursing handovers, and discharge summary quality checks.
---
# HMS NABH Accreditation & Clinical Governance Skill
This skill guides the agent through implementing, maintaining, and auditing hospital processes against **NABH (5th Edition)** hospital accreditation standards in E-Atria HMS.
---
## 1. 13 Statutory Informed Consent Templates
NABH mandates that all procedures, admissions, high-risk interventions, and surgical operations have documented informed consent signed by the patient (or legal guardian) and doctor.
The 13 statutory templates are seeded in the database via `App\Database\Seeds\Data\IpdDocumentSeedData`:
| Code | Template Title | Key NABH Mandatory Fields |
| :--- | :--- | :--- |
| `NABH-IPD-01` | Admission Request & Initial Assessment Form | Provisional diagnosis, primary consultant, vitals, allergy history, patient/attendant declaration |
| `NABH-IPD-02` | General Informed Consent for Medical Treatment | Explanation of treatment plan, potential risks, rights of patient, attendant signature |
| `NABH-IPD-03` | Informed Consent for Surgical Procedure / Operation | Named procedure, operating surgeon, alternative therapies explained, possibility of conversion/extension |
| `NABH-IPD-04` | Informed Consent for Administration of Anesthesia | General / Spinal / Epidural / Regional / Sedation, ASA physical status grade, fasting hours confirmed |
| `NABH-IPD-05` | High-Risk Informed Consent | Documented severe comorbidities, ICU requirement, explicit mortality risk disclosure, two witness signatures |
| `NABH-IPD-06` | Blood & Blood Component Transfusion Consent | PRBC / FFP / Platelets / Cryoprecipitate, adverse reaction disclosure, right to refuse |
| `NABH-IPD-07` | ICU / HDU Admission Informed Consent | Critical care management, central venous line, invasive arterial monitoring, mechanical ventilation |
| `NABH-IPD-08` | Discharge Against Medical Advice (DAMA / LAMA) | Declaration acknowledging refusal of medical advice, clinical risks of premature discharge, legal indemnity waiver |
| `NABH-IPD-09` | Consent for Bedside / Invasive Diagnostic Procedure | Pleural tap, Ascitic tap, Lumbar puncture, Endoscopy, Bone marrow biopsy |
| `NABH-IPD-10` | Refusal of Treatment / Specific Procedure Consent | Informed refusal documentation detailing potential health deterioration resulting from refusal |
| `NABH-IPD-11` | Chemotherapy / Specialized Medical Therapy Consent | Chemotherapeutic agents, cycle number, cumulative toxicity, extravasation risk |
| `NABH-IPD-12` | Restraint Application Consent | Physical / chemical restraint indication, patient safety rationale, alternative interventions attempted |
| `NABH-IPD-13` | Release of Medical Information / Records Consent | Third-party insurance / TPA disclosure authorization, medico-legal release |
---
## 2. Inpatient Clinical Care Standards (COP - Care of Patients)
1. **Initial Assessment Timelines**:
- **Doctor Assessment**: Must be completed within **24 hours** of admission (or immediately in Emergency/ICU). Contains past history, allergies, personal history, systemic examination, provisional diagnosis, and initial care plan.
- **Nursing Assessment**: Must be completed within **2 to 4 hours** of admission. Contains nutritional screening, fall risk assessment (Morse Fall Scale / Hendrich II), pressure ulcer risk assessment (Braden Scale), and pain assessment.
2. **Nursing Handover Protocol (SBAR)**:
- Shift handovers must adhere to the **SBAR Framework**:
- **S (Situation)**: Patient name, age, bed no, admitting consultant, current diagnosis.
- **B (Background)**: Admission date, surgical history, known allergies, baseline vitals.
- **A (Assessment)**: Current shift vitals, pain status, abnormal lab values, pending reports.
- **R (Recommendation)**: Pending doctor orders, next medication doses, scheduled scans.
3. **Medication Administration & Safety (MOM)**:
- High-alert medications (e.g. Concentrated Electrolytes, Insulins, Anticoagulants, Chemotherapy) must require **double-nursing check** before administration.
- Look-Alike Sound-Alike (LASA) drugs must be segregated with tall-man lettering.
---
## 3. Discharge Summary Quality Standard (AAC - Access, Assessment & Continuity of Care)
Under NABH, a discharge summary is a medico-legal document. It must be handed over to the patient at the time of discharge and contain:
1. Hospital UHID, IPD Number, Admission Date & Time, Discharge Date & Time.
2. Admitting Consultant, Department, and Operating Surgeon (if surgical).
3. Primary & Secondary Final Diagnoses with ICD-10 codes.
4. Reason for Admission & Brief Clinical History.
5. Key Physical Findings on Admission.
6. Summary of Pertinent Laboratory, Imaging & Diagnostic Reports.
7. Detailed Hospital Course, Surgical Procedures with Operative Findings.
8. Patient's Condition at Discharge (Vitals, Wound Status, Ambulation).
9. Discharge Medication Chart (Generic Name, Strength, Dosage, Route, Frequency, Duration).
10. Urgent Warning Signs / Emergency Red Flags (e.g., severe chest pain, breathlessness, sudden high fever, wound bleeding).
11. Scheduled Follow-up Date, Time, and OPD Room / Consultant Name.
12. Treating Consultant Doctor's Name, Qualifications, and Signature.
---
## 4. Digital Scans & Document Archiving (`nabh_ipd_scans`)
- Physical signed consent forms, outside lab reports, and signed anesthetic fitness sheets uploaded via `DoctorDocument.php` are stored in `nabh_ipd_scans`.
- Categorized strictly by standard NABH code (`NABH-IPD-01` to `13`).
- Linked to `ipd_id`, `patient_id`, `uploaded_by`, and timestamped for clinical audit trail.

View File

@ -0,0 +1,71 @@
---
name: hms-pathology
description: Use when working on laboratory investigations, pathology test masters, panels/profiles, normal reference intervals, LOINC coding, sample collection workflows, barcode tracking, result entry, pathologist authorization, and lab report generation.
---
# HMS Pathology & Laboratory Management Skill
This skill guides the agent through managing clinical pathology test masters, multi-parameter panels, specimen collection, result verification, and report publication in E-Atria HMS.
---
## 1. Laboratory Data Model
| Table Name | Description | Key Fields |
| :--- | :--- | :--- |
| `investigation` | Master catalog of single lab tests and investigation profiles | `id`, `name`, `cat`, `rate`, `normal_range`, `unit`, `method`, `loinc_code`, `status` |
| `invprofiles` | Multi-test profiles (e.g., CBC, LFT, KFT, Lipid Profile, Thyroid Panel) | `id`, `profile_name`, `profile_code`, `total_rate`, `category_id` |
| `lab_tests` | Specific test parameters within a profile/department | `id`, `test_name`, `group_id`, `default_unit`, `male_min`, `male_max`, `female_min`, `female_max`, `child_min`, `child_max`, `loinc_num` |
| `lab_rgroups` | Report groups / sub-headings (e.g., Differential Leukocyte Count in CBC) | `id`, `group_name`, `dept_id`, `display_order` |
| `lab_request` | Patient lab order requisition generated from OPD/IPD | `id`, `patient_id`, `doctor_id`, `opd_id`, `ipd_id`, `order_date`, `status`, `barcode_no` |
| `lab_request_item` | Individual investigations ordered in a `lab_request` | `id`, `lab_request_id`, `investigation_id`, `status` (`pending`, `collected`, `reported`, `approved`) |
| `lab_repo` | Published test report header | `id`, `lab_request_id`, `patient_id`, `approved_by`, `report_date`, `verified_status` |
| `lab_repotests` | Recorded numerical or textual values for each parameter | `id`, `lab_repo_id`, `test_id`, `result_value`, `unit`, `reference_range`, `is_abnormal` |
---
## 2. Standard Pathology Workflow
```mermaid
graph TD
A[Doctor Prescribes Lab Test in OPD/IPD] --> B[Billing / Lab Cashier Generates Invoice & Barcode]
B --> C[Phlebotomy: Sample Collection & Specimen Labeling]
C --> D[Laboratory Processing / Machine Analyzer Run]
D --> E[Technologist Result Entry in HMS]
E --> F{Values within Normal Limits?}
F -->|Out of Range| G[Flag Critical / Panic Values in Red]
F -->|Normal| H[Standard Value Presentation]
G --> I[Pathologist Review & Digital Signature]
H --> I
I --> J[Final PDF Report Published & Synced to ABDM/PHR]
```
---
## 3. Reference Ranges & Critical Values
1. **Demographic Range Splitting**:
- Reference ranges vary by patient age and gender.
- For CBC (Hemoglobin):
- Adult Male: 13.0 – 17.0 g/dL
- Adult Female: 12.0 – 15.0 g/dL
- Infant / Child: 11.0 – 14.0 g/dL
2. **Panic / Critical Limit Alerts**:
- Panic values (e.g. Potassium < 2.5 or > 6.5 mmol/L, Platelets < 20,000 /µL, Blood Sugar < 50 or > 450 mg/dL) must trigger immediate verbal notification to the treating physician and be flagged on the report.
---
## 4. LOINC & ABDM Diagnostics Standards
- Every test in `lab_tests` must be linked to its NRCeS/LOINC identifier (e.g., CBC Profile: `58410-2`, Fasting Blood Sugar: `1558-6`, Serum Creatinine: `2160-0`).
- Generated FHIR bundles must use `DiagnosticReport` profile:
- `https://nrces.in/ndhm/fhir/r4/StructureDefinition/DiagnosticReportLab`
- Observation resources for each component parameter must include LOINC coding and UCUM units (`mg/dL`, `g/dL`, `mmol/L`, `/uL`).
---
## 5. Report Header, Signatures & Printing
- Report headers must display Hospital Name, Accreditation logos (NABH/NABL if applicable), Barcode, Sample Collected Date/Time, and Report Authorized Date/Time.
- The reporting pathologist's digital signature, qualifications (MBBS, MD Path), and council registration number must appear at the bottom right.
- Patient full name must be fetched from `patient_master.p_fname`.

View File

@ -0,0 +1,58 @@
---
name: hms-radiology
description: Use when building, modifying, or testing radiology reporting, modality configurations (USG, X-Ray, CT, MRI, ECHO), structured clinical templates, findings, impressions, DICOM/PACS attachments, and radiologist sign-off workflows.
---
# HMS Radiology & Diagnostic Imaging Management Skill
This skill guides the agent through managing radiology reporting templates, imaging modalities, structured clinical findings, impressions, and report printing in E-Atria HMS.
---
## 1. Radiology Architecture & Modalities
The HMS categorizes diagnostic imaging under `radiology_modality` and structured templates in `opd_clinical_templates` / `doc_print_templates`:
| Modality Code | Modality Name | Common Procedures | Template Pattern |
| :--- | :--- | :--- | :--- |
| `USG` | Ultrasonography | Whole Abdomen, KUB, Pelvis, Obstetrics / Antenatal, Thyroid, Scrotum | Organ-by-organ evaluation (Liver, Gall Bladder, Spleen, Pancreas, Kidneys, Bladder, Uterus) |
| `XR` | Digital X-Ray | Chest PA, Spine (Cervical, Lumbar, Dorsal), Extremities, Skull | Bony cage, lung parenchyma, mediastinum, cardiothoracic ratio, soft tissues |
| `CT` | Computed Tomography | NCCT/CECT Head, CECT Abdomen & Pelvis, HRCT Chest, CT Angiography | Protocol, slice thickness, attenuation, parenchymal findings, 3D reconstructions |
| `MRI` | Magnetic Resonance | MRI Brain, MRI Spine (C/D/L), Musculoskeletal Joints (Knee, Shoulder) | Sequences (T1, T2, FLAIR, DWI), signal intensity, disc bulges, cord signals |
| `ECHO` | 2D Echocardiography | 2D Echo with Doppler | Chamber dimensions, ejection fraction (EF%), valve morphology, wall motion analysis |
---
## 2. Standard 5-Section Reporting Structure
Every radiology report generated in the HMS must follow a standard structured clinical format:
1. **Clinical History & Indication**:
- Reason for scan (e.g. "Acute right lower quadrant pain, rule out appendicitis", "Dry cough with fever x 2 weeks").
2. **Technique / Protocol**:
- Modality details (e.g. "Real-time high-resolution gray scale and color Doppler examination performed using 3.5 MHz convex and 7.5 MHz linear probes").
3. **Observations & Findings**:
- Systematic description of all evaluated structures.
- Normal organs must have standard negative findings (e.g. "Liver is normal in size and acoustic texture. No focal mass lesion or intrahepatic biliary radicle dilatation").
- Pathological lesions must state exact anatomical location, size (in mm/cm), margins, echogenicity/attenuation, and vascularity.
4. **Impression / Conclusion**:
- Concise diagnostic synthesis (e.g. "Ultrasonographic features suggestive of Acute Calculous Cholecystitis with mild pericholecystic fluid").
5. **Recommendations / Follow-up**:
- Further clinical advice (e.g. "Clinical and surgical correlation suggested. MRCP recommended if common bile duct stone is suspected").
---
## 3. Database Tables & Template Storage
- `radiology_modality`: Modality master (`id`, `modality_code`, `modality_name`, `is_active`).
- `radiology_ultrasound_template`: Built-in organ narrative templates for rapid reporting.
- `opd_clinical_templates`: Customizable rich-text templates with placeholders (`{{PATIENT_NAME}}`, `{{AGE}}`, `{{GENDER}}`, `{{DATE}}`, `{{REFERRING_DOCTOR}}`).
- `doc_print_templates`: Printable formats with letterhead/plain paper configurations.
---
## 4. Radiologist Digital Authorization & Sign-off
- Draft reports are saved with `status = 'draft'` and editable by resident doctors / technicians.
- Only registered Radiologists (`doctor_master` with specialization in Radiology / Radio-diagnosis) can approve and publish (`status = 'final'`).
- The final PDF includes the Radiologist's name, qualifications (MD Radio-diagnosis / DMRD), Medical Council Registration Number, and digital signature watermark.

13
.cursor/mcp.json Normal file
View File

@ -0,0 +1,13 @@
{
"mcpServers": {
"abdm-docs": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://docs.abdm.gov.in/mcp"
],
"url": "https://docs.abdm.gov.in/mcp"
}
}
}

View File

@ -0,0 +1,66 @@
---
name: abdm-fhir
description: Use when producing or checking FHIR for ABDM: building NRCES compliant document bundle generation into a codebase, or auditing the bundles an existing FHIR store already emits. Covers the resource profiles ABDM requires, the Composition rules, and the validator to check against.
type: skill
domain: fhir
agent_consumers:
- abdm-integration-agent
- abdm-call-debugger
- fhir-compliance-agent
requires:
- abdm-docs-mcp
produces:
- nrces-document-bundle
can_execute: true
can_orchestrate: false
---
# ABDM FHIR
Generated from the ABDM Developer Portal on 2026-09-16, catalogue version 2026.09.16.
This file is a snapshot. Re-download the whole folder from https://docs.abdm.gov.in/skills/abdm-fhir/ when it is older than the work you are doing: this router and every file under references/ that it links to. Fetching this file alone leaves those links pointing at files you do not have.
## What this skill covers
- **Design.** What a generator gets wrong before it reaches a profile table. [references/design.md](references/design.md)
- **Generate.** Build NRCES compliant bundle generation into a codebase. [references/generate.md](references/generate.md)
- **Audit.** Check an existing FHIR store's output against the same profiles. [references/audit.md](references/audit.md)
Open one when the work calls for it. This file is the map, not the material.
## Try asking
- "Add ABDM compliant FHIR bundle generation to this codebase"
- "Audit the FHIR bundles this codebase already emits"
Loaded with no task? Say in three lines what this skill does. Offer the prompts above. Then ask what the person is building, and whether the code for it exists yet.
## Before anything else
- Treat every request and response shape in this skill as unconfirmed until the sandbox has answered you. Check a response before you rely on its shape.
- The design section is different in kind. Its rules come from building a working front desk against the sandbox, and each atom it cites names what was observed and the date it was seen.
- A bundle that validates is not a bundle ABDM accepts. The NRCES profiles are the floor, and the milestone the bundle travels under adds its own rules on top.
## Practices that hold across every call
- Read the body, not only the status. A refusal often names the field in its body while the status says nothing useful.
- When ABDM publishes a value, read it rather than hard coding what it currently says. That covers a parameter, such as the encryption algorithm the certificate endpoints return beside the key, and it covers an enumeration. The registries publish theirs as master data calls: councils, courses, colleges, states and districts on the HPR, and facility types and LGD codes on the HFR. A table typed into your source goes stale silently. Purposes and HI types have no master data call: take them from the enumeration in the specification of the call you are making. Refuse to act on a published value you do not recognise rather than falling back to a default.
- Read every field in a response, not the one you came for. The M1 certificate call returns the encryption algorithm next to the key.
- Prove an assumption against a call that is able to disagree with you. A call that refuses every input with one message cannot tell you which input was right.
- Suspect the transport before the data. When a call refuses a value you believe in, check the encryption, the headers and the clock before you doubt the value.
- Do not carry an encryption path from one module to another. Read the certificate and the algorithm from the registry you are calling.
- Never log a sensitive value before you encrypt it, and never send one to a remote service to be encrypted. Both move the leak rather than removing it.
- Generate a fresh REQUEST-ID for every call and log it before sending. Once a call has failed it is the only handle on it.
- Check the host on any sample before you copy it. A request copied whole can be correct in every respect except where it is pointed, and that failure looks like credentials.
- Do not validate an identifier more strictly than the platform does. A schema that types a field as a UUID is not a promise that every value is one. Refusing a value ABDM would have accepted turns your own client into the thing that broke.
- Read a plural response as plural. A verification returns an accounts array and a consent request can produce more than one artefact. Store the collection and decide from its length.
- A documented callback path is not a documented callback payload. Log the whole body on arrival before you parse it, so a handler written against an assumed shape fails where you can see it.
- Decode a token before you use it. A call that hands you a token has not necessarily handed you the token the next call wants, and the claims are base64 that need no library to read.
- When a journey carries the same parameter through two calls, check what each call's specification asks for rather than carrying the first value forward.
- Do not infer which path an identifier belongs to from where that identifier is most discussed. Send every identifier to the lookup first and let the answer pick the path, so nobody who already holds an account is sent to create a second.
- Do not match an error code with string equality. A code may come back bare, as `ABDM-1001`, or with a trailing `: ` separator, as `ABDM-1001: `. Match on the code itself and tolerate the separator.
- Handle a failure that carries no body. Check for an empty body before you parse, or your client throws on the simplest failure there is.
- Back off on an authentication failure rather than retrying, and never loop a credential check.
- Send TIMESTAMP in UTC, ISO-8601 with milliseconds and a trailing Z, as in `2022-10-06T15:10:00.587Z`.
- Cache a public certificate with a validity window rather than forever. A rotation fails every encrypted call at once, and a cache with no expiry cannot recover on its own.

View File

@ -0,0 +1,91 @@
# fhir-audit
Audit an existing FHIR store's output against ABDM's NRCES profiles,
and fix the generation pipeline where it falls short. The store stays
authoritative: this skill patches what emits from it, it does not
replace it.
## 1. Collect representative output
From the integrator, get one real (or realistic test) document bundle
per record type their store produces, saved as local `.json` files.
Do not synthesize bundles yourself for this step; the point of the
audit is what the store actually emits, not what a correctly built
bundle would look like.
## 2. Tier 1 pass
Run `validate` with `kind: fhir` on each bundle, passing its `record_type`. Collect
every finding across every bundle into one gap report, grouped by
finding (the shape of the defect, for example "`Composition.author`
missing" or "`Composition.meta.profile` does not include ..."), not by
which bundle it came from. The same defect usually repeats across every
bundle the store produces, because it comes from one place in the
pipeline; grouping by bundle would make the same root cause look like
many separate problems.
## 3. Interpret with the knowledge surface
For each finding, use its Ref to read what NRCES actually demands and
why ABDM checks it. Ref names the NRCES profile the rule came from
(for example `OPConsultRecord` or `DocumentBundle`), not an atom id
directly; map it to the record type's mapping atom via `get`:
`shared.fhir.document-bundles` for envelope-level findings (Ref
`DocumentBundle`), or the type's mapping atom
(`shared.fhir.map-opconsultation`, `shared.fhir.map-prescription`,
`shared.fhir.map-diagnosticreport`, `shared.fhir.map-dischargesummary`,
`shared.fhir.map-immunizationrecord`,
`shared.fhir.map-healthdocumentrecord`, or
`shared.fhir.map-wellnessrecord`) for a Composition-element or
section-level finding. Four record types (Prescription,
DiagnosticReport, HealthDocumentRecord, ImmunizationRecord) have no
NRCES section slices: do not expect or ask for section-by-section
findings on these four, only Composition-element and entry-level ones.
Sort each finding into one of two buckets:
- **Generation-time fix.** The store already captures the data; the
pipeline just emits the wrong shape (wrong or missing
`meta.profile`, a malformed reference, a missing `Bundle.identifier`
field). This is fixable in code, in this session.
- **Mapping gap.** The store never captures the data a required
element needs at all (no encounter record to populate
`Composition.encounter`, no coded allergy list to populate an
`AllergyIntolerance` entry). This is not a code fix; it is a
conversation with the integrator about what their store needs to
start capturing, and it belongs in the gap report as an open item,
not a silent workaround.
## 4. Patch, do not replace
For every generation-time fix, amend the integrator's existing
generation pipeline directly, or add a thin adapter that post-processes
the store's output into the compliant shape if the pipeline itself is
not reasonably editable. Either way the store keeps producing its own
output; this skill's job is the layer between that output and what
ABDM requires, not a replacement generator.
## 5. Tier 2 pass
Follow `shared.fhir.hl7-validator-recipe` against the patched output
for each record type: download the pinned `validator_cli.jar`, run it
with `-ig ndhm.in#6.5.0` (the recipe atom is the authoritative source
for the pinned version, defer to it if this ever looks stale), and
iterate the same way as tier 1, fix, re-run, until the report lists no
errors. A warning is not the same as a pass; read each one and decide
deliberately whether it is acceptable.
## 6. Done means
The gap report shows every original finding either resolved (with the
fix that resolved it) or explicitly accepted by the integrator (mapping
gaps they have chosen to defer, named as such, not silently dropped).
Tier 1 and tier 2 are both clean against every collected bundle, and
the exact commands to re-run both checks are recorded in the
integrator's repo (a make target or script) so the checks outlive this
session.
Never invent clinical codes: where the integrator's data lacks a coded
value, surface the gap to the human rather than fabricating a SNOMED
code (tier 1 will not catch a wrong code; tier 2 may not either without
a terminology server).

View File

@ -0,0 +1,115 @@
# fhir-generate
Scaffold FHIR document bundle generation for one or more ABDM record
types, directly into the integrator's own codebase, and drive it to a
clean bill of health against both validation tiers.
## 1. Establish scope
Call `search` with `kind: fhir_profile` to get the full list of ABDM record types
(the seven `hiType` values: OPConsultation, Prescription,
DiagnosticReport, DischargeSummary, ImmunizationRecord,
HealthDocumentRecord, WellnessRecord). Confirm with the integrator
which of these seven their system must produce; do not build all seven
speculatively if only one or two are needed.
Identify the language and the repository (or the path within a
monorepo) where the generation module will live. If the integrator
already has a FHIR-adjacent module (a `fhir/`, `hie-cm/`, or similar
directory), that is where this work belongs.
## 2. Learn the target shape
For each in-scope record type:
- Call `get` with `fhir:<that type>`, and once with `fhir:DocumentBundle`
(the shared envelope profile every record type rides on top of).
- Call `get` with `fhir-example:<that type>`, to see a concrete, valid
bundle.
- Read `shared.fhir.document-bundles` via `get` for the envelope
rules that apply to every record type (`Bundle.type`, `Bundle.meta`,
`Bundle.identifier`, `Bundle.timestamp`).
- Read that type's mapping atom via `get`
(`shared.fhir.map-opconsultation`, `shared.fhir.map-prescription`,
`shared.fhir.map-diagnosticreport`, `shared.fhir.map-dischargesummary`,
`shared.fhir.map-immunizationrecord`,
`shared.fhir.map-healthdocumentrecord`, or
`shared.fhir.map-wellnessrecord`) for the Composition's required
elements and, where NRCES defines them, its section slices.
Four record types (Prescription, DiagnosticReport, HealthDocumentRecord,
ImmunizationRecord) have no NRCES section slices: their Composition
carries one unnamed, required section whose `entry` array is what is
actually constrained. Do not scaffold section-by-section guidance for
these four; scaffold the required entry resource types their mapping
atom names instead. OPConsultation, DischargeSummary and WellnessRecord
do have named section slices; use the mapping atom's section table for
those.
## 3. Scaffold in the integrator's stack
For each in-scope record type, write a builder function that:
- Takes the integrator's own domain data as input (their patient,
encounter, order, or report model, whatever they call it).
- Produces a document bundle matching the digest returned by
`get` with `fhir:<type>`: the correct `meta.profile` URL on the
Composition, every required top-level element the digest lists, and
the section shape the mapping atom describes for that type.
- Resolves every reference internally: any resource a section entry or
the Composition points at must be added to the bundle as its own
entry, not left dangling.
Then write one bundle-level wrapper, shared across all in-scope
builders, that applies the `DocumentBundle` envelope constraints:
`Bundle.type` fixed to `"document"`, `Bundle.meta` and
`Bundle.meta.versionId` set, `Bundle.identifier` (`.system` and
`.value`) set, `Bundle.timestamp` set. The Composition must be the
bundle's first entry.
Follow the repository's existing conventions for module layout, error
handling, and naming. If the integrator's stack already has a FHIR
library (a typed resource model, a bundle builder), build on it rather
than duplicating it. If it has none, plain JSON construction (maps or
structs marshaled to JSON) is fine; do not introduce a new FHIR library
dependency just for this.
## 4. Iterate against tier 1
Run each builder's output bundle through `validate` with `kind: fhir`, passing the
bundle and its `record_type`. For every finding returned:
- Read the finding's Fix text.
- Apply exactly that fix to the builder (not a workaround in the test
data).
- Re-run `validate` with `kind: fhir`.
Repeat until `validate` returns no findings for that record type,
then move to the next in-scope type.
## 5. Finish with tier 2
Tier 1 is structural and fast; it does not check nested cardinalities,
terminology bindings, or section slice discriminators. Follow
`shared.fhir.hl7-validator-recipe` end to end, in the integrator's own
environment: download the pinned `validator_cli.jar`, run it against
each builder's output bundle with `-ig ndhm.in#6.5.0` (the recipe atom
is the authoritative source for the pinned version, defer to it if
this ever looks stale), and resolve every error the report lists. A
warning is not an error; read each one and decide deliberately whether
it is acceptable, rather than treating a warning-only run as clean.
## 6. Done means
For every in-scope record type: tier 1 (`validate`, `kind: fhir`) returns no
findings, and tier 2 (the official HL7 validator) exits 0 with no
errors, against IG 6.5.0. Record the exact commands to re-run both
checks (a make target, an npm script, or a shell script committed to
the integrator's repo) so the checks outlive this session and the next
person who touches this module can re-verify without re-deriving the
commands.
Never invent clinical codes: where the integrator's data lacks a coded
value, surface the gap to the human rather than fabricating a SNOMED
code (tier 1 will not catch a wrong code; tier 2 may not either without
a terminology server).

View File

@ -0,0 +1,79 @@
---
name: abdm-gateway
description: Use when building, debugging or testing the ABDM gateway: the gateway session and bridge registry.
type: skill
domain: gateway
agent_consumers:
- abdm-integration-agent
- abdm-call-debugger
requires:
- sandbox-client-credentials
produces:
- gateway-session-token
- bridge-url
can_execute: true
can_orchestrate: false
---
# ABDM Gateway, sessions and the bridge registry
Generated from the ABDM Developer Portal on 2026-09-16, catalogue version 2026.09.16. Every fact below comes from a page in that portal, which is the place to look when this file does not carry enough.
This file is a snapshot. Re-download the whole folder from https://docs.abdm.gov.in/skills/abdm-gateway/ when it is older than the work you are doing: this router and every file under references/ that it links to. Fetching this file alone leaves those links pointing at files you do not have.
If the abdm-docs MCP server is connected, trust its answers over this file: it serves the current catalogue and stamps every response with its catalogue_version, which you can compare against the version above.
## What you can do with Gateway
- Bridge
- Session
What it cannot do yet matters as much. Read **Before anything else** below before assuming a capability is one endpoint away.
## Try asking
- "Get a gateway access token and register this bridge"
- "What has to be in place before my first Gateway call?"
- "My Gateway call failed. Here is the response: what is wrong, and how do I fix it?"
Loaded with no task? Say in three lines what this skill does. Offer the prompts above. Then ask what the person is building, and whether the code for it exists yet.
## What is in this folder
- **Scaffold.** Survey the codebase first when one exists, then build it flow by flow against the sandbox, as a loop that ends when the step's exit condition holds rather than on a call returning 200. [references/scaffold.md](references/scaffold.md)
- **Integrate.** 4 operations, with their hosts and headers. [references/integrate.md](references/integrate.md)
- **Debug.** The specification's examples return no error code for this module. [references/debug.md](references/debug.md)
This file is the map. Each line above is a file beside it, opened one at a time rather than read through.
## Before anything else
- Treat every request and response shape in this skill as unconfirmed until the sandbox has answered you. Check a response before you rely on its shape.
## Practices that hold across every call
- Read the body, not only the status. A refusal often names the field in its body while the status says nothing useful.
- When ABDM publishes a value, read it rather than hard coding what it currently says. That covers a parameter, such as the encryption algorithm the certificate endpoints return beside the key, and it covers an enumeration. The registries publish theirs as master data calls: councils, courses, colleges, states and districts on the HPR, and facility types and LGD codes on the HFR. A table typed into your source goes stale silently. Purposes and HI types have no master data call: take them from the enumeration in the specification of the call you are making. Refuse to act on a published value you do not recognise rather than falling back to a default.
- Read every field in a response, not the one you came for. The M1 certificate call returns the encryption algorithm next to the key.
- Prove an assumption against a call that is able to disagree with you. A call that refuses every input with one message cannot tell you which input was right.
- Suspect the transport before the data. When a call refuses a value you believe in, check the encryption, the headers and the clock before you doubt the value.
- Do not carry an encryption path from one module to another. Read the certificate and the algorithm from the registry you are calling.
- Never log a sensitive value before you encrypt it, and never send one to a remote service to be encrypted. Both move the leak rather than removing it.
- Generate a fresh REQUEST-ID for every call and log it before sending. Once a call has failed it is the only handle on it.
- Check the host on any sample before you copy it. A request copied whole can be correct in every respect except where it is pointed, and that failure looks like credentials.
- Do not validate an identifier more strictly than the platform does. A schema that types a field as a UUID is not a promise that every value is one. Refusing a value ABDM would have accepted turns your own client into the thing that broke.
- Read a plural response as plural. A verification returns an accounts array and a consent request can produce more than one artefact. Store the collection and decide from its length.
- A documented callback path is not a documented callback payload. Log the whole body on arrival before you parse it, so a handler written against an assumed shape fails where you can see it.
- Decode a token before you use it. A call that hands you a token has not necessarily handed you the token the next call wants, and the claims are base64 that need no library to read.
- When a journey carries the same parameter through two calls, check what each call's specification asks for rather than carrying the first value forward.
- Do not infer which path an identifier belongs to from where that identifier is most discussed. Send every identifier to the lookup first and let the answer pick the path, so nobody who already holds an account is sent to create a second.
- Do not match an error code with string equality. A code may come back bare, as `ABDM-1001`, or with a trailing `: ` separator, as `ABDM-1001: `. Match on the code itself and tolerate the separator.
- Handle a failure that carries no body. Check for an empty body before you parse, or your client throws on the simplest failure there is.
- Back off on an authentication failure rather than retrying, and never loop a credential check.
- Send TIMESTAMP in UTC, ISO-8601 with milliseconds and a trailing Z, as in `2022-10-06T15:10:00.587Z`.
- Cache a public certificate with a validity window rather than forever. A rotation fails every encrypted call at once, and a cache with no expiry cannot recover on its own.
## Where the detail is
- Every endpoint, with its body fields and responses: /docs/hiecm/v3/api/gateway
- Every error code across modules: /docs/hiecm/v3/reference/error-codes
- Terms: /docs/hiecm/v3/getting-started/glossary

View File

@ -0,0 +1,9 @@
# Debug Gateway, sessions and the bridge registry
The codes this module can return, with the message and the operation that returns each.
## Errors
The Gateway, sessions and the bridge registry specification's examples return no error code yet. That is a gap in the specification, not a promise that this module cannot fail.
A code you meet that is not above is one the specifications do not carry yet. Read the code together with the message: a code can appear twice with different meanings.

View File

@ -0,0 +1,37 @@
# Integrate Gateway, sessions and the bridge registry
The calls themselves: where they live, what they need in their headers, and one request written out in full.
## Hosts
- `https://dev.abdm.gov.in` ABDM gateway, sandbox
- `https://apis.abdm.gov.in` ABDM gateway, production
## Endpoints
4 operations, grouped by the journey they belong to.
### Other operations
| Method | Path | What it does |
| --- | --- | --- |
| `GET` | `/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id}` | Fetch the details of a service ID. |
| `GET` | `/api/hiecm/gateway/v3/bridge-services` | Fetch the service ids registered against a bridge. |
| `PATCH` | `/api/hiecm/gateway/v3/bridge/url` | Update the bridge URL. |
| `POST` | `/api/hiecm/gateway/v3/sessions` | Generate access token. |
## Headers
| Header | What it is |
| --- | --- |
| `REQUEST-ID` | Unique UUID for track the end to end request transaction |
| `TIMESTAMP` | Actual time of the request was initiated, ISO 8601 represents date and time by starting with the year, follow… |
| `X-CM-ID` | Suffix of the consent manager to which the request was intended |
## A request, in full
```bash
curl --request GET \
--url https://dev.abdm.gov.in/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id} \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx'
```

View File

@ -0,0 +1,208 @@
# HIE-CM gateway build
Scaffolds an ABDM gateway integration one journey at a time. It covers the gateway session and bridge registry.
## How this skill runs
Every journey below is an OODA loop, not a recipe: observe the actual state (last response, last error), orient against the step matched below, decide the cheapest next action, act, and return to observe. A step is done only when its exit condition is observed against the sandbox, never because it "should have worked."
Loop limit: 8 passes per step. Hitting the limit is an escalation: state what was observed, what was tried, and which operation page to read, then ask one question.
## Before the first journey, when the codebase already exists
Skip this section only for a system that does not exist yet. Otherwise it runs first, and its exit condition is a written plan, not a call.
### In plain words
Most ABDM integrations are not new systems. They are a hospital management
system, a laboratory system or a clinic application that already has patients,
visits, records, a login, an HTTP client and a way of keeping secrets. Every
ABDM journey has to land somewhere inside that, and a journey built before the
codebase has been read lands in the wrong place: a second HTTP client beside the
first, an ABHA column on the wrong table, a callback route the reverse proxy
never forwards.
So the first loop is not a journey. It is a survey of the system as it is, and
its exit condition is a written plan that names, for every ABDM touchpoint, the
file it will live in. The journeys then build against that plan rather than
against the specification's idea of a fresh codebase.
### Before you start
- The repository, checked out, with permission to read all of it. A survey of
half a codebase produces a plan for half a system.
- The answers to the deployment interview. The
code says what the system is. Only the integrator can say what the
deployment is, and the two together decide which journeys are built at all.
- The practices that hold across every call, which
the plan has to leave room for.
### What happens
This is one loop with a limit of eight passes over the codebase. Each pass
reads live state only, which here means the files themselves, never a README's
description of them and never an assumption carried from a similar system.
**Observe.** Inventory the system from its manifests and its tree, not from its
documentation. Record file paths for each of these, or record that none exists:
| Find | Where it usually shows | Why ABDM needs it |
|---|---|---|
| Languages and runtime versions | package manifests, lock files, toolchain files | Every generated call has to be idiomatic here |
| Build, run and test commands | manifests, CI configuration, a Makefile | Each journey's exit condition becomes a test that runs the same way |
| The frontend and backend split, and how they talk | the top level tree, an API client in the frontend, route definitions in the backend | The counter screens go in the frontend; every ABDM call goes through the backend |
| The outbound HTTP client the backend already uses | the dependency list, a shared client module | ABDM calls reuse it, or a second one appears and the two drift |
| How secrets and configuration reach the process | environment loading, a vault client, a config file | The client id, the secret and the access token travel the same way |
| The patient model, and the identifier fields it already carries | the schema, the ORM models, the migrations | The ABHA number and address become columns beside the existing identifiers, not a new table |
| The visit, encounter or record model | the same places | A care context maps to one of these, and the plan has to say which |
| Where inbound HTTP is routed and authenticated, and whether the deployment has a public URL | the router, the middleware, the reverse proxy configuration, the deployment manifests | ABDM calls back, and a callback route that nothing forwards is silence nobody notices |
| Existing cryptography helpers | a security or crypto module, the dependency list | The RSA encryption of identifiers reuses them |
| Where errors are shown to a user, and where they are logged | the frontend's error surface, the logging setup | A refused call has to land on the screen the person is looking at, and never log a token |
**Orient.** Map each ABDM touchpoint onto that inventory. Where the map is
exact, write the file path. Where it is not, write two candidates and say what
would decide between them. The common ambiguities: two places that could hold
the patient identifier, an HTTP client in the frontend and none in the backend,
a monorepo with several services and no obvious owner for callbacks.
Then read the interview answers against the inventory. A government integrator
gets the demographic route; a facility with no public URL gets no callback
driven journey until it has one; a desk with a fingerprint reader gets the
biometric method. The route set is the intersection of what the deployment
allows and what the code can host.
**Decide.** Order the journeys. The token comes first because every other call
needs it: the gateway session token, or for M4 the bearer token the registry calls
carry. Then the journey whose exit condition can be observed with
the least new code, usually a profile read for a patient who already holds an
ABHA. Creation and linking come after, because each depends on state the earlier
ones produce. For each journey, name the files it will touch and the test that
proves its exit condition.
**Act.** Write the plan. It is a file in the repository, at the path the
integrator names or at the root as `abdm-integration-plan.md`, and it is the
only output of this loop. Then return to observe once, reading the plan against
the tree, to confirm every path in it exists or is marked as new.
If the limit is reached with questions still open, escalate: name what was
found, name the two candidates that could not be separated, point at this
atom, and ask one question.
### How you know it worked
The plan exists and answers every row of the inventory table with a file path,
or with the words none, add at, followed by a path. No row is blank and no row
says to be decided.
Every ABDM touchpoint in the plan names one file, or names two candidates and
the observation that would choose between them. Every journey in the plan names
the test that proves its exit condition and the command that runs it.
Open the plan beside the tree. Every path it names resolves, or is marked as
new. That is the observation that ends this loop, and the first journey does
not start until it has been made.
### When it goes wrong
- **The plan puts the HTTP client in the frontend.** The survey found the
frontend's API client and stopped. Every ABDM call carries a secret, so it
goes through the backend, and the plan has to say which backend module.
- **Two patient tables, and the plan picked one.** Orient produced one
hypothesis where it needed two. Name both, and name the query that shows
which one the visit model points at.
- **The plan has a callback route and the deployment has no public URL.** The
inventory row on inbound routing was answered from the router rather than
from the deployment. Mark every callback driven journey as blocked on a URL,
and build the ones that are not.
- **The survey read the README and not the tree.** A README describes the
system somebody meant to build. The plan is for the one that exists.
- **Eight passes and the plan is still incomplete.** Escalate with the rows
that are answered, the rows that are not, this atom, and one question about
the row that blocks the most journeys.
From `shared.concept.survey-an-existing-codebase`.
## Journeys
### Bridge (`gateway-abdm-gateway`)
**Act: the calls in this journey, in order**
#### 1. Fetch the service ids registered against a bridge (`gateway_get_gateway_v3_bridge_services`)
```bash
curl --request GET \
--url https://dev.abdm.gov.in/api/hiecm/gateway/v3/bridge-services \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx'
```
#### 2. Fetch the details of a service ID (`gateway_get_gateway_v3_bridge_service_serviceid_service_id`)
```bash
curl --request GET \
--url https://dev.abdm.gov.in/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id} \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx'
```
#### 3. Update the bridge URL (`gateway_patch_gateway_v3_bridge_url`)
```bash
curl --request PATCH \
--url https://dev.abdm.gov.in/api/hiecm/gateway/v3/bridge/url \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"url": "<YOUR_CALLBACK_URL>"
}'
```
**Exit condition (Observe until this is true)**
A 202 response. The specification gives no body for it, so read what comes back.
### Session (`gateway-abdm-sessions`)
**Act: the calls in this journey, in order**
#### 1. Generate access token (`gateway_post_gateway_v3_sessions`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/gateway/v3/sessions \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"clientId": "SBX_0000",
"clientSecret": "0******-***-***-***-a****",
"grantType": "client_credentials"
}'
```
**Exit condition (Observe until this is true)**
A 202 whose body matches:
```json
{
"accessToken": "<TOKEN>",
"expiresIn": 1200,
"refreshExpiresIn": 1800,
"refreshToken": "<TOKEN>",
"tokenType": "bearer"
}
```
## Where the detail is
- Every operation, with its body fields and responses: /docs/hiecm/v3/api/gateway

View File

@ -0,0 +1,102 @@
---
name: abdm-m1
description: Use when building, debugging or testing ABDM Milestone 1: creating an ABHA number or address, ABHA login, profile management, or the gateway session token. Carries the endpoints, the required headers, the two token rule, the encryption rule and the error codes its specification's examples return. Also carries the scaffolding loop that builds it flow by flow and the loop from a failed call to a named fix, in references/.
type: skill
domain: m1
agent_consumers:
- abdm-integration-agent
- abdm-call-debugger
requires:
- gateway-session-token
produces:
- abha-number
- abha-address
- user-token
- abha-profile
can_execute: true
can_orchestrate: false
---
# ABDM M1, create and verify ABHA
Generated from the ABDM Developer Portal on 2026-09-16, catalogue version 2026.09.16. Every fact below comes from a page in that portal, which is the place to look when this file does not carry enough.
This file is a snapshot. Re-download the whole folder from https://docs.abdm.gov.in/skills/abdm-m1/ when it is older than the work you are doing: this router and every file under references/ that it links to. Fetching this file alone leaves those links pointing at files you do not have.
If the abdm-docs MCP server is connected, trust its answers over this file: it serves the current catalogue and stamps every response with its catalogue_version, which you can compare against the version above.
## What you can do with M1
- Create an ABHA for somebody who has none: by Aadhaar OTP, by demographic authentication, by face or fingerprint, or under a parent for a child.
- Log in somebody who already has one, by Aadhaar, mobile, ABHA number or ABHA address.
- Read their profile, which carries the whole registration form: names, date of birth, gender, mobile, address with its codes, and a photograph.
- Find an ABHA somebody has forgotten, and pick the right account when one mobile holds several.
- Show the ABHA card and QR code, and take a profile a patient shares by QR at your counter.
- Update a profile and change a mobile.
What it cannot do yet matters as much. Read **Before anything else** below before assuming a capability is one endpoint away.
## Try asking
- "Add ABHA creation by Aadhaar OTP to this codebase"
- "What has to be in place before my first M1 call?"
- "My M1 call returned ABDM-1017. What is wrong, and how do I fix it?"
- "Walk me through the M1 test cases before go-live"
Loaded with no task? Say in three lines what this skill does. Offer the prompts above. Then ask what the person is building, and whether the code for it exists yet.
## What is in this folder
- **Scaffold.** Survey the codebase first when one exists, then build it flow by flow against the sandbox, as a loop that ends when the step's exit condition holds rather than on a call returning 200. [references/scaffold.md](references/scaffold.md)
- **Design.** What the journey around the calls has to do, and what a screen is forbidden to claim. [references/design.md](references/design.md)
- **Integrate.** 123 operations, with their hosts and headers. [references/integrate.md](references/integrate.md)
- **Debug.** The loop from a failed call to a named fix, and 17 error codes from the specification's examples. [references/debug.md](references/debug.md)
- **Test.** The functional test cases, one loop each, with the evidence the sandbox can vouch for and the manifest that replaces a screenshot report. [references/test.md](references/test.md)
This file is the map. Each line above is a file beside it, opened one at a time rather than read through.
## Before anything else
- Treat every request and response shape in this skill as unconfirmed until the sandbox has answered you. Check a response before you rely on its shape.
- The design section is different in kind. Its rules come from building a working front desk against the sandbox, and each atom it cites names what was observed and the date it was seen.
- ABDM publishes operations, not a user experience. The journey is the integrator's to design, so offer the shape below as a suggestion and build what they ask for instead when they have a view of their own counter.
- The ABHA step comes before the registration form and fills it. A verified profile carries the whole form, so a journey that registers the patient first and offers ABHA afterwards has already spent the keystrokes it existed to save.
- Two ways the profile reaches the desk. The patient scans a QR and consents in their own app, and ABDM posts the profile to your callback, so nobody types or asks anything. Or the desk runs the identifier journey. The filled form is the destination either way.
- Decide deliberately whether a journey can complete without an ABHA. A record keyed by the facility's own number does not need one, and a journey that cannot finish without one blocks care for anyone who has none.
- An identifier and an auth method are two different questions, and listing them together is what makes M1 look like five choices. Ask which identifier first, then offer auth methods underneath it, and only where there is more than one.
- Every identifier starts on the login path, Aadhaar included. A verified login already returns the accounts, and only ABDM-1114 on a refusal means nobody holds one. Create on any other answer and the patient ends up with two numbers, which nothing merges.
- Get an access token first, from the gateway session endpoint. Every other call needs it in `Authorization: Bearer <token>`.
- Two tokens exist and they are not interchangeable. The gateway access token goes in `Authorization`. The user token from an enrolment or a login goes in `X-token`. Profile endpoints need both.
- Sensitive fields travel encrypted. Aadhaar numbers, mobile numbers, email addresses, OTP values and passwords are encrypted before they go in the body, then base64 encoded.
- The certificate response tells you the padding. `GET /v3/profile/public/certificate` returns `{"publicKey", "encryptionAlgorithm"}`. Read that field and translate it for your language. Do not hard code a padding: a constant is right until it is not, and the failure then looks like a bad value rather than a stale constant.
- One path serves several jobs. The `scope` array in the body picks which one, so read it before assuming an endpoint does one thing.
- The accounts array on a login verification already carries ABHANumber, preferredAbhaAddress, name, gender, dob, profilePhoto and kycVerified, so a registration form can fill the moment the OTP verifies and before any profile call.
## Practices that hold across every call
- Read the body, not only the status. A refusal often names the field in its body while the status says nothing useful.
- When ABDM publishes a value, read it rather than hard coding what it currently says. That covers a parameter, such as the encryption algorithm the certificate endpoints return beside the key, and it covers an enumeration. The registries publish theirs as master data calls: councils, courses, colleges, states and districts on the HPR, and facility types and LGD codes on the HFR. A table typed into your source goes stale silently. Purposes and HI types have no master data call: take them from the enumeration in the specification of the call you are making. Refuse to act on a published value you do not recognise rather than falling back to a default.
- Read every field in a response, not the one you came for. The M1 certificate call returns the encryption algorithm next to the key.
- Prove an assumption against a call that is able to disagree with you. A call that refuses every input with one message cannot tell you which input was right.
- Suspect the transport before the data. When a call refuses a value you believe in, check the encryption, the headers and the clock before you doubt the value.
- Do not carry an encryption path from one module to another. Read the certificate and the algorithm from the registry you are calling.
- Never log a sensitive value before you encrypt it, and never send one to a remote service to be encrypted. Both move the leak rather than removing it.
- Generate a fresh REQUEST-ID for every call and log it before sending. Once a call has failed it is the only handle on it.
- Check the host on any sample before you copy it. A request copied whole can be correct in every respect except where it is pointed, and that failure looks like credentials.
- Do not validate an identifier more strictly than the platform does. A schema that types a field as a UUID is not a promise that every value is one. Refusing a value ABDM would have accepted turns your own client into the thing that broke.
- Read a plural response as plural. A verification returns an accounts array and a consent request can produce more than one artefact. Store the collection and decide from its length.
- A documented callback path is not a documented callback payload. Log the whole body on arrival before you parse it, so a handler written against an assumed shape fails where you can see it.
- Decode a token before you use it. A call that hands you a token has not necessarily handed you the token the next call wants, and the claims are base64 that need no library to read.
- When a journey carries the same parameter through two calls, check what each call's specification asks for rather than carrying the first value forward.
- Do not infer which path an identifier belongs to from where that identifier is most discussed. Send every identifier to the lookup first and let the answer pick the path, so nobody who already holds an account is sent to create a second.
- Do not match an error code with string equality. A code may come back bare, as `ABDM-1001`, or with a trailing `: ` separator, as `ABDM-1001: `. Match on the code itself and tolerate the separator.
- Handle a failure that carries no body. Check for an empty body before you parse, or your client throws on the simplest failure there is.
- Back off on an authentication failure rather than retrying, and never loop a credential check.
- Send TIMESTAMP in UTC, ISO-8601 with milliseconds and a trailing Z, as in `2022-10-06T15:10:00.587Z`.
- Cache a public certificate with a validity window rather than forever. A rotation fails every encrypted call at once, and a cache with no expiry cannot recover on its own.
## Where the detail is
- Every endpoint, with its body fields and responses: /docs/hiecm/v3/api/m1
- The flows as diagrams: /docs/hiecm/v3/milestones/m1
- Every error code across modules: /docs/hiecm/v3/reference/error-codes
- Terms: /docs/hiecm/v3/getting-started/glossary

View File

@ -0,0 +1,139 @@
# HIE-CM m1 debug
Every error below is an OODA loop: observe the error code and last request id, orient against the matched code, decide the fix, act, and observe whether the original step now succeeds. Applying a fix is not the exit condition; the original step succeeding is.
Loop limit: 5 passes per error.
## Errors
### 404
**Specification example:** HTTP 404, `Runtime Error`, on `m1_post_v3_profile_login_verify_find_abha_face`.
**Exit condition: the original call now succeeds.**
### 900900
**Specification example:** HTTP 500, `Unclassified Authentication Failure`, on `m1_post_v3_enrollment_auth_byabdm_mobile_verify_create_ab_091285`.
**Exit condition: the original call now succeeds.**
### 900901
**Specification example:** HTTP 401, `Invalid Credentials`, on `m1_post_v3_enrollment_request_otp_aadhaar_otp`.
**Exit condition: the original call now succeeds.**
### 900902
**Specification example:** HTTP 401, `Missing Credentials`, on `m1_post_v3_profile_benefit_search_xmluid`.
**Exit condition: the original call now succeeds.**
### ABDM-1017
**Specification example:** HTTP 401, `Invalid Transaction Id`, on `m1_get_v3_enrollment_enrol_suggestion_create_abha_aadhaar_otp`.
**Exit condition: the original call now succeeds.**
### ABDM-1021
**Specification example:** HTTP 401, `Lack of required priviledges`, on `m1_post_v3_enrollment_enrol_byaadhaar_child_child_abha`.
**Exit condition: the original call now succeeds.**
### ABDM-1094
**Specification example:** HTTP 401, `X-token expired`, on `m1_post_v3_enrollment_enrol_byaadhaar_child_child_abha`.
**Exit condition: the original call now succeeds.**
### ABDM-1114
**Specification example:** HTTP 404, `User not found`, on `m1_patch_v3_profile_account_child_child_abha`.
**Exit condition: the original call now succeeds.**
### ABDM-1124
**Specification example:** HTTP 422, `The mobile number provided by you is already linked to 6 ABHA Numbers. Please provide a different Mobile Number.`, on `m1_post_v3_enrollment_enrol_byaadhaar_demo_auth_create_ab_81107d`.
**Exit condition: the original call now succeeds.**
### ABDM-1138
**Specification example:** HTTP 400, `The benefit record has already been de-linked`, on `m1_post_v3_profile_benefit_linkanddelink_x_token`.
**Exit condition: the original call now succeeds.**
### ABDM-1140
**Specification example:** HTTP 400, `The benefit record has already been linked`, on `m1_post_v3_profile_benefit_linkanddelink_x_token`.
**Exit condition: the original call now succeeds.**
### ABDM-1157
**Specification example:** HTTP 422, `Child ABHA’s account limit has been exceeded for the requested Abha ID number ‘<ABHA_NUMBER>`, on `m1_post_v3_enrollment_enrol_byaadhaar_child_child_abha`.
**Exit condition: the original call now succeeds.**
### ABDM-1160
**Specification example:** HTTP 422, `Non KYC CHILD ABHA is allowed to update their profile only once`, on `m1_patch_v3_profile_account_child_child_abha`.
**Exit condition: the original call now succeeds.**
### ABDM-1204
**Specification example:** HTTP 422, `UIDAI Error code : 400 : Invalid Aadhaar OTP value.`, on `m1_post_v3_enrollment_enrol_byaadhaar_otp`.
**Exit condition: the original call now succeeds.**
### ABDM-1207
**Specification example:** HTTP 422, `The information you provided does not match the details on record with Aadhaar. Please verify and provide accurate information.`, on `m1_post_v3_enrollment_enrol_byaadhaar_demo_auth_create_ab_81107d`.
**Exit condition: the original call now succeeds.**
### ABDM-1211
**Specification example:** HTTP 400, `User not found.`, on `m1_post_v3_phr_web_login_abha_search_abha_address_login_m_27a20f`.
**Exit condition: the original call now succeeds.**
### ABDM-1224
**Specification example:** HTTP 401, `Login via Biometric is not allowed.`, on `m1_post_v3_profile_login_request_otp_find_abha_face`.
**Exit condition: the original call now succeeds.**
## Where the detail is
- The operation that returns each code: /docs/hiecm/v3/api/m1
## Every code in the specification
### Codes
| Code | HTTP | Message | Returned by |
| --- | --- | --- | --- |
| `404` | 404 | Runtime Error | `m1_post_v3_profile_login_verify_find_abha_face` |
| `900900` | 500 | Unclassified Authentication Failure | `m1_post_v3_enrollment_auth_byabdm_mobile_verify_create_ab_091285` |
| `900901` | 401 | Invalid Credentials | `m1_post_v3_enrollment_request_otp_aadhaar_otp` |
| `900902` | 401 | Missing Credentials | `m1_post_v3_profile_benefit_search_xmluid` |
| `ABDM-1017` | 401 | Invalid Transaction Id | `m1_get_v3_enrollment_enrol_suggestion_create_abha_aadhaar_otp` |
| `ABDM-1021` | 401 | Lack of required priviledges | `m1_post_v3_enrollment_enrol_byaadhaar_child_child_abha` |
| `ABDM-1094` | 401 | X-token expired | `m1_post_v3_enrollment_enrol_byaadhaar_child_child_abha` |
| `ABDM-1114` | 404 | User not found | `m1_patch_v3_profile_account_child_child_abha` |
| `ABDM-1124` | 422 | The mobile number provided by you is already linked to 6 ABHA Numbers. Please provide a different Mobile Numb… | `m1_post_v3_enrollment_enrol_byaadhaar_demo_auth_create_ab_81107d` |
| `ABDM-1138` | 400 | The benefit record has already been de-linked | `m1_post_v3_profile_benefit_linkanddelink_x_token` |
| `ABDM-1140` | 400 | The benefit record has already been linked | `m1_post_v3_profile_benefit_linkanddelink_x_token` |
| `ABDM-1157` | 422 | Child ABHA’s account limit has been exceeded for the requested Abha ID number ‘<ABHA_NUMBER> | `m1_post_v3_enrollment_enrol_byaadhaar_child_child_abha` |
| `ABDM-1160` | 422 | Non KYC CHILD ABHA is allowed to update their profile only once | `m1_patch_v3_profile_account_child_child_abha` |
| `ABDM-1204` | 422 | UIDAI Error code : 400 : Invalid Aadhaar OTP value. | `m1_post_v3_enrollment_enrol_byaadhaar_otp` |
| `ABDM-1207` | 422 | The information you provided does not match the details on record with Aadhaar. Please verify and provide acc… | `m1_post_v3_enrollment_enrol_byaadhaar_demo_auth_create_ab_81107d` |
| `ABDM-1211` | 400 | User not found. | `m1_post_v3_phr_web_login_abha_search_abha_address_login_m_27a20f` |
| `ABDM-1224` | 401 | Login via Biometric is not allowed. | `m1_post_v3_profile_login_request_otp_find_abha_face` |
A code you meet that is not above is one the specifications do not carry yet. Read the code together with the message: a code can appear twice with different meanings.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,178 @@
# Integrate M1, create and verify ABHA
The calls themselves: where they live, what they need in their headers, and one request written out in full.
## Hosts
- `https://abhasbx.abdm.gov.in` ABHA service, sandbox
- `https://dev.abdm.gov.in` ABDM gateway, sandbox
- `https://apis.abdm.gov.in` ABDM gateway, production
## Endpoints
123 operations, grouped by the journey they belong to.
### Other operations
| Method | Path | What it does |
| --- | --- | --- |
| `POST` | `/abha/api/v3.1/profile/login/verify` | Login via Face Auth (QR) - verify |
| `POST` | `/abha/api/v3.1/profile/login/verify` | Login via Biometric (Fingerprint) - v3.1 single step |
| `POST` | `/abha/api/v3.1/profile/login/verify` | Login via Biometric (Iris) - v3.1 single step |
| `POST` | `/abha/api/v3/enrollment/auth/byAbdm` | After ABHA creation - verify email OTP (optional) |
| `POST` | `/abha/api/v3/enrollment/auth/byAbdm` | After ABHA creation - verify email OTP (optional) |
| `POST` | `/abha/api/v3/enrollment/auth/byAbdm` | After ABHA creation - verify email OTP (optional) |
| `POST` | `/abha/api/v3/enrollment/auth/byAbdm` | After ABHA creation - verify email OTP (optional) |
| `POST` | `/abha/api/v3/enrollment/auth/byAbdm` | After ABHA creation - verify mobile OTP (optional) |
| `POST` | `/abha/api/v3/enrollment/auth/byAbdm` | After ABHA creation - verify mobile OTP (optional) |
| `POST` | `/abha/api/v3/enrollment/auth/byAbdm` | After ABHA creation - verify mobile OTP (optional) |
| `POST` | `/abha/api/v3/enrollment/auth/byAbdm` | After ABHA creation - verify mobile OTP (optional) |
| `POST` | `/abha/api/v3/enrollment/enrol/abha-address` | After ABHA creation - create ABHA address |
| `POST` | `/abha/api/v3/enrollment/enrol/abha-address` | After ABHA creation - create ABHA address |
| `POST` | `/abha/api/v3/enrollment/enrol/abha-address` | After ABHA creation - create ABHA address |
| `POST` | `/abha/api/v3/enrollment/enrol/abha-address` | After ABHA creation - create ABHA address |
| `POST` | `/abha/api/v3/enrollment/enrol/auth/init` | Face auth - generate transaction ID (init) |
| `POST` | `/abha/api/v3/enrollment/enrol/auth/init` | Face auth - generate transaction ID (init) |
| `POST` | `/abha/api/v3/enrollment/enrol/byAadhaar` | Create Child ABHA |
| `POST` | `/abha/api/v3/enrollment/enrol/byAadhaar` | Create Child ABHA |
| `POST` | `/abha/api/v3/enrollment/enrol/byAadhaar` | Create ABHA - Demographic authentication (Demo Auth) |
| `POST` | `/abha/api/v3/enrollment/enrol/byAadhaar` | Create ABHA - Demographic authentication (Demo Auth) |
| `POST` | `/abha/api/v3/enrollment/enrol/byAadhaar` | Create ABHA - Aadhaar face authentication |
| `POST` | `/abha/api/v3/enrollment/enrol/byAadhaar` | Create ABHA - Aadhaar fingerprint (bio) |
| `POST` | `/abha/api/v3/enrollment/enrol/byAadhaar` | Create ABHA - Aadhaar IRIS |
| `POST` | `/abha/api/v3/enrollment/enrol/byAadhaar` | Create ABHA - verify Aadhaar OTP |
| `POST` | `/abha/api/v3/enrollment/enrol/capturePID` | Face auth - capture PID / track status |
| `POST` | `/abha/api/v3/enrollment/enrol/capturePID` | Face auth - capture PID / track status |
| `POST` | `/abha/api/v3/enrollment/enrol/capturePID` | Face auth - capture PID / track status |
| `GET` | `/abha/api/v3/enrollment/enrol/suggestion` | After ABHA creation - get ABHA address suggestions |
| `GET` | `/abha/api/v3/enrollment/enrol/suggestion` | After ABHA creation - get ABHA address suggestions |
| `GET` | `/abha/api/v3/enrollment/enrol/suggestion` | After ABHA creation - get ABHA address suggestions |
| `GET` | `/abha/api/v3/enrollment/enrol/suggestion` | After ABHA creation - get ABHA address suggestions |
| `GET` | `/abha/api/v3/enrollment/profile/children` | Get Child ABHA list of the parent |
| `GET` | `/abha/api/v3/enrollment/profile/children` | Get Child ABHA list of the parent |
| `POST` | `/abha/api/v3/enrollment/request/otp` | Send Aadhaar OTP for ABHA enrolment |
| `POST` | `/abha/api/v3/enrollment/request/otp` | After ABHA creation - send OTP to verify email (optional) |
| `POST` | `/abha/api/v3/enrollment/request/otp` | After ABHA creation - send OTP to verify email (optional) |
| `POST` | `/abha/api/v3/enrollment/request/otp` | After ABHA creation - send OTP to verify email (optional) |
| `POST` | `/abha/api/v3/enrollment/request/otp` | After ABHA creation - send OTP to verify email (optional) |
| `POST` | `/abha/api/v3/enrollment/request/otp` | After ABHA creation - send OTP to verify mobile (optional) |
| `POST` | `/abha/api/v3/enrollment/request/otp` | After ABHA creation - send OTP to verify mobile (optional) |
| `POST` | `/abha/api/v3/enrollment/request/otp` | After ABHA creation - send OTP to verify mobile (optional) |
| `POST` | `/abha/api/v3/enrollment/request/otp` | After ABHA creation - send OTP to verify mobile (optional) |
| `POST` | `/abha/api/v3/phr/web/login/abha/request/otp` | ABHA address login via Aadhaar OTP - send OTP |
| `POST` | `/abha/api/v3/phr/web/login/abha/request/otp` | ABHA address login via Fingerprint - send authentication request |
| `POST` | `/abha/api/v3/phr/web/login/abha/request/otp` | ABHA address login via IRIS - send authentication request |
| `POST` | `/abha/api/v3/phr/web/login/abha/request/otp` | ABHA address login via Mobile OTP - send OTP |
| `POST` | `/abha/api/v3/phr/web/login/abha/search` | Search ABHA address (auth methods) |
| `POST` | `/abha/api/v3/phr/web/login/abha/search` | Search ABHA address (auth methods) |
| `POST` | `/abha/api/v3/phr/web/login/abha/verify` | ABHA address login via Aadhaar OTP - verify |
| `POST` | `/abha/api/v3/phr/web/login/abha/verify` | ABHA address login via Fingerprint - verify |
| `POST` | `/abha/api/v3/phr/web/login/abha/verify` | ABHA address login via IRIS - verify |
| `POST` | `/abha/api/v3/phr/web/login/abha/verify` | ABHA address login via Mobile OTP - verify |
| `GET` | `/abha/api/v3/phr/web/login/profile/abha-profile` | Get ABHA-address profile |
| `GET` | `/abha/api/v3/phr/web/login/profile/abha-profile` | Get ABHA-address profile |
| `GET` | `/abha/api/v3/phr/web/login/profile/abha-profile` | Get ABHA-address profile |
| `GET` | `/abha/api/v3/phr/web/login/profile/abha-profile` | Get ABHA-address profile |
| `GET` | `/abha/api/v3/phr/web/login/profile/abha/phr-card` | Get PHR card |
| `GET` | `/abha/api/v3/phr/web/login/profile/abha/phr-card` | Get PHR card |
| `GET` | `/abha/api/v3/phr/web/login/profile/abha/phr-card` | Get PHR card |
| `GET` | `/abha/api/v3/phr/web/login/profile/abha/phr-card` | Get PHR card |
| `GET` | `/abha/api/v3/phr/web/login/profile/abha/qr-code` | Get ABHA-address QR code |
| `GET` | `/abha/api/v3/phr/web/login/profile/abha/qr-code` | Get ABHA-address QR code |
| `GET` | `/abha/api/v3/phr/web/login/profile/abha/qr-code` | Get ABHA-address QR code |
| `GET` | `/abha/api/v3/phr/web/login/profile/abha/qr-code` | Get ABHA-address QR code |
| `GET` | `/abha/api/v3/profile/account` | Get ABHA profile |
| `PATCH` | `/abha/api/v3/profile/account` | Update Child ABHA profile |
| `PATCH` | `/abha/api/v3/profile/account` | Update Child ABHA profile |
| `GET` | `/abha/api/v3/profile/account/abha-card` | Retrieve ABHA card image |
| `POST` | `/abha/api/v3/profile/account/abha/search` | Search ABHA by mobile |
| `POST` | `/abha/api/v3/profile/account/abha/search` | Search ABHA by mobile |
| `POST` | `/abha/api/v3/profile/account/abha/search` | Search ABHA by mobile |
| `POST` | `/abha/api/v3/profile/account/abha/search` | Search ABHA by mobile |
| `POST` | `/abha/api/v3/profile/account/abha/search` | Search ABHA by mobile |
| `GET` | `/abha/api/v3/profile/account/download-abha-card` | Download ABHA card |
| `GET` | `/abha/api/v3/profile/account/qrCode` | Get ABHA QR code |
| `POST` | `/abha/api/v3/profile/account/request/otp` | Child ABHA KYC - send Aadhaar OTP |
| `POST` | `/abha/api/v3/profile/account/request/otp` | Child ABHA KYC - send Aadhaar OTP |
| `POST` | `/abha/api/v3/profile/account/request/otp` | Re-KYC - send Aadhaar OTP |
| `POST` | `/abha/api/v3/profile/account/request/otp` | Update mobile - send OTP |
| `GET` | `/abha/api/v3/profile/account/request/token` | Refresh user token |
| `POST` | `/abha/api/v3/profile/account/verify` | Child ABHA KYC - verify Aadhaar OTP |
| `POST` | `/abha/api/v3/profile/account/verify` | Child ABHA KYC - verify Aadhaar OTP |
| `POST` | `/abha/api/v3/profile/account/verify` | Re-KYC - verify Aadhaar OTP |
| `POST` | `/abha/api/v3/profile/account/verify` | Update mobile - verify OTP |
| `GET` | `/abha/api/v3/profile/benefit/abha/{abhanumber}` | Get benefits linked to an ABHA number |
| `POST` | `/abha/api/v3/profile/benefit/linkAndDelink` | Link / De-link benefit using ABHA number |
| `POST` | `/abha/api/v3/profile/benefit/linkAndDelink` | Link / De-link benefit using X-token |
| `POST` | `/abha/api/v3/profile/benefit/linkAndDelink` | Link / De-link benefit using xmlUid |
| `POST` | `/abha/api/v3/profile/benefit/search` | Benefit search by ABHA number |
| `POST` | `/abha/api/v3/profile/benefit/search` | Benefit search by xmlUid |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Login via Aadhaar number - send Aadhaar OTP |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Login via ABHA number - send Aadhaar OTP |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Login via ABHA number - send ABHA (mobile) OTP |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Login via Biometric (Fingerprint) - send authentication request |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Login via Biometric (Iris) - send authentication request |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Find ABHA via Aadhaar OTP - send OTP |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Find ABHA via Face - send authentication request |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Find ABHA via Fingerprint - send authentication request |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Find ABHA via IRIS - send authentication request |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Find ABHA via Mobile - send OTP |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Forgot ABHA via Aadhaar - send OTP |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Forgot ABHA via Mobile - send OTP |
| `POST` | `/abha/api/v3/profile/login/request/otp` | Login via Mobile number - send OTP |
| `POST` | `/abha/api/v3/profile/login/verify` | Login via Aadhaar number - verify Aadhaar OTP |
| `POST` | `/abha/api/v3/profile/login/verify` | Login via ABHA number - verify Aadhaar OTP |
| `POST` | `/abha/api/v3/profile/login/verify` | Login via ABHA number - verify ABHA (mobile) OTP |
| `POST` | `/abha/api/v3/profile/login/verify` | Login via Biometric (Fingerprint) - verify |
| `POST` | `/abha/api/v3/profile/login/verify` | Login via Biometric (Iris) - verify |
| `POST` | `/abha/api/v3/profile/login/verify` | Find ABHA via Aadhaar OTP - verify OTP |
| `POST` | `/abha/api/v3/profile/login/verify` | Find ABHA via Face - verify |
| `POST` | `/abha/api/v3/profile/login/verify` | Find ABHA via Fingerprint - verify |
| `POST` | `/abha/api/v3/profile/login/verify` | Find ABHA via IRIS - verify |
| `POST` | `/abha/api/v3/profile/login/verify` | Find ABHA via Mobile - verify OTP |
| `POST` | `/abha/api/v3/profile/login/verify` | Forgot ABHA via Aadhaar - verify OTP |
| `POST` | `/abha/api/v3/profile/login/verify` | Forgot ABHA via Mobile - verify OTP |
| `POST` | `/abha/api/v3/profile/login/verify` | Login via Mobile number - verify OTP |
| `POST` | `/abha/api/v3/profile/login/verify/user` | Login via Mobile number - verify user (select ABHA) |
| `GET` | `/abha/api/v3/profile/public/certificate` | Get public certificate (RSA encryption key) |
| `GET` | `/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id}` | Fetch the details of a service ID. |
| `GET` | `/api/hiecm/gateway/v3/bridge-services` | Fetch the service ids registered against a bridge. |
| `PATCH` | `/api/hiecm/gateway/v3/bridge/url` | Update the bridge URL. |
| `POST` | `/api/hiecm/gateway/v3/sessions` | Generate access token. |
## Headers
| Header | What it is |
| --- | --- |
| `REQUEST-ID` | Unique UUID for every request. |
| `TIMESTAMP` | Current UTC timestamp in ISO-8601 format. |
| `BENEFIT_NAME` | **Applicable for user who is enrolling via Benefit Program.** |
| `X-token` | **Applicable for child abha creation. X-token of Parent user, user can get X-token after login to the system** |
| `TRANSACTION_ID` | Transaction ID from the ABHA creation response. |
| `Content-Type` | `application/json`. |
| `R-token` | Refresh token (`Bearer <refreshToken>`) received at login. |
| `T-token` | Short-lived token (`Bearer <token>`) returned by *Login via Mobile number - verify OTP*. |
| `X-CM-ID` | Suffix of the consent manager to which the request was intended |
## A request, in full
```bash
curl --request POST \
--url https://abhasbx.abdm.gov.in/abha/api/v3.1/profile/login/verify \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'Content-Type: application/json' \
--data '{
"scope": [
"abha-login",
"aadhaar-face-login-verify"
],
"authData": {
"authMethods": [
"face_auth"
],
"face_login": {
"txnId": "8220299c-40ad-40b6-bc52-13a7d46a69d0",
"aadhaar": "{{encrypted aadhaar number}}"
}
}
}'
```

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,401 @@
# HIE-CM m1 test
Walks the ABDM M1 functional test cases, ABHA creation and verification, against the system you built and the sandbox. Each case ends in one of four recorded outcomes, never in an opinion.
## What this skill does
- Runs every M1 test case in the ABHA creation and verification set against your system and the sandbox, one case at a time
- Records, for each case, the sandbox response and REQUEST-ID that prove it, or the screen that has to be attested, or the human step it stopped at
- Writes a manifest of case ids to request ids at the end, which is the evidence a reviewer checks against the gateway rather than a folder of screenshots
## What it needs from you
| Need | Where it comes from |
|---|---|
| Sandbox client id and secret | The ABDM sandbox portal, under your registered application |
| Your system running against the sandbox hosts | Your deployment or a local build. The skill drives your system, not the sandbox directly |
| A way to trigger each journey in your system | A screen, an API or a script. Say which at the start |
| A person with an Aadhaar linked mobile, for OTP cases | Present at the desk for the run. Every OTP is a human step and the skill stops for it |
| A fingerprint or face device, for the biometric cases | Only if you claim those cases. Without one they are recorded as not run |
| Whether you are a government or a private integrator | The set marks some cases mandatory for one and optional for the other |
## Say one of these
- "Walk the M1 test cases against my sandbox and log each one."
- "Run only the ABHA verification cases, VRFY_ABHA_101 to 405."
- "Re-run CRT_ABHA_112, the address suggestion case failed yesterday."
- "Write a terminal script that runs the M1 test cases and asks me for the Aadhaar number and each OTP."
## What happens first
One question: which cases. All of them, one function group, or a list of ids. Then the preconditions for the first case are checked before anything is sent. Nothing else is asked until a case needs a human.
## How this skill runs
Every case is an observe, orient, decide, act loop. Observe the live state: the last response, the last REQUEST-ID, what your screen shows. Orient against the case below. Decide the cheapest action that produces a new observation. Act, paste the raw result, return to observe. A case is done only when its exit condition is observed, never because the step should have worked.
Loop limit: 3 passes per test case. Hitting the limit is an escalation: state what was observed with request ids, what was tried, name one section of this skill or one operation page to read, and ask one question.
### The four outcomes
| Outcome | Record it when | Never when |
|---|---|---|
| `passed` | The exit condition is observed and the observation is pasted verbatim | The response was not pasted. A pass with no output is a fail |
| `failed` | Three passes and the exit condition was not observed, or the sandbox returned the refusal the case expects you to handle and your system did not handle it | A human step was missing. That is `needs-human` |
| `needs-human` | The case reached an OTP, a biometric scan, an operator's document check, or a person who was not there | Ever as a substitute for a fail you can see |
| `not-run` | The case does not apply to your entity, you do not claim the optional capability, or ABDM publishes no operation for it | To skip a mandatory case that applies to you |
### The three kinds of evidence
Every case names one of these. It decides what the manifest carries.
- **sandbox.** A call the gateway sees. Evidence is the HTTP status, the body and the REQUEST-ID, pasted. The exit condition is a literal in the body. A reviewer can check this against the gateway's own record, which is why it outranks the other two.
- **screen.** A rule about what your system shows or stores, which no call proves. Evidence is one screenshot or a short recording and the design rule it satisfies. A screen case is attested, not observed, and the manifest marks it so.
- **human.** A step only a person can do. Evidence is the observation just before it and the outcome `needs-human` when nobody was there.
### Rules that hold for every case
- Search before create. Every identifier goes to the login path first, and only ABDM-1114 on the verify says nobody holds an account. Creating on any other answer gives the patient two numbers, which nothing merges. `hiecm.concept.m1-avoiding-duplicate-abha`
- Never ask twice. A value the transaction already holds, the Aadhaar number, the mobile, the txnId, is carried, not re-entered. `hiecm.concept.m1-never-ask-twice`
- Two tokens. The gateway access token goes in `Authorization`. The user token an enrolment or a login returns goes in `X-token`. Profile calls need both.
- Fresh `REQUEST-ID` on every call, logged before sending. A reused id is refused, and after a failure the id is the only handle on the call.
- Paste the response. A step with no pasted output is not done.
- Sensitive values travel encrypted: Aadhaar, mobile, email, OTP. Read the algorithm from the certificate call rather than hard coding a padding.
- One question when you escalate. The person is being interrupted.
### The run record
Append one block per loop pass. It is the raw material for the manifest.
```text
case: CRT_ABHA_101 pass: 1 of 3 at: 2026-09-29T10:14:02Z
observed: POST /abha/api/v3/enrollment/enrol/byAadhaar REQUEST-ID 6f1c... HTTP 200
body: {"message":"Account created successfully","txnId":"...","tokens":{"token":"<X-token>",...},"ABHAProfile":{"ABHANumber":"91-...",...}}
matched: exit condition for CRT_ABHA_101, step 2
next: CRT_ABHA_113
```
### When the run is a script
Asked for a test script, a test command or automated tests, build one interactive terminal runner that walks the cases below. It does the typing. Every rule above still holds.
| Rule | Why |
|---|---|
| Name every check by its case id from this skill, such as `CRT_ABHA_101`. Never invent a numbering such as `TC01` | The functional testing report quotes these ids. A check with no case id answers nothing a reviewer asks |
| At each `human` step, stop and prompt in the terminal for the value: Aadhaar number, mobile, OTP, the chosen address. Read it from stdin, encrypt it, send it | Every M1 success path passes through an OTP. A runner that never asks never reaches one |
| Never write a typed value to disk, a log or the manifest, and never hard code one | An Aadhaar number and an OTP belong to the person, not the run |
| Run each `sandbox` case's success path and the refusal its exit condition names, as separate checks | The case passes only when both are observed |
| Compare the status and the body literal the exit condition names, such as `200` with `tokens.token` present, or `422` with `error.code` `ABDM-1204` | A status alone never passes a check |
| A `4xx` passes only where the case's exit condition names that refusal | A `400` on a success path step is `failed` |
| A blank answer at a prompt records the case `needs-human` and moves to the next case | Nobody present is neither a pass nor a fail |
| A `screen` case prints its check, then asks `passed? y/n` and the evidence file name | No call proves a screen, so the case is attested |
| At the end, print one line per case id with its outcome and request ids, then write the manifest in the last section | The person reads outcomes by case id, not by script step |
A run reads like this. The person's values are typed at the prompts and never echoed back.
```text
CRT_ABHA_105 POST /v3/enrollment/request/otp REQUEST-ID 3b9e... HTTP 200 txnId present matched
Enter the OTP sent to the mobile ending 1234, or leave blank if nobody is here:
CRT_ABHA_107 wrong OTP REQUEST-ID 7c02... HTTP 422 error.code ABDM-1204 matched
CRT_ABHA_107 right OTP REQUEST-ID 9a41... HTTP 200 tokens.token present matched
CRT_ABHA_107 passed
```
Nudge: calls with a bad `scope`, a bad `loginHint` or a made up `txnId` test your client, not a case. Run them first if you want them, label them `preflight`, and keep them out of the case counts.
## Test cases
The ids, the mandatory marks and the wording of each check are ABDM's, from the M1 ABHA creation and verification set. The sections are grouped as the set groups them. Where the set names an operation, the operation id here is the one in `references/integrate.md`, which carries the host, the headers and a full request.
### CRT_ABHA_101 to 115: create an ABHA by Aadhaar OTP
Applies to every integrator. Mandatory unless marked. This is the group every other creation group repeats with a different authentication step, so it is written in full and the others state only what differs.
Loop limit: 3 passes per test case.
**Preconditions.** A gateway access token less than 30 minutes old. A person present with an Aadhaar linked mobile. Their Aadhaar number searched first on the login path and not found, so the run creates rather than duplicates.
#### CRT_ABHA_101, the option exists. `sandbox`
Your system offers ABHA creation by Aadhaar OTP, and the journey completes. Drive it end to end through your screen or API.
Calls, in order: `m1_post_v3_enrollment_request_otp_aadhaar_otp`, `m1_post_v3_enrollment_enrol_byaadhaar_otp`, the optional mobile and email verifications, `m1_get_v3_enrollment_enrol_suggestion_create_abha_aadhaar_otp`, `m1_post_v3_enrollment_enrol_abha_address_create_abha_aadhaar_otp`, then `m1_get_v3_profile_account` and `m1_get_v3_profile_account_abha_card`.
Exit condition: three literals, all pasted.
1. `m1_post_v3_enrollment_enrol_byaadhaar_otp` returns 200 with `tokens.token` present and `ABHAProfile.ABHANumber` present.
2. `m1_post_v3_enrollment_enrol_abha_address_create_abha_aadhaar_otp` returns 200 with `healthIdNumber` and `preferredAbhaAddress`.
3. `m1_get_v3_profile_account`, sent with that `X-token`, returns 200 with the same `ABHANumber`.
Nudge: read `message` on step 1. `Account created successfully` is a new account. `This account already exist` is a 200 too, and it means the search-first rule was skipped or the sandbox person already holds one. Record which, because the second is a screen failure on CRT_ABHA_101 even though the API passed.
#### CRT_ABHA_102, consent is shown and recorded. `screen`
Your system shows the published ABDM consent text before the Aadhaar number is asked for, and stores that the person agreed, with when. Evidence: the consent screen, and the stored record for this run. `hiecm.concept.m1-screen-contract`
#### CRT_ABHA_103, consent in another language. `screen`, optional
The same consent offered in at least one language other than English. Evidence: the screen in that language. Record `not-run` if you do not claim it.
#### CRT_ABHA_104, an invalid Aadhaar number is refused before any call. `screen`
Enter an 11 digit and a 13 digit value. Your system refuses each with a message that says the number is not valid, and sends nothing. Evidence: the refusal on screen and an empty call log for that attempt. Your own check has to be the strict one here; the sandbox's refusal for a bad number is not the one this case is about. `hiecm.concept.m1-honest-screen-states`
#### CRT_ABHA_105, the Aadhaar OTP is requested and can be entered. `sandbox`, then `human`
Exit condition: `m1_post_v3_enrollment_request_otp_aadhaar_otp` returns 200 with a `txnId` and a `message` that names the masked mobile. Paste it. Then stop: the OTP arrives on the person's phone and only they enter it. If they are not there, record `needs-human` and the txnId, and do not mark the case passed or failed.
Screen check alongside: the prompt tells the person the OTP went to the mobile linked with Aadhaar and shows the last digits, which the `message` carries.
#### CRT_ABHA_106, resend OTP. `screen`
The resend control is disabled for 60 seconds after each send and works at most twice. Evidence: a recording or three timestamped screenshots: disabled at send, enabled after 60 seconds, disabled after the second resend. A resend that works reuses the `txnId`; a fresh `txnId` is a new request, not a resend.
#### CRT_ABHA_107, the OTP is verified, and a wrong OTP is refused. `sandbox`, `human`
Two observations, both needed.
1. A wrong OTP: `m1_post_v3_enrollment_enrol_byaadhaar_otp` returns 422 with `error.code` `ABDM-1204` and a message naming an invalid Aadhaar OTP value, and your screen says the OTP was wrong and lets the person retry without re-entering the Aadhaar number.
2. The right OTP: the 200 from CRT_ABHA_101 step 1.
The person enters both OTPs. Stop for each.
#### CRT_ABHA_108, the communication mobile is the Aadhaar mobile. `sandbox`, optional
If your system checks whether the mobile the person gave is the Aadhaar linked one and skips the second OTP when it is, drive that path. Exit condition: the journey reaches the ABHA address step with no `mobile-verify` call in the log. Record `not-run` if you always verify, which CRT_ABHA_109 then covers.
#### CRT_ABHA_109, a different communication mobile is verified. `sandbox`, `human`
Give a mobile that is not the Aadhaar linked one. Exit condition: `m1_post_v3_enrollment_request_otp_mobile_verify_create_ab_1b66bb` returns 200 with a `txnId`, the person enters the OTP, and `m1_post_v3_enrollment_auth_byabdm_mobile_verify_create_ab_091285` returns 200. A wrong OTP here is refused on screen and the person can retry.
#### CRT_ABHA_112, the ABHA address is suggested and validated. `sandbox` and `screen`
Mandatory for private and government integrators. Optional for a programme that creates a default address by demographic authentication.
Exit condition: `m1_get_v3_enrollment_enrol_suggestion_create_abha_aadhaar_otp` returns 200 with `abhaAddressList` holding at least three entries, and `m1_post_v3_enrollment_enrol_abha_address_create_abha_aadhaar_otp` returns 200 with `preferredAbhaAddress` equal to the one chosen.
Screen check: at least three suggestions are shown, or a free field with these rules printed beside it, and an address already taken is refused with a message that says so and offers the suggestions.
```text
length 8 to 18
letters, digits, or both
at most one dot and at most one underscore, neither first nor last
```
#### CRT_ABHA_113, the ABHA number is displayed. `screen`
The 14 digit ABHA number and the ABHA address from CRT_ABHA_112 are shown together after creation. Evidence: the screen, with the number matching `healthIdNumber` from the pasted response.
#### CRT_ABHA_114, the ABHA card can be viewed and downloaded. `sandbox` and `screen`
Mandatory for private integrators that generate the card. Exit condition: `m1_get_v3_profile_account_abha_card` returns 200 with content type `image/png`, sent with the `X-token` from creation. Screen check: the card shown carries the ABHA number, the QR code, date of birth, gender and the ABHA address. The photo is optional.
#### CRT_ABHA_115, your own card carries the ABHA details. `screen`
For an integrator that prints its own programme card instead. Mandatory for government where CRT_ABHA_114 is not done. The card shows the ABHA number and address, and your system stores both against your own patient id. Evidence: the card and the stored record.
### CRT_ABHA_201 to 210: create an ABHA by Aadhaar biometric
Applies to every integrator. Optional, except that CRT_ABHA_209 is mandatory for a private integrator that generates the card and one of 209 or 210 is mandatory for government.
Loop limit: 3 passes per test case.
Same cases as 101 to 115 with these differences. Run each as its counterpart above and record the counterpart's evidence.
| Case | Counterpart | What differs |
|---|---|---|
| CRT_ABHA_201 | 101 | The creation call is `m1_post_v3_enrollment_enrol_byaadhaar_fingerprint` or `m1_post_v3_enrollment_enrol_byaadhaar_face`. Exit condition is the same 200 with `tokens.token` and `ABHAProfile.ABHANumber` |
| CRT_ABHA_205 | 105 and 107 | `human`: the person scans. A failed scan is refused on screen and can be retried. Face runs `m1_post_v3_enrollment_enrol_auth_init_create_abha_face_au_4dea33` then the capture call first |
| CRT_ABHA_206, 207 | 108, 109 | Unchanged |
| CRT_ABHA_208 | 113 | Unchanged |
| CRT_ABHA_209, 210 | 114, 115 | Unchanged |
| CRT_ABHA_202, 203, 204 | 102, 103, 104 | Unchanged |
Without a registered device the whole group is `not-run`, with that reason.
### CRT_ABHA_301 to 309: create an ABHA by demographic authentication
Government entities only. Mandatory for them. A private integrator records the group `not-run`.
Loop limit: 3 passes per test case.
#### CRT_ABHA_301 and 305, the demographic call creates the account. `sandbox`
One call, `m1_post_v3_enrollment_enrol_byaadhaar_demo_auth_create_ab_81107d`, with the name, date of birth, gender, Aadhaar number, mobile, address, state and district as they read on the Aadhaar card. Exit condition: 200 with `healthIdNumber`, `healthId` and `kycVerified` `true`.
Then the mismatch: send the same call with the date of birth changed. Exit condition: a 422 whose message says the information does not match the details on record with Aadhaar, and your screen says so without creating anything. Both observations, both pasted.
Nudge: the same mobile on a seventh account is refused with ABDM-1124. That is a mobile limit, not a demographic mismatch. Read `error.message`.
#### CRT_ABHA_305 address, the three cases. `sandbox` and `screen`
The address on the card and the profile is the same one in all three cases: the existing address when the person had one, the address they chose when they chose one, and the default `<ABHA number>@sbx` when neither. Evidence: `healthId` in the creation response and the address on `m1_get_v3_profile_account`, equal, for whichever case the run hit. Record which.
#### CRT_ABHA_306, the profile is filled from the response, not typed. `screen`
Name, date of birth and gender are shown filled and not editable. Address, mobile and email are editable. Evidence: the form after creation. `hiecm.concept.m1-confirm-the-filled-form`
#### CRT_ABHA_302, 303, 304, 307, 308, 309
As 102, 103, 104, 113, 114 and 115.
### CRT_ABHA_401 to 411: create an ABHA by driving licence or PAN
ABDM's M1 specification publishes no enrolment by document operation. Record every case in this group `not-run` with that reason, whatever your entity type, until an operation is published. Do not improvise a call.
### VRFY_ABHA_101 and 102: verify an ABHA number or address by Aadhaar OTP
Applies to every integrator. Mandatory.
Loop limit: 3 passes per test case.
**Preconditions.** A person present with an ABHA and the Aadhaar linked mobile.
#### VRFY_ABHA_101, by ABHA number. `sandbox`, `human`
Calls: `m1_post_v3_profile_login_request_otp_abha_number_aadhaar_otp`, the OTP, `m1_post_v3_profile_login_verify_abha_number_aadhaar_otp`, then `m1_get_v3_profile_account` with the returned token as `X-token`.
Exit condition: the verify returns 200 with `authResult` `success` and `accounts[0].ABHANumber`, and the profile call returns 200 with the same `ABHANumber`. A wrong OTP returns 400 with `otpValue` naming an invalid OTP value, and your screen says the verification failed.
Screen checks alongside: resend as in CRT_ABHA_106; name, date of birth and gender shown not editable; the profile stored against your own patient id after verification.
Nudge: the accounts array already carries the whole registration form. Fill the form from it before the profile call, so the person reads back rather than types.
#### VRFY_ABHA_102, by ABHA address. `sandbox`, `human`
Calls: `m1_post_v3_phr_web_login_abha_search_abha_address_login_a_de8184`, `m1_post_v3_phr_web_login_abha_request_otp_aadhaar_otp`, the OTP, `m1_post_v3_phr_web_login_abha_verify_aadhaar_otp`, then `m1_get_v3_phr_web_login_profile_abha_profile_abha_address_c04e83`.
Exit condition: the verify returns 200 with a token, and the profile call returns 200 carrying the ABHA number and the address searched for. Paste both.
### VRFY_ABHA_201 and 202: verify by the ABHA linked mobile OTP
Mandatory. As VRFY_ABHA_101 and 102 with the mobile OTP operations: `m1_post_v3_profile_login_request_otp_abha_number_abha_otp` and `m1_post_v3_profile_login_verify_abha_number_abha_otp` for the number, `m1_post_v3_phr_web_login_abha_request_otp_mobile_otp` and `m1_post_v3_phr_web_login_abha_verify_mobile_otp` for the address. Same exit conditions, same screen checks.
Loop limit: 3 passes per test case.
### VRFY_ABHA_301 to 305: fetch ABHA details by the communication mobile
Mandatory. This is the lookup that costs no Aadhaar OTP, so it is the one your desk should run first.
Loop limit: 3 passes per test case.
#### VRFY_ABHA_301, an invalid mobile is refused. `screen`
A nine digit and an eleven digit value are refused on screen with a message asking for a valid mobile, and nothing is sent.
#### VRFY_ABHA_302, no ABHA on this mobile. `sandbox`, `human`
Calls: `m1_post_v3_profile_login_request_otp_mobile`, the OTP, `m1_post_v3_profile_login_verify_mobile_otp`.
Exit condition: the verify returns 404 with `error.code` `ABDM-1114`. Your screen says no ABHA number is linked to this mobile, and offers to create one. The create offer is the point of the case; a dead end fails it. `hiecm.concept.m1-journey-completes-without-abha`
#### VRFY_ABHA_303, one or more ABHAs on this mobile. `sandbox`, `human`
Same two calls with a mobile that holds accounts, then `m1_post_v3_profile_login_verify_user` with the chosen `ABHANumber` and the first verify's token as `T-token`, then `m1_get_v3_profile_account`.
Exit condition: the first verify returns 200 with `accounts` holding at least one entry with `ABHANumber`, `preferredAbhaAddress`, `name` and `profilePhoto`; the user verify returns 200 with `token`; the profile call returns 200 with the chosen `ABHANumber`.
Screen checks: every account in the array is listed with name, number, address and photo; choosing one already linked to a patient in your system says so and names your patient id; choosing one not yet linked registers and links it. `hiecm.concept.m1-two-routes-to-the-profile`
Nudge: read the array as plural. One mobile can hold up to six accounts, and a screen that shows the first one silently links the wrong person.
#### VRFY_ABHA_304, a wrong OTP. `sandbox`, `human`
Exit condition: `m1_post_v3_profile_login_verify_mobile_otp` returns 400 with `otpValue` naming an invalid OTP value, and your screen says so and allows a retry without re-entering the mobile.
#### VRFY_ABHA_305, resend. `screen`
As CRT_ABHA_106.
### VRFY_ABHA_401 to 405: fetch ABHA details by Aadhaar number
Mandatory.
Loop limit: 3 passes per test case.
#### VRFY_ABHA_401, an invalid Aadhaar is refused. `screen`
As CRT_ABHA_104, on the verification screen.
#### VRFY_ABHA_403, no ABHA on this Aadhaar. `sandbox`, `human`
Calls: `m1_post_v3_profile_login_request_otp_aadhaar`, the OTP, `m1_post_v3_profile_login_verify_aadhaar_otp`.
Exit condition: the request returns 200 with a `message` naming the masked Aadhaar mobile, the person enters the OTP, and the verify returns 404 with `error.code` `ABDM-1114` and a message that no ABHA user is registered with this Aadhaar number. Your screen says so and offers creation, and the creation path does not ask for the Aadhaar number again. `hiecm.concept.m1-never-ask-twice`
#### VRFY_ABHA_404, an ABHA exists on this Aadhaar. `sandbox`, `human`
Same calls with an Aadhaar that holds an account, then `m1_get_v3_profile_account`.
Exit condition: the verify returns 200 with `authResult` `success` and `accounts[0].ABHANumber`; the profile call returns 200 with the same number. Screen checks: the profile is shown, the card can be downloaded as in CRT_ABHA_114, and the account is registered and linked to your patient id if it was not already.
#### VRFY_ABHA_402 and 405
A wrong OTP and resend, as VRFY_ABHA_304 and 305.
### VRFY_ABHA_501 and 502: verify by fingerprint, government entities
Optional. `human`. Calls: `m1_post_v3_1_profile_login_verify_fingerprint` for a number. The set names no operation for an address by fingerprint; record VRFY_ABHA_502 `not-run` with that reason. Exit condition for 501: 200 with `accounts[0].ABHANumber`, then the profile call as VRFY_ABHA_101. Without a device, `not-run`.
Loop limit: 3 passes per test case.
### Reading the ABHA QR code, optional
The set numbers this row VRFY_ABHA_501 as well. Record it as `QR-read` so the two are told apart in the manifest.
`screen`. No call. Your system scans a person's ABHA QR code and fills name, date of birth, gender and mobile into registration from it. Evidence: the filled form after a scan, with nothing typed. `hiecm.concept.m1-two-routes-to-the-profile`
Loop limit: 3 passes per test case.
### PROF_ABHA_601 to 605: profile update
Optional. Each is `sandbox` and `human`, since every change is confirmed by an OTP.
Loop limit: 3 passes per test case.
| Case | Calls | Exit condition |
|---|---|---|
| PROF_ABHA_601, mobile | `m1_post_v3_profile_account_request_otp_update_mobile`, the OTP, `m1_post_v3_profile_account_verify_update_mobile` | The verify returns 200 with `authResult` `success` and a message that the mobile number was linked; `m1_get_v3_profile_account` then shows the new masked `mobile` |
| PROF_ABHA_602, photo | `m1_patch_v3_profile_account_profile_photo` | 200, and `m1_get_v3_profile_account` returns the new `profilePhoto` |
| PROF_ABHA_603, email | The request and verify calls above with the email scope | 200 on the verify, and the profile shows the new email |
| PROF_ABHA_604, re-KYC | `m1_post_v3_profile_account_request_otp_re_kyc`, the OTP, `m1_post_v3_profile_account_verify_re_kyc` | 200 on the verify, and the profile shows `kycVerified` `true` |
| PROF_ABHA_605, delete or deactivate | ABDM's M1 specification publishes no delete or deactivate operation | `not-run`, with that reason |
### TAGGING_UNIQUEPATIENTID_UNIQUEABHANUMBER: one ABHA per patient id
Mandatory. `screen`. Your system checks whether an ABHA number already exists in its database before it creates a patient id, on both the creation and the verification paths, so one ABHA never maps to two of your patients and one of your patients never holds two ABHAs.
Evidence: verify the same ABHA twice in a run. The second time, the screen says the record is already linked and names your patient id, and the database holds one row. `hiecm.concept.m1-avoiding-duplicate-abha`
Loop limit: 3 passes per test case.
### SHARE_PATIENT_PROFILE_701: share a profile by scanning the facility QR
This case is run from the person's ABHA app, and the call that proves it lands on your side as the `on-share` webhook. It belongs to the scan and register skill, `abdm-scan-and-register`, which carries the webhook and the token reply. Record it there. In this manifest, write `see abdm-scan-and-register`.
## When the last case is recorded
Write the manifest. It is the whole report. Case ids to request ids, nothing else, so a reviewer checks it against the gateway's own record rather than reading screenshots. Secrets never appear in it: no tokens, no OTPs, no Aadhaar numbers, no client secret.
```json
{
"skill": "abdm-m1",
"set": "M1 ABHA creation and verification, NHA, version 1.1",
"entity": "private",
"run_started": "2026-09-29T10:12:40Z",
"run_finished": "2026-09-29T11:48:03Z",
"client_id": "<your sandbox client id>",
"cases": [
{"id": "CRT_ABHA_101", "outcome": "passed", "evidence": "sandbox",
"request_ids": ["6f1c...", "a02d...", "c9e4..."],
"observed": ["byAadhaar 200 message=Account created successfully", "abha-address 200 healthIdNumber", "profile/account 200 ABHANumber"]},
{"id": "CRT_ABHA_102", "outcome": "passed", "evidence": "screen",
"attachment": "consent-2026-09-29.png", "rule": "hiecm.concept.m1-screen-contract"},
{"id": "CRT_ABHA_105", "outcome": "needs-human", "evidence": "human",
"request_ids": ["b7a1..."], "reason": "OTP arrives on the person's phone; nobody present"},
{"id": "CRT_ABHA_401", "outcome": "not-run", "reason": "no enrolment by document operation in the M1 specification"}
]
}
```
Then say, in three lines: how many cases passed, failed, need a human and were not run; which mandatory cases for your entity are not `passed`; and the one case to fix first.

View File

@ -0,0 +1,92 @@
---
name: abdm-m2
description: Use when building, debugging or testing ABDM Milestone 2: care contexts, HIP initiated linking, discovery, and pushing encrypted health records to a requester. Carries the endpoints and the encryption parameters. Also carries the scaffolding loop that builds it flow by flow and the loop from a failed call to a named fix, in references/.
type: skill
domain: m2
agent_consumers:
- abdm-integration-agent
- abdm-call-debugger
requires:
- gateway-session-token
- hip-registration
- callback-url
- nrces-document-bundle
produces:
- care-context
- link-token
- health-information-push
can_execute: true
can_orchestrate: false
---
# ABDM M2, create and link records
Generated from the ABDM Developer Portal on 2026-09-16, catalogue version 2026.09.16. Every fact below comes from a page in that portal, which is the place to look when this file does not carry enough.
This file is a snapshot. Re-download the whole folder from https://docs.abdm.gov.in/skills/abdm-m2/ when it is older than the work you are doing: this router and every file under references/ that it links to. Fetching this file alone leaves those links pointing at files you do not have.
If the abdm-docs MCP server is connected, trust its answers over this file: it serves the current catalogue and stamps every response with its catalogue_version, which you can compare against the version above.
## What you can do with M2
- Tell ABDM a patient had a visit with you, so their records can be found later.
- Answer a discovery request when somebody looks for that patient.
- Send records out encrypted when a consent says you must.
- Get the link token the linking calls need.
What it cannot do yet matters as much. Read **Before anything else** below before assuming a capability is one endpoint away.
## Try asking
- "Link a care context for this patient"
- "What has to be in place before my first M2 call?"
- "My M2 call returned ABDM-1000. What is wrong, and how do I fix it?"
Loaded with no task? Say in three lines what this skill does. Offer the prompts above. Then ask what the person is building, and whether the code for it exists yet.
## What is in this folder
- **Scaffold.** Survey the codebase first when one exists, then build it flow by flow against the sandbox, as a loop that ends when the step's exit condition holds rather than on a call returning 200. [references/scaffold.md](references/scaffold.md)
- **Design.** What the journey around the calls has to do, and what a screen is forbidden to claim. [references/design.md](references/design.md)
- **Integrate.** 24 operations, with their hosts and headers. [references/integrate.md](references/integrate.md)
- **Debug.** The loop from a failed call to a named fix, and 120 error codes from the specification's examples. [references/debug.md](references/debug.md)
This file is the map. Each line above is a file beside it, opened one at a time rather than read through.
## Before anything else
- Treat every request and response shape in this skill as unconfirmed until the sandbox has answered you. Check a response before you rely on its shape.
- The design section is different in kind. Its rules come from building a working front desk against the sandbox, and each atom it cites names what was observed and the date it was seen.
- You act as the HIP.
- Before M2, three things must hold: the facility is registered in the HFR with a valid HFR ID, that HIP ID is linked to your client ID (through the NHPR portal or the M4 software linkage APIs), and a callback URL is set for the client ID with the Update Bridge API.
- You are the side that encrypts, and the parameters arrive from the requester rather than from you. The health information request carries `keyMaterial` with `cryptoAlg`, `curve: Curve25519`, the requester's `dhPublicKey` and a `nonce`. Generate your own Curve25519 pair and your own nonce, and send your public key and nonce back with the data so the requester can derive the same secret.
- The key derivation and the symmetric cipher applied over that shared secret are not in the specification. The data flow page (/docs/hiecm/v3/concepts/data-flow) and the Fidelius reference (shared.concept.fidelius-ecdh-interop) give the scheme: HKDF over the shared secret, and AES-GCM for the payload. Build from those, not from a sample.
## Practices that hold across every call
- Read the body, not only the status. A refusal often names the field in its body while the status says nothing useful.
- When ABDM publishes a value, read it rather than hard coding what it currently says. That covers a parameter, such as the encryption algorithm the certificate endpoints return beside the key, and it covers an enumeration. The registries publish theirs as master data calls: councils, courses, colleges, states and districts on the HPR, and facility types and LGD codes on the HFR. A table typed into your source goes stale silently. Purposes and HI types have no master data call: take them from the enumeration in the specification of the call you are making. Refuse to act on a published value you do not recognise rather than falling back to a default.
- Read every field in a response, not the one you came for. The M1 certificate call returns the encryption algorithm next to the key.
- Prove an assumption against a call that is able to disagree with you. A call that refuses every input with one message cannot tell you which input was right.
- Suspect the transport before the data. When a call refuses a value you believe in, check the encryption, the headers and the clock before you doubt the value.
- Do not carry an encryption path from one module to another. Read the certificate and the algorithm from the registry you are calling.
- Never log a sensitive value before you encrypt it, and never send one to a remote service to be encrypted. Both move the leak rather than removing it.
- Generate a fresh REQUEST-ID for every call and log it before sending. Once a call has failed it is the only handle on it.
- Check the host on any sample before you copy it. A request copied whole can be correct in every respect except where it is pointed, and that failure looks like credentials.
- Do not validate an identifier more strictly than the platform does. A schema that types a field as a UUID is not a promise that every value is one. Refusing a value ABDM would have accepted turns your own client into the thing that broke.
- Read a plural response as plural. A verification returns an accounts array and a consent request can produce more than one artefact. Store the collection and decide from its length.
- A documented callback path is not a documented callback payload. Log the whole body on arrival before you parse it, so a handler written against an assumed shape fails where you can see it.
- Decode a token before you use it. A call that hands you a token has not necessarily handed you the token the next call wants, and the claims are base64 that need no library to read.
- When a journey carries the same parameter through two calls, check what each call's specification asks for rather than carrying the first value forward.
- Do not infer which path an identifier belongs to from where that identifier is most discussed. Send every identifier to the lookup first and let the answer pick the path, so nobody who already holds an account is sent to create a second.
- Do not match an error code with string equality. A code may come back bare, as `ABDM-1001`, or with a trailing `: ` separator, as `ABDM-1001: `. Match on the code itself and tolerate the separator.
- Handle a failure that carries no body. Check for an empty body before you parse, or your client throws on the simplest failure there is.
- Back off on an authentication failure rather than retrying, and never loop a credential check.
- Send TIMESTAMP in UTC, ISO-8601 with milliseconds and a trailing Z, as in `2022-10-06T15:10:00.587Z`.
- Cache a public certificate with a validity window rather than forever. A rotation fails every encrypted call at once, and a cache with no expiry cannot recover on its own.
## Where the detail is
- Every endpoint, with its body fields and responses: /docs/hiecm/v3/api/m2
- The flows as diagrams: /docs/hiecm/v3/milestones/m2
- Every error code across modules: /docs/hiecm/v3/reference/error-codes
- Terms: /docs/hiecm/v3/getting-started/glossary

View File

@ -0,0 +1,860 @@
# HIE-CM m2 debug
Every error below is an OODA loop: observe the error code and last request id, orient against the matched code, decide the fix, act, and observe whether the original step now succeeds. Applying a fix is not the exit condition; the original step succeeding is.
Loop limit: 5 passes per error.
## Errors
### ABDM-1000
**NHA's list for the module:** `Unable to connect the database`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1001
**NHA's list for the module:** `No data found`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1004
**NHA's list for the module:** `SMS Gateway is unavailable`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1006
**NHA's list for the module:** `Bad Request, invalid request Body`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1007
**NHA's list for the module:** `Connection failed due to timeout`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1008
**NHA's list for the module:** `SMS service currently disabled`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1010
**NHA's list for the module:** `Validation failed`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1011
**NHA's list for the module:** `Gateway database unavailable`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1012
**NHA's list for the module:** `No records found against the ABHA Address`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1013
**NHA's list for the module:** `Invalid ABHA Number`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1015
**NHA's list for the module:** `Invalid Response`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1016
**NHA's list for the module:** `Invalid TimeStamp`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1017
**NHA's list for the module:** `Invalid TransactionId`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1018
**NHA's list for the module:** `Share Profile database unavailable`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1019
**NHA's list for the module:** `Dependent Service Unavailable`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1020
**NHA's list for the module:** `Unknown database`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1022
**NHA's list for the module:** `Too many requests`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1023
**NHA's list for the module:** `Invalid User`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1024
**NHA's list for the module:** `Dependent service unavailable`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1025
**NHA's list for the module:** `Invalid ServiceId`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1026
**NHA's list for the module:** `Invalid Link Token`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1027
**NHA's list for the module:** `You are blocked. Please try again after 24 hours.`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1028
**NHA's list for the module:** `HIP is unavailable`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1029
**NHA's list for the module:** `Redis server is unavailable`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1030
**NHA's list for the module:** `Invalid request ID`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1031
**NHA's list for the module:** `Invalid request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1032
**NHA's list for the module:** `Invalid header`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1033
**NHA's list for the module:** `HIU is unavailable`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1034
**NHA's list for the module:** `Notification service unavailable`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1035
**NHA's list for the module:** `Invalid HIP ID`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1036
**NHA's list for the module:** `Data does not matched`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1037
**NHA's list for the module:** `Counter and Care context count mismatch`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1038
**NHA's list for the module:** `ABHA address and Link token mismatch`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1040
**NHA's list for the module:** `Invalid HIU ID`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1041
**NHA's list for the module:** `Invalid Acknowledgement`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1042
**NHA's list for the module:** `Provider Mandatory`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1043
**NHA's list for the module:** `ABHA Address does not match with KYC details.`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1044
**NHA's list for the module:** `Broadcast Failed`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1045
**NHA's list for the module:** `Database Access is restricted`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1046
**NHA's list for the module:** `Invalid Purpose`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1047
**NHA's list for the module:** `Purpose does not exist`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1048
**NHA's list for the module:** `Timeout`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1049
**NHA's list for the module:** `Invalid Profile Share Intent Keys`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1050
**NHA's list for the module:** `Invalid Profile Share Metadata Keys`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1051
**NHA's list for the module:** `Invalid ABHA Number or ABHA Address`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1052
**NHA's list for the module:** `Invalid TransactionId or response's requestId`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1401
**NHA's list for the module:** `HIP is not available`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1061
**NHA's list for the module:** `Consent artefact expired`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1062
**NHA's list for the module:** `Consent Not granted`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1063
**NHA's list for the module:** `Date Range given is invalid`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1064
**NHA's list for the module:** `request with this request id already exists`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1109
**NHA's list for the module:** `ABHA DB service unavailable`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1108
**NHA's list for the module:** `Notification DB service unavailable`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1201
**NHA's list for the module:** `IDP Gateway is unavailable`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-9999
**NHA's list for the module:** `Unknown exception`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1006
**NHA's list for the module:** `Invalid combinations of scopes`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1056
**NHA's list for the module:** `This care contexts has been already linked`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1055
**NHA's list for the module:** `Invalid HIP Id or PHR Id`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1056
**NHA's list for the module:** `Invalid Link Reference Number`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1057
**NHA's list for the module:** `Invalid Care Contexts`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1059
**NHA's list for the module:** `Invalid Care Contexts count`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1060
**NHA's list for the module:** `Invalid Patient Reference Number`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1061
**NHA's list for the module:** `Invalid Patient Display`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1062
**NHA's list for the module:** `ABHA number mismatch with Link token`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1063
**NHA's list for the module:** `HIP Id mismatch with Link token`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1064
**NHA's list for the module:** `Request body was missing`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1065
**NHA's list for the module:** `Invalid X Auth token`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1066
**NHA's list for the module:** `Invalid JWT token`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1067
**NHA's list for the module:** `Request body not required`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1170
**NHA's list for the module:** `Invalid ABHA address`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1084
**NHA's list for the module:** `ABHA address mismatch with X Auth token`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1085
**NHA's list for the module:** `ABHA number mismatch with X Auth token`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1086
**NHA's list for the module:** `Patient profile mismatch with X Auth token`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1087
**NHA's list for the module:** `Duplicate patient share request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1090
**NHA's list for the module:** `Duplicate HIP link request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1091
**NHA's list for the module:** `Duplicate Get links request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1092
**NHA's list for the module:** `Duplicate Link token request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1093
**NHA's list for the module:** `Duplicate Bridge request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1094
**NHA's list for the module:** `Duplicate bridge patch request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1095
**NHA's list for the module:** `Duplicate Bridge service request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1102
**NHA's list for the module:** `Profile information cannot be null`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1103
**NHA's list for the module:** `Duplicate Discovery request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1104
**NHA's list for the module:** `Duplicate Init request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1105
**NHA's list for the module:** `Duplicate Confirm request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1106
**NHA's list for the module:** `Duplicate On discovery request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1107
**NHA's list for the module:** `Duplicate On init request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1108
**NHA's list for the module:** `Duplicate On confirm request`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1109
**NHA's list for the module:** `Invalid On discovery response`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1110
**NHA's list for the module:** `Invalid On init response`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1111
**NHA's list for the module:** `Invalid On confirm response`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1112
**NHA's list for the module:** `Invalid or already expired consent artefact id`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1113
**NHA's list for the module:** `Duplicate health information provider data flow response`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1149
**NHA's list for the module:** `Intent type is not supported at HIP end`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1150
**NHA's list for the module:** `Bridge API version cannot be null`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1402
**NHA's list for the module:** `Acknowledgement is not received from HIP`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-9999
**NHA's list for the module:** `HIP is unable to generate a token at this time. Please try again later.`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-9999
**NHA's list for the module:** `HIP is unable to process at this time. Please try again later.`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1030
**NHA's list for the module:** `Request id not found`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-2500
**NHA's list for the module:** `No mapping found for`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-2401
**NHA's list for the module:** `The X Auth token is invalid.`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-2402
**NHA's list for the module:** `Invalid Timestamp`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-2404
**NHA's list for the module:** `Invalid Request Id`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-2429
**NHA's list for the module:** `Too many requests found`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-2501
**NHA's list for the module:** `Payment status should be : SUCCESS,CANCELED,PENDING,FAIL,REFUND_INITIATED,REFUND_SUCCESS`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-2500
**NHA's list for the module:** `Authorization header is missing`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-2403
**NHA's list for the module:** `Invalid X-CM-ID`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-2406
**NHA's list for the module:** `Invalid API sequence flow, please follow logical flow`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-2406
**NHA's list for the module:** `The status is invalid. Please follow the logical status flow or transition.`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-9999
**NHA's list for the module:** `User not found`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-9999
**NHA's list for the module:** `Cannot process the request at the moment, please try later.`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-9001
**NHA's list for the module:** `No open order against ABHA. Please ensure a minimum of one open order`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-9002
**NHA's list for the module:** `No registration found at <<hospital name>>. Contact counter support`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-9003
**NHA's list for the module:** `Hospital services temporarily unavailable. Please try again after some time.`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-9004
**NHA's list for the module:** `Services disrupted, please try again.`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-9005
**NHA's list for the module:** `Bank server not responding. Please try again later`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-9006
**NHA's list for the module:** `Service details mismatch. Please ensure original service ID from HMIS`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-9007
**NHA's list for the module:** `The Scan and Pay functionality is not enabled at this facility. Kindly contact the hospital administration.`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1006
**NHA's list for the module:** `Invalid count, must be 2 digit and ranges between 1 to 20`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1407
**NHA's list for the module:** `The ABHA Number associated with this ABHA Address is currently deactivated. Please reactivate it.`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
### ABDM-1006
**NHA's list for the module:** `Invalid HIType, it must be in Prescription,DiagnosticReport,OPConsultation,DischargeSummary,ImmunizationRecord,HealthDocumentRecord,WellnessRecord,Invoice`. NHA names no HTTP status and no call for it.
**Exit condition: the original call now succeeds.**
## Where the detail is
- The operation that returns each code: /docs/hiecm/v3/api/m2
## Every code in the specification
### Codes
| Code | HTTP | Message | Returned by |
| --- | --- | --- | --- |
| `ABDM-1000` | | Unable to connect the database | NHA's list for the module |
| `ABDM-1001` | | No data found | NHA's list for the module |
| `ABDM-1004` | | SMS Gateway is unavailable | NHA's list for the module |
| `ABDM-1006` | | Bad Request, invalid request Body | NHA's list for the module |
| `ABDM-1007` | | Connection failed due to timeout | NHA's list for the module |
| `ABDM-1008` | | SMS service currently disabled | NHA's list for the module |
| `ABDM-1010` | | Validation failed | NHA's list for the module |
| `ABDM-1011` | | Gateway database unavailable | NHA's list for the module |
| `ABDM-1012` | | No records found against the ABHA Address | NHA's list for the module |
| `ABDM-1013` | | Invalid ABHA Number | NHA's list for the module |
| `ABDM-1015` | | Invalid Response | NHA's list for the module |
| `ABDM-1016` | | Invalid TimeStamp | NHA's list for the module |
| `ABDM-1017` | | Invalid TransactionId | NHA's list for the module |
| `ABDM-1018` | | Share Profile database unavailable | NHA's list for the module |
| `ABDM-1019` | | Dependent Service Unavailable | NHA's list for the module |
| `ABDM-1020` | | Unknown database | NHA's list for the module |
| `ABDM-1022` | | Too many requests | NHA's list for the module |
| `ABDM-1023` | | Invalid User | NHA's list for the module |
| `ABDM-1024` | | Dependent service unavailable | NHA's list for the module |
| `ABDM-1025` | | Invalid ServiceId | NHA's list for the module |
| `ABDM-1026` | | Invalid Link Token | NHA's list for the module |
| `ABDM-1027` | | You are blocked. Please try again after 24 hours. | NHA's list for the module |
| `ABDM-1028` | | HIP is unavailable | NHA's list for the module |
| `ABDM-1029` | | Redis server is unavailable | NHA's list for the module |
| `ABDM-1030` | | Invalid request ID | NHA's list for the module |
| `ABDM-1031` | | Invalid request | NHA's list for the module |
| `ABDM-1032` | | Invalid header | NHA's list for the module |
| `ABDM-1033` | | HIU is unavailable | NHA's list for the module |
| `ABDM-1034` | | Notification service unavailable | NHA's list for the module |
| `ABDM-1035` | | Invalid HIP ID | NHA's list for the module |
| `ABDM-1036` | | Data does not matched | NHA's list for the module |
| `ABDM-1037` | | Counter and Care context count mismatch | NHA's list for the module |
| `ABDM-1038` | | ABHA address and Link token mismatch | NHA's list for the module |
| `ABDM-1040` | | Invalid HIU ID | NHA's list for the module |
| `ABDM-1041` | | Invalid Acknowledgement | NHA's list for the module |
| `ABDM-1042` | | Provider Mandatory | NHA's list for the module |
| `ABDM-1043` | | ABHA Address does not match with KYC details. | NHA's list for the module |
| `ABDM-1044` | | Broadcast Failed | NHA's list for the module |
| `ABDM-1045` | | Database Access is restricted | NHA's list for the module |
| `ABDM-1046` | | Invalid Purpose | NHA's list for the module |
| `ABDM-1047` | | Purpose does not exist | NHA's list for the module |
| `ABDM-1048` | | Timeout | NHA's list for the module |
| `ABDM-1049` | | Invalid Profile Share Intent Keys | NHA's list for the module |
| `ABDM-1050` | | Invalid Profile Share Metadata Keys | NHA's list for the module |
| `ABDM-1051` | | Invalid ABHA Number or ABHA Address | NHA's list for the module |
| `ABDM-1052` | | Invalid TransactionId or response's requestId | NHA's list for the module |
| `ABDM-1401` | | HIP is not available | NHA's list for the module |
| `ABDM-1061` | | Consent artefact expired | NHA's list for the module |
| `ABDM-1062` | | Consent Not granted | NHA's list for the module |
| `ABDM-1063` | | Date Range given is invalid | NHA's list for the module |
| `ABDM-1064` | | request with this request id already exists | NHA's list for the module |
| `ABDM-1109` | | ABHA DB service unavailable | NHA's list for the module |
| `ABDM-1108` | | Notification DB service unavailable | NHA's list for the module |
| `ABDM-1201` | | IDP Gateway is unavailable | NHA's list for the module |
| `ABDM-9999` | | Unknown exception | NHA's list for the module |
| `ABDM-1006` | | Invalid combinations of scopes | NHA's list for the module |
| `ABDM-1056` | | This care contexts has been already linked | NHA's list for the module |
| `ABDM-1055` | | Invalid HIP Id or PHR Id | NHA's list for the module |
| `ABDM-1056` | | Invalid Link Reference Number | NHA's list for the module |
| `ABDM-1057` | | Invalid Care Contexts | NHA's list for the module |
| `ABDM-1059` | | Invalid Care Contexts count | NHA's list for the module |
| `ABDM-1060` | | Invalid Patient Reference Number | NHA's list for the module |
| `ABDM-1061` | | Invalid Patient Display | NHA's list for the module |
| `ABDM-1062` | | ABHA number mismatch with Link token | NHA's list for the module |
| `ABDM-1063` | | HIP Id mismatch with Link token | NHA's list for the module |
| `ABDM-1064` | | Request body was missing | NHA's list for the module |
| `ABDM-1065` | | Invalid X Auth token | NHA's list for the module |
| `ABDM-1066` | | Invalid JWT token | NHA's list for the module |
| `ABDM-1067` | | Request body not required | NHA's list for the module |
| `ABDM-1170` | | Invalid ABHA address | NHA's list for the module |
| `ABDM-1084` | | ABHA address mismatch with X Auth token | NHA's list for the module |
| `ABDM-1085` | | ABHA number mismatch with X Auth token | NHA's list for the module |
| `ABDM-1086` | | Patient profile mismatch with X Auth token | NHA's list for the module |
| `ABDM-1087` | | Duplicate patient share request | NHA's list for the module |
| `ABDM-1090` | | Duplicate HIP link request | NHA's list for the module |
| `ABDM-1091` | | Duplicate Get links request | NHA's list for the module |
| `ABDM-1092` | | Duplicate Link token request | NHA's list for the module |
| `ABDM-1093` | | Duplicate Bridge request | NHA's list for the module |
| `ABDM-1094` | | Duplicate bridge patch request | NHA's list for the module |
| `ABDM-1095` | | Duplicate Bridge service request | NHA's list for the module |
| `ABDM-1102` | | Profile information cannot be null | NHA's list for the module |
| `ABDM-1103` | | Duplicate Discovery request | NHA's list for the module |
| `ABDM-1104` | | Duplicate Init request | NHA's list for the module |
| `ABDM-1105` | | Duplicate Confirm request | NHA's list for the module |
| `ABDM-1106` | | Duplicate On discovery request | NHA's list for the module |
| `ABDM-1107` | | Duplicate On init request | NHA's list for the module |
| `ABDM-1108` | | Duplicate On confirm request | NHA's list for the module |
| `ABDM-1109` | | Invalid On discovery response | NHA's list for the module |
| `ABDM-1110` | | Invalid On init response | NHA's list for the module |
| `ABDM-1111` | | Invalid On confirm response | NHA's list for the module |
| `ABDM-1112` | | Invalid or already expired consent artefact id | NHA's list for the module |
| `ABDM-1113` | | Duplicate health information provider data flow response | NHA's list for the module |
| `ABDM-1149` | | Intent type is not supported at HIP end | NHA's list for the module |
| `ABDM-1150` | | Bridge API version cannot be null | NHA's list for the module |
| `ABDM-1402` | | Acknowledgement is not received from HIP | NHA's list for the module |
| `ABDM-9999` | | HIP is unable to generate a token at this time. Please try again later. | NHA's list for the module |
| `ABDM-9999` | | HIP is unable to process at this time. Please try again later. | NHA's list for the module |
| `ABDM-1030` | | Request id not found | NHA's list for the module |
| `ABDM-2500` | | No mapping found for | NHA's list for the module |
| `ABDM-2401` | | The X Auth token is invalid. | NHA's list for the module |
| `ABDM-2402` | | Invalid Timestamp | NHA's list for the module |
| `ABDM-2404` | | Invalid Request Id | NHA's list for the module |
| `ABDM-2429` | | Too many requests found | NHA's list for the module |
| `ABDM-2501` | | Payment status should be : SUCCESS,CANCELED,PENDING,FAIL,REFUND_INITIATED,REFUND_SUCCESS | NHA's list for the module |
| `ABDM-2500` | | Authorization header is missing | NHA's list for the module |
| `ABDM-2403` | | Invalid X-CM-ID | NHA's list for the module |
| `ABDM-2406` | | Invalid API sequence flow, please follow logical flow | NHA's list for the module |
| `ABDM-2406` | | The status is invalid. Please follow the logical status flow or transition. | NHA's list for the module |
| `ABDM-9999` | | User not found | NHA's list for the module |
| `ABDM-9999` | | Cannot process the request at the moment, please try later. | NHA's list for the module |
| `ABDM-9001` | | No open order against ABHA. Please ensure a minimum of one open order | NHA's list for the module |
| `ABDM-9002` | | No registration found at <<hospital name>>. Contact counter support | NHA's list for the module |
| `ABDM-9003` | | Hospital services temporarily unavailable. Please try again after some time. | NHA's list for the module |
| `ABDM-9004` | | Services disrupted, please try again. | NHA's list for the module |
| `ABDM-9005` | | Bank server not responding. Please try again later | NHA's list for the module |
| `ABDM-9006` | | Service details mismatch. Please ensure original service ID from HMIS | NHA's list for the module |
| `ABDM-9007` | | The Scan and Pay functionality is not enabled at this facility. Kindly contact the hospital administration. | NHA's list for the module |
| `ABDM-1006` | | Invalid count, must be 2 digit and ranges between 1 to 20 | NHA's list for the module |
| `ABDM-1407` | | The ABHA Number associated with this ABHA Address is currently deactivated. Please reactivate it. | NHA's list for the module |
| `ABDM-1006` | | Invalid HIType, it must be in Prescription,DiagnosticReport,OPConsultation,DischargeSummary,ImmunizationRecor… | NHA's list for the module |
A code you meet that is not above is one the specifications do not carry yet. Read the code together with the message: a code can appear twice with different meanings.

View File

@ -0,0 +1,639 @@
# Design M2, create and link records
What the integration has to do to the journey around the calls: how many questions a patient is asked, where a failure is shown, and what a screen is forbidden to claim. Every rule below comes from a Catalogue atom, cited at the end.
## The unit of work is an exchange, not a call
### In plain words
Every M2 and M3 call answers twice. Once straight away, saying the request was
accepted, and later on a callback to your own bridge, saying what actually
happened. Do not treat the first as success. It says the request was accepted,
not that anything was linked.
So the request id stops being a log handle and becomes the join key. An
outbound call, the wait, and the callback that answers it are one exchange, and
they should read as one row with a timeline. Shown as three separate lines they
read as noise, and the difference between accepted and done stays invisible,
which is the one thing the interface exists to show.
### What happens
Register the waiter before sending. A callback that arrives before the HTTP
response returns is a race the sandbox eventually wins.
Then hold five outcomes apart. These must not look alike:
| State | Means | Observed |
|---|---|---|
| sent | in the air | |
| accepted, waiting | `202`, nothing back yet | real patient, 340 ms |
| answered | the callback arrived | |
| refused before waiting | a synchronous `400`, nothing was ever pending | fictional patient, 91 ms |
| no answer in the window | accepted, then silence | real patient, 60,000 ms |
The fourth and fifth are the ones implementations collapse into each other. A
refused call closing its waiter through the same function as an answered one
renders a synchronous `400` as a green callback arrived. Fix that in the shared
function rather than at the call sites that reach it.
The fourth outcome is also useful. Generate link token validates the patient
before accepting the request, so an identity nobody holds is refused at once
with `400` and `ABDM-9999`, while a recognised one is accepted with `202` and
answers later. The two are distinguishable at the first response, so only a
recognised patient is worth waiting for. Note the code: `ABDM-9999` is the catch
all, and the message is the only part naming the cause.
No timeout is published for any of these, so the honest words for the fifth
outcome are that nothing arrived in the window you chose.
### How you know it worked
Send one linking call and read one row. It carries the request id, the outbound
call, the elapsed wait, and the callback when it lands, in one timeline.
Send a call for an identity nobody holds. The row shows refused within a few
hundred milliseconds, never shows waiting, and no waiter is left open.
### When it goes wrong
- A synchronous refusal shows as a completed exchange. The refusal path and the
callback path share the function that closes the waiter.
- A callback cannot be matched to its call. The waiter was registered after
sending, and the callback won the race.
- Every call is accepted and nothing ever answers. No callback URL is registered
against the facility id, which is a configuration cause for a runtime symptom.
## Nobody is standing there, so never block and never lose the state
### In plain words
M1's rules do not carry over to M2. There is no patient to spare a question, no
one time password to save, and no screen anybody is looking at. The patient has
left. What there is instead is a call that was accepted and then went quiet, and
a callback that may arrive tomorrow or never.
Two consequences follow, and they are the opposite of how an M1 journey is
built.
### What happens
**Never block.** Linking is several calls, each answered on a callback that may
be a minute away. A button that waits for the outcome is a button that hangs for
sixty seconds and then says nothing useful. Start the work, return at once, and
point at where it can be watched. The desk gets on with the next patient.
**State outlives the session.** Where a link has got to belongs on the record,
not in a page's memory. Reopening the application must show where everything
stands without re-running anything. This is the reverse of M1, where the whole
journey lives and dies inside one person's visit.
**Name the step, not the spinner.** Linking tells a receptionist nothing. These
do:
- Asking ABDM for a link token.
- Asking ABDM for a link token: ABDM accepted it and no answer came back. This
client has no callback URL registered, so the answer has nowhere to go.
- Asking ABDM for a link token: refused. `ABDM-9999`, user not found.
The second is the interesting one. It names a configuration cause for a runtime
symptom, which is the difference between a receptionist raising a ticket and an
integrator fixing one line of configuration.
### How you know it worked
Start a link and close the page. Reopen the application and the record shows
which step the link reached, and when, without any call being made again.
Press the button that starts linking. It returns immediately and points at where
progress can be watched. It does not sit waiting for a callback.
### When it goes wrong
- The interface hangs for sixty seconds and then reports nothing. Something is
waiting on the callback inside the request that started the work.
- Reopening the application shows a link as not started when it was started
yesterday. The state was held in the page rather than on the record.
- A receptionist raises a ticket for what turns out to be a missing callback
URL. The message named the symptom without naming the configuration cause.
## A refused request is still remembered, so a retry is a duplicate
### In plain words
ABDM records a link token request even when it refuses the patient, and
deduplicates the next identical request against the one it refused. So a retry
inside that window cannot succeed, and its refusal no longer names the original
cause.
The second message says duplicate, which reads as though the first attempt had
worked. It had not.
### What happens
The same request for the same unknown address, sent twice:
| When | Result |
|---|---|
| 14:17:42 | `400`, `ABDM-9999`, user not found |
| 14:18:51, 69 seconds later | `400`, `ABDM-1092`, duplicate link token request |
The length of the deduplication window is not published. It is at least sixty
nine seconds.
So do not offer a button that cannot work. Where a duplicate is the answer,
explain it, and say that the earlier refusal is the one that names the cause.
Point the reader back at the first exchange rather than at the second.
This is the reason the first refusal has to be kept rather than replaced. An
interface that overwrites the last error with the newest one destroys the only
message that explained anything.
### How you know it worked
Send a request that is refused, then send it again inside the window. The
interface shows `ABDM-1092`, does not present it as a new failure, and links
back to the first exchange and its `ABDM-9999`.
The retry control is absent or disabled while the window is open, rather than
present and failing.
### When it goes wrong
- A retry loop runs and every attempt after the first says duplicate. Nothing is
checking whether a retry can succeed.
- The cause of a failure cannot be found because the newest message replaced it.
Keep every exchange, and treat the first refusal as the authoritative one.
- A duplicate refusal is read as evidence that the first request succeeded.
It is not. The first was refused, and ABDM remembered the refusal.
## What the integrator needs on screen, separately from the patient
### In plain words
A desk that talks to ABDM asynchronously cannot be debugged without a view built
for the integrator rather than the receptionist. It is cheap to build and it is
the difference between a fix that takes a minute and one that takes a day.
### What happens
**A live view of every call and callback, grouped by request id**, so an
outbound call, its wait, and the callback answering it read as one exchange with
a timeline.
**Redact by name and length, never by value.** Show that an `Authorization`
header was sent and how long it was. Never its contents. The panel is a browser.
**Show what would be sent, before sending it.** A request preview or a bundle
inspector turns it failed at the far end into something checkable at the desk.
**A readiness check that names what is missing**, and this is where two
configuration failures have to be told apart:
| Missing | Effect | Treat as |
|---|---|---|
| Facility id | the call cannot be sent | blocker, refuse locally |
| Callback URL | the call sends and is accepted, and the answer has nowhere to go | warning, send anyway |
Treating both as blockers is the tempting mistake. Refusing to send when no
callback URL is registered hides exactly the behaviour the panel exists to make
visible. Send, accept, wait, time out, and say why.
Refuse the first locally and name the value. An invented facility id comes back
from ABDM as an entitlement error that reads like a credentials problem, and
sends the integrator to the console instead of to one line of configuration.
Presence is not validity. `X-HIU-ID` is checked for presence rather than
against any registry: absent is refused `401`, and an invented id is accepted
`202`. Anyone testing with a made up id sees acknowledgements that look like
progress, which is why the local check has to be the strict one.
### How you know it worked
Clear the facility id and press the button. The call is refused before anything
is sent, and the message names the configuration value that is absent.
Clear the callback URL and press the same button. The call is sent, accepted,
waits the window, and reports that nothing arrived and why.
Open the panel during a linking run. Each exchange is one row, headers are shown
by name and length, and no header value appears anywhere.
### When it goes wrong
- A token appears in the panel. Redaction is by value rather than by name and
length. This is a credential leak, not a display bug.
- An integrator is sent to the developer console by an entitlement error. The
facility id was not checked locally before the call went out.
- Calls are accepted and nothing ever answers, and the panel says only waiting.
Name the missing callback URL as the cause, rather than leaving the reader
with a timeout.
## Inbound is a surface, and silence there is a failure state
### In plain words
M2 and M3 are not only things your desk asks ABDM. ABDM asks your desk things
and waits: a discovery request, a link initiation, a link confirmation, a
request for the records a consent covers, and a consent notification.
Four of those five carry no documented payload in the published sources. A
handler written against an assumed shape fails on the first real delivery,
asynchronously, where nobody is watching. And a handler that only logs leaves a
patient's records undiscoverable while appearing to work.
### What happens
Answer the transport quickly and reason afterwards. ABDM is waiting on a `2xx`,
and a handler that thinks before it replies is a handler that times out.
Then give the interface a state for ABDM asked and this desk has not replied.
Not an empty list, and not silence. A named, visible condition, saying what a
correct reply would have been.
Where the payload is undocumented, record the entire body and the entire header
set on the first delivery of each path, before anything tries to read it.
Record header names and lengths, never values. The name is the finding. The
value is a credential.
Every inbound callback carries a bearer token in the `Authorization` header, as
`Bearer <token>`. Verify it before your handler does any work. See
[proving a callback came from ABDM](/docs/hiecm/v3/concepts/callback-authenticity).
The security rule underneath: a URL reachable by ABDM is reachable by everyone.
A presented signature that fails verification is refused everywhere. An absent
one may be tolerated on a sandbox, and where it is, the record has to be marked
as unverified rather than passed off as genuine.
### How you know it worked
Trigger a discovery against your bridge. The transport is acknowledged inside
the window, and the interface shows the delivery, the reply, and the time
between them.
Take a path you have never received before. The whole body and the whole header
name set are recorded before any code reads a field, so the shape can be learned
from the record rather than guessed.
Leave an inbound request unanswered on purpose. The interface names it as
unanswered rather than showing nothing.
### When it goes wrong
- A patient's records cannot be found from another facility, and nothing looks
broken. A discovery handler is logging and not replying.
- Deliveries time out under load. Work is being done before the acknowledgement
rather than after it.
- A handler throws on the first real delivery. It was written against an assumed
payload, and the body was never recorded whole.
## A care context and its records are one thing
### In plain words
A care context is the visit. The records are what happened at it. Neither is
useful alone.
A bundle nobody can name a care context for cannot be sent. A care context with
nothing behind it is a promise the next discovery cannot keep: another facility
finds the visit, asks for the records, and there are none.
So store them together and show them together.
### What happens
Show the counts that matter to a patient rather than the ones that are easy to
compute: visits opened, documents attached, and visits not yet findable
elsewhere. The third is the one worth surfacing, because it means a record
exists that no other facility can reach.
Validate before storing, not before sending. Refusing to store a bundle the
receiver could not read is cheap. Discovering it after a consent has been served
is not.
Let the desk inspect a bundle before it goes: the profile it claims, the
resources inside it, the attachment type, and whether every reference resolves
within the bundle. The upload itself wants a drop target, a title prefilled from
the filename but editable, and named refusals for type and for size. Show a hash
and a size so a file is identifiable in a list without keeping a second copy of
it.
Write the title for the patient. They read it in their own application months
later, not the receptionist filing it today.
Never log the attachment. It is a patient's record, and it belongs in the bundle
and in the encrypted payload built from it, nowhere else.
### How you know it worked
Open a visit and attach nothing. The interface counts it as a visit not yet
findable elsewhere, rather than as a completed link.
Attach a document and the same count falls by one.
Try to store a bundle whose references do not resolve inside it. Storing is
refused, and the refusal names the reference that pointed outward.
### When it goes wrong
- Another facility discovers a visit and receives nothing. A care context was
linked with no records behind it.
- A bundle is refused at the far end, asynchronously, with no explanation
reaching the desk. It was validated before sending rather than before storing.
- A list of visits becomes slow to open. Bundles are being held in the list
rather than stored separately and read when needed.
## Asynchronous calls and callbacks, why a 200 means very little
### In plain words
Nothing goes participant to participant. Every request is addressed to the gateway, which forwards it. Two things follow.
- **You get an acknowledgement, not an answer.** In the [M3](/docs/hiecm/v3/getting-started/glossary#m3) consent flow the [HIU](/docs/hiecm/v3/getting-started/glossary#hiu) asks, the HIE-CM returns the consent request id on a callback, and the patient's decision comes back later. Each call's page in the [API reference](/docs/hiecm/v3/api) names the callback it produces.
- **You have to be reachable.** Half of [M2](/docs/hiecm/v3/getting-started/glossary#m2) is endpoints the gateway calls on your system.
One exception. In the health information flow the HIU supplies a data push URL, and the HIP encrypts the records and pushes them there. That URL may differ from the HIU's registered gateway URL, to improve privacy. The permission came through the gateway. The bytes do not.
Match each callback to the call that caused it by `response.requestId`, which carries the `REQUEST-ID` you sent. Callbacks do not arrive in the order you sent the requests, and the same one can arrive twice, so a repeat must change nothing. Each callback is described in [the API reference](/docs/hiecm/v3/api).
### What happens
Send the call with a fresh `REQUEST-ID`, treat the 202 as receipt only, and wait for the callback. Key the handler on `response.requestId`, answer it quickly, and make a second delivery of the same request id a no-op.
### How you know it worked
A callback reaches your URL whose `response.requestId` equals the `REQUEST-ID` you sent. Given three calls and two callbacks, the call whose request id has no callback is the one outstanding.
### When it goes wrong
Nothing arrives: work through [the callback never arrives](/docs/hiecm/v3/troubleshooting/callback-never-arrives). A retry is appended as a new event: key on the request id. The code waits on the response body for the result: it never comes there, so the integration hangs.
## Proving a callback really came from ABDM
### In plain words
Every callback in the specifications declares bearer authentication. The token
arrives in the `Authorization` header as `Bearer <token>`. Check three things
before your handler does any work:
1. **A bearer token is present.** Reject a callback without one, and log the
rejection.
2. **An answer answers a call you made.** Its `response.requestId` matches the
`REQUEST-ID` of a request you sent. A callback that answers nothing you sent
is not yours to act on.
3. **It is for a facility you serve.** `X-HIP-ID` or `X-HIU-ID` names one of
your own facilities. This is the only check that covers a callback that
answers nothing, such as a discovery request, a link init or a consent
notification. A bridge can receive callbacks for services that are not
yours: on a shared sandbox bridge, another organisation's consent
notifications and link callbacks have arrived at an integrator's URL.
Storing one keeps another organisation's patient data, and answering one
acts on its behalf.
The keys that verify the token's signature are not among the published gateway
calls. Confirm at onboarding how to verify the token, and meanwhile hold the
three checks above.
The signature inside a consent artefact is a different thing. It signs the
artefact's contents and proves the artefact was not altered. Checking the
delivery does not check the artefact, and checking the artefact does not check
the delivery.
### How you know it worked
A callback carrying a bearer token and a request id you sent is processed. The
same body with the `Authorization` header removed is rejected before your
handler reads the payload, and the rejection is logged. The second is the test
worth writing, because it is the only one that fails loudly when the check is
silently skipped.
### When it goes wrong
**The check is skipped under load.** A handler that checks inside a try block
and continues on failure is worse than one that never checked, because it reads
as safe. Fail closed.
**Nothing arrives at all**, which is a different problem. See
[the callback never arrives](/docs/hiecm/v3/troubleshooting/callback-never-arrives).
### What happens
In the handler, before parsing the body for action: require the `Authorization` header with a bearer token; require that `X-HIP-ID` or `X-HIU-ID` names one of your facilities; and, on a callback that answers a call, require that `response.requestId` matches a `REQUEST-ID` your system sent and has not already handled. Reject otherwise. Do not invent a signature check against a key source the specifications do not publish.
### How you know it worked
A test posts a valid callback body without `Authorization` and sees it rejected and logged before any handler work.
### When it goes wrong
Never fall back to processing a callback that failed a check while you investigate. A callback whose request id is unknown to you, or whose facility header names a facility you do not serve, is logged and dropped, not stored, answered or retried.
## Care contexts, how records are grouped so they can be found
### In plain words
Each care context contains only two pieces of information:
- **Reference ID.** A unique internal identifier assigned by the
[HRP](/docs/hiecm/v3/getting-started/glossary#hrp) (HMIS/LMIS). Used to link
and retrieve the associated health records.
- **Display Name.** A user-friendly description to help identify the group of
records. Must not include any sensitive or confidential information such as
test results or diagnoses. Example: "OPD records (X-Ray, Prescription) from
3rd March 2023".
### Recommended approach for structuring care contexts
To ensure clarity and usability, it is recommended to organise patient data as
follows:
- Create one care context per outpatient visit (OPD)
- Create one care context per inpatient admission (IPD)
This approach provides a clear and event-based grouping of health records.
### JSON structure of care contexts
```json
{
"patient": {
"referenceNumber": "TMH-PUID-001",
"display": "TMH records for Kiran Kumar",
"careContexts": [
{
"referenceNumber": "2375639",
"display": "OPD records for 03 Oct 2022"
}
]
}
}
```
### What happens
Give each care context a `referenceNumber` your own system resolves to the records behind it, and a `display` a person recognises months later. Group by encounter: one per outpatient visit, one per inpatient admission, not one per test or document.
### How you know it worked
Three tests in one visit are one care context. A display name reads like "OPD records for 03 Oct 2022" and carries no diagnosis or result.
### When it goes wrong
A diagnosis or result in `display` leaks clinical information into a system built never to hold it, visible to anyone who can list the patient's care contexts. One care context per record produces a list no person can navigate.
## How a health record is encrypted between HIP and HIU
### In plain words
The scheme is [Elliptic Curve Diffie-Hellman](/docs/hiecm/v3/getting-started/glossary#ecdh) key exchange on Curve25519, with AES-GCM for the payload and HKDF to derive the session key. Only the HIU holding valid consent can read the data, and the design gives perfect forward secrecy: key material compromised later does not expose data exchanged earlier.
### Who holds which key
| Key material | Generated by | Where it goes |
| --- | --- | --- |
| Short term private key, DHSK(U) | HIU | Never leaves the HIU |
| Short term public key, DHPK(U) | HIU | Sent with the request |
| Nonce, RAND(U), 32 bytes | HIU | Sent with the request |
| Short term private key, DHSK(P) | HIP | Never leaves the HIP |
| Short term public key, DHPK(P) | HIP | Sent with the encrypted data |
| Nonce, RAND(P), 32 bytes | HIP | Sent with the encrypted data |
| Shared key, DHK(U,P) | Computed independently by both | Never transmitted |
| Session key, SK(U,P), 256 bit AES-GCM | Derived independently by both | Never transmitted |
| Long term private key | HIP | Never leaves the HIP. Signs the encrypted payload. |
A new key pair per exchange is what buys forward secrecy.
### What the HIP does, step by step
Six steps, once consent has validated.
1. Generate a key pair, DHSK(P) and DHPK(P), in the group the HIU specified.
2. Generate a 32 byte random value, RAND(P).
3. Compute the shared key DHK(U,P) from the HIU's public key DHPK(U) and the HIP's own private key DHSK(P).
4. Derive the salt and IV by XOR of RAND(P) and RAND(U). The first 20 bytes are the salt for HKDF, the last 12 bytes the IV.
5. Compute a 256 bit AES-GCM session key SK(U,P) with HKDF-SHA256, from the x coordinate of the shared key and that salt. The HKDF `info` is empty.
6. Encrypt the data with AES-256-GCM, that key and that IV, with no additional authenticated data. Append the 16 byte authentication tag to the ciphertext and base64 encode the result.
The HIP then sends DHPK(P), RAND(P) and the encrypted data. The HIU derives the same session key from its own private key DHSK(U) and the HIP's public key DHPK(P), with salt and IV from the same XOR.
Build the shared key from the HIU's public key and the HIP's private key. That is the pairing that makes the Diffie-Hellman exchange work.
### Do not write this yourself
Two reference implementations exist. Fidelius, at [github.com/sukreet/fidelius](https://github.com/sukreet/fidelius), and the Fidelius CLI, which is Java, with worked examples for Node.js, Python, Ruby and PHP at [github.com/mgrmtech/fidelius-cli](https://github.com/mgrmtech/fidelius-cli/tree/main/examples) that run the binary as a subprocess. A webinar covers the CLI from both sides, at [youtu.be/rSir2gbkEmk](https://youtu.be/rSir2gbkEmk?t=9232) from 2:33:52.
### What happens
Generate a fresh key pair and nonce per transfer. XOR the two nonces: the first 20 bytes are the HKDF salt, the last 12 the IV. Derive the key with HKDF-SHA256 over the x coordinate of the ECDH result, with an empty `info`, for 32 bytes. Encrypt with AES-256-GCM, no additional authenticated data, and append the 16 byte tag before base64 encoding.
### How you know it worked
The HIU decrypts every entry and its tag check passes. Before any peer is involved, round trip a record through the Fidelius CLI and compare bytes.
### When it goes wrong
Every tag check fails: compare the salt and IV split, the HKDF input (the x coordinate, not the whole shared secret) and an `info` or additional data that should be empty. One HIP fails while others work: compare how its public key is encoded.
## Reading an ABDM error code
### In plain words
ABDM returns [several different error shapes](/docs/hiecm/v3/api/m1/errors), and
only some of them carry a code. Parse for all of them before you write any handling,
because the shape tells you where the failure came from.
Every code in the [error code reference](/docs/hiecm/v3/reference/error-codes)
carries an action. Key your handling to that column rather than to a list of
codes you maintain by hand.
| Action | What your code does |
| --- | --- |
| Fix request | Do not retry. Something you sent is wrong, and sending it again will not help |
| Fix auth | Fetch a fresh token, then retry once |
| New request id | Generate a new `REQUEST-ID`, then retry once |
| Retry | Back off and retry, with a ceiling on attempts |
| Cannot proceed | Stop, and tell the person why in their own terms |
| Ask support | Stop, and collect the ids before the context is lost |
| Unclassified | Treat as Cannot proceed until you have seen it once and know better |
Symptom first debugging, for the failures that produce no useful code at all, is
in [troubleshooting](/docs/hiecm/v3/troubleshooting).
Read the code in the body before the HTTP status. A 404 can carry `ABDM-1016`,
Invalid Timestamp: the route exists and the request was refused. A 404 whose
body carries `Status report` and no code means no route matched the request. A
code can arrive bare or with a trailing colon and space, as in `ABDM-1016: `, so
match on the code itself.
### What happens
Parse the body for an error code before acting on the status. Strip a trailing colon and space from the code, then key the handling on the action column of the [error code reference](/docs/hiecm/v3/reference/error-codes), not on a list maintained by hand.
### How you know it worked
Given a code, you can say what it means and which header or field it concerns: `ABDM-2403` is Invalid X-CM-ID, the consent manager header.
### When it goes wrong
A one line message is read as a diagnosis: Invalid header covers many causes. A code that is not in the reference is handled as Unclassified, not guessed at. A 404 is treated as a wrong path when its body carries a code.
## Roles, which entity your software acts for and which way the record moves
### In plain words
There are two integrator roles on HIE-CM, and your product is one of them for its
whole life. What decides it is which entity your software acts for.
| Role | It acts for | What you build |
| --- | --- | --- |
| [IMS](/docs/hiecm/v3/getting-started/glossary#ims) | A care provider. An HMIS in a hospital, an EMR in a clinic, a LIMS in a laboratory, a PMS in a pharmacy | [M1](/docs/hiecm/v3/milestones/m1) to [M4](/docs/hiecm/v3/milestones/m4) |
| [PHR](/docs/hiecm/v3/getting-started/glossary#phr) | A care seeker, who holds their own records and gives consent | [P1](/docs/hiecm/v3/milestones/p1) to [P3](/docs/hiecm/v3/milestones/p3) |
[HIP](/docs/hiecm/v3/getting-started/glossary#hip) and
[HIU](/docs/hiecm/v3/getting-started/glossary#hiu) are not a third and a fourth
role, and they are not something you register as. They are the two ends of one
record moving: whoever publishes it is the HIP for that exchange, and whoever
asks to read one they did not create is the HIU.
Both roles are both, and it changes call by call:
- A hospital is the HIP when it shares a discharge summary, and the HIU when it pulls an earlier prescription, through the same IMS.
- A citizen is the HIP when they push a record from their PHR application, and the HIU when they fetch one.
Neither is a thing you can build once and be. See
[HIP and HIU](/docs/hiecm/v3/concepts/hip-hiu).
So the milestones you build follow the direction your records move, not the kind
of product you sell. A PHR app that lets a citizen push a record publishes as
the HIP, and builds the M2 linking and transfer calls as well. See
[where the citizen is the HIP](/docs/hiecm/v3/milestones/p2#where-the-citizen-is-the-hip).
Records never pass through the consent manager: it routes the request and holds
the consent, and the record goes from the system that holds it to the system
that asked.
### What happens
Decide the role once, IMS or PHR, from the entity. Then list every direction a record moves through the product: publishing a record is HIP behaviour, fetching one it did not create is HIU behaviour. Build the milestones for each direction the product uses.
### How you know it worked
For a hospital system that also pulls a patient's history, you can name the role, IMS, both directions, and the milestones: M1, M2 and M3. For a PHR app that uploads a scanned prescription, you can say the citizen is the HIP for that record.
### When it goes wrong
HIP, HIU, health repository and health locker are chosen as though they were one list of company types: two are directions, one is custody, one is a product. A PHR app is built for P1 alone and then cannot publish the first record a citizen pushes. A fetch is designed against the consent manager, which holds no records.
## Where these came from
- `hiecm.concept.m2-exchange-not-call`
- `hiecm.concept.m2-never-block-the-desk`
- `hiecm.concept.m2-retry-is-a-duplicate`
- `hiecm.concept.m2-integrator-call-panel`
- `hiecm.concept.m2-inbound-is-a-surface`
- `hiecm.concept.m2-care-context-and-records`
- `hiecm.concept.asynchronous-callbacks`
- `hiecm.concept.callback-authenticity`
- `hiecm.concept.care-context`
- `hiecm.concept.data-flow-encryption`
- `hiecm.concept.error-codes`
- `hiecm.concept.roles`

View File

@ -0,0 +1,70 @@
# Integrate M2, create and link records
The calls themselves: where they live, what they need in their headers, and one request written out in full.
## Hosts
- `https://dev.abdm.gov.in` ABDM gateway, sandbox
- `https://apis.abdm.gov.in` ABDM gateway, production
## Endpoints
24 operations, grouped by the journey they belong to.
### Other operations
| Method | Path | What it does |
| --- | --- | --- |
| `POST` | `/api/hiecm/consent/v3/request/hip/on-notify` | Acknowledge the notification sent when a consent request is approved/revoked/ex… |
| `POST` | `/api/hiecm/data-flow/v3/health-information/hip/on-request` | Health information data request acknowledgement from HIP. |
| `POST` | `/api/hiecm/data-flow/v3/health-information/notify` | Notifications corresponding to events during data flow |
| `GET` | `/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id}` | Fetch the details of a service ID. |
| `GET` | `/api/hiecm/gateway/v3/bridge-services` | Fetch the service ids registered against a bridge. |
| `PATCH` | `/api/hiecm/gateway/v3/bridge/url` | Update the bridge URL. |
| `POST` | `/api/hiecm/gateway/v3/sessions` | Generate access token. |
| `POST` | `/api/hiecm/hip/v3/link/carecontext` | Perform HIP initiated linking. |
| `POST` | `/api/hiecm/hip/v3/link/context/notify` | Notify CM about any update on the already linked care context for a patient. |
| `POST` | `/api/hiecm/hip/v3/link/patient/links/sms/notify2` | Send SMS notification to patient that a care context is linked. |
| `POST` | `/api/hiecm/user-initiated-linking/v3/link/care-context/on-confirm` | Sharing the response of /api/hiecm/user-initiated-linking/v3/link/care-context/… |
| `POST` | `/api/hiecm/user-initiated-linking/v3/link/care-context/on-init` | As a result of the initialization, HIP has to generate a unique reference-numbe… |
| `POST` | `/api/hiecm/user-initiated-linking/v3/patient/care-context/on-discover` | HMIS/LIMS/HIP has to ensure that only unlinked records of the patient has to be… |
| `POST` | `/api/hiecm/v3/token/generate-token` | Generate link token to link the health records |
| `POST` | `/api/v3/consent/request/hip/notify` | This is a callback API to notify HIP when consent is APPROVED or REVOKED. |
| `POST` | `/api/v3/hip/health-information/request` | Health information data request to HIP. |
| `POST` | `/api/v3/hip/link/care-context/confirm` | Confirm the linking of care contexts for a patient. It allows healthcare inform… |
| `POST` | `/api/v3/hip/link/care-context/init` | Initiate the linking of care contexts for a patient. It allows healthcare infor… |
| `POST` | `/api/v3/hip/patient/care-context/discover` | Discover care contexts associated with a patient. It allows healthcare informat… |
| `POST` | `/api/v3/hip/token/on-generate-token` | This is a call back API of [/api/hiecm/v3/token/generate-token]. |
| `POST` | `/api/v3/link/on_carecontext` | Is a callback API that will be called by HIE-CM. The response will be received … |
| `POST` | `/api/v3/links/context/on-notify` | This API endpoint is a call back API for /api/hiecm/hip/v3/link/context/notify … |
| `POST` | `/api/v3/patients/sms/on-notify` | This API endpoint is a call back API for /api/hiecm/hip/v3/link/patient/links/s… |
| `POST` | `/health-information/transfer` | health information transfer API |
## Headers
| Header | What it is |
| --- | --- |
| `REQUEST-ID` | Unique UUID for track the end to end request transaction |
| `TIMESTAMP` | Actual time of the request was initiated, ISO 8601 represents date and time by starting with the year, follow… |
| `X-CM-ID` | Suffix of the consent manager to which the request was intended |
| `X-HIP-ID` | Identifier of the health information provider to which the request was intended |
| `X-LINK-TOKEN` | JWT Authentication token which was issued by ABDM after successful validation of username and password |
| `X-HIU-ID` | Identifier of the health information user to which the request was intended |
## A request, in full
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/consent/v3/request/hip/on-notify \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"acknowledgement": {
"status": "OK",
"consentId": "e3c74829-3f82-4f94-959e-e10f57bcd57b"
},
"response": {
"requestId": "6f0b4665-a915-4c92-aa36-65afb4a2cd71"
}
}'
```

View File

@ -0,0 +1,562 @@
# HIE-CM m2 build
Scaffolds an ABDM m2 integration one journey at a time. It covers care contexts, HIP initiated linking, discovery, and pushing encrypted records to a requester.
## How this skill runs
Every journey below is an OODA loop, not a recipe: observe the actual state (last response, last error), orient against the step matched below, decide the cheapest next action, act, and return to observe. A step is done only when its exit condition is observed against the sandbox, never because it "should have worked."
Loop limit: 8 passes per step. Hitting the limit is an escalation: state what was observed, what was tried, and which operation page to read, then ask one question.
## Before the first journey, when the codebase already exists
Skip this section only for a system that does not exist yet. Otherwise it runs first, and its exit condition is a written plan, not a call.
### In plain words
Most ABDM integrations are not new systems. They are a hospital management
system, a laboratory system or a clinic application that already has patients,
visits, records, a login, an HTTP client and a way of keeping secrets. Every
ABDM journey has to land somewhere inside that, and a journey built before the
codebase has been read lands in the wrong place: a second HTTP client beside the
first, an ABHA column on the wrong table, a callback route the reverse proxy
never forwards.
So the first loop is not a journey. It is a survey of the system as it is, and
its exit condition is a written plan that names, for every ABDM touchpoint, the
file it will live in. The journeys then build against that plan rather than
against the specification's idea of a fresh codebase.
### Before you start
- The repository, checked out, with permission to read all of it. A survey of
half a codebase produces a plan for half a system.
- The answers to the deployment interview. The
code says what the system is. Only the integrator can say what the
deployment is, and the two together decide which journeys are built at all.
- The practices that hold across every call, which
the plan has to leave room for.
### What happens
This is one loop with a limit of eight passes over the codebase. Each pass
reads live state only, which here means the files themselves, never a README's
description of them and never an assumption carried from a similar system.
**Observe.** Inventory the system from its manifests and its tree, not from its
documentation. Record file paths for each of these, or record that none exists:
| Find | Where it usually shows | Why ABDM needs it |
|---|---|---|
| Languages and runtime versions | package manifests, lock files, toolchain files | Every generated call has to be idiomatic here |
| Build, run and test commands | manifests, CI configuration, a Makefile | Each journey's exit condition becomes a test that runs the same way |
| The frontend and backend split, and how they talk | the top level tree, an API client in the frontend, route definitions in the backend | The counter screens go in the frontend; every ABDM call goes through the backend |
| The outbound HTTP client the backend already uses | the dependency list, a shared client module | ABDM calls reuse it, or a second one appears and the two drift |
| How secrets and configuration reach the process | environment loading, a vault client, a config file | The client id, the secret and the access token travel the same way |
| The patient model, and the identifier fields it already carries | the schema, the ORM models, the migrations | The ABHA number and address become columns beside the existing identifiers, not a new table |
| The visit, encounter or record model | the same places | A care context maps to one of these, and the plan has to say which |
| Where inbound HTTP is routed and authenticated, and whether the deployment has a public URL | the router, the middleware, the reverse proxy configuration, the deployment manifests | ABDM calls back, and a callback route that nothing forwards is silence nobody notices |
| Existing cryptography helpers | a security or crypto module, the dependency list | The RSA encryption of identifiers reuses them |
| Where errors are shown to a user, and where they are logged | the frontend's error surface, the logging setup | A refused call has to land on the screen the person is looking at, and never log a token |
**Orient.** Map each ABDM touchpoint onto that inventory. Where the map is
exact, write the file path. Where it is not, write two candidates and say what
would decide between them. The common ambiguities: two places that could hold
the patient identifier, an HTTP client in the frontend and none in the backend,
a monorepo with several services and no obvious owner for callbacks.
Then read the interview answers against the inventory. A government integrator
gets the demographic route; a facility with no public URL gets no callback
driven journey until it has one; a desk with a fingerprint reader gets the
biometric method. The route set is the intersection of what the deployment
allows and what the code can host.
**Decide.** Order the journeys. The token comes first because every other call
needs it: the gateway session token, or for M4 the bearer token the registry calls
carry. Then the journey whose exit condition can be observed with
the least new code, usually a profile read for a patient who already holds an
ABHA. Creation and linking come after, because each depends on state the earlier
ones produce. For each journey, name the files it will touch and the test that
proves its exit condition.
**Act.** Write the plan. It is a file in the repository, at the path the
integrator names or at the root as `abdm-integration-plan.md`, and it is the
only output of this loop. Then return to observe once, reading the plan against
the tree, to confirm every path in it exists or is marked as new.
If the limit is reached with questions still open, escalate: name what was
found, name the two candidates that could not be separated, point at this
atom, and ask one question.
### How you know it worked
The plan exists and answers every row of the inventory table with a file path,
or with the words none, add at, followed by a path. No row is blank and no row
says to be decided.
Every ABDM touchpoint in the plan names one file, or names two candidates and
the observation that would choose between them. Every journey in the plan names
the test that proves its exit condition and the command that runs it.
Open the plan beside the tree. Every path it names resolves, or is marked as
new. That is the observation that ends this loop, and the first journey does
not start until it has been made.
### When it goes wrong
- **The plan puts the HTTP client in the frontend.** The survey found the
frontend's API client and stopped. Every ABDM call carries a secret, so it
goes through the backend, and the plan has to say which backend module.
- **Two patient tables, and the plan picked one.** Orient produced one
hypothesis where it needed two. Name both, and name the query that shows
which one the visit model points at.
- **The plan has a callback route and the deployment has no public URL.** The
inventory row on inbound routing was answered from the router rather than
from the deployment. Mark every callback driven journey as blocked on a URL,
and build the ones that are not.
- **The survey read the README and not the tree.** A README describes the
system somebody meant to build. The plan is for the one that exists.
- **Eight passes and the plan is still incomplete.** Escalate with the rows
that are answered, the rows that are not, this atom, and one question about
the row that blocks the most journeys.
From `shared.concept.survey-an-existing-codebase`.
## Journeys
### Link token (`m2-abdm-link-token-hip`)
**Act: the calls in this journey, in order**
#### 1. Generate link token to link the health records (`m2_post_v3_token_generate_token`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/v3/token/generate-token \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-HIP-ID: IN2810014366' \
--header 'Content-Type: application/json' \
--data '{
"abhaNumber": 12345678901234,
"abhaAddress": "<ABHA_ADDRESS>",
"name": "first_name + middle_name + last_name",
"gender": "M",
"yearOfBirth": 9999
}'
```
**Exit condition (Observe until this is true)**
Each call you made in this journey answered by its callback, with `response.requestId` equal to the `REQUEST-ID` you sent on that call. The 202 on a call is receipt, not the outcome: the outcome is in the callback's body.
- `POST /api/hiecm/v3/token/generate-token` is answered by `POST /api/v3/hip/token/on-generate-token` on your bridge.
### HIP initiated linking (`m2-abdm-hip-initiated-linking-hip`)
**Act: the calls in this journey, in order**
#### 1. Perform HIP initiated linking (`m2_post_hip_v3_link_carecontext`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/hip/v3/link/carecontext \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-HIP-ID: IN2810014366' \
--header 'X-LINK-TOKEN: <TOKEN>' \
--header 'Content-Type: application/json' \
--data '{
"abhaNumber": 12345678901234,
"abhaAddress": "<ABHA_ADDRESS>",
"patient": [
{
"referenceNumber": "TMH-PUID-001",
"display": "String",
"careContexts": [
{
"referenceNumber": "TMH-PUID-001",
"display": "display 1"
}
],
"hiType": "DiagnosticReport",
"count": 1
}
]
}'
```
#### 2. Notify a change to a linked care context (`m2_post_hip_v3_link_context_notify`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/hip/v3/link/context/notify \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-HIP-ID: IN2810014366' \
--header 'Content-Type: application/json' \
--data '{
"notification": {
"patient": {
"id": "<ABHA_ADDRESS>"
},
"careContext": {
"patientReference": "<ABHA_ADDRESS>",
"careContextReference": "b009a970-8b04-4779-abd1-b50f113245bf"
},
"hiTypes": [
"DiagnosticReport"
],
"date": "2024-05-09T10:34:00.387Z",
"hip": {
"id": "ABDM_HIP"
}
}
}'
```
#### 3. Send SMS notification to patient that a care context is linked (`m2_post_hip_v3_link_patient_links_sms_notify2`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/hip/v3/link/patient/links/sms/notify2 \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"notification": {
"phoneNo": "986543***",
"hip": {
"id": "ABDM_HIP",
"name": "ABC Hospital"
}
}
}'
```
**Exit condition (Observe until this is true)**
Each call you made in this journey answered by its callback, with `response.requestId` equal to the `REQUEST-ID` you sent on that call. The 202 on a call is receipt, not the outcome: the outcome is in the callback's body.
- `POST /api/hiecm/hip/v3/link/carecontext` is answered by `POST /api/v3/link/on_carecontext` on your bridge.
- `POST /api/hiecm/hip/v3/link/context/notify` is answered by `POST /api/v3/links/context/on-notify` on your bridge.
- `POST /api/hiecm/hip/v3/link/patient/links/sms/notify2` is answered by `POST /api/v3/patients/sms/on-notify` on your bridge.
### User initiated linking (`m2-abdm-user-initiated-linking-hip`)
**Act: the calls in this journey, in order**
#### 1. Answer the care context discovery (`m2_post_user_initiated_linking_v3_patient_care_context_on_8c9340`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/user-initiated-linking/v3/patient/care-context/on-discover \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-HIU-ID: IN2810014366' \
--header 'Content-Type: application/json' \
--data '{
"transactionId": "f901b782-bfdf-4224-9f8d-da2cadc20c0d",
"patient": [
{
"referenceNumber": "<ABHA_ADDRESS>",
"display": "12345",
"careContexts": [
{
"referenceNumber": "abc123",
"display": "12345"
}
],
"hiType": "Prescription",
"count": 1
}
],
"matchedBy": [
"MR"
],
"response": {
"requestId": "f29f0e59-8388-4698-9fe6-05db67aeac46"
}
}'
```
#### 2. Link care context on init (`m2_post_user_initiated_linking_v3_link_care_context_on_init`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/user-initiated-linking/v3/link/care-context/on-init \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"transactionId": "f901b782-bfdf-4224-9f8d-da2cadc20c0d",
"link": {
"referenceNumber": "d353b782-bfdf-4224-9f8d-da2cadc20c0d",
"authenticationType": "DIRECT",
"meta": {
"communicationMedium": "MOBILE",
"communicationHint": "OTP",
"communicationExpiry": "2024-05-01T05:22:34.123Z"
}
},
"response": {
"requestId": "f29f0e59-8388-4698-9fe6-05db67aeac46"
}
}'
```
#### 3. Link care context on confirm (`m2_post_user_initiated_linking_v3_link_care_context_on_confirm`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/user-initiated-linking/v3/link/care-context/on-confirm \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"patient": [
{
"referenceNumber": "<ABHA_ADDRESS>",
"display": "12345",
"careContexts": [
{
"referenceNumber": "abc123",
"display": "12345"
}
],
"hiType": "Prescription",
"count": 1
}
],
"response": {
"requestId": "f29f0e59-8388-4698-9fe6-05db67aeac46"
}
}'
```
**Exit condition (Observe until this is true)**
A 202 on this reply, sent with `response.requestId` set to the `REQUEST-ID` of the `POST /api/v3/hip/link/care-context/confirm` request it answers. A reply without that id answers nothing.
### Consent and data flow (`m2-consent-management-data-flow-hip`)
**Act: the calls in this journey, in order**
#### 1. Acknowledge the consent notification (`m2_post_consent_v3_request_hip_on_notify`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/consent/v3/request/hip/on-notify \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"acknowledgement": {
"status": "OK",
"consentId": "e3c74829-3f82-4f94-959e-e10f57bcd57b"
},
"response": {
"requestId": "6f0b4665-a915-4c92-aa36-65afb4a2cd71"
}
}'
```
#### 2. Submit the health information data request acknowledgement from HIP (`m2_post_data_flow_v3_health_information_hip_on_request`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/data-flow/v3/health-information/hip/on-request \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"hiRequest": {
"transactionId": "18235d89-cb13-479d-ad71-7a57d5f669a8",
"sessionStatus": "ACKNOWLEDGED"
},
"response": {
"requestId": "6f0b4665-a915-4c92-aa36-65afb4a2cd71"
}
}'
```
#### 3. Submit the notifications corresponding to events during data flow (`m2_post_data_flow_v3_health_information_notify`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/data-flow/v3/health-information/notify \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"notification": {
"consentId": "18235d89-cb13-479d-ad71-7a57d5f669a8",
"transactionId": "18235d89-cb13-479d-ad71-7a57d5f669a8",
"doneAt": "2023-01-24T06:35:44.167Z",
"notifier": {
"type": "HIP",
"id": "IN2810014366"
},
"statusNotification": {
"sessionStatus": "TRANSFERRED",
"hipId": "IN2810014366",
"statusResponses": [
{
"careContextReference": "10004-20200001768-1",
"hiStatus": "DELIVERED",
"description": "Data sent successfully"
}
]
}
}
}'
```
**Exit condition (Observe until this is true)**
A 202 response. The specification gives no body for it, so read what comes back.
### Callbacks (`m2-callbacks`)
**Act: the calls in this journey, in order**
#### 1. Receive the HIP token on generate token (`m2_post_v3_hip_token_on_generate_token`)
Inbound to your bridge at `/api/v3/hip/token/on-generate-token`. Acknowledge it and continue.
#### 2. Link on carecontext (`m2_post_v3_link_on_carecontext`)
Inbound to your bridge at `/api/v3/link/on_carecontext`. Acknowledge it and continue.
#### 3. Receive the links context on notify (`m2_post_v3_links_context_on_notify`)
Inbound to your bridge at `/api/v3/links/context/on-notify`. Acknowledge it and continue.
#### 4. Receive the patients SMS on notify (`m2_post_v3_patients_sms_on_notify`)
Inbound to your bridge at `/api/v3/patients/sms/on-notify`. Acknowledge it and continue.
#### 5. Discover care contexts associated with a patient (`m2_post_v3_hip_patient_care_context_discover`)
Inbound to your bridge at `/api/v3/hip/patient/care-context/discover`. Acknowledge it and continue.
#### 6. Initiate the linking of care contexts for a patient (`m2_post_v3_hip_link_care_context_init`)
Inbound to your bridge at `/api/v3/hip/link/care-context/init`. Acknowledge it and continue.
#### 7. Confirm the linking of care contexts for a patient (`m2_post_v3_hip_link_care_context_confirm`)
Inbound to your bridge at `/api/v3/hip/link/care-context/confirm`. Acknowledge it and continue.
#### 8. Receive the consent decision (`m2_post_v3_consent_request_hip_notify`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/v3/consent/request/hip/notify \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-HIP-ID: IN2810014366' \
--header 'Content-Type: application/json' \
--data '{
"notification": {
"status": "GRANTED",
"consentId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"consentDetail": {
"schemaVersion": "v3",
"consentId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"createdAt": "2024-05-01T05:10:20.123Z",
"patient": {
"id": "<ABHA_ADDRESS>"
},
"careContexts": [
{
"patientReference": "batman@tmh",
"careContextReference": "Episode1"
}
],
"purpose": {
"text": "Care Management",
"code": "CAREMGT",
"refUri": "www.abc.com"
},
"hip": {
"id": "cowin_hip_01",
"name": "Cowin",
"type": "HIP"
},
"hiu": {
"id": "cowin_hiu_01",
"name": "Cowin",
"type": "HIU"
},
"consentManager": {
"id": "abdm"
},
"requester": {
"name": "<ABHA_ADDRESS>",
"identifier": {
"value": "REG1",
"type": "MH1001",
"system": "https://www.sample.com"
}
},
"hiTypes": [
"Prescription"
],
"permission": {
"accessMode": "VIEW",
"dateRange": {
"from": "2021-09-28T12:30:08.573Z",
"to": "2021-09-28T12:30:08.573Z"
},
"dataEraseAt": "2021-09-28T12:30:08.573Z",
"frequency": {
"unit": "HOUR",
"value": 1,
"repeats": 0
}
}
},
"signature": "e8nY601CYDsC0FKoDjSp+7GeQ2s2R8oZncLCz5ce+pEuDOr5bZV0aaHjwJg4b9S9V+twjt4hbojx3fl7egrt8+0c+lfPTi5/bBUAQXCABTfFmtFU7jn65HlTt8kgkiONx26ZBhJ0wX3xjYI72PPtzYIiT5Q08YtDoILA62KceioV7lwuKssw7wC4ECbBAvRuXT121TmtrPhf+0myJATSnaajS06S6OthrKfZLNTUFf3pFiJzqouSTrjNblOX6DT2+JuO3rom1Szz/03c0HQG+wWASv+PO3J6uRs0UI4JvKmM/4tP+Z+/HPKM15K5U5K+4pqf6czKrbIDpkT/kP8bGg==",
"grantAcknowledgement": false
}
}'
```
#### 9. Receive the health information data request to HIP (`m2_post_v3_hip_health_information_request`)
Inbound to your bridge at `/api/v3/hip/health-information/request`. Acknowledge it and continue.
#### 10. Push the encrypted records to the HIU's data push URL (`m2_post_health_information_transfer`)
Outbound from your bridge. POST each page of encrypted records to the `dataPushUrl` in the health information request of step 9. The call goes straight to the HIU, not through the gateway. The HIU answers 202 for each page.
**Exit condition (Observe until this is true)**
A 202 response. The specification gives no body for it, so read what comes back.
## Where the detail is
- Every operation, with its body fields and responses: /docs/hiecm/v3/api/m2
- Error codes: /docs/hiecm/v3/api/m2/errors

View File

@ -0,0 +1,91 @@
---
name: abdm-m3
description: Use when building, debugging or testing ABDM Milestone 3: raising a consent request, tracking its status, reading consent artefacts, and fetching encrypted health records as an HIU. Carries the endpoints and the consent rules. Also carries the scaffolding loop that builds it flow by flow and the loop from a failed call to a named fix, in references/.
type: skill
domain: m3
agent_consumers:
- abdm-integration-agent
- abdm-call-debugger
requires:
- gateway-session-token
- hiu-registration
- callback-url
- abha-address
produces:
- consent-request-id
- consent-artefact
can_execute: true
can_orchestrate: false
---
# ABDM M3, fetch data with consent
Generated from the ABDM Developer Portal on 2026-09-16, catalogue version 2026.09.16. Every fact below comes from a page in that portal, which is the place to look when this file does not carry enough.
This file is a snapshot. Re-download the whole folder from https://docs.abdm.gov.in/skills/abdm-m3/ when it is older than the work you are doing: this router and every file under references/ that it links to. Fetching this file alone leaves those links pointing at files you do not have.
If the abdm-docs MCP server is connected, trust its answers over this file: it serves the current catalogue and stamps every response with its catalogue_version, which you can compare against the version above.
## What you can do with M3
- Ask a patient, through their consent manager, for records another provider holds.
- Track that request through a grant, a denial, a revocation and an expiry.
- Receive the encrypted records at your data push URL and decrypt them.
- Handle one request that produces several consent artefacts.
What it cannot do yet matters as much. Read **Before anything else** below before assuming a capability is one endpoint away.
## Try asking
- "Raise a consent request and fetch the records it covers"
- "What has to be in place before my first M3 call?"
- "My M3 call failed. Here is the response: what is wrong, and how do I fix it?"
Loaded with no task? Say in three lines what this skill does. Offer the prompts above. Then ask what the person is building, and whether the code for it exists yet.
## What is in this folder
- **Scaffold.** Survey the codebase first when one exists, then build it flow by flow against the sandbox, as a loop that ends when the step's exit condition holds rather than on a call returning 200. [references/scaffold.md](references/scaffold.md)
- **Design.** What the journey around the calls has to do, and what a screen is forbidden to claim. [references/design.md](references/design.md)
- **Integrate.** 16 operations, with their hosts and headers. [references/integrate.md](references/integrate.md)
- **Debug.** The specification's examples return no error code for this module. [references/debug.md](references/debug.md)
This file is the map. Each line above is a file beside it, opened one at a time rather than read through.
## Before anything else
- Treat every request and response shape in this skill as unconfirmed until the sandbox has answered you. Check a response before you rely on its shape.
- The design section is different in kind. Its rules come from building a working front desk against the sandbox, and each atom it cites names what was observed and the date it was seen.
- One consent request produces one artefact per HIP, so store the request id and every artefact id. Taking the first element is the bug that silently drops half a fetch.
- You act as the HIU. The HIE-CM holds the consent and asks the patient on your behalf. No artefact, no records.
- The patient must be known to you by ABHA address before you can raise a request.
- Records arrive encrypted at the `dataPushUrl` the health information request names. Decrypt them with the key material that request carries.
## Practices that hold across every call
- Read the body, not only the status. A refusal often names the field in its body while the status says nothing useful.
- When ABDM publishes a value, read it rather than hard coding what it currently says. That covers a parameter, such as the encryption algorithm the certificate endpoints return beside the key, and it covers an enumeration. The registries publish theirs as master data calls: councils, courses, colleges, states and districts on the HPR, and facility types and LGD codes on the HFR. A table typed into your source goes stale silently. Purposes and HI types have no master data call: take them from the enumeration in the specification of the call you are making. Refuse to act on a published value you do not recognise rather than falling back to a default.
- Read every field in a response, not the one you came for. The M1 certificate call returns the encryption algorithm next to the key.
- Prove an assumption against a call that is able to disagree with you. A call that refuses every input with one message cannot tell you which input was right.
- Suspect the transport before the data. When a call refuses a value you believe in, check the encryption, the headers and the clock before you doubt the value.
- Do not carry an encryption path from one module to another. Read the certificate and the algorithm from the registry you are calling.
- Never log a sensitive value before you encrypt it, and never send one to a remote service to be encrypted. Both move the leak rather than removing it.
- Generate a fresh REQUEST-ID for every call and log it before sending. Once a call has failed it is the only handle on it.
- Check the host on any sample before you copy it. A request copied whole can be correct in every respect except where it is pointed, and that failure looks like credentials.
- Do not validate an identifier more strictly than the platform does. A schema that types a field as a UUID is not a promise that every value is one. Refusing a value ABDM would have accepted turns your own client into the thing that broke.
- Read a plural response as plural. A verification returns an accounts array and a consent request can produce more than one artefact. Store the collection and decide from its length.
- A documented callback path is not a documented callback payload. Log the whole body on arrival before you parse it, so a handler written against an assumed shape fails where you can see it.
- Decode a token before you use it. A call that hands you a token has not necessarily handed you the token the next call wants, and the claims are base64 that need no library to read.
- When a journey carries the same parameter through two calls, check what each call's specification asks for rather than carrying the first value forward.
- Do not infer which path an identifier belongs to from where that identifier is most discussed. Send every identifier to the lookup first and let the answer pick the path, so nobody who already holds an account is sent to create a second.
- Do not match an error code with string equality. A code may come back bare, as `ABDM-1001`, or with a trailing `: ` separator, as `ABDM-1001: `. Match on the code itself and tolerate the separator.
- Handle a failure that carries no body. Check for an empty body before you parse, or your client throws on the simplest failure there is.
- Back off on an authentication failure rather than retrying, and never loop a credential check.
- Send TIMESTAMP in UTC, ISO-8601 with milliseconds and a trailing Z, as in `2022-10-06T15:10:00.587Z`.
- Cache a public certificate with a validity window rather than forever. A rotation fails every encrypted call at once, and a cache with no expiry cannot recover on its own.
## Where the detail is
- Every endpoint, with its body fields and responses: /docs/hiecm/v3/api/m3
- The flows as diagrams: /docs/hiecm/v3/milestones/m3
- Every error code across modules: /docs/hiecm/v3/reference/error-codes
- Terms: /docs/hiecm/v3/getting-started/glossary

View File

@ -0,0 +1,9 @@
# Debug M3, fetch data with consent
The codes this module can return, with the message and the operation that returns each.
## Errors
The M3, fetch data with consent specification's examples return no error code yet. That is a gap in the specification, not a promise that this module cannot fail.
A code you meet that is not above is one the specifications do not carry yet. Read the code together with the message: a code can appear twice with different meanings.

View File

@ -0,0 +1,156 @@
# Design M3, fetch data with consent
What the integration has to do to the journey around the calls: how many questions a patient is asked, where a failure is shown, and what a screen is forbidden to claim. Every rule below comes from a Catalogue atom, cited at the end.
## Read plural as plural, and never translate a code into a meaning
### In plain words
Two habits cause most of the avoidable failures on the consent side, and both
are about reading what came back rather than what you expected.
A consent request produces one artefact per HIP, so a request that spans
facilities returns several. Taking the first element is
the bug that silently drops half a fetch.
And the same error code means different things in different modules, so a code
alone is not a meaning.
### What happens
Hold the collection. A length of one is a case, not the normal case. It is worth
having a function whose existence prevents any call site from reaching for the
first element, because the failure is silent: half the records simply never
arrive, and nothing reports an error.
Carry ABDM's message through to the screen and never translate a code into words
of your own. `ABDM-1112` is an unusable consent in one place and a DigiLocker
gender mismatch in a module error table. `ABDM-1062` is a withheld consent in
one and a link token mismatch in another. Whichever you choose to display, you
will be wrong for the other module, and the message ABDM sent is the only part
that names the actual cause.
Handle two answers from consent status and consent fetch. The specification
documents them as synchronous responses carrying a status and an artefact
array. One run against ids that did not exist returned `202` with an empty
body instead. That single observation is not a rule: check the status before
you read the body, treat a `200` as the documented answer, treat a `202` with
no body as an acknowledgement whose answer arrives on the callback, and confirm
which you get on your own data before building on either.
### How you know it worked
Raise a consent covering care contexts at two HIPs. The number of artefacts you
hold matches the number ABDM returned, and a fetch runs for each one.
Trigger a refusal. The screen shows ABDM's own message text alongside the code,
and no wording of your own has replaced it.
### When it goes wrong
- A fetch returns fewer records than the consent covers, and nothing errors.
Something took the first artefact and discarded the rest.
- A displayed explanation contradicts what ABDM sent. A code was translated
locally instead of the message being carried through.
- A `202` with an empty body is read as a failure, or a `200` with a body is
parsed as if it were empty. The status decides which answer you hold.
## Refuse to guess an undocumented step, and say so before the work starts
### In plain words
M3's data transfer needs a key derivation and a symmetric cipher over the shared
secret. Neither is in the specification. The
[data flow page](/docs/hiecm/v3/concepts/data-flow) and the
Fidelius reference give the
scheme: HKDF over the shared secret, and AES-GCM for the payload. Build the step
from those. A desk that reads only the specification cannot complete it, and no
amount of care in the code around it changes that.
What matters is where the integrator finds out. A desk that discovers it cannot
decrypt at the moment records arrive has discovered it in the worst place
available: asynchronously, after a consent has been served, with a patient's
records in hand and nothing to do with them.
### What happens
Build every step from what is documented. Where a step is documented nowhere,
throw on it with a message naming exactly what is missing. Not a generic
failure. The name of the step, and what would have to be published for it to
work.
Then report it in the readiness check up front, rather than at the moment the
first encrypted bundle arrives.
The rule generalises past encryption. Where a capability cannot work, say so
before somebody depends on it, in the place they would act on it. A capability
that is going to fail should fail in the readiness check, where an integrator is
already looking for problems, not in a flow where they are looking for records.
Do not add a dependency to paper over a scheme nobody has written down. A guess
with a package name on it is still a guess, and it is harder to find later
because it looks like a decision somebody made deliberately.
### How you know it worked
Open the readiness check before running anything. It names any step that is
documented nowhere as unavailable, and says which part is missing.
Run the flow anyway. Where a step is missing, it fails at that step with a
message naming it, rather than at a later point with a decoding error.
### When it goes wrong
- Records arrive and cannot be read, and the failure reads as a corrupt payload.
The undocumented step failed quietly somewhere earlier.
- A library appeared in the dependency list to solve the cipher, chosen from a
sample rather than from the data flow page. Check it implements HKDF and
AES-GCM as that page gives them.
- The readiness check is green and the capability does not work. The check is
testing configuration rather than capability.
## Consent, what it authorises and how it ends
### In plain words
There are five states, in the two sections a PHR app shows: Requests holds Requested, Denied and Expired; Approved holds Granted and Revoked.
```mermaid
stateDiagram-v2
[*] --> Requested: HIU raises a consent request
Requested --> Granted: Patient approves
Requested --> Denied: Patient refuses
Requested --> Expired: Patient does not act in time
Granted --> Revoked: Patient withdraws access
Granted --> [*]: Validity period ends
```
| State | What it means | What your system does |
| --- | --- | --- |
| Requested | The patient has not acted yet. | Wait. Poll the request status if you need to show progress. |
| Granted | The patient approved, and set how long the access lasts. | Fetch the artefact ids, then request the data. |
| Denied | The patient refused. | Stop. There is no partial result and no retry that changes the answer. |
| Expired | The patient did not act inside the window the HIU set on the request. | Raise a new request if the clinical need is still there. |
| Revoked | The patient withdrew a consent they had already granted. | Stop fetching under that artefact from that moment. |
Two clocks run here. The **request window** is how long the patient has to answer, set by the HIU, and running out produces Expired. The **consent validity period** is how long access lasts once granted, set by the patient as they grant, with a defined expiry date and time. Neither is the **date range**, which says which records are in scope by when the care happened: a consent granted today can cover records from 2019.
Granted is not permanent. Revoked and Expired are ordinary destinations, not faults, and your system will meet both in production.
### What happens
Store the consent request id from the init callback, then every consent artefact id a grant returns. Before each fetch, check the artefact is still usable: the patient can revoke at any time, and the validity period ends on its own.
### How you know it worked
A granted request returns at least one artefact id, and a fetch under it is accepted while the artefact is within its validity period and not revoked.
### When it goes wrong
A fetch that worked last week fails today because the patient revoked or the validity period ended; that is the system working. `ABDM-1062` is consent not granted, and `ABDM-1112` is an artefact id that is invalid or already expired. Records kept past the consent window are a legal problem, not a technical one.
## Where these came from
- `hiecm.concept.m3-plural-artefacts-and-codes`
- `hiecm.concept.m3-refuse-to-guess`
- `hiecm.concept.consent-artefact`

View File

@ -0,0 +1,55 @@
# Integrate M3, fetch data with consent
The calls themselves: where they live, what they need in their headers, and one request written out in full.
## Hosts
- `https://dev.abdm.gov.in` ABDM gateway, sandbox
- `https://apis.abdm.gov.in` ABDM gateway, production
## Endpoints
16 operations, grouped by the journey they belong to.
### Other operations
| Method | Path | What it does |
| --- | --- | --- |
| `POST` | `/api/hiecm/consent/v3/fetch` | Fetch the consent details |
| `POST` | `/api/hiecm/consent/v3/request/hiu/on-notify` | Acknowledge the notification sent when a consent request is approved/denied/rev… |
| `POST` | `/api/hiecm/consent/v3/request/init` | Initiate the consent request |
| `POST` | `/api/hiecm/consent/v3/request/status` | Get consent request status |
| `POST` | `/api/hiecm/data-flow/v3/health-information/notify` | Notifications corresponding to events during data flow |
| `POST` | `/api/hiecm/data-flow/v3/health-information/request` | Health information data request from HIU. |
| `GET` | `/api/hiecm/data-flow/v3/health-information/request/status/{transaction-id}` | Get the current status of the Health Information Request. |
| `GET` | `/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id}` | Fetch the details of a service ID. |
| `GET` | `/api/hiecm/gateway/v3/bridge-services` | Fetch the service ids registered against a bridge. |
| `PATCH` | `/api/hiecm/gateway/v3/bridge/url` | Update the bridge URL. |
| `POST` | `/api/hiecm/gateway/v3/sessions` | Generate access token. |
| `POST` | `/api/v3/hiu/consent/on-fetch` | This is a callback API called by CM to provide fetched consent artefact details… |
| `POST` | `/api/v3/hiu/consent/request/notify` | This is a callback API to notify HIU when consent is APPROVED, DENIED or REVOKE… |
| `POST` | `/api/v3/hiu/consent/request/on-init` | Callback API of consent request for patient HIU. |
| `POST` | `/api/v3/hiu/consent/request/on-status` | Callback API of consent status request. |
| `POST` | `/api/v3/hiu/health-information/on-request` | Health information data request acknowledgement to HIU. |
## Headers
| Header | What it is |
| --- | --- |
| `REQUEST-ID` | Unique UUID for track the end to end request transaction |
| `TIMESTAMP` | Actual time of the request was initiated, ISO 8601 represents date and time by starting with the year, follow… |
| `X-CM-ID` | Suffix of the consent manager to which the request was intended |
| `X-HIU-ID` | Identifier of the health information user to which the request was intended |
## A request, in full
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/consent/v3/fetch \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-HIU-ID: IN2810014366' \
--header 'Content-Type: application/json' \
--data '{
"consentId": "5f7a535d-a3fd-416b-b069-c97d021fbacd"
}'
```

View File

@ -0,0 +1,377 @@
# HIE-CM m3 build
Scaffolds an ABDM m3 integration one journey at a time. It covers raising a consent request, tracking it, and fetching the records it covers as an HIU.
## How this skill runs
Every journey below is an OODA loop, not a recipe: observe the actual state (last response, last error), orient against the step matched below, decide the cheapest next action, act, and return to observe. A step is done only when its exit condition is observed against the sandbox, never because it "should have worked."
Loop limit: 8 passes per step. Hitting the limit is an escalation: state what was observed, what was tried, and which operation page to read, then ask one question.
## Before the first journey, when the codebase already exists
Skip this section only for a system that does not exist yet. Otherwise it runs first, and its exit condition is a written plan, not a call.
### In plain words
Most ABDM integrations are not new systems. They are a hospital management
system, a laboratory system or a clinic application that already has patients,
visits, records, a login, an HTTP client and a way of keeping secrets. Every
ABDM journey has to land somewhere inside that, and a journey built before the
codebase has been read lands in the wrong place: a second HTTP client beside the
first, an ABHA column on the wrong table, a callback route the reverse proxy
never forwards.
So the first loop is not a journey. It is a survey of the system as it is, and
its exit condition is a written plan that names, for every ABDM touchpoint, the
file it will live in. The journeys then build against that plan rather than
against the specification's idea of a fresh codebase.
### Before you start
- The repository, checked out, with permission to read all of it. A survey of
half a codebase produces a plan for half a system.
- The answers to the deployment interview. The
code says what the system is. Only the integrator can say what the
deployment is, and the two together decide which journeys are built at all.
- The practices that hold across every call, which
the plan has to leave room for.
### What happens
This is one loop with a limit of eight passes over the codebase. Each pass
reads live state only, which here means the files themselves, never a README's
description of them and never an assumption carried from a similar system.
**Observe.** Inventory the system from its manifests and its tree, not from its
documentation. Record file paths for each of these, or record that none exists:
| Find | Where it usually shows | Why ABDM needs it |
|---|---|---|
| Languages and runtime versions | package manifests, lock files, toolchain files | Every generated call has to be idiomatic here |
| Build, run and test commands | manifests, CI configuration, a Makefile | Each journey's exit condition becomes a test that runs the same way |
| The frontend and backend split, and how they talk | the top level tree, an API client in the frontend, route definitions in the backend | The counter screens go in the frontend; every ABDM call goes through the backend |
| The outbound HTTP client the backend already uses | the dependency list, a shared client module | ABDM calls reuse it, or a second one appears and the two drift |
| How secrets and configuration reach the process | environment loading, a vault client, a config file | The client id, the secret and the access token travel the same way |
| The patient model, and the identifier fields it already carries | the schema, the ORM models, the migrations | The ABHA number and address become columns beside the existing identifiers, not a new table |
| The visit, encounter or record model | the same places | A care context maps to one of these, and the plan has to say which |
| Where inbound HTTP is routed and authenticated, and whether the deployment has a public URL | the router, the middleware, the reverse proxy configuration, the deployment manifests | ABDM calls back, and a callback route that nothing forwards is silence nobody notices |
| Existing cryptography helpers | a security or crypto module, the dependency list | The RSA encryption of identifiers reuses them |
| Where errors are shown to a user, and where they are logged | the frontend's error surface, the logging setup | A refused call has to land on the screen the person is looking at, and never log a token |
**Orient.** Map each ABDM touchpoint onto that inventory. Where the map is
exact, write the file path. Where it is not, write two candidates and say what
would decide between them. The common ambiguities: two places that could hold
the patient identifier, an HTTP client in the frontend and none in the backend,
a monorepo with several services and no obvious owner for callbacks.
Then read the interview answers against the inventory. A government integrator
gets the demographic route; a facility with no public URL gets no callback
driven journey until it has one; a desk with a fingerprint reader gets the
biometric method. The route set is the intersection of what the deployment
allows and what the code can host.
**Decide.** Order the journeys. The token comes first because every other call
needs it: the gateway session token, or for M4 the bearer token the registry calls
carry. Then the journey whose exit condition can be observed with
the least new code, usually a profile read for a patient who already holds an
ABHA. Creation and linking come after, because each depends on state the earlier
ones produce. For each journey, name the files it will touch and the test that
proves its exit condition.
**Act.** Write the plan. It is a file in the repository, at the path the
integrator names or at the root as `abdm-integration-plan.md`, and it is the
only output of this loop. Then return to observe once, reading the plan against
the tree, to confirm every path in it exists or is marked as new.
If the limit is reached with questions still open, escalate: name what was
found, name the two candidates that could not be separated, point at this
atom, and ask one question.
### How you know it worked
The plan exists and answers every row of the inventory table with a file path,
or with the words none, add at, followed by a path. No row is blank and no row
says to be decided.
Every ABDM touchpoint in the plan names one file, or names two candidates and
the observation that would choose between them. Every journey in the plan names
the test that proves its exit condition and the command that runs it.
Open the plan beside the tree. Every path it names resolves, or is marked as
new. That is the observation that ends this loop, and the first journey does
not start until it has been made.
### When it goes wrong
- **The plan puts the HTTP client in the frontend.** The survey found the
frontend's API client and stopped. Every ABDM call carries a secret, so it
goes through the backend, and the plan has to say which backend module.
- **Two patient tables, and the plan picked one.** Orient produced one
hypothesis where it needed two. Name both, and name the query that shows
which one the visit model points at.
- **The plan has a callback route and the deployment has no public URL.** The
inventory row on inbound routing was answered from the router rather than
from the deployment. Mark every callback driven journey as blocked on a URL,
and build the ones that are not.
- **The survey read the README and not the tree.** A README describes the
system somebody meant to build. The plan is for the one that exists.
- **Eight passes and the plan is still incomplete.** Escalate with the rows
that are answered, the rows that are not, this atom, and one question about
the row that blocks the most journeys.
From `shared.concept.survey-an-existing-codebase`.
## Journeys
### Consent and data flow (`m3-consent-management-data-flow-hiu`)
**Act: the calls in this journey, in order**
#### 1. Initiate the consent request (`m3_post_consent_v3_request_init`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/consent/v3/request/init \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"consent": {
"purpose": {
"text": "Care Management",
"code": "CAREMGT",
"refUri": "www.abc.com"
},
"patient": {
"id": "<ABHA_ADDRESS>"
},
"hip": null,
"hiu": {
"id": "cowin_hiu_01"
},
"careContexts": [
{
"patientReference": "batman@tmh",
"careContextReference": "Episode1"
}
],
"requester": {
"name": "<ABHA_ADDRESS>",
"identifier": {
"value": "REG1",
"type": "MH1001",
"system": "https://www.sample.com"
}
},
"hiTypes": [
"Prescription"
],
"permission": {
"accessMode": "VIEW",
"dateRange": {
"from": "2021-09-28T12:30:08.573Z",
"to": "2021-09-28T12:30:08.573Z"
},
"dataEraseAt": "2021-09-28T12:30:08.573Z",
"frequency": {
"unit": "HOUR",
"value": 1,
"repeats": 0
}
}
}
}'
```
#### 2. Get consent request status (`m3_post_consent_v3_request_status`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/consent/v3/request/status \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-HIU-ID: IN2810014366' \
--header 'Content-Type: application/json' \
--data '{
"consentRequestId": "5f7a535d-a3fd-416b-b069-c97d021fbacd"
}'
```
#### 3. Acknowledge the consent notification (`m3_post_consent_v3_request_hiu_on_notify`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/consent/v3/request/hiu/on-notify \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"acknowledgement": [
{
"status": "OK",
"consentId": "e3c74829-3f82-4f94-959e-e10f57bcd57b"
}
],
"error": {
"code": "ABDM-1001",
"message": "unable to connect database"
},
"response": {
"requestId": "6f0b4665-a915-4c92-aa36-65afb4a2cd71"
}
}'
```
#### 4. Fetch the consent details (`m3_post_consent_v3_fetch`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/consent/v3/fetch \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-HIU-ID: IN2810014366' \
--header 'Content-Type: application/json' \
--data '{
"consentId": "5f7a535d-a3fd-416b-b069-c97d021fbacd"
}'
```
#### 5. Submit the health information data request from HIU (`m3_post_data_flow_v3_health_information_request`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/data-flow/v3/health-information/request \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'X-HIU-ID: IN2810014366' \
--header 'Content-Type: application/json' \
--data '{
"hiRequest": {
"consent": {
"id": "18235d89-cb13-479d-ad71-7a57d5f669a8"
},
"dateRange": {
"from": "2022-10-06T15:10:00.587Z",
"to": "2022-11-06T15:10:00.587Z"
},
"dataPushUrl": "https://live.ndhm.gov.in/api-hiu/data/notification",
"keyMaterial": {
"cryptoAlg": "ECDH",
"curve": "curve25519",
"dhPublicKey": {
"expiry": "2022-12-28T13:18:20.742Z",
"parameters": "Ephemeral public key",
"keyValue": "BFN7KTdOT0jIAExG2A8Jg+01wMPWxptiGqwHRVvtiVEsUq2FR7P2UdqZxJyPJSeR6muai21iQhasNxnhh8I5M+g="
},
"nonce": "28236d89-cb13-479d-ad71-7a57d5f669a9"
}
}
}'
```
#### 6. Submit the notifications corresponding to events during data flow (`m3_post_data_flow_v3_health_information_notify`)
```bash
curl --request POST \
--url https://dev.abdm.gov.in/api/hiecm/data-flow/v3/health-information/notify \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx' \
--header 'Content-Type: application/json' \
--data '{
"notification": {
"consentId": "18235d89-cb13-479d-ad71-7a57d5f669a8",
"transactionId": "18235d89-cb13-479d-ad71-7a57d5f669a8",
"doneAt": "2023-01-24T06:35:44.167Z",
"notifier": {
"type": "HIU",
"id": "100005"
},
"statusNotification": {
"sessionStatus": "RECEIVED",
"hipId": "IN2810014366",
"statusResponses": [
{
"careContextReference": "10004-20200001768-1",
"hiStatus": "OK",
"description": "Data received successfully"
}
]
}
}
}'
```
#### 7. Get the current status of the health information request (`m3_get_data_flow_v3_health_information_request_status_tra_550104`)
```bash
curl --request GET \
--url https://dev.abdm.gov.in/api/hiecm/data-flow/v3/health-information/request/status/{transaction-id} \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'X-CM-ID: sbx'
```
**Exit condition (Observe until this is true)**
Each call you made in this journey answered by its callback, with `response.requestId` equal to the `REQUEST-ID` you sent on that call. The 202 on a call is receipt, not the outcome: the outcome is in the callback's body.
- `POST /api/hiecm/consent/v3/request/init` is answered by `POST /api/v3/hiu/consent/request/on-init` on your bridge.
- `POST /api/hiecm/consent/v3/request/status` is answered by `POST /api/v3/hiu/consent/request/on-status` on your bridge.
- `POST /api/hiecm/consent/v3/fetch` is answered by `POST /api/v3/hiu/consent/on-fetch` on your bridge.
- `POST /api/hiecm/data-flow/v3/health-information/request` is answered by `POST /api/v3/hiu/health-information/on-request` on your bridge.
Then `GET /api/hiecm/data-flow/v3/health-information/request/status/{transaction-id}` returns a 200 whose body matches:
```json
{
"transactionId": "18235d89-cb13-479d-ad71-7a57d5f669a8",
"status": "TRANSFERRED"
}
```
### Callbacks (`m3-callbacks`)
**Act: the calls in this journey, in order**
#### 1. Receive the consent request for patient HIU (`m3_post_v3_hiu_consent_request_on_init`)
Inbound to your bridge at `/api/v3/hiu/consent/request/on-init`. Acknowledge it and continue.
#### 2. Receive the consent status request (`m3_post_v3_hiu_consent_request_on_status`)
Inbound to your bridge at `/api/v3/hiu/consent/request/on-status`. Acknowledge it and continue.
#### 3. Notify HIU when consent is APPROVED, DENIED or REVOKED (`m3_post_v3_hiu_consent_request_notify`)
Inbound to your bridge at `/api/v3/hiu/consent/request/notify`. Acknowledge it and continue.
#### 4. Receive the provide fetched consent artefact details to HIU (`m3_post_v3_hiu_consent_on_fetch`)
Inbound to your bridge at `/api/v3/hiu/consent/on-fetch`. Acknowledge it and continue.
#### 5. Receive the health information data request acknowledgement to HIU (`m3_post_v3_hiu_health_information_on_request`)
Inbound to your bridge at `/api/v3/hiu/health-information/on-request`. Acknowledge it and continue.
**Exit condition (Observe until this is true)**
A 200 response. The specification gives no body for it, so read what comes back.
## Where the detail is
- Every operation, with its body fields and responses: /docs/hiecm/v3/api/m3
- Error codes: /docs/hiecm/v3/api/m3/errors

View File

@ -0,0 +1,88 @@
---
name: abdm-m4
description: Use when building, debugging or testing ABDM Milestone 4, the NHPR: creating an HPID, registering a healthcare professional on the HPR, onboarding a facility to the HFR, and linking that facility to a bridge. Carries the operations, their hosts and headers.
type: skill
domain: m4
agent_consumers:
- abdm-integration-agent
- abdm-call-debugger
requires:
- gateway-session-token
produces:
- hpid
- facility-id
- bridge-facility-link
can_execute: true
can_orchestrate: false
---
# ABDM M4, register facilities and professionals
Generated from the ABDM Developer Portal on 2026-09-16, catalogue version 2026.09.16. Every fact below comes from a page in that portal, which is the place to look when this file does not carry enough.
This file is a snapshot. Re-download the whole folder from https://docs.abdm.gov.in/skills/abdm-m4/ when it is older than the work you are doing: this router and every file under references/ that it links to. Fetching this file alone leaves those links pointing at files you do not have.
If the abdm-docs MCP server is connected, trust its answers over this file: it serves the current catalogue and stamps every response with its catalogue_version, which you can compare against the version above.
## What you can do with M4
- Create an HPID for a professional and register them in the HPR.
- Register a facility in the HFR and carry it through to submission.
- Link a facility to a bridge and set the type of each link.
- Fetch the council, course, college, university and geography codes these calls take instead of names.
What it cannot do yet matters as much. Read **Before anything else** below before assuming a capability is one endpoint away.
## Try asking
- "Onboard this facility to the HFR and link its HIP bridge"
- "What has to be in place before my first M4 call?"
- "My M4 call failed. Here is the response: what is wrong, and how do I fix it?"
Loaded with no task? Say in three lines what this skill does. Offer the prompts above. Then ask what the person is building, and whether the code for it exists yet.
## What is in this folder
- **Scaffold.** Survey the codebase first when one exists, then build it flow by flow against the sandbox, as a loop that ends when the step's exit condition holds rather than on a call returning 200. [references/scaffold.md](references/scaffold.md)
- **Integrate.** 91 operations, with their hosts and headers. [references/integrate.md](references/integrate.md)
- **Debug.** The specification's examples return no error code for this module. [references/debug.md](references/debug.md)
This file is the map. Each line above is a file beside it, opened one at a time rather than read through.
## Before anything else
- Treat every request and response shape in this skill as unconfirmed until the sandbox has answered you. Check a response before you rely on its shape.
- Neither registry moves a health record. M4 establishes who the professional is and what the facility is, so every record flow has a verified provider behind it.
- The register professional call carries an `hprToken` in its payload, beside the practitioner.
- The facility calls are keyed to a `trackingId`, and the facility status values in the examples include `Draft` and `Submitted`. Read the status rather than assuming a facility is complete.
- Register professional takes codes, not names. Fetch council, course, college, university, state, district and language from the master data APIs first.
- `POST /v1/bridges/MutipleHRPAddUpdateServices` links a facility to a bridge. Each entry names a `bridgeId`, a `hipName`, a `type` such as `HIP`, and whether it is `active`.
## Practices that hold across every call
- Read the body, not only the status. A refusal often names the field in its body while the status says nothing useful.
- When ABDM publishes a value, read it rather than hard coding what it currently says. That covers a parameter, such as the encryption algorithm the certificate endpoints return beside the key, and it covers an enumeration. The registries publish theirs as master data calls: councils, courses, colleges, states and districts on the HPR, and facility types and LGD codes on the HFR. A table typed into your source goes stale silently. Purposes and HI types have no master data call: take them from the enumeration in the specification of the call you are making. Refuse to act on a published value you do not recognise rather than falling back to a default.
- Read every field in a response, not the one you came for. The M1 certificate call returns the encryption algorithm next to the key.
- Prove an assumption against a call that is able to disagree with you. A call that refuses every input with one message cannot tell you which input was right.
- Suspect the transport before the data. When a call refuses a value you believe in, check the encryption, the headers and the clock before you doubt the value.
- Do not carry an encryption path from one module to another. Read the certificate and the algorithm from the registry you are calling.
- Never log a sensitive value before you encrypt it, and never send one to a remote service to be encrypted. Both move the leak rather than removing it.
- Generate a fresh REQUEST-ID for every call and log it before sending. Once a call has failed it is the only handle on it.
- Check the host on any sample before you copy it. A request copied whole can be correct in every respect except where it is pointed, and that failure looks like credentials.
- Do not validate an identifier more strictly than the platform does. A schema that types a field as a UUID is not a promise that every value is one. Refusing a value ABDM would have accepted turns your own client into the thing that broke.
- Read a plural response as plural. A verification returns an accounts array and a consent request can produce more than one artefact. Store the collection and decide from its length.
- A documented callback path is not a documented callback payload. Log the whole body on arrival before you parse it, so a handler written against an assumed shape fails where you can see it.
- Decode a token before you use it. A call that hands you a token has not necessarily handed you the token the next call wants, and the claims are base64 that need no library to read.
- When a journey carries the same parameter through two calls, check what each call's specification asks for rather than carrying the first value forward.
- Do not infer which path an identifier belongs to from where that identifier is most discussed. Send every identifier to the lookup first and let the answer pick the path, so nobody who already holds an account is sent to create a second.
- Do not match an error code with string equality. A code may come back bare, as `ABDM-1001`, or with a trailing `: ` separator, as `ABDM-1001: `. Match on the code itself and tolerate the separator.
- Handle a failure that carries no body. Check for an empty body before you parse, or your client throws on the simplest failure there is.
- Back off on an authentication failure rather than retrying, and never loop a credential check.
- Send TIMESTAMP in UTC, ISO-8601 with milliseconds and a trailing Z, as in `2022-10-06T15:10:00.587Z`.
- Cache a public certificate with a validity window rather than forever. A rotation fails every encrypted call at once, and a cache with no expiry cannot recover on its own.
## Where the detail is
- Every endpoint, with its body fields and responses: /docs/hiecm/v3/api/m4
- The flows as diagrams: /docs/hiecm/v3/milestones/m4
- Every error code across modules: /docs/hiecm/v3/reference/error-codes
- Terms: /docs/hiecm/v3/getting-started/glossary

View File

@ -0,0 +1,9 @@
# Debug M4, register facilities and professionals
The codes this module can return, with the message and the operation that returns each.
## Errors
The M4, register facilities and professionals specification's examples return no error code yet. That is a gap in the specification, not a promise that this module cannot fail.
A code you meet that is not above is one the specifications do not carry yet. Read the code together with the message: a code can appear twice with different meanings.

View File

@ -0,0 +1,133 @@
# Integrate M4, register facilities and professionals
The calls themselves: where they live, what they need in their headers, and one request written out in full.
## Hosts
- `https://apihspsbx.abdm.gov.in/v4/int` NHPR, sandbox
- `https://dev.abdm.gov.in` ABDM gateway, sandbox
- `https://apis.abdm.gov.in` ABDM gateway, production
## Endpoints
91 operations, grouped by the journey they belong to.
### Other operations
| Method | Path | What it does |
| --- | --- | --- |
| `POST` | `/aadhaar/generateLink` | Generate Aadhaar Link |
| `POST` | `/aadhaar/isAuthenticated` | Is Aadhaar Authenticated |
| `GET` | `/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id}` | Fetch the details of a service ID. |
| `GET` | `/api/hiecm/gateway/v3/bridge-services` | Fetch the service ids registered against a bridge. |
| `PATCH` | `/api/hiecm/gateway/v3/bridge/url` | Update the bridge URL. |
| `POST` | `/api/hiecm/gateway/v3/sessions` | Generate access token. |
| `POST` | `/api/v1/auth/authPassword` | Login Via Password |
| `GET` | `/api/v1/auth/cert` | Get Public Certificate |
| `POST` | `/api/v1/auth/confirmWithAadhaarOtp` | Verify Aadhaar OTP |
| `POST` | `/api/v1/auth/init` | Send Via Aadhaar OTP |
| `POST` | `/api/v2/auth/loginViaMobileSendOTP` | Send Verify OTP |
| `POST` | `/apis/v1/doctors/fetch-documents-list` | Fetch Documents |
| `POST` | `/apis/v1/doctors/fetch-professional-info` | Get Professional Info |
| `POST` | `/apis/v1/doctors/generate-mobile-otp` | Generate Mobile OTP 2 |
| `POST` | `/apis/v1/doctors/generate-verification-email` | Send Verification Email |
| `POST` | `/apis/v1/doctors/regenerate-mobile-otp` | Regenerate Mobile OTP |
| `POST` | `/apis/v1/doctors/register-professional-new` | Register Professional |
| `POST` | `/apis/v1/doctors/resent-verify-email` | Resend Verification Email |
| `POST` | `/apis/v1/doctors/update-professional-new` | Update Professional |
| `POST` | `/apis/v1/doctors/verify-email-otp` | Verify Email OTP |
| `POST` | `/apis/v1/doctors/verify-mobile-otp` | Verify Mobile OTP |
| `GET` | `/apis/v1/masters/affiliated-board` | Get All Affiliated Board |
| `GET` | `/apis/v1/masters/affiliated-board/{id}` | Get Affiliated Board By ID |
| `GET` | `/apis/v1/masters/affiliated-board/states/{id}` | Get Affiliated Board By State ID |
| `GET` | `/apis/v1/masters/colleges/{id}` | Get College By State |
| `GET` | `/apis/v1/masters/colleges/{stateId}/{medicineId}` | Get College By State And Medicine ID |
| `GET` | `/apis/v1/masters/countries` | Get All Countries |
| `GET` | `/apis/v1/masters/countries/{id}` | Get Countries By ID |
| `POST` | `/apis/v1/masters/courses` | List Courses |
| `GET` | `/apis/v1/masters/district` | Get All Districts |
| `GET` | `/apis/v1/masters/district/{id}` | Get Districts By State |
| `GET` | `/apis/v1/masters/languages` | List Government Health Programmes |
| `GET` | `/apis/v1/masters/languages/{id}` | Get Pi Languages By ID |
| `GET` | `/apis/v1/masters/medical-councils` | Get All Medical Council |
| `GET` | `/apis/v1/masters/medical-councils/name` | Get Medical Council By System Of Medicine Name |
| `GET` | `/apis/v1/masters/nurse-councils` | Get All Nurse Councils |
| `GET` | `/apis/v1/masters/states` | Get All States |
| `GET` | `/apis/v1/masters/states/{id}` | Get Status |
| `GET` | `/apis/v1/masters/sub-districts` | Get All Sub Districts |
| `GET` | `/apis/v1/masters/sub-districts/{id}` | Get All Sub Districts 1 |
| `GET` | `/apis/v1/masters/system-of-medicines` | Get All Medical System |
| `GET` | `/apis/v1/masters/universites` | List All University |
| `GET` | `/apis/v1/masters/universites/{id}` | Get University By College |
| `POST` | `/apis/v1/uploads/upload-document` | Upload Documents |
| `POST` | `/FacilityManagement/v1.5/facility/bygeoLocation/searchWithinRadiusWithFilter` | Get Facility Within Radius With Filter |
| `POST` | `/FacilityManagement/v1.5/facility/search` | Search Facility 1 |
| `GET` | `/getPsuDetailsByMinistry` | Get Psu Data |
| `GET` | `/hpid/get/categories` | Fetch HPID Categories |
| `GET` | `/hpid/get/subCategories` | Fetch HPID Sub Categories From Category |
| `POST` | `/password/change/byPassword` | Change Password |
| `POST` | `/password/recover/byAadhaar` | Recover Password Via Aadhaar |
| `POST` | `/password/recover/byMobile/sendMobileOTP` | Generate Mobile OTP 1 |
| `POST` | `/password/recover/byMobile/verifyMobileOTP` | Verify Mobile OTP 1 |
| `POST` | `/password/recover/confirmByAadhaar` | Recover Password Confirm By Aadhaar |
| `POST` | `/password/reset/password` | Reset Password And Session |
| `POST` | `/password/resetPassword` | Reset Password |
| `POST` | `/search/address/filter/deduplicate` | Get Filtered Address Post |
| `POST` | `/v1.0/facility/search-facilities` | Search Facility |
| `POST` | `/v1.5/facility/additional-information` | V15Facility Additional Information |
| `POST` | `/v1.5/facility/basic-information` | V15Basic Facility Information |
| `POST` | `/v1.5/facility/detailed-information` | V15Facility Detailed Information |
| `POST` | `/v1.5/facility/fetch-facility-Sub-type` | Get All Facility Sub Type By Facility Type |
| `POST` | `/v1.5/facility/fetch-facility-type` | Get All Facility Type By Ownership And Sys Of Med |
| `GET` | `/v1.5/facility/get-master-data` | Get Master Data |
| `GET` | `/v1.5/facility/get-master-types` | Get All Master Type |
| `POST` | `/v1.5/facility/get-owner-subtype` | Get All Sub Types By Owner Ship Type And Sub Type |
| `POST` | `/v1.5/facility/get-specialities` | Get All Specialities By System Of Medicine Code |
| `GET` | `/v1.5/facility/lgd/districts` | Get All District By State ID |
| `GET` | `/v1.5/facility/lgd/states` | Get All States By LGD |
| `GET` | `/v1.5/facility/lgd/subdistricts` | Get All Sub District By District Code |
| `POST` | `/v1.5/facility/sendOtpToContact` | Send OTP To Contact |
| `POST` | `/v1.5/facility/submit-facility` | V15Submit Facility Details |
| `POST` | `/v1.5/facility/validateOtp` | Validate OTP |
| `GET` | `/v1/account/getIdCard` | Get Account Png Card |
| `GET` | `/v1/account/information` | Get User Profile By JWT |
| `GET` | `/v1/account/user-details/{hprId}` | Get User Details |
| `POST` | `/v1/bridges/MutipleHRPAddUpdateServices` | Facility Add And Update |
| `POST` | `/v1/forgot/hprId/aadhaar` | Retrieval Health ID By Aadhaar |
| `POST` | `/v1/forgot/hprId/mobile` | Retrieval Health ID By Mobile |
| `POST` | `/v1/forgot/hprId/mobile/generateOtp` | Generate Mobile OTP |
| `POST` | `/v1/registration/aadhaar/checkHpIdAccountExist` | Account Exist |
| `POST` | `/v1/registration/aadhaar/generateMobileOTP` | Generate Mobile OTP |
| `POST` | `/v1/registration/aadhaar/hpid/suggestion` | Get Suggesstion |
| `POST` | `/v1/registration/aadhaar/verifyMobileOTP` | Verify Mobile OTP |
| `GET` | `/v1/search/existsByHprId/{hprId}` | Exists By HPR ID |
| `GET` | `/v1/search/searchByHprId/{hprId}` | Search User By HPR ID |
| `GET` | `/v1/search/searchByMobile/{mobile}` | Search User By Mobile No |
| `POST` | `/v2/registration/aadhaar/createHprIdWithPreVerified` | Create HPR ID V2 |
| `POST` | `/v2/registration/aadhaar/demographicAuthViaMobile` | Demographic Auth Via Mobile |
| `POST` | `/v2/registration/aadhaar/verifyOTP` | Verify OTP |
| `GET` | `/v4/auth/logout` | Logout |
## Headers
| Header | What it is |
| --- | --- |
| `Authorization` | |
| `REQUEST-ID` | Unique UUID for track the end to end request transaction |
| `TIMESTAMP` | Actual time of the request was initiated, ISO 8601 represents date and time by starting with the year, follow… |
| `X-CM-ID` | Suffix of the consent manager to which the request was intended |
| `x-hprid-auth` | The HPR token of the signed-in professional, from the HPR login. |
| `x-hprid-auth-verifier` | The HPR token of the professional verifying the facility submission. |
| `X-Token` | The HPR token of the signed-in professional, from the HPR login. |
## A request, in full
```bash
curl --request POST \
--url https://apihspsbx.abdm.gov.in/v4/int/aadhaar/generateLink \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'Content-Type: application/json' \
--data '{
"scopes": [
"nhpr-register"
],
"source": "NHPR"
}'
```

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,88 @@
---
name: abdm-p1
description: Use when building, debugging or testing ABDM P1 in a PHR app: creating an ABHA address and logging in to it.
type: skill
domain: p1
agent_consumers:
- abdm-integration-agent
- abdm-call-debugger
requires:
- gateway-session-token
produces:
- phr-login
- abha-profile
can_execute: true
can_orchestrate: false
---
# ABDM P1, PHR registration and login
Generated from the ABDM Developer Portal on 2026-09-16, catalogue version 2026.09.16. Every fact below comes from a page in that portal, which is the place to look when this file does not carry enough.
This file is a snapshot. Re-download the whole folder from https://docs.abdm.gov.in/skills/abdm-p1/ when it is older than the work you are doing: this router and every file under references/ that it links to. Fetching this file alone leaves those links pointing at files you do not have.
If the abdm-docs MCP server is connected, trust its answers over this file: it serves the current catalogue and stamps every response with its catalogue_version, which you can compare against the version above.
## What you can do with P1
- PHR certificate and session token
- Create ABHA number, Aadhaar OTP
- Create ABHA address, mobile number
- Create ABHA address, ABHA number with ABHA OTP
- Create ABHA address, ABHA number with Aadhaar OTP
- PHR login, mobile number
- PHR login, ABHA address with mobile OTP
- PHR login, ABHA number with Aadhaar OTP
- PHR login, ABHA number with ABHA OTP
- PHR login, ABHA address with password
- PHR login, Aadhaar OTP
What it cannot do yet matters as much. Read **Before anything else** below before assuming a capability is one endpoint away.
## Try asking
- "Register a new user in this PHR app and log them in"
- "What has to be in place before my first P1 call?"
- "My P1 call returned ABDM-1107. What is wrong, and how do I fix it?"
Loaded with no task? Say in three lines what this skill does. Offer the prompts above. Then ask what the person is building, and whether the code for it exists yet.
## What is in this folder
- **Scaffold.** Survey the codebase first when one exists, then build it flow by flow against the sandbox, as a loop that ends when the step's exit condition holds rather than on a call returning 200. [references/scaffold.md](references/scaffold.md)
- **Integrate.** 15 operations, with their hosts and headers. [references/integrate.md](references/integrate.md)
- **Debug.** The loop from a failed call to a named fix, and 4 error codes from the specification's examples. [references/debug.md](references/debug.md)
This file is the map. Each line above is a file beside it, opened one at a time rather than read through.
## Before anything else
- Treat every request and response shape in this skill as unconfirmed until the sandbox has answered you. Check a response before you rely on its shape.
## Practices that hold across every call
- Read the body, not only the status. A refusal often names the field in its body while the status says nothing useful.
- When ABDM publishes a value, read it rather than hard coding what it currently says. That covers a parameter, such as the encryption algorithm the certificate endpoints return beside the key, and it covers an enumeration. The registries publish theirs as master data calls: councils, courses, colleges, states and districts on the HPR, and facility types and LGD codes on the HFR. A table typed into your source goes stale silently. Purposes and HI types have no master data call: take them from the enumeration in the specification of the call you are making. Refuse to act on a published value you do not recognise rather than falling back to a default.
- Read every field in a response, not the one you came for. The M1 certificate call returns the encryption algorithm next to the key.
- Prove an assumption against a call that is able to disagree with you. A call that refuses every input with one message cannot tell you which input was right.
- Suspect the transport before the data. When a call refuses a value you believe in, check the encryption, the headers and the clock before you doubt the value.
- Do not carry an encryption path from one module to another. Read the certificate and the algorithm from the registry you are calling.
- Never log a sensitive value before you encrypt it, and never send one to a remote service to be encrypted. Both move the leak rather than removing it.
- Generate a fresh REQUEST-ID for every call and log it before sending. Once a call has failed it is the only handle on it.
- Check the host on any sample before you copy it. A request copied whole can be correct in every respect except where it is pointed, and that failure looks like credentials.
- Do not validate an identifier more strictly than the platform does. A schema that types a field as a UUID is not a promise that every value is one. Refusing a value ABDM would have accepted turns your own client into the thing that broke.
- Read a plural response as plural. A verification returns an accounts array and a consent request can produce more than one artefact. Store the collection and decide from its length.
- A documented callback path is not a documented callback payload. Log the whole body on arrival before you parse it, so a handler written against an assumed shape fails where you can see it.
- Decode a token before you use it. A call that hands you a token has not necessarily handed you the token the next call wants, and the claims are base64 that need no library to read.
- When a journey carries the same parameter through two calls, check what each call's specification asks for rather than carrying the first value forward.
- Do not infer which path an identifier belongs to from where that identifier is most discussed. Send every identifier to the lookup first and let the answer pick the path, so nobody who already holds an account is sent to create a second.
- Do not match an error code with string equality. A code may come back bare, as `ABDM-1001`, or with a trailing `: ` separator, as `ABDM-1001: `. Match on the code itself and tolerate the separator.
- Handle a failure that carries no body. Check for an empty body before you parse, or your client throws on the simplest failure there is.
- Back off on an authentication failure rather than retrying, and never loop a credential check.
- Send TIMESTAMP in UTC, ISO-8601 with milliseconds and a trailing Z, as in `2022-10-06T15:10:00.587Z`.
- Cache a public certificate with a validity window rather than forever. A rotation fails every encrypted call at once, and a cache with no expiry cannot recover on its own.
## Where the detail is
- Every endpoint, with its body fields and responses: /docs/hiecm/v3/api/p1
- Every error code across modules: /docs/hiecm/v3/reference/error-codes
- Terms: /docs/hiecm/v3/getting-started/glossary

View File

@ -0,0 +1,48 @@
# HIE-CM p1 debug
Every error below is an OODA loop: observe the error code and last request id, orient against the matched code, decide the fix, act, and observe whether the original step now succeeds. Applying a fix is not the exit condition; the original step succeeding is.
Loop limit: 5 passes per error.
## Errors
### 900902
**Specification example:** HTTP 401, `Missing Credentials`, on `p1_get_v3_phr_app_enrollment_isexists`.
**Exit condition: the original call now succeeds.**
### ABDM-1107
**Specification example:** HTTP 400, `Invalid combinations of scopes`, on `p1_post_v3_phr_app_login_verify`.
**Exit condition: the original call now succeeds.**
### ABDM-1211
**Specification example:** HTTP 400, `User not found.`, on `p1_post_v3_phr_app_login_search`.
**Exit condition: the original call now succeeds.**
### ABDM-9999
**Specification example:** HTTP 400, `Invalid LoginId`, on `p1_post_v3_phr_app_enrollment_request_otp`.
**Exit condition: the original call now succeeds.**
## Where the detail is
- The operation that returns each code: /docs/hiecm/v3/api/p1
## Every code in the specification
### Codes
| Code | HTTP | Message | Returned by |
| --- | --- | --- | --- |
| `900902` | 401 | Missing Credentials | `p1_get_v3_phr_app_enrollment_isexists` |
| `ABDM-1107` | 400 | Invalid combinations of scopes | `p1_post_v3_phr_app_login_verify` |
| `ABDM-1211` | 400 | User not found. | `p1_post_v3_phr_app_login_search` |
| `ABDM-9999` | 400 | Invalid LoginId | `p1_post_v3_phr_app_enrollment_request_otp` |
A code you meet that is not above is one the specifications do not carry yet. Read the code together with the message: a code can appear twice with different meanings.

View File

@ -0,0 +1,74 @@
# Integrate P1, PHR registration and login
The calls themselves: where they live, what they need in their headers, and one request written out in full.
## Hosts
- `https://abhasbx.abdm.gov.in` ABHA service, sandbox
- `https://dev.abdm.gov.in` ABDM gateway, sandbox
- `https://apis.abdm.gov.in` ABDM gateway, production
## Endpoints
15 operations, grouped by the journey they belong to.
### Other operations
| Method | Path | What it does |
| --- | --- | --- |
| `POST` | `/abha/api/v3/phr/app/enrollment/enrol` | 3 flows: Enrol ABHA Address |
| `GET` | `/abha/api/v3/phr/app/enrollment/isExists` | 3 flows: isExists API, isExists API Copy |
| `POST` | `/abha/api/v3/phr/app/enrollment/request/otp` | 3 flows: OTP Request - Mobile, OTP Request - ABHA OTP, OTP Request - AADHAR OTP |
| `POST` | `/abha/api/v3/phr/app/enrollment/suggestion` | 3 flows: Suggestion API |
| `POST` | `/abha/api/v3/phr/app/enrollment/verify` | 3 flows: OTP Verify - Mobile, OTP Verify - ABHA OTP, OTP Verify - AADHAR OTP |
| `GET` | `/abha/api/v3/phr/app/login/public/certificate` | PHR Certificate |
| `POST` | `/abha/api/v3/phr/app/login/request/otp` | 5 flows: OTP Request - Mobile, OTP Request - ABHAADDRES Mobile, OTP Request - A… |
| `POST` | `/abha/api/v3/phr/app/login/search` | Search Auth Methods - ABHAAddress |
| `POST` | `/abha/api/v3/phr/app/login/verify` | 6 flows: Login OTP Verify - Mobile, Login OTP Verify - ABHAADDRES Mobile, Login… |
| `POST` | `/abha/api/v3/phr/app/login/verify/user` | 5 flows: Verify User, Verify - User |
| `POST` | `/abha/api/v3/profile/account/request/emailVerificationLink` | Email Verification Link |
| `GET` | `/api/hiecm/gateway/v3/bridge-service/serviceId/{service-id}` | Fetch the details of a service ID. |
| `GET` | `/api/hiecm/gateway/v3/bridge-services` | Fetch the service ids registered against a bridge. |
| `PATCH` | `/api/hiecm/gateway/v3/bridge/url` | Update the bridge URL. |
| `POST` | `/api/hiecm/gateway/v3/sessions` | Generate access token. |
## Headers
| Header | What it is |
| --- | --- |
| `REQUEST-ID` | Unique UUID for each request. |
| `TIMESTAMP` | Request timestamp in UTC, ISO-8601 with Z. |
| `T-token` | The transaction token from the preceding login step, sent with a `Bearer ` prefix. It is valid only for that … |
| `X-token` | The user token from a login or enrolment response, sent with a `Bearer ` prefix. It acts for that ABHA holder. |
| `X-CM-ID` | Suffix of the consent manager to which the request was intended |
## A request, in full
```bash
curl --request POST \
--url https://abhasbx.abdm.gov.in/abha/api/v3/phr/app/enrollment/enrol \
--header 'Authorization: Bearer <ACCESS_TOKEN_FROM_SESSIONS_CALL>' \
--header 'REQUEST-ID: 18235d89-cb13-479d-ad71-7a57d5f669a8' \
--header 'TIMESTAMP: 2022-10-06T15:10:00.587Z' \
--header 'Content-Type: application/json' \
--data '{
"txnId": "27d444b7-2a3d-46d8-bf67-e5590b6c46b6",
"phrDetails": {
"mobile": "<ENCRYPTED_MOBILE>",
"firstName": "John",
"middleName": "",
"lastName": "Doe",
"yearOfBirth": "<DOB>",
"dayOfBirth": "",
"monthOfBirth": "<DOB>",
"gender": "M",
"email": "",
"profilePhoto": "",
"address": "<ADDRESS>",
"stateName": "Maharashtra",
"stateCode": "27",
"districtName": "<ADDRESS>",
"districtCode": "123",
"pinCode": "<PINCODE>",
"abhaAddress": "<ABHA_ADDRESS>",
"password": "<ENCRYPTED_PASSWORD>"
}
}'
```

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
---
name: abdm-p2
description: Use when building, debugging or testing ABDM P2 in a PHR app: the PHR profile, linking an ABHA number, switching profiles, and linking, sharing and consent for the patient.
type: skill
domain: p2
agent_consumers:
- abdm-integration-agent
- abdm-call-debugger
requires:
- phr-login
produces:
- consent-decision
can_execute: true
can_orchestrate: false
---
# ABDM P2, Consents Management
Generated from the ABDM Developer Portal on 2026-09-16, catalogue version 2026.09.16. Every fact below comes from a page in that portal, which is the place to look when this file does not carry enough.
This file is a snapshot. Re-download the whole folder from https://docs.abdm.gov.in/skills/abdm-p2/ when it is older than the work you are doing: this router and every file under references/ that it links to. Fetching this file alone leaves those links pointing at files you do not have.
If the abdm-docs MCP server is connected, trust its answers over this file: it serves the current catalogue and stamps every response with its catalogue_version, which you can compare against the version above.
## What you can do with P2
- PHR profile, update mobile
- PHR profile, update password
- Link ABHA number, ABHA OTP
- Link ABHA number, Aadhaar OTP
- PHR profile, switch profile
- PHR profile, card, QR code and session
- Quick OPD Registration
- User initiated linking
- Consent manager, HIU and HIP
- Consent manager, fetch and manage consent requests
What it cannot do yet matters as much. Read **Before anything else** below before assuming a capability is one endpoint away.
## Try asking
- "Link this user's records to their ABHA address from the PHR app"
- "What has to be in place before my first P2 call?"
- "My P2 call returned ABDM-9999. What is wrong, and how do I fix it?"
Loaded with no task? Say in three lines what this skill does. Offer the prompts above. Then ask what the person is building, and whether the code for it exists yet.
## What is in this folder
- **Scaffold.** Survey the codebase first when one exists, then build it flow by flow against the sandbox, as a loop that ends when the step's exit condition holds rather than on a call returning 200. [references/scaffold.md](references/scaffold.md)
- **Integrate.** 39 operations, with their hosts and headers. [references/integrate.md](references/integrate.md)
- **Debug.** The loop from a failed call to a named fix, and 2 error codes from the specification's examples. [references/debug.md](references/debug.md)
This file is the map. Each line above is a file beside it, opened one at a time rather than read through.
## Before anything else
- Treat every request and response shape in this skill as unconfirmed until the sandbox has answered you. Check a response before you rely on its shape.
## Practices that hold across every call
- Read the body, not only the status. A refusal often names the field in its body while the status says nothing useful.
- When ABDM publishes a value, read it rather than hard coding what it currently says. That covers a parameter, such as the encryption algorithm the certificate endpoints return beside the key, and it covers an enumeration. The registries publish theirs as master data calls: councils, courses, colleges, states and districts on the HPR, and facility types and LGD codes on the HFR. A table typed into your source goes stale silently. Purposes and HI types have no master data call: take them from the enumeration in the specification of the call you are making. Refuse to act on a published value you do not recognise rather than falling back to a default.
- Read every field in a response, not the one you came for. The M1 certificate call returns the encryption algorithm next to the key.
- Prove an assumption against a call that is able to disagree with you. A call that refuses every input with one message cannot tell you which input was right.
- Suspect the transport before the data. When a call refuses a value you believe in, check the encryption, the headers and the clock before you doubt the value.
- Do not carry an encryption path from one module to another. Read the certificate and the algorithm from the registry you are calling.
- Never log a sensitive value before you encrypt it, and never send one to a remote service to be encrypted. Both move the leak rather than removing it.
- Generate a fresh REQUEST-ID for every call and log it before sending. Once a call has failed it is the only handle on it.
- Check the host on any sample before you copy it. A request copied whole can be correct in every respect except where it is pointed, and that failure looks like credentials.
- Do not validate an identifier more strictly than the platform does. A schema that types a field as a UUID is not a promise that every value is one. Refusing a value ABDM would have accepted turns your own client into the thing that broke.
- Read a plural response as plural. A verification returns an accounts array and a consent request can produce more than one artefact. Store the collection and decide from its length.
- A documented callback path is not a documented callback payload. Log the whole body on arrival before you parse it, so a handler written against an assumed shape fails where you can see it.
- Decode a token before you use it. A call that hands you a token has not necessarily handed you the token the next call wants, and the claims are base64 that need no library to read.
- When a journey carries the same parameter through two calls, check what each call's specification asks for rather than carrying the first value forward.
- Do not infer which path an identifier belongs to from where that identifier is most discussed. Send every identifier to the lookup first and let the answer pick the path, so nobody who already holds an account is sent to create a second.
- Do not match an error code with string equality. A code may come back bare, as `ABDM-1001`, or with a trailing `: ` separator, as `ABDM-1001: `. Match on the code itself and tolerate the separator.
- Handle a failure that carries no body. Check for an empty body before you parse, or your client throws on the simplest failure there is.
- Back off on an authentication failure rather than retrying, and never loop a credential check.
- Send TIMESTAMP in UTC, ISO-8601 with milliseconds and a trailing Z, as in `2022-10-06T15:10:00.587Z`.
- Cache a public certificate with a validity window rather than forever. A rotation fails every encrypted call at once, and a cache with no expiry cannot recover on its own.
## Where the detail is
- Every endpoint, with its body fields and responses: /docs/hiecm/v3/api/p2
- Every error code across modules: /docs/hiecm/v3/reference/error-codes
- Terms: /docs/hiecm/v3/getting-started/glossary

View File

@ -0,0 +1,34 @@
# HIE-CM p2 debug
Every error below is an OODA loop: observe the error code and last request id, orient against the matched code, decide the fix, act, and observe whether the original step now succeeds. Applying a fix is not the exit condition; the original step succeeding is.
Loop limit: 5 passes per error.
## Errors
### 900902
**Specification example:** HTTP 401, `Missing Credentials`, on `p2_get_v3_phr_app_login_profile`.
**Exit condition: the original call now succeeds.**
### ABDM-9999
**Specification example:** HTTP 400, `Invalid LoginId`, on `p2_post_v3_phr_app_login_profile_request_otp`.
**Exit condition: the original call now succeeds.**
## Where the detail is
- The operation that returns each code: /docs/hiecm/v3/api/p2
## Every code in the specification
### Codes
| Code | HTTP | Message | Returned by |
| --- | --- | --- | --- |
| `900902` | 401 | Missing Credentials | `p2_get_v3_phr_app_login_profile` |
| `ABDM-9999` | 400 | Invalid LoginId | `p2_post_v3_phr_app_login_profile_request_otp` |
A code you meet that is not above is one the specifications do not carry yet. Read the code together with the message: a code can appear twice with different meanings.

Some files were not shown because too many files have changed in this diff Show More