
Israeli Id Validator
- 58 installs
- 9 repo stars
- Updated August 3, 2026
- skills-il/developer-tools
Israeli ID Validator is an agent skill that validates and formats Israeli identification numbers—including Teudat Zehut and company-related IDs—using the standard check-digit algorithm.
About
Israeli ID Validator is a focused integration reference skill for solo builders shipping apps, APIs, or internal tools that must accept Israeli identification numbers correctly. It explains Teudat Zehut length and padding, where the check digit lives, and related entity numbers so your agent does not guess locale-specific rules from generic validation snippets. Use it when users ask for teudat zehut validation, mispar zehut checks, or company registration number formatting in Hebrew or English product copy. It explicitly scopes out non-Israeli ID systems, which keeps prompts tight. Typical outcomes are correct validator functions, edge-case handling for shortened input, and reproducible test IDs—common needs for onboarding, billing, or government-adjacent forms in the Israeli market.
- Validates Teudat Zehut with 9-digit padding and position-9 check digit
- Covers company, amuta (non-profit), and partnership number formats
- Documents Ministry of Interior issuance context and valid ranges
- Includes check digit algorithm suitable for code implementation
- Supports test ID generation for dev and QA flows
Israeli Id Validator by the numbers
- 58 all-time installs (skills.sh)
- Ranked #3,178 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/skills-il/developer-tools --skill israeli-id-validatorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 58 |
|---|---|
| repo stars | ★ 9 |
| Security audit | 3 / 3 scanners passed |
| Last updated | August 3, 2026 |
| Repository | skills-il/developer-tools ↗ |
What it does
Implement and validate Israeli Teudat Zehut, company, amuta, and partnership ID numbers with the official check-digit algorithm in your backend or forms.
Who is it for?
Best when you're building Israeli-market SaaS, APIs, or admin tools that collect national or business registration identifiers.
Skip if: Non-Israeli identity documents, KYC vendors that replace in-app validation, or legal identity proofing without your own compliance review.
When should I use this skill?
User asks to validate Israeli ID, teudat zehut, mispar zehut, company number validation, or implement Israeli ID validation in code.
What you get
You implement correct validation and formatting helpers plus test IDs aligned with Israeli Teudat Zehut and related registration number rules.
- Check-digit validation function or module
- Formatting rules for padded 9-digit Teudat Zehut
- Test ID examples for QA
By the numbers
- Teudat Zehut: 9 digits with check digit at position 9
Files
Israeli ID Validator
Instructions
Step 1: Identify ID Type
| Type | Prefix | Length | Example | Notes |
|---|---|---|---|---|
| Teudat Zehut (personal ID) | none (cannot be inferred) | 9 digits | 123456782 | Assigned sequentially; the digits encode NO birth date, age, or residency status |
| Corporate / registered entity | first digit 5 | 9 digits | 51-530820-3 | Lives in the 5XX-million block; the number begins with 5 and the second digit selects the entity type (codes 50-59, see next table). Same check digit as a personal ID |
Corporate and registered-entity codes (first two digits):
| Prefix | Entity |
|---|---|
| 50 | Government company, pension/provident fund, or local committee |
| 51 | Private company (Chevra Ba'am / Ltd) |
| 52 | Public company |
| 53 | Mandatory partnership |
| 54 | General partnership |
| 55 | Partnership (Shutafut) |
| 56 | Foreign company |
| 57 | Cooperative society (Aguda Shitufit) / kibbutz |
| 58 | Amuta (non-profit) / public-benefit company |
| 59 | Endowment (Hekdesh) |
Prefix-based typing is a heuristic: a 9-digit number starting with 5 is overwhelmingly a registered entity (corporate numbers are allocated from the 5XX block), but only the issuing registry is authoritative. A personal Teudat Zehut cannot be typed from its prefix.
Step 2: Validate Using Check Digit Algorithm
The Israeli ID check digit algorithm (applies to all types):
def validate_israeli_id(id_number: str) -> bool:
"""Validate Israeli ID number (TZ, company, amuta, etc.)"""
# Remove dashes and spaces, pad to 9 digits
id_str = id_number.replace('-', '').replace(' ', '').zfill(9)
if len(id_str) != 9 or not id_str.isdigit():
return False
if id_str == '000000000': # passes Luhn but is never a real ID
return False
total = 0
for i, digit in enumerate(id_str):
# Position counting from left: odd positions (0,2,4,6,8) multiply by 1
# Even positions (1,3,5,7) multiply by 2
weight = 1 if i % 2 == 0 else 2
val = int(digit) * weight
if val > 9:
val = val // 10 + val % 10 # Sum digits if > 9
total += val
return total % 10 == 0Step 3: Provide Result
For valid IDs: Confirm valid, identify type by prefix For invalid IDs: Report invalid, show which check failed, suggest common errors:
- Transposed digits
- Missing/extra digit
- Incorrect check digit
Step 4: Generate Test IDs (Development Use)
For development and testing, generate valid test IDs:
def generate_test_id(prefix: str = "") -> str:
"""Generate a valid Israeli ID number for testing."""
import random
base = prefix + ''.join([str(random.randint(0, 9)) for _ in range(8 - len(prefix))])
# Calculate check digit
total = 0
for i, digit in enumerate(base):
weight = 1 if i % 2 == 0 else 2
val = int(digit) * weight
if val > 9:
val = val // 10 + val % 10
total += val
check = (10 - (total % 10)) % 10
return base + str(check)CAVEAT: Generated IDs are for testing only. Never use random IDs as real identification.
Examples
Example 1: Validate TZ
User says: "Is 123456782 a valid Israeli ID?" Result: Run algorithm, report valid/invalid with explanation.
Example 2: Code Implementation
User says: "I need Israeli ID validation in JavaScript" Result: Provide equivalent algorithm in JavaScript.
Example 3: Generate Test Data
User says: "I need 10 valid test company numbers" Result: Generate 10 valid IDs with 51- prefix for testing.
Bundled Resources
Scripts
scripts/validate_id.py, Validates, identifies, formats, and generates Israeli ID numbers (Teudat Zehut, company, amuta, partnership). Supports verbose mode showing step-by-step check digit calculation, batch test ID generation with prefix control, and type identification from any ID number. Run:python scripts/validate_id.py --help
References
references/id-formats.md, Specification of all Israeli ID number formats including Teudat Zehut, company (51-prefix), amuta (58-prefix), partnership (55-prefix), and cooperative society (57-prefix) with issuing authorities, format patterns, the Luhn-variant check digit algorithm with a worked example, and common validation errors. Consult when implementing validation logic or debugging check digit failures.
Reference Links
- Misrad HaPnim, ID numbering page (gov.il) , Official Ministry of Interior page on Teudat Zehut issuance, structure, and renewal.
- ICA Companies Registrar (justice.gov.il) , Lookup for company (51), amuta (58), partnership (55), and cooperative society (57) numbers.
- Kolzchut, "תעודות זהות, דרכונים ותעודות מעבר" , Citizen-rights wiki hub for identity cards, passports, and travel documents, covering eligibility, replacement, and number ranges.
- Privacy Protection Law, Amendment 13 (IAPP analysis) , 2025 amendment tightening consent, breach-notification, and PII handling rules. In force 14 August 2025.
Gotchas
- Israeli ID numbers (Teudat Zehut) are exactly 9 digits with a Luhn (mod 10) check digit. Agents may generate random 9-digit numbers that fail the check digit validation.
- Israeli ID numbers with fewer than 9 digits must be left-padded with zeros. An ID like "12345678" is actually "012345678". Agents may strip leading zeros and break validation.
- Israeli ID numbers are NOT date-encoded. They are assigned sequentially; you cannot infer birth date, age, birth year, or residency status from the digits. Agents trained on US SSN-style intuition often invent this assumption.
- Do not type or reject a personal ID by its leading-digit range. There is no documented citizen-status encoding in the number (the common "native vs resident vs foreign-worker by range" split is folklore). Every personal ID passes the same Luhn check regardless of its first digit; treat them all as plain 9-digit IDs.
- PII / privacy logging: never log unredacted Israeli IDs in application logs, error messages, telemetry, or analytics events. Israel's Privacy Protection Law Amendment 13 (in force 14 August 2025) tightens consent and breach-notification rules. When displaying an ID to a non-authorized context (debug UI, support tooling, customer-facing receipt), mask the middle digits, e.g.
123****82. Hash or tokenize before persisting in non-essential stores. - Israeli military IDs (mispar ishi) use a different format than civilian IDs and should not be validated with the same algorithm.
000000000passes the Luhn check (its digit sum is 0, divisible by 10) but is never a real ID. It is the most common sentinel / empty-field false positive: an empty string or a numeric-default column zero-pads straight into it. Reject all-zeros explicitly before trusting a "valid" result.- Do not reject a personal ID by its leading digit. There is no documented "temporary resident vs permanent" prefix for the 9-digit Luhn-checked Teudat Zehut; validate the format only and pad with
zfill(9)rather than filtering by range.
Troubleshooting
Error: "ID appears valid but isn't recognized"
Cause: Check digit passes but the ID isn't issued Solution: The algorithm only validates FORMAT, not existence. Verifying if an ID is actually issued requires Tax Authority or Interior Ministry systems.
Error: "ID fails validation after a range/prefix filter"
Cause: An upstream filter is rejecting IDs by leading-digit range (e.g. treating a given first digit as "not a personal ID"), or the check digit is failing because the ID was stored as 8 digits with the leading zero dropped. Solution: Every personal ID uses the same 9-digit Luhn check regardless of leading digit, and there is no reliable status-by-range mapping. Re-pad with leading zeros (zfill(9)) before validating, and remove any leading-digit range whitelist. Note that a 9-digit number starting with 5 is usually a registered entity, not a personal ID.
Error: "Length mismatch / leading-zero stripped"
Cause: Spreadsheet, JSON parser, or numeric column dropped the leading zero (e.g., 012345678 stored as integer becomes 12345678). Solution: Always store IDs as strings. On read, left-pad to 9 with zfill(9) (Python) / padStart(9, '0') (JS) before running the check. Reject only after re-padding.
Error: "Invalid input, dashes or spaces in ID"
Cause: User pasted a formatted company or amuta number such as 51-530820-3 or 58 012345 3. Solution: Strip all non-digit characters (re.sub(r'\D', '', id)) before length checks. Both human-formatted and raw-digit forms must validate identically.
Error: "9-digit input but algorithm fails"
Cause: Common cause is a transposition or single-digit typo in the body of the ID, not the check digit itself. Other causes: copy-paste from a Hebrew RTL source where digit order was reversed, or the value is a military mispar ishi (which does not share the civilian Luhn algorithm). Solution: Ask the user to retype the ID from the source document. If it still fails and the user insists it is correct, suggest an out-of-band verification with the issuing registry; do not "fix" check digits silently.
{
"schemaVersion": "1.0",
"skill": "israeli-id-validator",
"generated": "2026-06-16",
"claims": [
{
"claim": "The Israeli ID number (Mispar Zehut) is nine digits, the last of which is a check digit calculated using the Luhn algorithm. The skill's algorithm (pad to 9, alternating x1/x2 weights, sum-digits-if-product>9, total divisible by 10) is the standard Luhn-variant implementation of this.",
"source_url": "https://en.wikipedia.org/wiki/Israeli_identity_card",
"raw_snippet": "Identity number (Mispar Zehut) comprising nine digits, the last of which is a check digit calculated using the Luhn algorithm",
"effective_date": "2026-06-16",
"verification": "Confirmed empirically with the bundled scripts/validate_id.py: all 6 worked examples (123456782, 612345678, 515308203, 550123459, 570123455, 580123453) return VALID and the deliberately-wrong 123456789 returns INVALID."
},
{
"claim": "Corporate and registered-entity numbers carry a check digit whose calculation rules are identical to the personal ID check digit, so company / partnership / cooperative / amuta numbers pass the same algorithm.",
"source_url": "https://he.wikipedia.org/wiki/תאגיד",
"raw_snippet": "הספרה הימנית ביותר במספר התאגיד היא ספרת ביקורת, שכללי חישובה זהים לאלה של חישוב ספרת הביקורת במספר זהות",
"effective_date": "2026-06-16"
},
{
"claim": "A corporate/registered-entity number is 9 digits; the first two digits map to the entity type: 50 government company / provident fund / pension fund / local committee, 51 private company, 52 public company, 53 mandatory partnership, 54 general partnership, 55 partnership, 56 foreign company, 57 cooperative society / kibbutz, 58 amuta / non-profit / public-benefit company, 59 endowment.",
"source_url": "https://he.wikipedia.org/wiki/תאגיד",
"raw_snippet": "זהו מספר בן 9 ספרות. על פי רוב שתי הספרות הראשונות במספר רישום התאגיד קשורות לסוג התאגיד, כדלהלן: 50 = חברה ממשלתית, קופת גמל, קרן פנסיה, ועד מקומי; 51 = חברה פרטית; 52 = חברה ציבורית; 53 = שותפות מנדטורית; 54 = שותפות כללית; 55 = שותפות; 56 = חברה זרה; 57 = אגודה שיתופית, קיבוץ; 58 = עמותה, מלכ\"ר, חברה לתועלת הציבור; 59 = הקדש",
"effective_date": "2026-06-16",
"notes": "53 is שותפות מנדטורית = mandatory (Mandate-era) partnership, NOT limited partnership."
},
{
"claim": "The authoritative structural description of the Mispar Zehut specifies only that it is nine digits ending in a Luhn check digit; it documents no field encoding birth date, age, residency status, or a native/resident/foreign-worker number range. The common range-by-status split is therefore unsupported folklore.",
"source_url": "https://en.wikipedia.org/wiki/Israeli_identity_card",
"raw_snippet": "Identity number (Mispar Zehut) comprising nine digits, the last of which is a check digit calculated using the Luhn algorithm",
"effective_date": "2026-06-16",
"notes": "The cited source describes ONLY the nine-digit + check-digit structure; it asserts no date/age/status/range encoding, which is the basis for treating the range-by-status claim as folklore."
},
{
"claim": "Israel's Privacy Protection Law Amendment 13 (Amendment 13 to the 1981 Privacy Protection Law) tightening consent and breach-notification rules came into force on 14 August 2025.",
"source_url": "https://iapp.org/news/a/israel-marks-a-new-era-in-privacy-law-amendment-13-ushers-in-sweeping-reform",
"raw_snippet": "Amendment 13 to Israel's Privacy Protection Law entered into force on 14 August 2025, introducing sweeping reform to consent, enforcement and breach-notification obligations.",
"effective_date": "2025-08-14"
},
{
"claim": "The Ministry of the Interior (Misrad HaPnim) publishes the official Teudat Zehut issuance/structure topic page at gov.il.",
"source_url": "https://www.gov.il/he/departments/topics/identity_card",
"raw_snippet": "Official Ministry of Interior topic page for Teudat Zehut (identity card) issuance, structure, and renewal. gov.il blocks non-browser user agents (HTTP 403 to bots) but the page is live in a browser.",
"effective_date": "2026-06-16"
},
{
"claim": "The Israeli Corporations Authority (Rashut HaTaagidim) registrar lookup for company, amuta, partnership, and cooperative-society numbers is hosted at ica.justice.gov.il.",
"source_url": "https://ica.justice.gov.il/",
"raw_snippet": "ica.justice.gov.il returns HTTP 200 and redirects to /GenericCorporarionInfo/SearchCorporation?unit=8, the corporation search lookup of the Israeli Corporations Authority under the Ministry of Justice.",
"effective_date": "2026-06-16"
},
{
"claim": "Kol-Zchut maintains a citizen-rights hub for identity cards, passports, and travel documents.",
"source_url": "https://www.kolzchut.org.il/he/תעודות_זהות,_דרכונים_ותעודות_מעבר",
"raw_snippet": "https://www.kolzchut.org.il/he/תעודות_זהות,_דרכונים_ותעודות_מעבר returns HTTP 200; the page covers identity cards, passports, and travel documents (eligibility, replacement, document types).",
"effective_date": "2026-06-16"
}
]
}
{
"author": "skills-il",
"version": "1.1.2",
"category": "developer-tools",
"tags": {
"he": [
"אימות",
"מספר-זהות",
"תעודת-זהות",
"מפתחים",
"ישראל"
],
"en": [
"validation",
"id",
"teudat-zehut",
"developer",
"israel"
]
},
"display_name": {
"he": "מאמת תעודת זהות",
"en": "Israeli ID Validator"
},
"display_description": {
"he": "מאמתים מספרי תעודת זהות, ח\"פ ומספרי רישום חברות.",
"en": "Validate and format Israeli identification numbers including Teudat Zehut (personal ID), company numbers, amuta (non-profit) numbers, and partnership numbers. Use when user asks to validate Israeli ID, \"teudat zehut\", \"mispar zehut\", company number validation, or needs to implement Israeli ID validation in code. Includes check digit algorithm and test ID generation. Do NOT use for non-Israeli identification systems."
},
"supported_agents": [
"claude-code",
"cursor",
"github-copilot",
"windsurf",
"opencode",
"codex",
"openclaw",
"antigravity",
"gemini-cli"
]
}
{
"cycles": [
{
"version": "1.1.2",
"date": "2026-06-16",
"lessons": [
"Anti-circularity defect fixed: all four organization-number examples in the type table (company 51-530820-1, partnership 55-012345-6, cooperative 57-012345-6, amuta 58-012345-6) FAILED the skill's own Luhn check digit. Regenerated with correct check digits (51-530820-3, 55-012345-9, 57-012345-5, 58-012345-3) and verified all 6 worked examples pass via the bundled validate_id.py. A validator skill must never ship examples that fail its own validator.",
"Folklore removed (refuted via WebSearch + en.wikipedia): the 'native-born 100-499 million vs resident/foreign 500-899 million' range-by-status framing is undocumented folklore, and the 'foreign-worker IDs land in the 3xx-million sub-range of the 500-899 million block' line was self-contradictory (3xx < 500). Replaced with the accurate model: personal IDs are not typeable by prefix; corporate/registered entities occupy the 5XX-million block.",
"Prefix model corrected and broadened (he.wikipedia תאגיד, verbatim): keying only on 51/55/57/58 wrongly classified public (52), government (50), foreign (56), mandatory/general partnerships (53/54), and endowments (59) as personal IDs. identify_id_type now covers the full 50-59 table. 53 = שותפות מנדטורית = MANDATORY partnership (Mandate-era), NOT limited; the body label was correct and the fabricated evidence snippet was the error.",
"Expert MAJOR (all-zeros trap) fixed: validate_israeli_id('000000000') and validate_israeli_id('') both returned True (empty zero-pads into all-zeros, which passes Luhn). Added an explicit reject plus a gotcha. This is the most common sentinel/empty-field false positive in production KYC.",
"Expert MAJOR (code-vs-prose contradiction) fixed: identify_id_type returned a hard corporate label for any 5X number while the prose hedged; added a heuristic caveat to the CLI output and a code comment on format_id so the tool output matches the documented hedge.",
"Judge caught a fabricated evidence snippet: claim #4 cited the Nefesh B'Nefesh page with a raw_snippet that does not appear on that live page. Re-grounded on the verbatim en.wikipedia nine-digit-Luhn quote with an honest absence-of-status-field framing. Lesson: never paraphrase a source into a raw_snippet; fetch and quote verbatim.",
"Amendment 13 in-force date tightened to 14 August 2025 (IAPP). Replaced the JS-rendered Knesset ASPX reference link (returns blank to fetchers, judge-unverifiable) with the IAPP analysis page.",
"Confirmed correct (no change): the Luhn check-digit algorithm, zfill(9) leading-zero handling, and the same-check-digit-for-orgs claim. Biometric-ID-mandatory 2026 development correctly out of scope for a number-format validator."
],
"buckets": {
"persistent_fail": [],
"deferred": [
"identify_id_type still returns a clean corporate label programmatically (the ambiguity hedge lives only in the CLI output layer); a future cycle could return an ambiguity-typed object. Low priority since corporate numbers genuinely occupy the 5XX pool and personal IDs have not reached it."
]
}
}
]
}
Israeli ID Number Formats Reference
Teudat Zehut (Personal ID)
- Length: 9 digits (padded with leading zeros if shorter)
- Prefix: Any (no fixed prefix for personal IDs)
- Check digit: Position 9 (last digit)
- Issued by: Ministry of Interior (Misrad HaPnim)
- Range: Numbers up to 999999999
- Notes: Issued at birth to Israeli citizens and permanent residents
Company Number (Chevra Ba'am / Ltd)
- Length: 9 digits
- Prefix: 51 (private company). Registered entities span the whole 50-59 block, see "Registered-entity codes" below; keying only on "51" wrongly rejects public (52), government (50), and foreign (56) companies.
- Format: 51-XXXXXX-C (where C is check digit)
- Issued by: Companies Registrar (Rasham HaChavarot)
- Registry: ica.justice.gov.il
Amuta Number (Non-profit / Registered Association)
- Length: 9 digits
- Prefix: 58
- Format: 58-XXXXXX-C
- Issued by: Registrar of Amutot
- Registry: ica.justice.gov.il
Partnership Number (Shutafut)
- Length: 9 digits
- Prefix: 55
- Format: 55-XXXXXX-C
- Issued by: Registrar of Partnerships
Cooperative Society (Aguda Shitufit)
- Length: 9 digits
- Prefix: 57
- Format: 57-XXXXXX-C
Registered-entity codes (first two digits)
Corporate and registered-entity numbers occupy the 5XX-million block. The number begins with 5 and the second digit selects the entity type; the check digit is identical to a personal Teudat Zehut. Only the issuing registry is authoritative, prefix typing is a heuristic.
| Prefix | Entity |
|---|---|
| 50 | Government company, pension/provident fund, or local committee |
| 51 | Private company (Chevra Ba'am / Ltd) |
| 52 | Public company |
| 53 | Mandatory partnership |
| 54 | General partnership |
| 55 | Partnership (Shutafut) |
| 56 | Foreign company |
| 57 | Cooperative society (Aguda Shitufit) / kibbutz |
| 58 | Amuta (non-profit) / public-benefit company |
| 59 | Endowment (Hekdesh) |
Teudat Zehut range note
Personal IDs are assigned sequentially with NO embedded meaning: the digits do not encode birth date, age, or residency status, and there is no documented "native vs resident vs foreign-worker by number range" mapping (that split is folklore). A personal ID therefore cannot be typed from its prefix.
Check Digit Algorithm
All Israeli ID types use the same Luhn-variant algorithm:
1. Take the 9-digit number (pad with leading zeros if needed) 2. Multiply each digit by alternating weights: 1, 2, 1, 2, 1, 2, 1, 2, 1 3. If any product exceeds 9, replace it with the sum of its digits 4. Sum all the results 5. The number is valid if the sum is divisible by 10
Worked Example: 123456782
Digit: 1 2 3 4 5 6 7 8 2
Weight: 1 2 1 2 1 2 1 2 1
Product: 1 4 3 8 5 12 7 16 2
Adjusted: 1 4 3 8 5 3 7 7 2
Sum: 1 + 4 + 3 + 8 + 5 + 3 + 7 + 7 + 2 = 40
40 % 10 = 0 -> VALIDCommon Errors
- Transposed digits: Swapping two adjacent digits usually breaks validation
- Missing leading zero: Short IDs must be zero-padded to 9 digits
- Confusing entity types: Using a personal ID where a company number is needed
- Format vs existence: Algorithm validates format only, not that the ID was actually issued
#!/usr/bin/env python3
"""Israeli ID Number Validator and Test ID Generator.
Validates and generates Israeli identification numbers including:
- Teudat Zehut (personal ID) - 9 digits, Luhn check digit
- Corporate / registered-entity numbers - 9 digits starting with 5, where the
second digit selects the type (50-59: government/private/public company,
mandatory/general partnership, partnership, foreign company, cooperative
society, amuta, endowment). All types share the same check-digit algorithm.
Usage:
python validate_id.py validate 123456782
python validate_id.py generate --count 10 --prefix 51
python validate_id.py identify 515308203
"""
import argparse
import random
import sys
def validate_israeli_id(id_number: str) -> bool:
"""Validate Israeli ID number using the check digit algorithm.
The algorithm:
1. Pad to 9 digits with leading zeros
2. Multiply each digit alternately by 1, 2, 1, 2, ...
3. If product > 9, sum the digits of the product
4. Sum all results
5. Valid if total is divisible by 10
Args:
id_number: Israeli ID number (with or without dashes/spaces)
Returns:
True if the ID number is valid, False otherwise
"""
id_str = id_number.replace('-', '').replace(' ', '').zfill(9)
if len(id_str) != 9 or not id_str.isdigit():
return False
# 000000000 passes the Luhn check (digit sum 0) but is never a real ID. It
# is the most common sentinel/empty-field false positive (an empty string
# zero-pads straight into it), so reject it explicitly.
if id_str == '000000000':
return False
total = 0
for i, digit in enumerate(id_str):
val = int(digit) * ((i % 2) + 1)
if val > 9:
val = val // 10 + val % 10
total += val
return total % 10 == 0
# Corporate / registered-entity codes: 9-digit numbers in the 5XX-million block.
# The first two digits encode the entity type; the check digit is identical to a
# personal Teudat Zehut.
CORPORATE_PREFIXES = {
"50": "Government company / pension or provident fund / local committee",
"51": "Company (Chevra Ba'am / Ltd)",
"52": "Public company",
"53": "Mandatory partnership",
"54": "General partnership",
"55": "Partnership (Shutafut)",
"56": "Foreign company",
"57": "Cooperative Society (Aguda Shitufit) / kibbutz",
"58": "Amuta (Non-profit / Registered Association)",
"59": "Endowment (Hekdesh)",
}
def identify_id_type(id_number: str) -> str:
"""Identify the type of Israeli ID based on prefix.
Prefix typing is a best-effort heuristic: corporate and registered-entity
numbers are allocated from the 5XX-million block (first two digits 50-59),
so a 9-digit number starting with 5 is overwhelmingly a registered entity.
A personal Teudat Zehut cannot be reliably typed from its prefix; only the
issuing registry is authoritative.
Args:
id_number: Israeli ID number
Returns:
String describing the ID type
"""
id_str = id_number.replace('-', '').replace(' ', '').zfill(9)
return CORPORATE_PREFIXES.get(id_str[:2], "Teudat Zehut (Personal ID)")
def generate_test_id(prefix: str = "") -> str:
"""Generate a valid Israeli ID number for testing.
Args:
prefix: Optional prefix (e.g., '51' for company, '58' for amuta)
Returns:
A valid 9-digit Israeli ID number
"""
base = prefix + ''.join([str(random.randint(0, 9)) for _ in range(8 - len(prefix))])
total = 0
for i, digit in enumerate(base):
val = int(digit) * ((i % 2) + 1)
if val > 9:
val = val // 10 + val % 10
total += val
check = (10 - (total % 10)) % 10
return base + str(check)
def format_id(id_number: str) -> str:
"""Format an Israeli ID number with standard dashes.
Args:
id_number: Raw ID number
Returns:
Formatted ID string (e.g., '51-530820-3' for company numbers)
"""
id_str = id_number.replace('-', '').replace(' ', '').zfill(9)
id_type = identify_id_type(id_str)
if id_type.startswith("Teudat Zehut"):
return id_str
else:
# Registered-entity display format XX-XXXXXX-X, applied to 5X-prefixed
# numbers. This is the heuristic corporate grouping (see identify_id_type);
# a personal ID starting with 5 would also be grouped this way.
return f"{id_str[:2]}-{id_str[2:8]}-{id_str[8]}"
def validate_with_details(id_number: str) -> dict:
"""Validate an ID and return detailed results.
Args:
id_number: Israeli ID number
Returns:
Dictionary with validation results and details
"""
id_str = id_number.replace('-', '').replace(' ', '').zfill(9)
result = {
"input": id_number,
"normalized": id_str,
"formatted": format_id(id_str),
"valid": False,
"type": identify_id_type(id_str),
"details": []
}
if len(id_str) != 9:
result["details"].append(f"Invalid length: {len(id_str)} (expected 9)")
return result
if not id_str.isdigit():
result["details"].append("Contains non-digit characters")
return result
if id_str == "000000000":
result["details"].append("Placeholder ID (all zeros): passes Luhn but is never a real ID")
return result
# Show step-by-step calculation
multipliers = []
products = []
total = 0
for i, digit in enumerate(id_str):
mult = (i % 2) + 1
val = int(digit) * mult
original_val = val
if val > 9:
val = val // 10 + val % 10
multipliers.append(mult)
products.append(val)
total += val
result["details"].append(
f"Digit {i+1}: {digit} x {mult} = {original_val}"
+ (f" -> {val}" if original_val != val else "")
)
result["details"].append(f"Sum: {total}")
result["details"].append(f"Divisible by 10: {total % 10 == 0}")
result["valid"] = total % 10 == 0
return result
def main():
parser = argparse.ArgumentParser(
description="Israeli ID Number Validator and Generator"
)
subparsers = parser.add_subparsers(dest="command", help="Command to execute")
# Validate command
validate_parser = subparsers.add_parser("validate", help="Validate an Israeli ID")
validate_parser.add_argument("id_number", help="ID number to validate")
validate_parser.add_argument("-v", "--verbose", action="store_true",
help="Show step-by-step calculation")
# Generate command
generate_parser = subparsers.add_parser("generate", help="Generate test IDs")
generate_parser.add_argument("--count", type=int, default=1,
help="Number of IDs to generate (default: 1)")
generate_parser.add_argument("--prefix", default="",
help="ID prefix (51=company, 58=amuta, 55=partnership)")
# Identify command
identify_parser = subparsers.add_parser("identify", help="Identify ID type")
identify_parser.add_argument("id_number", help="ID number to identify")
args = parser.parse_args()
if args.command == "validate":
if args.verbose:
result = validate_with_details(args.id_number)
print(f"Input: {result['input']}")
print(f"Normalized: {result['normalized']}")
print(f"Formatted: {result['formatted']}")
print(f"Type: {result['type']}")
print(f"Valid: {result['valid']}")
print("\nCalculation:")
for detail in result["details"]:
print(f" {detail}")
else:
is_valid = validate_israeli_id(args.id_number)
id_type = identify_id_type(args.id_number)
status = "VALID" if is_valid else "INVALID"
print(f"{status} - {id_type}: {format_id(args.id_number)}")
sys.exit(0 if is_valid else 1)
elif args.command == "generate":
print(f"Generating {args.count} test ID(s)"
+ (f" with prefix '{args.prefix}'" if args.prefix else "") + ":")
print("WARNING: These are for TESTING ONLY. Do not use as real IDs.\n")
for i in range(args.count):
test_id = generate_test_id(args.prefix)
id_type = identify_id_type(test_id)
print(f" {format_id(test_id)} ({id_type})")
elif args.command == "identify":
id_type = identify_id_type(args.id_number)
is_valid = validate_israeli_id(args.id_number)
print(f"Type: {id_type}")
print(f"Valid: {is_valid}")
norm = args.id_number.replace('-', '').replace(' ', '').zfill(9)
if norm[:2] in CORPORATE_PREFIXES:
print("Note: Prefix typing is heuristic. A 9-digit number starting with 5 is "
"usually a registered entity, but a personal ID cannot be ruled out by "
"prefix alone; only the issuing registry is authoritative.")
else:
parser.print_help()
if __name__ == "__main__":
main()
מאמת תעודת זהות ישראלית
הוראות
שלב 1: זיהוי סוג המספר
| סוג | קידומת | אורך | דוגמה | הערות |
|---|---|---|---|---|
| תעודת זהות (אישית) | אין (לא ניתן להסיק) | 9 ספרות | 123456782 | מוקצה בסדר עוקב; הספרות אינן מקודדות תאריך לידה, גיל או מעמד תושבות |
| תאגיד / ישות רשומה | ספרה ראשונה 5 | 9 ספרות | 51-530820-3 | נמצא בבלוק 5XX מיליון; המספר מתחיל ב-5 והספרה השנייה קובעת את סוג הישות (קודים 50-59, ראו טבלה הבאה). אותה ספרת ביקורת כמו במספר אישי |
קודי תאגידים וישויות רשומות (שתי ספרות ראשונות):
| קידומת | ישות |
|---|---|
| 50 | חברה ממשלתית, קופת פנסיה/גמל או ועד מקומי |
| 51 | חברה פרטית (בע"מ) |
| 52 | חברה ציבורית |
| 53 | שותפות חובה |
| 54 | שותפות כללית |
| 55 | שותפות |
| 56 | חברה זרה |
| 57 | אגודה שיתופית / קיבוץ |
| 58 | עמותה / חברה לתועלת הציבור |
| 59 | הקדש |
זיהוי לפי קידומת הוא היוריסטיקה: מספר בן 9 ספרות שמתחיל ב-5 הוא כמעט תמיד ישות רשומה (מספרי תאגיד מוקצים מהבלוק 5XX), אך רק הרשם המנפיק הוא מקור סמכא. תעודת זהות אישית אינה ניתנת לזיהוי לפי קידומת.
שלב 2: אימות דרך אלגוריתם ספרת ביקורת
אלגוריתם ספרת הביקורת של מספר זהות ישראלי (חל על כל הסוגים):
def validate_israeli_id(id_number: str) -> bool:
"""Validate Israeli ID number (TZ, company, amuta, etc.)"""
# Remove dashes and spaces, pad to 9 digits
id_str = id_number.replace('-', '').replace(' ', '').zfill(9)
if len(id_str) != 9 or not id_str.isdigit():
return False
if id_str == '000000000': # passes Luhn but is never a real ID
return False
total = 0
for i, digit in enumerate(id_str):
# Position counting from left: odd positions (0,2,4,6,8) multiply by 1
# Even positions (1,3,5,7) multiply by 2
weight = 1 if i % 2 == 0 else 2
val = int(digit) * weight
if val > 9:
val = val // 10 + val % 10 # Sum digits if > 9
total += val
return total % 10 == 0שלב 3: מתן תוצאה
למספרים תקינים: אישור תקינות, זיהוי סוג לפי קידומת למספרים לא תקינים: דיווח על אי-תקינות, הצגת הבדיקה שנכשלה, הצעת שגיאות נפוצות:
- ספרות מוחלפות
- ספרה חסרה/עודפת
- ספרת ביקורת שגויה
שלב 4: יצירת מספרים לבדיקה (לשימוש בפיתוח)
לצורכי פיתוח ובדיקות, אפשר ליצור מספרי זיהוי תקינים:
def generate_test_id(prefix: str = "") -> str:
"""Generate a valid Israeli ID number for testing."""
import random
base = prefix + ''.join([str(random.randint(0, 9)) for _ in range(8 - len(prefix))])
# Calculate check digit
total = 0
for i, digit in enumerate(base):
weight = 1 if i % 2 == 0 else 2
val = int(digit) * weight
if val > 9:
val = val // 10 + val % 10
total += val
check = (10 - (total % 10)) % 10
return base + str(check)הערה חשובה: מספרים שנוצרו מיועדים לבדיקות בלבד. לעולם אל תשתמשו במספרים אקראיים כזיהוי אמיתי.
דוגמאות
דוגמה 1: אימות תעודת זהות
המשתמש אומר: "האם 123456782 הוא מספר תעודת זהות תקין?" תוצאה: הרצת האלגוריתם, דיווח תקין/לא תקין עם הסבר.
דוגמה 2: מימוש בקוד
המשתמש אומר: "אני צריך אימות תעודת זהות ישראלית ב-JavaScript" תוצאה: מתן אלגוריתם מקביל ב-JavaScript.
דוגמה 3: יצירת נתוני בדיקה
המשתמש אומר: "אני צריך 10 מספרי חברה תקינים לבדיקה" תוצאה: יצירת 10 מספרים תקינים עם קידומת 51- לבדיקה.
משאבים מצורפים
סקריפטים
scripts/validate_id.py, מאמת, מזהה, מעצב ומייצר מספרי זיהוי ישראליים (תעודת זהות, חברה, עמותה, שותפות). תומך במצב מפורט המציג חישוב ספרת ביקורת שלב אחר שלב, יצירת מספרי בדיקה באצווה עם בקרת קידומת, וזיהוי סוג מכל מספר. הרצה:python scripts/validate_id.py --help
חומרי עזר
references/id-formats.md, מפרט כל פורמטי מספרי הזיהוי הישראליים כולל תעודת זהות, חברה (קידומת 51), עמותה (קידומת 58), שותפות (קידומת 55), ואגודה שיתופית (קידומת 57) עם רשויות מנפיקות, תבניות פורמט, אלגוריתם ספרת ביקורת מסוג Luhn עם דוגמה מפורטת, ושגיאות אימות נפוצות. עיינו בו בעת מימוש לוגיקת אימות או דיבוג כשלים בספרת ביקורת.
קישורי עזר
- משרד הפנים, עמוד תעודת זהות (gov.il) , עמוד רשמי של משרד הפנים על הנפקת תעודת זהות, מבנה המספר וחידוש התעודה.
- רשם החברות (justice.gov.il) , איתור מספרי חברה (51), עמותה (58), שותפות (55), ואגודה שיתופית (57).
- כל-זכות, "תעודות זהות, דרכונים ותעודות מעבר" , ערך מרכזי בויקי הזכויות לתעודות זהות, דרכונים ותעודות מעבר, כולל זכאות, החלפה וטווחי מספרים.
- חוק הגנת הפרטיות, תיקון 13 (ניתוח IAPP) , התיקון מ-2025 שמהדק את חובות ההסכמה והדיווח על אירועי דליפה. נכנס לתוקף ב-14 באוגוסט 2025.
מלכודות נפוצות
- מספרי תעודת זהות ישראליים הם בדיוק 9 ספרות עם ספרת ביקורת מסוג Luhn (mod 10). סוכנים עלולים ליצור מספרים אקראיים בני 9 ספרות שנכשלים בבדיקת ספרת הביקורת.
- מספרי תעודת זהות עם פחות מ-9 ספרות חייבים להיות מרופדים באפסים משמאל. מספר כמו "12345678" הוא בעצם "012345678". סוכנים עלולים למחוק אפסים מובילים ולשבור ולידציה.
- מספרי תעודת זהות אינם מקודדים תאריך. הם מוקצים בסדר עוקב; אי אפשר להסיק מהמספר את תאריך הלידה, הגיל, שנת הלידה או מעמד התושבות. סוכנים שלמדו על מספרי SSN בארה"ב נוטים להמציא הנחה כזו.
- אין לסווג או לפסול תעודת זהות אישית לפי טווח הספרה הראשונה. אין במספר קידוד מעמד אזרחי מתועד (החלוקה הנפוצה ל"יליד הארץ מול תושב מול עובד זר לפי טווח" היא מיתוס). כל תעודת זהות אישית עוברת את אותה בדיקת Luhn ללא תלות בספרה הראשונה; יש להתייחס לכולן כמספרים רגילים בני 9 ספרות.
- שמירת PII ופרטיות בלוגים: לעולם אל תכתבו לוג של תעודת זהות בלי מסיכה בלוגי האפליקציה, בהודעות שגיאה, בטלמטריה או באירועי אנליטיקה. חוק הגנת הפרטיות, תיקון 13 (תוקף 14 באוגוסט 2025), מהדק את חובות ההסכמה והדיווח על דליפות. בהצגה של תעודה בהקשר לא מורשה (UI לדיבוג, כלים לתמיכה, קבלה ללקוח) הסתירו את הספרות באמצע, למשל
123****82. לפני שמירה במאגר לא הכרחי, השתמשו ב-hash או טוקניזציה. - מספר אישי צבאי משתמש בפורמט שונה מתעודת זהות אזרחית ולא צריך להיבדק עם אותו אלגוריתם.
- המספר 000000000 עובר את בדיקת Luhn (סכום הספרות הוא 0, מתחלק ב-10) אך לעולם אינו תעודה אמיתית. זו תקלת ה-false positive הנפוצה ביותר: מחרוזת ריקה או עמודה עם ברירת מחדל מספרית מתרפדת באפסים ישירות אליו. דחו במפורש מספר של אפסים בלבד לפני שסומכים על תוצאת "תקין".
- אין לדחות תעודת זהות אישית לפי הספרה הראשונה. אין קידומת מתועדת של "תושב זמני מול קבוע" עבור תעודת הזהות בת 9 הספרות עם בדיקת Luhn; אמתו את הפורמט בלבד ורפדו עם
zfill(9)במקום לסנן לפי טווח.
פתרון בעיות
שגיאה: "המספר נראה תקין אך לא מזוהה"
סיבה: ספרת הביקורת עוברת אך המספר לא הונפק בפועל פתרון: האלגוריתם מאמת רק את הפורמט, לא את הקיום בפועל. אימות האם מספר הונפק בפועל דורש גישה למערכות רשות המסים או משרד הפנים.
שגיאה: "תעודה נכשלת באימות אחרי סינון לפי טווח/קידומת"
סיבה: פילטר במעלה הזרם דוחה מספרים לפי טווח הספרה הראשונה (למשל מתייחס לספרה ראשונה מסוימת כ"לא תעודה אישית"), או שספרת הביקורת נכשלת כי המספר נשמר ב-8 ספרות והאפס המוביל אבד. פתרון: כל תעודת זהות אישית משתמשת באותה בדיקת Luhn בת 9 ספרות ללא תלות בספרה הראשונה, ואין מיפוי אמין של מעמד לפי טווח. הוסיפו אפסים מובילים (zfill(9)) לפני האימות, והסירו כל רשימת היתר לפי טווח ספרה ראשונה. שימו לב שמספר בן 9 ספרות שמתחיל ב-5 הוא לרוב ישות רשומה ולא תעודה אישית.
שגיאה: "אורך לא תואם / אפס מוביל נחתך"
סיבה: גיליון אלקטרוני, parser של JSON או עמודה מספרית הפילו את האפס המוביל (למשל 012345678 שנשמר כ-integer הופך ל-12345678). פתרון: שמרו תמיד את התעודה כמחרוזת. בקריאה הוסיפו אפסים משמאל לאורך 9 עם zfill(9) (Python) או padStart(9, '0') (JS) לפני שמריצים את הבדיקה. דחו רק אחרי הריפוד.
שגיאה: "קלט לא תקין, יש מקפים או רווחים בתעודה"
סיבה: המשתמש הדביק מספר חברה או עמותה מעוצב כמו 51-530820-3 או 58 012345 3. פתרון: הסירו את כל התווים שאינם ספרות (re.sub(r'\D', '', id)) לפני בדיקת אורך. גם הצורה האנושית-מעוצבת וגם הספרות הגולמיות חייבות לעבור את אותה בדיקה.
שגיאה: "קלט בן 9 ספרות אבל האלגוריתם נכשל"
סיבה: לרוב מדובר בהחלפת מקום בין שתי ספרות או שגיאת הקלדה בגוף המספר, לא בספרת הביקורת. סיבות נוספות: העתקה ממקור עברי בכיוון RTL שהפך את סדר הספרות, או שמדובר במספר אישי צבאי (שאינו עובר את אלגוריתם Luhn האזרחי). פתרון: בקשו מהמשתמש להקליד מחדש מהמסמך המקורי. אם זה עדיין נכשל והמשתמש מתעקש שהמספר נכון, הציעו אימות חיצוני מול הרשם המנפיק; לא "מתקנים" ספרת ביקורת בלי לדעת מה האמת.
Related skills
How it compares
Use as a locale-specific validation spec skill—not a generic UUID or credit-card validator pattern.
FAQ
Who is israeli-id-validator for?
It is for developers and agent users implementing Israeli ID, ח"פ, or amuta number checks in applications targeting users or companies in Israel.
When should I use israeli-id-validator?
Use it during Build/backend when adding signup, invoicing, or compliance forms that accept teudat zehut or Israeli company numbers, or when writing unit tests that need valid test IDs.
Is israeli-id-validator safe to install?
Review the Security Audits panel on this Prism page; the skill is reference and algorithm guidance and should not require live PII unless you explicitly pass sample numbers in chat.