Generator · Polish data

Polish PESEL

Endpoint GET /v1/pl/pesel

What it covers

Returns a valid Polish PESEL with a correct checksum. Constrain the person with `sex` and any combination of age/birth-date filters; contradictory combinations are rejected with a 400. Set `invalid=true` to get a PESEL with a deliberately wrong check digit (birth date and sex stay valid), for testing checksum validators.

A PESEL encodes a real birth date, a sex, and an ordinal serial into eleven digits, then closes with a check digit. Because the birth century is folded into the month field, the same two month digits mean different centuries — a PESEL alone tells you the full birth date without a separate century field.

How it’s calculated

The eleventh digit is a weighted mod-10 check digit over the first ten digits.

Algorithm

  1. Take the first ten digits d₁…d₁₀ (date + serial, century already folded into the month).
  2. Multiply each by the repeating weight pattern 1, 3, 7, 9, 1, 3, 7, 9, 1, 3.
  3. Sum the ten products.
  4. Take that sum modulo 10.
  5. The check digit is (10 − (sum mod 10)) mod 10 — the final mod 10 turns a would-be “10” back into 0.

Worked example

4405140135? (a person born 1944-05-14, serial 0135)

4×1 = 4
4×3 = 12
0×7 = 0
5×9 = 45
1×1 = 1
4×3 = 12
0×7 = 0
1×9 = 9
3×1 = 3
5×3 = 15
sum = 4+12+0+45+1+12+0+9+3+15 = 101
101 mod 10 = 1
(10 − 1) mod 10 = 9

The check digit is 9, so the full PESEL is 44051401359.

Edge cases

  • The century is carried in the month, not a separate field: month digits have 80 added for 1800–1899, 0 for 1900–1999, 20 for 2000–2099, 40 for 2100–2199, and 60 for 2200–2299. So a January birth reads as month 01, 21, 41, 61, or 81 depending on the century.
  • The serial’s last digit sets the sex: odd → male, even → female. Constraining sex therefore constrains the tenth digit’s parity, not a separate flag.
  • With invalid=true the check digit is deliberately wrong while the birth date and sex stay valid — so a validator that only checks the date passes it, but one that verifies the checksum rejects it. That’s the point: it isolates checksum-validation bugs.

Gotchas

  • A PESEL is not a random 11-digit string — the first ten digits must form a real calendar date after removing the century offset, or no amount of check-digit fixing makes it valid.
  • Contradictory age/birth-date constraints (e.g. atAge with a bornOn that disagrees) are rejected with a 400 rather than silently ignored.

Parameters

ParameterTypeDescription
atAgeintegerExact age in years at request time.
bornAfterstringpattern ^\d{4}(?:-\d{2}(?:-\d{2})?)?$Born after this date or fragment (YYYY, YYYY-MM, YYYY-MM-DD).
bornBeforestringpattern ^\d{4}(?:-\d{2}(?:-\d{2})?)?$Born before this date or fragment (YYYY, YYYY-MM, YYYY-MM-DD).
bornOnstringpattern ^\d{4}(?:-\d{2}(?:-\d{2})?)?$Born on a date or within a fragment: YYYY, YYYY-MM, or YYYY-MM-DD.
countinteger1–1000Number of records to return, 1–1000 (your plan may lower this). Omitted returns a single record; set it for a batch.
edgebooleanRestrict output to edge-case values.
extremebooleanReturn a correct PESEL whose value is wrapped in a hostile encoding (untrimmed whitespace, invisible/zero-width characters, BOM, or bidi/combining marks). The eleven digits stay recoverable after normalisation; birthDate and sex stay clean.
invalidbooleanReturn a PESEL with a deliberately wrong check digit; birth date and sex stay valid.
olderThanintegerMinimum age in years at request time.
seedintegerInteger seed for reproducible output: the same seed always yields the same record.
sex"m" | "f"Encoded sex: "m" or "f".
youngerThanintegerMaximum age in years at request time.

Response fields

FieldTypeDescription
valuestringThe canonical 11-digit PESEL.
birthDatestringThe encoded birth date, ISO `YYYY-MM-DD`.
sex"m" | "f"Encoded sex: `m` (odd) or `f` (even) tenth digit.

Other generators for Poland

See all generators for Poland →

The same kind of identifier elsewhere

Try it

Generate a live example below — every response is valid by format and entirely synthetic.