NPS Zaruri Hai
Technical document

Account Information – Status, profile, portfolio, returns and transactions

The eight read APIs for an existing subscriber's accounts

The eight read APIs for an existing subscriber's accounts — what each returns, how partial results from several CRAs are reported, and how to page and filter.

Version
Version 1.0
Status
Final
Last updated
Updated 12/10/2026
Audience:
Registered partners (points of presence)
Prepared by:
NPS Central Engineering
Document control
Title
Account Information — Status, profile, portfolio, returns and transactions
Version
1.0
Status
Issued
Date of issue
12 October 2026
Owner
NPS Central Engineering
Classification
Confidential — for registered partners

1About this document

This document describes the eight APIs that read an existing subscriber's NPS accounts: status, profile, portfolio, holdings, returns, transactions, recent contributions and the contribution tracker. It is written for engineers building account screens, statements or reconciliation on top of the Partner API.

A subscriber may hold accounts at more than one Central Recordkeeping Agency (CRA). NPS Central asks each CRA and combines the answers into one response, and most of what is particular to these APIs follows from that: how a response says that one CRA did not answer, how fields that a CRA does not provide are reported, and how totals are formed. Section 3 explains this and is worth reading before the individual reads.

1.1Notation

In field tables, the presence column shows M for a field that is always present when the account is READY, and O for one that may be absent. Money means a decimal string with two places, such as "184250.37"; units and NAV are decimal strings with four places. The API refers to an existing subscriber as the subject, which is why paths and fields carry names such as subjectRef and subject-links.

2Before you begin

Credential
A subscriber session token, from an OTP subject link or an asserted session
Scope
subject:read
Method
GET, synchronous. No request body and no Idempotency-Key.
Encryption
If your account encrypts payloads, responses arrive in the NPSC envelope (application/vnd.npsc.envelope+json); see Payload Encryption.
Path parameter
subjectRef — the value returned when the session was opened. Any other value returns 404.

2.1The APIs at a glance

APIPath (under /v1/subjects/{subjectRef})Key in each accountReturns
Account status/statusstatusEach tier's status and the POP / POP-SP it is registered under
Profile/profileprofileIdentity, personal details, contact, addresses, banks, nominees
Portfolio/portfolioportfolioValue, contributions, gain or loss, allocation and holdings per tier, plus totals across accounts
Holdings/holdingsholdingsPer-scheme units, NAV and value
Returns/returnsreturnsXIRR per account and per tier
Transactions/transactionstransactionsThe transaction ledger, paged
Recent contributions/contributions/recentcontributions_recentThe latest credited contributions
Contribution tracker/contributions/trackercontributions_trackerContributions made but not yet converted to units

2.2Query parameters

ParameterApplies toDescription
pranAll APIsReturns one account only. The response shape is unchanged; accounts[] has one entry. Must be an account in the session, otherwise 404.
tierAll APIsTIER_1 or TIER_2. On transactions and recent contributions it keeps rows labelled with that tier; if a CRA left rows unlabelled, the tier field is listed in meta.unavailableFields.
from, toTransactionsYYYY-MM-DD. If omitted, to defaults to today and from to one year before to. The window may not exceed 366 days.
orderTransactionsNEWEST_FIRST or OLDEST_FIRST: sorts by transactionDate across all accounts before paging. If omitted, each CRA's own order is kept, account by account.
limitTransactions, recent contributionsPage size. Default 25, maximum 100.
cursorTransactionsThe previous page's page.nextCursor.

3How responses are structured

3.1The envelope

Every read has the same outer shape: data.accounts[] holds one entry per account, with the read's data under the key shown in section 2.1, and meta describes the response as a whole.

