nationalId — Iranian National ID validation & generation
import {
verifyIranianNationalId,
createIranianNationalId,
createIranianNationalIdDetailed,
validateNationalIdChecksum,
} from "@persian-tools/persian-tools";
// CommonJS
const {
verifyIranianNationalId,
createIranianNationalId,
createIranianNationalIdDetailed,
validateNationalIdChecksum,
} = require("@persian-tools/persian-tools");
Public exports
// Validation
verifyIranianNationalId(
nationalId: string | number | undefined,
options?: VerifyIranianNationalIdOptions,
): boolean | undefined
interface VerifyIranianNationalIdOptions {
checkPrefix?: boolean; // default true — also validate 3-digit city prefix
}
// Data
validNationalIdPrefixes: Set<string> // ~600 valid 3-digit city codes
invalidNationalIdSequences: Set<string> // codes that pass the checksum but are reserved
// Generation
createIranianNationalId(opts?: NationalIdGenerationOptions): string
createIranianNationalIdDetailed(opts?: NationalIdGenerationOptions): NationalIdGenerationResult
createIranianRoundNationalId(opts?: NationalIdGenerationOptions): string
isValidNationalIdFormat(value: string): boolean
validateNationalIdChecksum(value: string): boolean
interface NationalIdGenerationOptions {
preventRepeatedDigits?: boolean;
maxRetries?: number;
randomGenerator?: () => number;
}
interface NationalIdGenerationResult {
nationalId: string;
checkDigit: number;
attempts: number;
hasRepeatedDigits: boolean;
digits: number[];
}
Validation
import { verifyIranianNationalId } from "@persian-tools/persian-tools";
verifyIranianNationalId("0499370899"); // true
verifyIranianNationalId("1234567890"); // false (checksum fails)
verifyIranianNationalId(undefined); // undefined (falsy input → undefined return)
// Skip the city-prefix check
verifyIranianNationalId("9999970899", { checkPrefix: false }); // boolean based on checksum only
Algorithm
- Reject
undefined/falsy → returnsundefined. - Length must be ≥ 8; shorter inputs are zero-padded to 10 (so
499370899is accepted as0499370899). - Reject if the digits are in
invalidNationalIdSequences(e.g.0000000000,1111111111). - If
checkPrefix !== false, the leading 3 digits must be invalidNationalIdPrefixes. - Check digit:
sum = Σ digit[i] * (10 - i) for i in 0..8 r = sum mod 11 valid = (r < 2 && digit[9] === r) || (r >= 2 && digit[9] === 11 - r)
Important quirks
- Persian/Arabic digit input is NOT auto-normalized.
verifyIranianNationalId("۰۴۹۹۳۷۰۸۹۹")returnsfalsebecauseparseIntof Persian digits isNaN. RunautoConvertDigitsToENfirst if input may contain them. - Return type is
boolean | undefined—undefinedfor empty/falsy input,booleanafter the checksum runs. Don't truthy-check; use=== true.
Generation (for tests / fixtures)
import {
createIranianNationalId,
createIranianNationalIdDetailed,
validateNationalIdChecksum,
} from "@persian-tools/persian-tools";
createIranianNationalId();
// e.g. "0499370899" — random valid ID with a valid city prefix and check digit
createIranianNationalId({ preventRepeatedDigits: true });
// guarantees the ten digits are not all identical, with bounded retry
const detailed = createIranianNationalIdDetailed({ preventRepeatedDigits: true, maxRetries: 50 });
// {
// nationalId: "1234567890",
// checkDigit: 0,
// attempts: 1,
// hasRepeatedDigits: false,
// digits: [1, 2, 3, 4, 5, 6, 7, 8, 9, 0],
// }
validateNationalIdChecksum(detailed.nationalId); // true
For deterministic test seeds, pass randomGenerator:
createIranianNationalId({ randomGenerator: () => 0.5 });
// reproducible — always uses 0.5 for every digit draw
Common pitfalls
- Don't commit real National IDs as test fixtures. Use
createIranianNationalIdto generate synthetic ones with valid checksums. getPlaceByIranNationalIdis a separate module for city/province lookup. It does NOT validate the checksum — it only slices the first 3 digits and looks them up. See thegetPlaceByIranNationalIdskill.- City-prefix list is data, not law. New prefixes get assigned over time. When extending the library, update
validNationalIdPrefixes(and the place-lookup tables) together.
References
- Tests:
test/verifyIranianNationalId.spec.ts - Related:
getPlaceByIranNationalIdskill,iranian-validation-expert(algorithm details) in.agents/