Paste an ISIN and find out whether it passes the ISO 6166 check digit. If it does not, this tells you exactly what is wrong and shows you the arithmetic, so you can see the answer rather than take someone's word for it.
An ISIN is always twelve characters, in three parts. Most problems people run into are in the first two, and they are usually a copy-and-paste accident rather than anything to do with the arithmetic.
| Part | Length | What it is | Example |
|---|---|---|---|
| Country code | 2 | Two letters, ISO 3166. IN for India, US for the United States. XS is used for international issues that do not belong to one country. | US |
| Identifier | 9 | Letters and digits, assigned by the national numbering agency. In India that is NSDL or CDSL. | 037833100 |
| Check digit | 1 | A single digit, calculated from the other eleven. This is what catches a typo. | 5 |
Indian mutual fund ISINs start INF rather than IN plus something. That is not a mistake: IN is the country and F is the first character of the identifier, which NSDL uses to mean a fund. Equities are usually INE.
It is a Luhn-style mod 10, the same family as the check on a credit card number. The point of it is to catch a single mistyped character and most swapped pairs, which is why a wrong ISIN is usually a wrong ISIN rather than somebody else's security.
Every letter becomes a two-digit number, A being 10 through to Z being 35. Digits stay as they are.
These are the ASCII codes minus 55, which is why A is 10.
Put another way, the whole twelve-character ISIN including its check digit adds up to a multiple of ten. That is the whole test.
Apple's ISIN is US0378331005, and the check digit is the final five. U is 30 and S is 28, so the first eleven characters become 3028037833100. Doubling every second digit from the right and adding the digits gives 45. The next multiple of ten is 50, and 50 minus 45 is 5.
Type it into the box above to see the same thing laid out in full.
A passing check digit means the ISIN is well formed. It does not mean the security exists, that it is still listed, or that it is the one you wanted. The check digit catches typing mistakes, nothing more.
Equally, a real and perfectly valid ISIN can fail to turn up in any given database, which is a different problem from being malformed. If a system tells you an ISIN is not found, check here first: if it passes, the ISIN is fine and the gap is in the data, not in what you typed.
If you would rather do this yourself, it is about fifteen lines. This is the whole algorithm, not a simplification.
def isin_check_digit(body): # body = the first 11 characters
digits = "".join(str(ord(c) - 55) if c.isalpha() else c for c in body.upper())
total, double = 0, True # rightmost body digit is doubled
for ch in reversed(digits):
d = int(ch) * (2 if double else 1)
total += d - 9 if d > 9 else d
double = not double
return (10 - total % 10) % 10
def is_valid(isin):
return (len(isin) == 12 and isin[:2].isalpha() and isin[2:11].isalnum()
and isin[11].isdigit()
and isin_check_digit(isin[:11]) == int(isin[11]))
Do check it against a known-good ISIN and a deliberately broken one before you trust it. A validator that accepts everything looks exactly like a validator that works.