oneapi
Sign in
Identificatori v1 / Identificatori

Validate a personal numeric code

It does not go through the caching service: the value must never end up in a cache key, not even hashed. It is computed on every request; it is pure arithmetic anyway.

POST
https://oneapi.ro/api/identificatori/v1/cnp

Request body

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

NameTypeDescriptionAccepted values
cnprequired text Maximum 20. max 20 car.
A man born in 1980 Request body
{
    "cnp": "1800101410013"
}
A woman, leap year Request body
{
    "cnp": "2990230412345"
}
Born after 2000 Request body
{
    "cnp": "5041225410010"
}

Query parameters

This route accepts no query parameters.

How it behaves

  • The body has a single field, cnp (string, required, at most 20 characters). Body fields do not appear in the parameter table, hence the description here.
  • Why POST. In a GET, the code would land in the server access logs, the browser history and the next page's Referer header — three places you cannot get it out of. The equivalent GET route answers 405 and points here.
  • Zero retention. The code is never written anywhere: not to the database, not to logs, not into a cache key. The response does not even echo the value — valoare is always (ascuns), because the caller already has it and we have no reason to put it in a body that may end up in their own logs. Error messages do not repeat it either.
  • The components are DERIVED from the code sent, not looked up: date of birth, sex and county are literally written into it. They do not confirm the person exists.
  • There is no generator endpoint for valid codes, not even "for testing". A generator would mostly help someone trying to get past a validation, not someone trying to validate.
  • The county codes in the personal numeric code are neither SIRUTA codes nor vehicle-plate letters: they are the alphabetical order of the counties as of 1978. Călărași and Giurgiu, created in 1981, received 51 and 52. Code 47 is Sectorul Agricol Ilfov, which existed from 1981 to 1997 and appears in codes issued then.
  • For a leading digit of 7 or 8 (foreign residents) and 9 (no Romanian citizenship), the century is not encoded, so the date of birth cannot be derived — it is absent from the components, which is correct rather than an oversight.

What it is for

  • Catch a typo while a form is being filled in, before the data travels further.
  • Check a file for consistency: the declared date of birth must match the one in the code.
  • Derive a person's age from the code you already hold, without querying a database.

Response structure

All fields below live inside data.

FieldTypeDescription
tip string The type used for validation.
valoare string Always (ascuns). The code received is not echoed.
valid boolean Whether it passes the check digit and all consistency checks.
componente.data_nasterii string Derived from the code. Absent for foreign residents, where the century is not encoded.
componente.varsta integer Age in completed years, at the time of the request.
componente.sex string masculin or feminin, from the leading digit.
componente.judet_nastere string The county or Bucharest sector of registration.
componente.cod_judet string The code as written in the personal numeric code, two digits.
componente.rezident_strain boolean Leading digit 7 or 8.
componente.fara_cetatenie_romana boolean Leading digit 9.
observatie string A note on how to read the response: a computation convention or a limit of the data.
motive array What is wrong: check digit, non-existent date, unallocated county code.

Response examples

body: {"cnp": "1800101410013"}

POSThttps://oneapi.ro/api/identificatori/v1/cnp
{
    "data": {
        "tip": "cnp",
        "valoare": "(ascuns)",
        "valid": true,
        "componente": {
            "data_nasterii": "1980-01-01",
            "varsta": 46,
            "sex": "masculin",
            "judet_nastere": "București — Sectorul 1",
            "cod_judet": "41",
            "rezident_strain": false,
            "fara_cetatenie_romana": false
        },
        "observatie": "Componentele sunt DERIVATE din CNP-ul trimis — nu vin dintr-o bază de date și nu confirmă că persoana există. CNP-ul nu se stochează și nu se loghează nicăieri."
    }
}

Error codes

CodeSlugWhen it occurs
401neautentificatToken missing, invalid, expired or revoked.
403feature_indisponibilThe current plan does not include the feature the route depends on.
422validareThe cnp field is missing or too long. The message does NOT repeat the value received.
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": "The cnp field is missing or too long. The message does NOT repeat the value received."
    }
}