Response envelopeJSON
{
  "data": {
    "subjectRef": "sub_01JA6Z3KQ8M4N7P2R5S9T1V0WZ",
    "accounts": [
      { "pran": "110012345678", "craRef": "cra_7f3a", "craCode": "PROTEAN",
        "craName": "Protean eGov Technologies Limited", "state": "READY",
        "fetchedAt": "2026-10-09T10:16:02.000Z",
        "portfolio": { "…": "the account's data" } },
      { "pran": "400011506418", "craRef": "cra_91c2", "craCode": "KFIN",
        "craName": "KFin Technologies Limited", "state": "UNAVAILABLE",
        "reason": "SOURCE_TIMEOUT" }
    ],
    "totals": {
      "basis": "PARTIAL",
      "includedAccounts": [ { "pran": "110012345678", "craRef": "cra_7f3a" } ],
      "currentValue": "184250.37", "totalContribution": "150000.00",
      "notionalGainLoss": "34250.37"
    }
  },
  "meta": {
    "fetchedAt": "2026-10-09T10:16:02.000Z",
    "freshness": "LIVE",
    "completeness": "PARTIAL",
    "unavailableFields": ["portfolio.amountInTransit"]
  }
}

3.2Account entries

Every account entry, and every row that refers to an account, identifies it the same way. In the field tables that follow, these four are referred to as the account reference.

FieldDescription
pranThe account's 12-digit PRAN.
craRefThe CRA holding the account: an opaque, stable handle (cra_…). Store and correlate on this.
craCodeCAMS, KFIN or PROTEAN. For display.
craNameThe CRA's registered entity name. For display.
stateREADY — data present. PENDING — still being fetched; ask again shortly. UNAVAILABLE — see reason. STALE — an earlier answer is being shown. NOT_ASKED — the CRA was not asked for this read.
reasonWith UNAVAILABLE: NOT_SUPPORTED (permanent), SOURCE_TIMEOUT or SOURCE_ERROR (temporary — retry later), NO_DATA (the CRA answered and holds nothing yet).
fetchedAtWhen the data was obtained.

3.3meta, totals and page

FieldDescription
meta.fetchedAtWhen the response was assembled.
meta.freshnessLIVE (asked of the CRA now) or CACHED (answered earlier in this session). STALE_ON_ERROR is used only on the profile read.
meta.cacheTtlSecondsHow long the answer may be reused.
meta.completenessCOMPLETE, or PARTIAL when any account or field is missing.
meta.unavailableFieldsFields left out because a CRA does not provide them, e.g. portfolio.amountInTransit.
meta.sources[]Per account: the account reference, state, reason, fetchedAt, and with PENDING a since timestamp.
data.totalsPortfolio read only. Sums across accounts in state READY: basis, includedAccounts[], asOf, currentValue, totalContribution, notionalGainLoss. Rates are never totalled.
pageTransactions only. hasMore, nextCursor (absent on the last page) and limit.

3.4Rules that apply to every read

  • Absent, never null or zero. A field a CRA cannot supply is left out of the response and named in meta.unavailableFields. A zero is always a real zero. Do not default missing values to 0 in your own model.
  • Money is a string with two decimal places; units and NAV are strings with four. Parse them into a decimal type, not a floating-point number. Rates and percentages are JSON numbers.
  • Correlate on craRef, display craCode or craName.
  • Asserted sessions see only the accounts the session holds; a session opened by PRAN alone holds that one account. A pran filter naming any other account returns 404.

4The APIs

The tables in this section describe the per-account object, that is data.accounts[].<key>.

4.1Account status

GET/v1/subjects/{subjectRef}/statusAccount status
Query
pran, tier

The account inventory: which tiers are open, and which POP / POP-SP each is registered under.

Fields
  • account reference
    objectRequired

    See section 3.2.

  • tiers[].tier
    enumOptional

    TIER_1 or TIER_2.

  • tiers[].status
    enumOptional

    ACTIVE, FROZEN, CLOSED or UNKNOWN. CLOSED also covers accounts the CRA reports as inactive or suspended.

  • tiers[].freezeReason
    stringOptional

    With FROZEN, the reason where known.

  • tiers[].pop
    objectOptional

    popRegNo and popSpRegNo (7 digits each): the point of presence and service provider the tier is registered under. Per tier.

4.2Profile

GET/v1/subjects/{subjectRef}/profileProfile
Query
pran, tier

The subscriber's details as each account's CRA holds them. PAN, contact details and bank account numbers are masked. Because each CRA keeps its own record, two accounts can show different details for the same person; that is a real difference to resolve with a modification, not a fault in the read.

