ABDM v3 · M1–M4 implemented

Developers ABDM API

The ABDM API, as ordinary REST and webhooks

ABDM v3 is a gateway, a consent manager, two registries and a callback for almost every call. This API puts one REST surface over all of it: a bearer token, JSON in and out, and a signed webhook when ABDM answers.

01 Conventions

Six rules that hold on every endpoint

Learn these once and the other ninety-odd endpoints read the same way.

Errors

One envelope, a stable code

{"error": {"code", "message", "details", "request_id"}}. The code is stable and safe to branch on; the message is for people.

Validation

422 with per-field detail

A request that is well-formed but wrong gets a 422 naming each field. 400 is kept for input that is genuinely malformed.

Async

202 means accepted, never completed

ABDM answers linking, consent and data requests later, on another channel. A 202 says ABDM took the request; the outcome arrives by webhook.

Retries

Idempotency-Key on writes

Send one on a POST, PUT or PATCH and a retry replays the original response instead of creating a second link request.

Correlation

X-Request-Id, all the way through

Echoed back on the response, threaded through the ABDM calls it causes, and stamped on the webhooks that come back as correlation_id.

Lists

Cursor pagination

Stable under concurrent writes, so a page boundary does not skip or repeat a record while a busy OPD is registering patients.

02 Authentication

Client credentials, then a bearer token

These are your credentials for this API. The connector’s own ABDM credentials are never exposed through it.

  1. Issue a credential

    From the portal, under Settings → API keys. The secret is returned once and stored hashed. Ask for a subset of your application’s scopes; asking for one it is not entitled to is refused with 403, not silently dropped.

  2. Exchange it for a token

    POST /v1/auth/token, grant type client_credentials. The token is valid for an hour and names its environment.

  3. Check it before you trust it

    GET /v1/auth/whoami returns the application, its milestone capabilities and the token’s scopes — the fastest way to explain a 403 insufficient_scope.

  4. Contain and rotate

    An IP allowlist per credential is enforced at the token endpoint and on every request. Rotation issues a successor and keeps the old key working for a 24-hour grace period while you deploy.

authenticate Sandbox
POST /v1/auth/token
{
  "client_id": "swk_sand_…",
  "client_secret": "sk_sand_…",
  "grant_type": "client_credentials",
  "scope": "patient:write care_context:write"
}

← 200 OK
{
  "access_token": "eyJ…",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "patient:write care_context:write",
  "environment": "sandbox"
}

# then, on every request
Authorization: Bearer eyJ…
Idempotency-Key: link-OPD-2291

03 Resource map

The API by ABDM milestone

A credential only reaches the milestones its application is entitled to. The full list, with request and response schemas, is in the API reference.

AreaMain endpointsAnswers arrive as
System /v1/auth/token, /v1/auth/whoami, /v1/facility, /v1/facility/scan-share-qr Synchronous
M1 · ABHA /v1/abha/enrolment/aadhaar, /v1/abha/enrolment/document, /v1/abha/login, /v1/abha/sessions/{session_id}/profile, /card, /qr abha.created, abha.verified
M2 · HIP /v1/patients, /v1/care-contexts, /v1/care-contexts/link, /v1/link-requests/{link_request_id}, /v1/discoveries care_context.link_requested, care_context.linked, care_context.link_failed, consent.notified, health_information.requested, health_information.sent, health_information.failed
M3 · HIU /v1/consents, /v1/consent-artefacts, /v1/health-information, /v1/records, /v1/records/{bundle_id}/content consent.request_acknowledged, consent.granted, consent.denied, consent.revoked, consent.expired, health_information.received, health_information.erased
M4 · HFR Your hospital’s HFR record on /v1/facility; registration and bridge linkage in the portal Synchronous
M4 · HPR /v1/practitioners (your hospital’s roster), /v1/hpr/professionals, /v1/hpr/enrolments, /v1/hpr/registrations Synchronous
Webhooks Set up per application in the portal — signed deliveries to your URL —
Audit /v1/audit/events, /v1/audit/requests, /v1/audit/abdm-transactions, /v1/audit/trace/{correlation_id} —

You send flat JSON; FHIR is built for you. A care context can carry a bundle you built, or plain fields the connector turns into an NRCeS-profiled FHIR R4 document — see FHIR integration. For what a HIP has to do with those records under consent, see HIP integration.

04 Webhooks

ABDM’s callbacks, as one signed event

ABDM calls the connector’s bridge. The connector verifies the gateway’s token, stores the callback, matches it to your request and posts one event to your endpoint.

