Full-stack app for validating South African ID numbers and extracting date of birth, gender, citizenship, and age via a checksum-verified API + React UI.
# South African ID Validator
A full-stack toolkit for working with South African ID numbers: validate a single
ID, validate a whole list (with fraud/duplicate flags), derive age-based social
grant indicators, and keep a POPIA-conscious audit trail — all without depending
on any external identity service.
**🔗 Live demo:**
samukelo-mkhonza.github.io
> The hosted demo is the **frontend only** (GitHub Pages is static). The UI loads,
> but validation and other API-backed features need the Express backend running —
> point the deployed site at a hosted API via `REACT_APP_API_BASE` (see
> Configuration), or run the full stack
> locally with `npm run dev`.
## What it does — and what it deliberately does not
South African ID numbers encode real personal information (date of birth, gender
and citizenship) in a checksum-verified 13-digit format. This project parses and
**structurally validates** that format.
> **Important:** a well-formed, checksum-passing number is **not** proof that the
> ID exists in the National Population Register or belongs to a real person. True
> identity/existence verification requires accredited **Department of Home Affairs
> (HANIS/NPR)** access, which is out of scope here. Treat a valid result as
> "well-formed", never as "verified identity".
Everything in this repo works *today*, offline, with no DHA integration — which is
exactly why it is useful for data-quality, pre-screening and fraud-signalling work.
## Features
### Core validation (hardened)
- 13-digit length and digits-only checks (tolerates incidental spaces)
- **Strict calendar-date validation** — rejects impossible dates like month `13`
or `30 February` instead of silently rolling them over
- **Rejects future dates of birth**
- **Century-aware year handling** — instead of a naive fixed pivot, both the 1900s
and 2000s readings are tested and the plausible, non-future one is chosen;
genuinely ambiguous years are flagged (`birthDateAmbiguous`)
- Luhn checks …