Skip to main content
The Iranian National ID (کد ملی) is a 10-digit code with a check digit and an embedded 3-digit city/registration prefix. Persian Tools provides validation, prefix lookup, and a generator family for tests.

Validate

verifyIranianNationalId(nationalId, options?)

import { verifyIranianNationalId } from "@persian-tools/persian-tools";

verifyIranianNationalId("0499370899"); // true
verifyIranianNationalId("1234567890"); // false (checksum fails)
verifyIranianNationalId(undefined); // undefined (falsy input)

// Skip the city-prefix check (still verifies the checksum)
verifyIranianNationalId("9999970899", { checkPrefix: false });
interface VerifyIranianNationalIdOptions {
	checkPrefix?: boolean; // default true
}

Algorithm

  1. Falsy → undefined.
  2. Length must be ≥ 8; shorter inputs are zero-padded to 10 (so 499370899 is accepted as 0499370899).
  3. Reject all-same-digit sequences (0000000000, 1111111111, …) via the exported invalidNationalIdSequences set.
  4. If checkPrefix !== false, the leading 3 digits must be in validNationalIdPrefixes.
  5. Standard check-digit computation: sum = Σ digit[i] * (10 - i) for i = 0..8, then digit[9] must equal sum % 11 (or 11 - sum%11 if sum%11 ≥ 2).

Look up the place

For city/province from a National ID’s 3-digit prefix, see the Place by National ID page.

Generate (for tests)

import {
	createIranianNationalId,
	createIranianNationalIdDetailed,
	createIranianRoundNationalId,
	validateNationalIdChecksum,
	isValidNationalIdFormat,
} from "@persian-tools/persian-tools";

createIranianNationalId(); // random valid ID
createIranianNationalId({ preventRepeatedDigits: true }); // forbids all-same-digit results
createIranianNationalId({ randomGenerator: () => 0.5 }); // deterministic seed for tests

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
isValidNationalIdFormat("0499370899"); // true (just shape)
interface NationalIdGenerationOptions {
	preventRepeatedDigits?: boolean;
	maxRetries?: number;
	randomGenerator?: () => number;
}
interface NationalIdGenerationResult {
	nationalId: string;
	checkDigit: number;
	attempts: number;
	hasRepeatedDigits: boolean;
	digits: number[];
}

Pitfalls

  • Persian/Arabic digit input is NOT auto-normalized. verifyIranianNationalId("۰۴۹۹۳۷۰۸۹۹") returns false because parseInt of Persian digits yields NaN. Run autoConvertDigitsToEN first.
  • Return type is boolean | undefined — use === true, not truthy checks.
  • For test fixtures, generate IDs with createIranianNationalId(...). Don’t commit real personal data.

Source

src/modules/nationalId/index.ts, src/modules/nationalId/create-national-id.ts · Tests: test/verifyIranianNationalId.spec.ts