oneapi
Sign in
Financiar v1 / Validare

CNP validation

Checks the check digit of a personal numeric code and reads the information encoded in it: sex, date of birth, age and county.

A correct check digit does NOT mean the person exists — the response says so explicitly, in confirma_existenta_persoanei. A valid code can be generated in two minutes; the route checks the form, not the identity.

Zero retention: the code is written nowhere — not to logs, not to statistics, not to a cache. The route is POST and non-cacheable, so the response is not stored either.

POST
https://oneapi.ro/api/financiar/v1/validare/cnp

Request body

Sent as JSON in the request body (Content-Type: application/json) — not in the query string.

NameTypeDescriptionAccepted values
cnprequired string Required, in the request body. Exactly 13 digits. max 13 car.
Valid CNP Request body
{
    "cnp": "1800101410013"
}
A woman's national ID, born in Cluj Request body
{
    "cnp": "2850722120015"
}
A foreign resident Request body
{
    "cnp": "7900315400025"
}
Wrong check digit Request body
{
    "cnp": "1800101410014"
}

Query parameters

This route accepts no query parameters.

How it behaves

  • Verifies the check digit of a Romanian personal numeric code and reads the information encoded in it: sex, date of birth, age and county.
  • A correct check digit does NOT mean the person exists. The response says so explicitly, in confirma_existenta_persoanei, which is always false. A valid CNP can be generated in two minutes; this route checks the form, not the identity. Used as an identity check, it gives false confidence.
  • Zero retention. The CNP is never written anywhere: not to logs, not to usage statistics, not into cache keys. That is not merely a policy — the route is POST and non-cacheable, and the component that could store a response only works on GET, so the data has no path to storage.
  • An invalid CNP is not a bad request: the response is 200 with valid: false.
  • Foreign residents (first digit 7, 8 or 9): the century is not encoded, so the date of birth cannot be established and is not guessed — data_nasterii and varsta are null, and an_incert is true. With digit 9 the sex is not encoded either. An invented birth date with a 50% chance of being right would be worse than its absence. Day and month are still checked in both plausible centuries (1900 and 2000): the CNP is accepted if the date exists in at least one — 29 February of year "00" exists only in 2000.
  • County code 70 is not a county. Since May 2024, through the integrated civil-status system (SIIEASC), the county component is filled with 70 on every new registration regardless of place of birth. The CNP is perfectly valid, but the county is no longer encoded — judet.denumire is null and judet.motiv is nu_e_codificat. CNPs issued earlier are unchanged.
  • The county codes are a numbering of their own, not to be confused with SIRUTA or with vehicle-plate codes: 01 Alba … 39 Vrancea in the alphabetical order of the 1968 division, 40 Bucharest, 41–46 its districts, 47–48 the former districts 7 and 8 (abolished in 1979, but present in CNPs issued until then), and Călăraşi and Giurgiu — created in 1981 — at the end, 51 and 52.
  • The sequence number inside the CNP (the daily counter) is not returned: it has no use for a client and would be one more personal detail travelling for nothing.

What it is for

  • Checking a CNP in a form before storing it.
  • Auto-filling sex and date of birth.
  • Catching typing errors through a mismatch between the CNP and a manually entered date.

Response structure

FieldTypeDescription
data.valid boolean The verification result: check digit, date and county code.
data.sex string M, F, or null when the first digit is 9.
data.data_nasterii string null for foreign residents, where the century is not encoded.
data.varsta integer Completed years, counted on the Romanian day. null when the date of birth cannot be established.
data.judet object Code and name. With code 70, denumire is null and motiv explains why.
data.judet.cod integer Code from the source code list — the key you filter on.
data.judet.denumire string The name, exactly as the source publishes it.
data.judet.motiv null
data.an_incert boolean true when the century of birth is not encoded.
data.rezident_strain boolean true when the first digit is 7, 8 or 9.
data.confirma_existenta_persoanei boolean Always false. Present precisely so it is not assumed otherwise.
meta.temei string The legal basis for the values or for the way they are computed.
meta.retentie string Confirmation that the input was not stored anywhere.
meta.nota string A note on how to read the response — a pitfall, a convention or a limit of the source.

Response examples

body: {"cnp": "1800101410013"}

POSThttps://oneapi.ro/api/financiar/v1/validare/cnp
{
    "data": {
        "valid": true,
        "sex": "M",
        "data_nasterii": "1980-01-01",
        "varsta": 46,
        "judet": {
            "cod": 41,
            "denumire": "Bucureşti — Sectorul 1",
            "motiv": null
        },
        "an_incert": false,
        "rezident_strain": false,
        "confirma_existenta_persoanei": false
    },
    "meta": {
        "temei": "structura CNP + cifra de control (cheia 279146358279).",
        "retentie": "zero — CNP-ul şi datele derivate nu se stochează şi nu se cache-uiesc.",
        "nota": "CNP valid ca structură. Verificarea nu atestă că persoana există."
    }
}

Error codes

CodeSlugWhen it occurs
401neautentificatToken missing, invalid, expired or revoked.
403feature_indisponibilThe current plan does not include the feature the route depends on.
422validarecnp missing or not exactly 13 characters. A CNP that is present but wrong returns 200 with valid: false.
429cota_depasitaThe plan's monthly quota has been exceeded (see Retry-After).

All errors share the same shape. eroare.cod is stable and is the value you should branch on in code — not the text in mesaj, which may change.

{
    "eroare": {
        "cod": "validare",
        "mesaj": "cnp missing or not exactly 13 characters. A CNP that is present but wrong returns 200 with valid: false."
    }
}