npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@akhilesharora/abdm-abha-sdk

v1.1.0

Published

ABDM ABHA (Ayushman Bharat Health Account) SDK for Node.js - V3 API integration for Indian healthcare systems

Readme

ABDM ABHA SDK

Unofficial Version - This SDK is not affiliated with or endorsed by ABDM/NHA.

ABDM (Ayushman Bharat Digital Mission) ABHA integration SDK for Node.js applications.

Based on ABHA V3 APIs SOP V1.2 (October 2024) - Official Documentation.

npm version License: MIT

Features

  • Complete V3 API Types - Full TypeScript definitions for all ABHA V3 APIs
  • Validation Utilities - Validate ABHA numbers, addresses, mobile numbers, Aadhaar
  • Format Helpers - Format and parse ABHA identifiers
  • Constants - All API endpoints, scopes, error codes
  • Zero Dependencies - Lightweight, no external dependencies
  • Tree Shakeable - Import only what you need

Installation

npm install @akhilesharora/abdm-abha-sdk
yarn add @akhilesharora/abdm-abha-sdk
pnpm add @akhilesharora/abdm-abha-sdk

Quick Start

Validate ABHA Number

import { isValidABHANumber, formatABHANumber, maskABHANumber } from '@akhilesharora/abdm-abha-sdk'

// Validate format
isValidABHANumber('91-1234-5678-9012')  // true
isValidABHANumber('1234567890123')      // false (wrong format)

// Format raw digits
formatABHANumber('91123456789012')      // '91-1234-5678-9012'

// Mask for display
maskABHANumber('91-1234-5678-9012')     // 'XX-XXXX-XXXX-9012'

Validate ABHA Address

import { isValidABHAAddress, formatABHAAddress, parseABHAAddress } from '@akhilesharora/abdm-abha-sdk'

// Validate
isValidABHAAddress('john.doe@abdm')     // true (production)
isValidABHAAddress('test_user@sbx')     // true (sandbox)
isValidABHAAddress('[email protected]')    // false

// Format
formatABHAAddress('JohnDoe', 'production')  // 'johndoe@abdm'
formatABHAAddress('TestUser', 'sandbox')    // 'testuser@sbx'

// Parse
parseABHAAddress('john.doe@abdm')       // { username: 'john.doe', domain: 'abdm' }

Validate Mobile & Aadhaar

import { isValidMobile, isValidAadhaar, maskMobile, maskAadhaar } from '@akhilesharora/abdm-abha-sdk'

// Mobile (Indian 10-digit)
isValidMobile('9876543210')     // true
maskMobile('9876543210')        // 'XXXXXX3210'

// Aadhaar (12-digit)
isValidAadhaar('123456789012')  // true
maskAadhaar('123456789012')     // 'XXXXXXXX9012'

Complete Integration Example

Here's a full working example showing how to integrate ABHA login in your application:

import crypto from 'crypto'
import {
  ABDM_BASE_URLS,
  ABDM_SESSION_URLS,
  API_ENDPOINTS,
  SCOPES,
  LOGIN_HINTS,
  OTP_SYSTEMS,
  HEADERS,
  isValidABHANumber,
  formatABHAName,
} from '@akhilesharora/abdm-abha-sdk'
import type {
  ABHAProfile,
  OTPGenerateRequest,
  OTPVerifyRequest,
  OTPGenerateResponse,
  OTPVerifyResponse,
} from '@akhilesharora/abdm-abha-sdk'

// ============================================================================
// CONFIGURATION - Replace with your sandbox/production credentials
// ============================================================================
const config = {
  clientId: 'YOUR_CLIENT_ID',
  clientSecret: 'YOUR_CLIENT_SECRET',
  environment: 'sandbox' as const,
}

const BASE_URL = ABDM_BASE_URLS[config.environment]
const SESSION_URL = ABDM_SESSION_URLS[config.environment]

// ============================================================================
// HELPER: Generate required headers
// ============================================================================
function getHeaders(accessToken: string, userToken?: string) {
  const headers: Record<string, string> = {
    'Content-Type': 'application/json',
    [HEADERS.REQUEST_ID]: crypto.randomUUID(),
    [HEADERS.TIMESTAMP]: new Date().toISOString(),
    [HEADERS.AUTHORIZATION]: `Bearer ${accessToken}`,
  }
  if (userToken) {
    headers[HEADERS.X_TOKEN] = `Bearer ${userToken}`
  }
  return headers
}

// ============================================================================
// STEP 1: Get Session Token (call once, cache for 30 min)
// ============================================================================
async function getSessionToken(): Promise<string> {
  const response = await fetch(SESSION_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      clientId: config.clientId,
      clientSecret: config.clientSecret,
      grantType: 'client_credentials',
    }),
  })
  const data = await response.json()
  return data.accessToken  // Valid for 1800 seconds (30 min)
}