Block / fieldDescription
identitypan (masked), kycMode, kycReference, cersaiId (the CKYC number, masked).
personname, nameParts, dateOfBirth, gender, maritalStatus, fatherName, motherName, spouseName.
contactmobile and email (masked), mobileVerified, emailVerified. An absent verification flag means the CRA does not report it, not false.
addresses[]type (PERMANENT, CORRESPONDENCE, OFFICE), line1–line4, city, stateCode, pinCode, country. Where a CRA delivers the address as one unsplit string, it is in raw instead.
banks[]tier, accountNumber (masked), ifsc, accountType, bankName, verificationStatus, pennyDropVerified.
nominees[]tier, name, relationship, sharePercentage (integers totalling 100 within a tier), dateOfBirth, isMinor, guardianName.
sectorrawCode and rawText as the CRA records them; resolved where the CRA publishes a code table. Raw codes are not comparable across CRAs.
openedOnThe PRAN generation date, where the CRA states it.
sourceExtensionsFields only one CRA reports. Carried for completeness; do not build logic on them.

4.3Portfolio

GET/v1/subjects/{subjectRef}/portfolioPortfolio
Query
pran, tier

The account's position, with figures per tier, today's allocation, the subscriber's chosen split for future contributions, and holdings. data.totals sums the READY accounts (section 3.3).

Account and tier figures
  • asOf
    datetimeOptional

    Valuation date. Where it is derived from per-scheme NAV dates, the earliest is used.

  • currentValue
    moneyOptional

    Value today.

  • totalContribution
    moneyOptional

    Contributions to date.

  • notionalGainLoss
    moneyOptional

    Gain or loss. Never computed from a partial contribution history.

  • totalWithdrawal
    moneyOptional

    Withdrawn to date. On the account, present only when every tier states it.

  • amountInTransit
    moneyOptional

    Contributions received but not yet converted to units.

  • tiers[]
    arrayOptional

    The same five money fields per tier, plus tier, status and the investment-choice fields.

  • tiers[].investmentChoice
    stringOptional

    ACTIVE, AUTO, LC25, LC50 or LC75, or the CRA's own wording. Absent where the tier's schemes disagree.

  • tiers[].pfmCode
    stringOptional

    The pension fund manager running every scheme in the tier.

  • tiers[].allocation[]
    arrayOptional

    What the tier is worth today, by asset class: assetClass (E, C, G, A), percentage and value.

  • tiers[].schemePreference[]
    arrayOptional

    How future contributions are split across schemes.

  • tiers[].holdings[]
    arrayOptional

    Per-scheme holdings (section 4.4). Absent where the CRA reports only aggregates.

4.4Holdings

GET/v1/subjects/{subjectRef}/holdingsHoldings
Query
pran, tier

Per-scheme holdings across the account's tiers, as an array under holdings. The same row appears in portfolio.tiers[].holdings[].

Fields
  • tier
    stringOptional

    TIER_1 or TIER_2.

  • schemeCode
    stringRequired

    The scheme's SM… code. Consistent across every CRA: the one reliable join key.

  • schemeName
    stringOptional

    As the CRA writes it. For display only; spellings differ between CRAs.

  • pfmCode, pfmName
    stringOptional

    The pension fund manager. Group by pfmCode.

  • assetClass
    stringOptional

    Usually E, C, G or A. Not a closed list; passed through unchanged.

  • units
    objectOptional

    total; free and blocked where the CRA states them. Four decimals.

  • nav, navDate
    units, dateOptional

    The NAV used for the valuation and its date.

  • value
    moneyOptional

    Current value of the holding.

  • allocationPercent
    numberOptional

    The scheme's share of the tier's current value, one decimal.

4.5Returns

GET/v1/subjects/{subjectRef}/returnsReturns
Query
pran, tier
Fields
  • xirr
    numberRequired

    Rate of return as a decimal fraction, six places: 0.114300 is 11.43 %.

  • xirrPercent
    numberOptional

    The same rate as a percentage.

  • period
    objectRequired

    What the rate was measured over: basis (SINCE_INCEPTION, PERIOD, FINANCIAL_YEAR). Always show the period with the rate.

  • scaleBasis
    enumRequired

    CONFIRMED or ASSUMED: whether the CRA's percentage scale is confirmed or read on a stated assumption.

  • tiers[]
    arrayOptional

    The same fields per tier. TIER_2 appears where the account holds one.

