Participant registry
Get session token
Exchanges the participant's client_id and client_secret (OAuth 2.0 client credentials) for a Bearer access_token valid for 1200 seconds.
### Business purpose
Every NHCX API call, whether a registry lookup, a certificate fetch or a claim submission, is rejected unless it carries a valid Bearer token, so this is the first call any integration makes and the first thing to check when a working integration starts failing. It answers the question of who is calling the gateway. It is deliberately separate from payload confidentiality: a request can be perfectly encrypted and still fail with 401, and vice versa.
### When to use
Call it at start-up and whenever the cached token is close to expiry. The Integration Handbook documents it as POST /get/session on host apisbx.abdm.gov.in with Content-Type application/x-www-form-urlencoded and body client_id=<NHCX_CLIENT_ID>&client_secret=<NHCX_CLIENT_SECRET>&grant_type=client_credentials. The response carries access_token, expires_in 1200 and token_type Bearer. Both sandbox-exit checklists list /get/session as the auth-token API. Note that the FAQ instead lists https://dev.abdm.gov.in/api/hiecm/gateway/v3/sessions as the Session API, and the OpenAPI entry (operationId getSession) calls the operation internal and returns ParticipantSessionResponse with a single accessToken field; confirm the current host with your onboarding contact. There is no refresh token: renewal is simply another client-credentials call.
### Preconditions
- client_id and client_secret issued at the end of onboarding; client_secret is generated by the NHCX instance, stored encrypted and never returned by any registry API, so a lost secret must be reissued. - Credentials scoped to the right environment; sandbox credentials do not work against production and vice versa. - Content-Type application/x-www-form-urlencoded with grant_type=client_credentials fixed; the two secrets are the only variables. - No Bearer token is needed for this call itself.
### Postconditions
HTTP 200 with { access_token, expires_in: 1200, token_type: Bearer }. The access_token is a JWT that should be treated as opaque; place it in the Authorization (bearer_auth) header as Bearer <token> on every subsequent call. Its lifetime is 1200 seconds (20 minutes); after that any call returns 401. The OpenAPI schema names the field accessToken and omits expiry, so read whichever key is present and assume 1200 seconds when expires_in is absent. A 400 indicates a malformed body. Nothing asynchronous follows.
### Common mistakes
- Not implementing automatic refresh, so calls that worked minutes ago start returning 401 or 401 Unauthorized - Sender is not authorized to execute the operation once 20 minutes pass. - Sending the token without the Bearer prefix in bearer_auth, which also produces a plain 401. - Using the wrong Content-Type (JSON instead of form-urlencoded), omitting grant_type=client_credentials, or misspelling a credential field, which yields 400. - Minting a fresh token for every transaction instead of caching it. - Continuing to use a cached client_secret after the instance rotated it; every token minted from the old secret stops working. - Pairing a sandbox token with the production gateway.
### Best practices
- Cache the token in memory keyed by environment and refresh proactively at roughly 80 to 90 percent of the lifetime computed from the expires_in actually received. - Serialise refresh behind a lock so concurrent workers do not fire simultaneous token requests. - On any 401, discard the cached token, mint a new one and replay the original request exactly once; if the second attempt also fails, stop and alert, since the credentials are wrong or revoked. - Never log the access_token or client_secret; log the expiry timestamp instead. - Store secrets so they can be rotated without a code deploy. - The token is validated by ABDM, so a 401 on any NHCX call carries no hint that expiry is the cause; treat 401 as refresh-and-retry first.
### Related scenario
At 09:00 a hospital's claims engine starts and POSTs its client_id and client_secret to /get/session, receiving an access_token with expires_in 1200. It caches the token and immediately calls /fetch/certs for the payer it will submit to. At 09:17 a background timer renews the token before the 20-minute mark, so the /v1/preauth/submit sent at 09:21 carries a fresh Bearer header. Later a worker receives a 401 after a network stall; it drops the cached token, calls /get/session once more, replays the request and succeeds. Had the second attempt also failed, the engine would have alerted operations rather than looping.
### Specification
Chapter [Base URLs](/docs/nhcx/v1/getting-started/base-urls) of the NHCX integration specification. On every NHCX call, the token goes in a header called It is HTTP 200 with { access_token, expires_in: 1200, token_type: Bearer }.Authorizations
Authorizationbearer tokenRequiredbearer_auth, with the word Bearer and a space in front. The sources are not unanimous: the authentication page and the FAQ both write the example as Authorization, and the notification endpoint uses Authorization. The safe course, and what the adapter does, is to send both headers with the same value.Headers
bearer_authstringRequiredbearer_auth, not Authorization, on NHCX's own endpoints.Body
_contentTypestringclient_idstringclient_secretstringgrant_typestringResponses
200