// ============================================================================
// STEP 2: Get RSA Public Key for encryption
// ============================================================================
async function getPublicKey(accessToken: string): Promise<string> {
  const response = await fetch(`${BASE_URL}${API_ENDPOINTS.PUBLIC_KEY}`, {
    headers: getHeaders(accessToken),
  })
  const data = await response.json()
  return data.publicKey  // PEM format RSA public key
}

// ============================================================================
// STEP 3: RSA Encrypt sensitive data (ABHA number, OTP, etc.)
// ============================================================================
function rsaEncrypt(data: string, publicKeyPem: string): string {
  const buffer = Buffer.from(data, 'utf8')
  const encrypted = crypto.publicEncrypt(
    {
      key: publicKeyPem,
      padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
      oaepHash: 'sha1',  // ABDM requires SHA-1 for OAEP
    },
    buffer
  )
  return encrypted.toString('base64')
}

// ============================================================================
// STEP 4: Request OTP
// ============================================================================
async function requestOTP(
  accessToken: string,
  publicKey: string,
  abhaNumber: string
): Promise<{ txnId: string; message: string }> {
  // Validate before sending
  if (!isValidABHANumber(abhaNumber)) {
    throw new Error('Invalid ABHA number format. Expected: XX-XXXX-XXXX-XXXX')
  }

  const request: OTPGenerateRequest = {
    scope: [SCOPES.ABHA_LOGIN, SCOPES.MOBILE_VERIFY],
    loginHint: LOGIN_HINTS.ABHA_NUMBER,
    loginId: rsaEncrypt(abhaNumber.replace(/-/g, ''), publicKey),  // Encrypt without dashes
    otpSystem: OTP_SYSTEMS.ABDM,
  }

  const response = await fetch(`${BASE_URL}${API_ENDPOINTS.LOGIN_REQUEST_OTP}`, {
    method: 'POST',
    headers: getHeaders(accessToken),
    body: JSON.stringify(request),
  })

  const data: OTPGenerateResponse = await response.json()
  return { txnId: data.txnId, message: data.message }
}

// ============================================================================
// STEP 5: Verify OTP and get profile
// ============================================================================
async function verifyOTP(
  accessToken: string,
  publicKey: string,
  txnId: string,
  otp: string
): Promise<{ profile: ABHAProfile; tokens: { token: string; refreshToken: string } }> {
  const request: OTPVerifyRequest = {
    scope: [SCOPES.ABHA_LOGIN, SCOPES.MOBILE_VERIFY],
    authData: {
      authMethods: ['otp'],
      otp: {
        txnId,
        otpValue: rsaEncrypt(otp, publicKey),
      },
    },
  }

  const response = await fetch(`${BASE_URL}${API_ENDPOINTS.LOGIN_VERIFY}`, {
    method: 'POST',
    headers: getHeaders(accessToken),
    body: JSON.stringify(request),
  })

  const data: OTPVerifyResponse = await response.json()
  return {
    profile: data.ABHAProfile,
    tokens: {
      token: data.tokens.token,           // User token for profile APIs
      refreshToken: data.tokens.refreshToken,
    },
  }
}

// ============================================================================
// USAGE EXAMPLE
// ============================================================================
async function loginWithABHA(abhaNumber: string, otp: string) {
  // 1. Get session token (cache this!)
  const accessToken = await getSessionToken()

  // 2. Get public key (cache for a few hours)
  const publicKey = await getPublicKey(accessToken)

  // 3. Request OTP
  const { txnId } = await requestOTP(accessToken, publicKey, abhaNumber)
  console.log('OTP sent! Transaction ID:', txnId)

  // 4. User enters OTP, then verify
  const { profile, tokens } = await verifyOTP(accessToken, publicKey, txnId, otp)

  // 5. Use the profile
  console.log('Welcome,', formatABHAName(profile))
  console.log('ABHA Number:', profile.ABHANumber)
  console.log('ABHA Address:', profile.preferredAbhaAddress)
  console.log('KYC Verified:', profile.kycVerified)

  // Store tokens.token for subsequent API calls
  return { profile, userToken: tokens.token }
}

// Example call (in your API route or service)
// await loginWithABHA('91-1234-5678-9012', '123456')

Key Points

  1. Session Token: Call once, cache for 30 minutes. Used in all API calls.
  2. Public Key: Fetch once per session. Used to encrypt all sensitive data.
  3. Encryption: ALL sensitive data (ABHA, mobile, Aadhaar, OTP) must be RSA encrypted.
  4. Headers: Every request needs REQUEST-ID (UUID) and TIMESTAMP (ISO 8601).
  5. User Token: After login, use X-token header for profile APIs.

Express.js Route Example

