Skip to main content

Iranian National ID Validation

The verifyIranianNationalId utility validates Iranian national identification numbers using the official checksum algorithm and format requirements.

Basic Usage

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

Simple Validation

verifyIranianNationalId("0499370899"); // true
verifyIranianNationalId("0684159415"); // true
verifyIranianNationalId("1234567890"); // false
verifyIranianNationalId("0000000000"); // false

Validation Rules

The function validates Iranian national IDs based on:
  • Must be exactly 10 digits
  • Cannot be all the same digit (e.g., 1111111111)
  • Must contain only numeric characters
  • Uses modulo-11 checksum validation - Last digit serves as check digit - Implements official Iranian algorithm
  • All zeros: 0000000000
  • All same digits: 1111111111, 2222222222, etc.
  • Sequential patterns in some cases

Input Format Support

The function accepts various input formats:
// Standard numeric string
verifyIranianNationalId("0499370899"); // true

// With Persian digits
verifyIranianNationalId("۰۴۹۹۳۷۰۸۹۹"); // true

// With Arabic digits
verifyIranianNationalId("٠٤٩٩٣٧٠٨٩٩"); // true

// Number input
verifyIranianNationalId(499370899); // true (auto-padded to 10 digits)

Advanced Examples

Form Validation

interface UserForm {
	nationalId: string;
	name: string;
	phone: string;
}

function validateUserForm(form: UserForm) {
	const errors: string[] = [];

	// Validate National ID
	if (!verifyIranianNationalId(form.nationalId)) {
		errors.push("کد ملی معتبر نیست");
	}

	return {
		isValid: errors.length === 0,
		errors,
		normalizedNationalId: digitsFaToEn(digitsArToEn(form.nationalId)),
	};
}

Batch Validation

function validateNationalIdBatch(ids: string[]) {
	return ids.map((id) => ({
		original: id,
		normalized: digitsFaToEn(digitsArToEn(id)),
		isValid: verifyIranianNationalId(id),
		location: verifyIranianNationalId(id) ? getPlaceByIranNationalId(id) : null,
	}));
}

const results = validateNationalIdBatch(["0499370899", "۰۶۸۴۱۵۹۴۱۵", "1234567890"]);

Database Integration

class UserService {
	async createUser(userData: { nationalId: string; name: string }) {
		// Normalize and validate National ID
		const normalizedId = digitsFaToEn(digitsArToEn(userData.nationalId));

		if (!verifyIranianNationalId(normalizedId)) {
			throw new Error("کد ملی معتبر نیست");
		}

		// Check for existing user
		const existingUser = await this.findByNationalId(normalizedId);
		if (existingUser) {
			throw new Error("کاربر با این کد ملی قبلاً ثبت‌نام کرده است");
		}

		// Create user with normalized ID
		return this.save({
			...userData,
			nationalId: normalizedId,
		});
	}
}

Valid National ID Examples

Here are some valid Iranian national IDs for testing:
const validIds = [
	"0499370899", // خمین
	"0684159415", // شیراز
	"0076229645", // تهران
	"0013542419", // تهران
	"0012016467", // تهران
	"0010859657", // تهران
];

validIds.forEach((id) => {
	console.log(`${id}: ${verifyIranianNationalId(id)}`); // all true
});

Edge Cases

Invalid Formats

verifyIranianNationalId(""); // false
verifyIranianNationalId("123"); // false (too short)
verifyIranianNationalId("12345678901"); // false (too long)
verifyIranianNationalId("abcd123456"); // false (contains letters)
verifyIranianNationalId(null); // false
verifyIranianNationalId(undefined); // false

Special Invalid Patterns

verifyIranianNationalId("0000000000"); // false (all zeros)
verifyIranianNationalId("1111111111"); // false (all same digit)
verifyIranianNationalId("2222222222"); // false (all same digit)
verifyIranianNationalId("9999999999"); // false (all same digit)

Checksum Failures

verifyIranianNationalId("1234567890"); // false (invalid checksum)
verifyIranianNationalId("0123456789"); // false (invalid checksum)
verifyIranianNationalId("9876543210"); // false (invalid checksum)

Algorithm Details

The validation follows these steps:
  1. Format Check: Ensure exactly 10 digits
  2. Pattern Check: Reject all-same-digit patterns
  3. Checksum Calculation: Apply modulo-11 algorithm
  4. Check Digit Verification: Compare with last digit
// Simplified algorithm illustration
function nationalIdChecksum(id: string): boolean {
	const digits = id.split("").map(Number);
	const checkDigit = digits[9];

	let sum = 0;
	for (let i = 0; i < 9; i++) {
		sum += digits[i] * (10 - i);
	}

	const remainder = sum % 11;
	const expectedCheck = remainder < 2 ? remainder : 11 - remainder;

	return checkDigit === expectedCheck;
}

Performance

  • Average execution: ~0.05ms
  • Batch validation: Linear scaling
  • Memory usage: Minimal (no caching needed)
  • CPU overhead: Very low
  • 1,000 validations: ~50ms
  • 10,000 validations: ~500ms
  • 100,000 validations: ~5s

TypeScript Support

import { verifyIranianNationalId } from "persian-tools";

// Type-safe validation
const isValid: boolean = verifyIranianNationalId("0499370899");

// Custom validation function with typing
function validateNationalId(id: string | number): {
	isValid: boolean;
	normalized: string;
} {
	const normalized = digitsFaToEn(digitsArToEn(id.toString()));
	return {
		isValid: verifyIranianNationalId(normalized),
		normalized,
	};
}

Integration Patterns

React Hook

import { useState, useEffect } from "react";

function useNationalIdValidation(id: string) {
	const [validation, setValidation] = useState({
		isValid: false,
		isChecking: false,
		error: null,
	});

	useEffect(() => {
		if (!id) {
			setValidation({ isValid: false, isChecking: false, error: null });
			return;
		}

		setValidation((prev) => ({ ...prev, isChecking: true }));

		const timeoutId = setTimeout(() => {
			const isValid = verifyIranianNationalId(id);
			setValidation({
				isValid,
				isChecking: false,
				error: isValid ? null : "کد ملی معتبر نیست",
			});
		}, 300); // Debounce

		return () => clearTimeout(timeoutId);
	}, [id]);

	return validation;
}

Express.js Middleware

import { Request, Response, NextFunction } from "express";

function validateNationalId(req: Request, res: Response, next: NextFunction) {
	const { nationalId } = req.body;

	if (!nationalId) {
		return res.status(400).json({ error: "کد ملی الزامی است" });
	}

	if (!verifyIranianNationalId(nationalId)) {
		return res.status(400).json({ error: "کد ملی معتبر نیست" });
	}

	// Normalize and attach to request
	req.body.nationalId = digitsFaToEn(digitsArToEn(nationalId));
	next();
}

Security Considerations

National ID validation should be used alongside other verification methods. A valid checksum doesn’t guarantee the ID belongs to the person claiming it.
// Good practice: Combined validation
interface UserVerification {
	nationalId: string;
	phone: string;
	name: string;
}

function verifyUser(data: UserVerification): boolean {
	return (
		verifyIranianNationalId(data.nationalId) &&
		verifyIranianNationalId(data.phone) && // additional checks
		data.name.length > 0
	);
}

Place by National ID

Get location information from National ID

Card Number Validation

Validate Iranian bank card numbers

Phone Number Validation

Validate Iranian phone numbers

Legal ID Validation

Validate Iranian legal entity IDs