---
title: "What is an ISIN? A developer's guide to fund and ETF identifiers"
description: "ISIN format, check digit, how it differs from tickers, SEDOL, CUSIP and WKN, and how to validate an ISIN in code before you look up fund data."
canonical: https://fundfactsapi.com/blog/what-is-an-isin
published: 2026-08-12
updated: 2026-08-12
publisher: FundFacts API
---

# What is an ISIN? A developer's guide to fund and ETF identifiers

> ISIN format, check digit, how it differs from tickers, SEDOL, CUSIP and WKN, and how to validate an ISIN in code before you look up fund data.

If you work with investment funds, you will meet the ISIN before anything else. It is printed on factsheets, KIDs, order confirmations and custody statements, and it is the key that almost every fund data API — including [FundFacts API](https://fundfactsapi.com/) — accepts as input. This guide explains what an ISIN is, how it is built, how it compares with other identifiers and how to validate one in code.

## The short definition

An **ISIN** (International Securities Identification Number) is a 12-character code that uniquely identifies a security worldwide. It is defined by ISO 6166 and issued by each country's National Numbering Agency. Every share class of every fund has its own ISIN, which is exactly why it is the right key for fund data: `IE00B4L5Y983` means one specific share class of one specific ETF, not "the MSCI World ETF" in general.

## Anatomy of an ISIN

| Position | Meaning | Example (`IE00B4L5Y983`) |
| --- | --- | --- |
| 1–2 | ISO 3166 country code of the issuing agency | `IE` (Ireland) |
| 3–11 | National Securities Identifying Number (NSIN), padded with zeros | `00B4L5Y98` |
| 12 | Check digit (Luhn algorithm) | `3` |

A few practical consequences:

- The country prefix tells you **where the fund is domiciled**, not where it is sold. Irish (`IE`) and Luxembourg (`LU`) prefixes dominate UCITS funds distributed across Europe.
- The middle part often embeds a national code. For UK and Irish securities it is the SEDOL; for US securities it is the CUSIP. That is why US ISINs look like `US` + 9-digit CUSIP + check digit.
- Letters are allowed anywhere in positions 3–11, so never store ISINs as numbers.

## ISIN vs ticker, SEDOL, CUSIP, WKN

| Identifier | Scope | Unique per share class? | Typical use |
| --- | --- | --- | --- |
| ISIN | Global | Yes | Fund data, settlement, regulatory reporting |
| Ticker | Per exchange | No — the same ETF has different tickers on Xetra, LSE and Borsa Italiana | Trading screens |
| SEDOL | UK / Ireland | Yes | UK custody and settlement |
| CUSIP | US / Canada | Yes | North American markets |
| WKN | Germany | Yes | German retail platforms |

Tickers are the trap. `IWDA` on the London Stock Exchange, `EUNL` on Xetra and `SWDA` on Borsa Italiana are all the same share class — the ISIN is what unifies them. If your users type tickers, map them to ISINs first; if they type ISINs, you are already done.

## Validating an ISIN in code

Before you spend a request on a lookup, check the format and the check digit. The check digit uses the Luhn algorithm applied to the digit expansion of the code (A=10, B=11 … Z=35).

```javascript
const ISIN_RE = /^[A-Z]{2}[A-Z0-9]{9}\d$/;

export function isValidIsin(raw) {
  const isin = String(raw ?? "").trim().toUpperCase();
  if (!ISIN_RE.test(isin)) return false;

  let digits = "";
  for (const ch of isin) {
    const code = ch.charCodeAt(0);
    digits += code >= 65 ? String(code - 55) : ch; // A -> 10 ... Z -> 35
  }

  let sum = 0;
  let double = false;
  for (let i = digits.length - 1; i >= 0; i--) {
    let d = Number(digits[i]);
    if (double) { d *= 2; if (d > 9) d -= 9; }
    sum += d;
    double = !double;
  }
  return sum % 10 === 0;
}

isValidIsin("IE00B4L5Y983"); // true
isValidIsin("IE00B4L5Y984"); // false — bad check digit
```

The same logic in Python:

```python
import re

ISIN_RE = re.compile(r"^[A-Z]{2}[A-Z0-9]{9}\d$")

def is_valid_isin(raw: str) -> bool:
    isin = (raw or "").strip().upper()
    if not ISIN_RE.match(isin):
        return False
    digits = "".join(str(ord(c) - 55) if c.isalpha() else c for c in isin)
    total, double = 0, False
    for ch in reversed(digits):
        d = int(ch)
        if double:
            d = d * 2
            if d > 9:
                d -= 9
        total += d
        double = not double
    return total % 10 == 0
```

> **Tip** FundFacts API runs exactly this validation server-side and returns `400 invalid_isin` for malformed codes, so a typo never counts against your quota. Validating client-side just saves a round trip.

## Common gotchas

- **Lower case and whitespace.** Users paste ISINs from PDFs with stray spaces. Normalise with `trim().toUpperCase()`.
- **Confusing 0 and O.** `O` is a valid character in positions 3–11; the check digit will usually catch a swap, but not always. Show the parsed ISIN back to the user.
- **Share classes.** A fund family can have dozens of ISINs (accumulating vs distributing, hedged vs unhedged, retail vs institutional). Ask for the ISIN, not the fund name.
- **Reused codes.** ISINs are not recycled, but a fund can be liquidated. A valid ISIN does not guarantee a live product — your data layer should return a clean 404 in that case.

## From ISIN to data

Once you have a valid ISIN, a single request returns the structured factsheet:

```bash
curl https://fundfactsapi.com/api/v1/funds/IE00B4L5Y983 \
  -H "Authorization: Bearer ffk_your_key"
```

The response contains key facts, holdings, exposures, risk metrics and performance in one JSON schema. See [how to get fund data from an ISIN](https://fundfactsapi.com/blog/fund-data-api-from-isin) for a full walkthrough, or [create a free key](https://fundfactsapi.com/signup) and try your own ISIN.

## About FundFacts API

FundFacts turns any fund or ETF ISIN into one dated factsheet (fees and KID costs, the 1–7 risk indicator, holdings, sector and country exposure, returns) read from the fund house's own documents: as a client-ready PDF under your firm's name for advisers and wealth managers, as JSON through its API for developers, or inside ChatGPT and Claude through its MCP server.

FundFacts works inside ChatGPT and Claude as a connector (a remote MCP server): ask about any fund or ETF by ISIN, ticker or name and the assistant answers from FundFacts' dated figures, fees, risk, holdings, exposure and returns, with fund cards, side-by-side comparisons, holdings overlap and portfolio look-through.

- Free API key, no card: https://fundfactsapi.com/signup
- Documentation: https://fundfactsapi.com/docs (OpenAPI: https://fundfactsapi.com/openapi.json)
- MCP server: https://fundfactsapi.com/api/mcp (set-up for every client: https://fundfactsapi.com/mcp-server)
- Pricing: https://fundfactsapi.com/pricing
- Site index for AI assistants: https://fundfactsapi.com/llms.txt
- Informational data, not investment advice.