a delivery Sandbox
POST https://your-hmis.example/abdm/events
X-Swastik-Event: care_context.linked
X-Swastik-Event-Id: 9c0e…
X-Swastik-Signature: t=17572…,v1=4f1a…

{
  "id": "9c0e…",
  "event": "care_context.linked",
  "created_at": "2026-09-07T10:31:12+05:30",
  "correlation_id": "5f3c9a1e",
  "data": {
    "patient_reference": "MRN-90881",
    "care_contexts": ["OPD-2291"]
  }
}

# verify before parsing
signed_payload = f"{t}.{raw_body}"
hmac_sha256(secret, signed_payload) == v1

Signing

Verify, then parse

HMAC-SHA256 over the timestamp and the raw body, with the secret returned once when you register the endpoint. Compare in constant time and reject a t older than five minutes.

Content

Identifiers, never records

Payloads carry ids and status. Clinical content is fetched over the authenticated API, where the read is logged against your credential.

Delivery

Retried, then retryable by you

Failed deliveries back off from seconds to hours. An exhausted one can be re-queued from the portal’s Webhooks page.

Failure

Silence is not an outcome

An ABDM call that fails every retry raises abdm.error, so a record nobody shared does not look shared.

05Idempotency, three ways

ABDM delivers at least once and hospital systems retry, so a request can arrive twice from either direction. Each direction is handled where it belongs.

  • You to the connector. The first response for an Idempotency-Key is stored and replayed. The key is bound to the request body: reuse it with different data and you get 409 idempotency_key_reuse, never a stale success. A failed request is not stored, so retrying the same key can still get through.
  • ABDM to the connector. Every callback is persisted before it is processed, and a duplicate of the same gateway request id is recognised rather than applied twice.
  • The connector to ABDM. Retries reuse the same request id, which ABDM de-duplicates on, and a re-delivered data request reuses its transfer instead of sending the records again.

06Errors you can branch on

The status says who has to act; the code says what happened. A few worth handling explicitly:

  • 401 token_expired — exchange the credential again. Tokens last an hour.
  • 403 insufficient_scope — the token lacks a scope; /v1/auth/whoami shows which it has.
  • 403 ip_not_allowed — the request came from outside the credential’s allowlist.
  • 403 production_access_not_granted — a production call from an organization not yet approved.
  • 422 with an abdm_ code — ABDM rejected the request itself, and its own error code is passed through, because that is what separates an expired OTP from a malformed one.
  • 429 abdm_rate_limited — ABDM is throttling; retry later rather than immediately.
  • 503 — ABDM could not be reached, the request was not delivered, and the identical request is safe to retry.

07When you cannot receive webhooks

Webhooks are the normal path, but the state behind every event is also readable. An on-premise system that cannot expose an HTTPS endpoint can poll the request it made: GET /v1/link-requests/{link_request_id} for a link, GET /v1/consents/{consent_request_id} for a consent request, GET /v1/health-information/{hi_request_id} for a data request.

POST /v1/consents/{consent_request_id}/refresh re-asks ABDM itself, and is for a notification that appears lost. Calling it on a schedule spends a rate limit that every tenant of the connector shares.

08Audit and the end-to-end trace

Four read endpoints answer “what happened” without a support ticket. /v1/audit/requests lists your API calls with status and duration. /v1/audit/abdm-transactions lists the calls the connector made to ABDM for you, with the abdm_request_id ABDM support will ask for. /v1/audit/events records privacy-significant changes.

/v1/audit/trace/{correlation_id} puts them together: your call, the ABDM calls it caused and the audit events that followed, under one id. It is the shortest route from “this didn’t work” to where it stopped. For the flow those ids follow, read how ABDM integration works.

Read the spec, then call it

Sandbox keys are issued on email verification. The reference has curl, Python and JavaScript for every endpoint.

FAQ Common questions

Frequently asked questions

How do I authenticate to the ABDM API?
Exchange your client id and secret for a bearer token at POST /v1/auth/token using the OAuth2 client-credentials grant. The token is valid for an hour and carries the scopes granted to that credential.
How are ABDM callbacks delivered to my application?
As signed webhooks. The connector receives ABDM's asynchronous callbacks, verifies and correlates them, and posts one event — such as care_context.linked or consent.granted — to your HTTPS endpoint, signed with a secret you verify.
Is there an OpenAPI specification for the ABDM API?
Yes. The full OpenAPI reference is in the portal, with copy-pasteable curl, Python and JavaScript for every endpoint and a test console that makes real sandbox calls.
Are ABDM API requests safe to retry?
Yes. Send an Idempotency-Key header and the first response is stored and replayed on a retry. Reusing a key with a different body is refused with a 409 rather than answered with a stale success.