import express from 'express'
import { isValidABHANumber, isValidOTP } from '@akhilesharora/abdm-abha-sdk'

const router = express.Router()

// POST /api/abha/request-otp
router.post('/request-otp', async (req, res) => {
  const { abhaNumber } = req.body

  if (!isValidABHANumber(abhaNumber)) {
    return res.status(400).json({ error: 'Invalid ABHA number format' })
  }

  const { txnId } = await requestOTP(accessToken, publicKey, abhaNumber)
  res.json({ txnId, message: 'OTP sent to registered mobile' })
})

// POST /api/abha/verify-otp
router.post('/verify-otp', async (req, res) => {
  const { txnId, otp } = req.body

  if (!isValidOTP(otp)) {
    return res.status(400).json({ error: 'OTP must be 6 digits' })
  }

  const { profile, tokens } = await verifyOTP(accessToken, publicKey, txnId, otp)
  res.json({ profile, token: tokens.token })
})

API Reference

Types

import type {
  ABHAProfile,
  ABHATokens,
  ABHASession,
  OTPGenerateRequest,
  OTPVerifyResponse,
  MobileLoginResponse,
  ABHAAccountSummary,
} from '@akhilesharora/abdm-abha-sdk'

Constants

import {
  ABDM_BASE_URLS,
  ABDM_SESSION_URLS,
  API_ENDPOINTS,
  SCOPES,
  LOGIN_HINTS,
  OTP_SYSTEMS,
  ERROR_CODES,
} from '@akhilesharora/abdm-abha-sdk'

// Base URLs
ABDM_BASE_URLS.sandbox      // 'https://abhasbx.abdm.gov.in/abha/api'
ABDM_BASE_URLS.production   // 'https://abha.abdm.gov.in/api/abha'

// Scopes
SCOPES.ABHA_ENROL           // 'abha-enrol'
SCOPES.ABHA_LOGIN           // 'abha-login'
SCOPES.MOBILE_VERIFY        // 'mobile-verify'

// Login Hints
LOGIN_HINTS.ABHA_NUMBER     // 'abha-number'
LOGIN_HINTS.MOBILE          // 'mobile'
LOGIN_HINTS.AADHAAR         // 'aadhaar'

// OTP Systems
OTP_SYSTEMS.AADHAAR         // 'aadhaar' (OTP to Aadhaar-linked mobile)
OTP_SYSTEMS.ABDM            // 'abdm' (OTP to ABHA-linked mobile)

Validation Functions

| Function | Description | |----------|-------------| | isValidABHANumber(value) | Validate XX-XXXX-XXXX-XXXX format | | isValidABHAAddress(value) | Validate username@abdm format | | isValidMobile(value) | Validate 10-digit Indian mobile | | isValidAadhaar(value) | Validate 12-digit Aadhaar | | isValidOTP(value) | Validate 6-digit OTP | | isValidPinCode(value) | Validate 6-digit PIN code |

Format Functions

| Function | Description | |----------|-------------| | formatABHANumber(digits) | Format 14 digits to XX-XXXX-XXXX-XXXX | | formatABHAAddress(username, env) | Create username@abdm or @sbx | | formatMobile(mobile) | Format as 98765 43210 | | formatAadhaar(aadhaar) | Format as 1234 5678 9012 | | formatABHAName(profile) | Combine first/middle/last name |

Mask Functions

| Function | Description | |----------|-------------| | maskABHANumber(value) | XX-XXXX-XXXX-1234 | | maskMobile(value) | XXXXXX3210 | | maskAadhaar(value) | XXXXXXXX9012 |

Gender Helpers

import { toABHAGender, fromABHAGender, getGenderDisplay } from '@akhilesharora/abdm-abha-sdk'

toABHAGender('MALE')        // 'M'
fromABHAGender('M')         // 'MALE'
getGenderDisplay('M')       // 'Male'

Date Helpers

import { parseABHADate, toABHADate, calculateAge } from '@akhilesharora/abdm-abha-sdk'

parseABHADate('26-11-1989')  // Date object
toABHADate(new Date())       // '10-02-2026'
calculateAge('26-11-1989')   // 36

API Endpoints

Base URLs

| Environment | URL | |-------------|-----| | Sandbox | https://abhasbx.abdm.gov.in/abha/api | | Production | https://abha.abdm.gov.in/api/abha | | Session (Sandbox) | https://dev.abdm.gov.in/api/hiecm/gateway/v3/sessions | | PHR (Sandbox) | https://abhasbx.abdm.gov.in/abha/api/v3/phr/web |

Key Endpoints