4.6Transactions

GET/v1/subjects/{subjectRef}/transactionsTransactions
Query
pran, tier, from, to, order, limit, cursor

The ledger, as one list across the account's tiers, paged with page. Each row is a transaction row.

Transaction row
  • tier
    stringOptional

    TIER_1 or TIER_2 where the CRA states it.

  • transactionDate
    dateRequired

    When the transaction took place.

  • navDate
    dateOptional

    The NAV date used.

  • direction
    enumRequired

    CREDIT or DEBIT.

  • amount
    moneyRequired

    Always positive. Read direction for the sign.

  • transactionType
    stringOptional

    The CRA's type code. Never inferred from the description.

  • schemeCode, schemeName
    stringOptional

    The scheme.

  • description
    stringOptional

    The CRA's own description of the row.

  • openingBalance, closingBalance
    moneyOptional

    Where the CRA states them.

4.7Recent contributions

GET/v1/subjects/{subjectRef}/contributions/recentRecent contributions
Query
pran, tier, limit

The most recent credited contributions, as transaction rows (section 4.6) under contributions_recent. A contribution appears here only once units have been allotted; for anything earlier, use the tracker.

4.8Contribution tracker

GET/v1/subjects/{subjectRef}/contributions/trackerContribution tracker
Query
pran, tier

Contributions that have been made but not yet converted to units. This is the only read that shows a contribution before it settles, so it is the right one for "your payment is being processed" screens.

Fields
  • tier
    enumRequired

    TIER_1 or TIER_2.

  • stage
    enumRequired

    PENDING (received; funds not yet confirmed), FRC_UPLOADED (funds confirmed; units not yet allotted), UNITS_CREDITED (done), or UNKNOWN. Branch on this field.

  • sourceStatus
    stringOptional

    The CRA's own wording, for display and support.

  • amount
    moneyOptional

    The contribution amount.

  • requestedOn
    stringOptional

    When the contribution was raised.

  • frcUploadedOn
    stringOptional

    When the funds receipt confirmation was uploaded. Absent while PENDING.

  • unitsCreditedOn
    stringOptional

    When units were allotted. Absent until UNITS_CREDITED.

5Errors

Errors are problem documents (application/problem+json). A CRA being unavailable is not an error: it is an account in state UNAVAILABLE inside a 200 response.

HTTPcodeCauseWhat to do
401AUTH_FAILEDNo token, a partner token instead of a subscriber session token, an expired or ended session, or no subject:read scopeOpen a new subscriber session.
404NOT_FOUNDsubjectRef is not the session's subscriber, or pran is not an account in the sessionUse the values returned when the session was opened.
422validationA malformed query parameter (named in errors[])Fix the request.
422ORDER_INVALIDorder is not NEWEST_FIRST or OLDEST_FIRSTFix the request.
422DATE_RANGE_INVALIDto is before fromFix the request.
422DATE_RANGE_TOO_WIDEThe window spans more than 366 daysRequest narrower windows.
429RATE_LIMITEDToo many requestsWait for Retry-After.
503 / 504CRA_UNAVAILABLE / CRA_TIMEOUTThe read could not be completed at allRetry after a pause.
Appendix A

AImplementation notes

  • Use a decimal type for money, units and NAV. Totals computed in floating point will not match the figures NPS Central returns.
  • Model absence explicitly. Keep "not provided" distinct from zero, and drive "not available from your CRA" messages from meta.unavailableFields.
  • Retry PENDING and temporary UNAVAILABLE accounts, not the whole read. A second request within the session may be served from cache (freshness: CACHED).
  • Join schemes on schemeCode and managers on pfmCode. Names are for display and differ between CRAs.
  • Display tracker dates as given, and branch on stage rather than sourceStatus.
  • Keep the session alive with sessions:refresh while the subscriber is browsing; reads do not extend the idle timeout.