| Endpoint | Method | Description | |----------|--------|-------------| | /v3/profile/public/certificate | GET | Get RSA public key | | /v3/enrollment/request/otp | POST | Generate OTP for enrollment | | /v3/enrollment/enrol/byAadhar | POST | Create ABHA via Aadhaar | | /v3/profile/login/request/otp | POST | Generate OTP for login | | /v3/profile/login/verify | POST | Verify OTP and get profile | | /v3/profile/account | GET | Get ABHA profile | | /v3/profile/account/qrCode | GET | Generate QR code | | /v3/profile/account/abha-card | GET | Get ABHA card |

Typical Flows

Login via ABHA OTP (Recommended for HIP)

import { API_ENDPOINTS, SCOPES, LOGIN_HINTS, OTP_SYSTEMS } from '@akhilesharora/abdm-abha-sdk'
import type { OTPGenerateRequest, OTPVerifyRequest, OTPVerifyResponse } from '@akhilesharora/abdm-abha-sdk'

// Step 1: Generate OTP
const otpRequest: OTPGenerateRequest = {
  scope: [SCOPES.ABHA_LOGIN, SCOPES.MOBILE_VERIFY],
  loginHint: LOGIN_HINTS.ABHA_NUMBER,
  loginId: encryptedABHANumber,  // RSA encrypted
  otpSystem: OTP_SYSTEMS.ABDM,
}

// POST to API_ENDPOINTS.LOGIN_REQUEST_OTP

// Step 2: Verify OTP
const verifyRequest: OTPVerifyRequest = {
  scope: [SCOPES.ABHA_LOGIN, SCOPES.MOBILE_VERIFY],
  authData: {
    authMethods: ['otp'],
    otp: {
      txnId: txnIdFromStep1,
      otpValue: encryptedOTP,  // RSA encrypted
    },
  },
}

// POST to API_ENDPOINTS.LOGIN_VERIFY
// Response includes tokens + ABHAProfile

Mobile Login (Multiple Accounts)

When logging in via mobile number, the response includes an accounts array since multiple ABHAs can be linked to one mobile:

import type { MobileLoginResponse, ABHAAccountSummary } from '@akhilesharora/abdm-abha-sdk'

// Response structure
const response: MobileLoginResponse = {
  tokens: { ... },
  accounts: [
    {
      ABHANumber: '91-4819-7073-XXXX',
      preferredAbhaAddress: 'user@sbx',
      name: 'John Doe',
      status: 'ACTIVE',
      profilePhoto: '...',  // Base64
    },
    // ... more accounts
  ],
}

Required Headers

All V3 APIs require these headers:

| Header | Description | |--------|-------------| | REQUEST-ID | UUID for tracking | | TIMESTAMP | ISO 8601 timestamp | | Authorization | Bearer {accessToken} from session API | | X-token | Bearer {userToken} (for profile APIs after login) |

Encryption

All sensitive data (Aadhaar, Mobile, OTP, Password) must be RSA encrypted using the public key from /v3/profile/public/certificate.

import { ENCRYPTION } from '@akhilesharora/abdm-abha-sdk'

// Algorithm: RSA/ECB/OAEPWithSHA-1AndMGF1Padding
console.log(ENCRYPTION.ALGORITHM)

Error Handling

import { ERROR_CODES } from '@akhilesharora/abdm-abha-sdk'

// Common error codes
ERROR_CODES.INVALID_ABHA_NUMBER    // 'ABHA_INVALID_NUMBER'
ERROR_CODES.OTP_EXPIRED            // 'ABHA_OTP_EXPIRED'
ERROR_CODES.PROFILE_NOT_FOUND      // 'ABHA_PROFILE_NOT_FOUND'
ERROR_CODES.SESSION_EXPIRED        // 'ABHA_SESSION_EXPIRED'

ABHAProfile Structure

interface ABHAProfile {
  // Identity
  ABHANumber: string        // '91-1601-4548-XXXX'
  phrAddress?: string[]     // ['user@sbx']
  preferredAbhaAddress?: string

  // Name (from Aadhaar KYC)
  firstName: string
  middleName?: string
  lastName: string

  // Demographics
  dob: string               // 'DD-MM-YYYY'
  gender: 'M' | 'F' | 'O'
  mobile: string            // Masked: '******1670'
  email?: string

  // Address (from Aadhaar)
  address?: string
  stateName?: string
  districtName?: string
  pinCode?: string

  // Status
  abhaType: 'STANDARD' | 'CHILD'
  abhaStatus: 'ACTIVE' | 'INACTIVE' | 'DELETED' | 'DEACTIVATED'

  // Verification
  kycVerified?: boolean
  verificationStatus?: string
  verificationType?: string
  authMethods?: string[]

  // Photo
  photo?: string            // Base64 JPEG
}

Requirements

  • Node.js >= 16.0.0
  • TypeScript >= 5.0 (for TypeScript users)

License

MIT

Contributing

Contributions are welcome! Please read our contributing guidelines before submitting a pull request.

Resources

Author

Akhilesh Arora