Guide · Node.js · SDK · REST API

SEDOL Validation in Node.js

A 7-character identifier that underpins UK and Irish securities markets. Here's how to validate SEDOLs correctly — weighted check digit algorithm, edge cases, and a single API call that enriches the result with live instrument data.

1. What is a SEDOL?

A SEDOL (Stock Exchange Daily Official List) is a 7-character alphanumeric identifier assigned by the London Stock Exchange Group (LSEG) to securities listed on UK and Irish exchanges, as well as a large number of internationally traded instruments. First introduced in 1979, SEDOLs are the primary security identifier in the UK financial infrastructure.

CREST — the central securities depository for UK and Irish equities and bonds, operated by Euroclear — uses SEDOLs as a key reference in settlement instructions. The UK's Financial Conduct Authority (FCA) references SEDOLs in transaction reporting under MiFIR (Markets in Financial Instruments Regulation), alongside ISINs.

SEDOLs cover equities, gilts (UK government bonds), corporate bonds, exchange-traded funds, and investment trusts. The SEDOL Masterfile — maintained by LSEG — contains over 100 million securities from markets worldwide, making SEDOL a global identifier despite its UK origins.


2. SEDOL anatomy

Every SEDOL is exactly 7 characters long, divided into two parts:

PartPositionsLengthDescription
Base code1 – 66Alphanumeric identifier assigned by LSEG (digits 0–9 and consonants B–Z)
Check digit71Single digit (0–9) computed using a weighted modulo-10 algorithm

Modern SEDOLs (issued after 2004) use only consonants — vowels (A, E, I, O, U) are excluded from the base code to avoid ambiguity when codes are spoken or handwritten. Older SEDOLs allocated before 2004 may contain vowels and remain valid.

Some well-known examples:

SEDOLBase (1–6)Check (7)Security
07980590798059BP PLC (Common Stock)
05405280540528HSBC Holdings PLC (Common Stock)
07188750718875Rio Tinto PLC (Common Stock)
ℹ️SEDOLs are exchange-specific — the same underlying company may have multiple SEDOLs if its shares are listed on more than one market. Unlike ISINs (which are global and exchange-agnostic), a SEDOL identifies a specific listing on a specific market.

3. The check digit algorithm

The SEDOL check digit uses a weighted modulo-10 algorithm — simpler than the CUSIP modified Luhn, but with its own specific weight sequence and character mapping. The character values are:

CharacterNumeric value
0 – 90 – 9 (face value)
A – Z10 – 35 (A=10, B=11, …, Z=35)

The fixed position weights applied to the first 6 characters are:

Position123456
Weight131739

The algorithm is:

  1. For each of the first 6 characters, convert it to its numeric value using the mapping above.
  2. Multiply each value by the corresponding weight from the table above.
  3. Sum all 6 weighted values to get S.
  4. The check digit is (10 - (S % 10)) % 10.

Example — BP PLC (079805):

PosCharValueWeightProduct
10010
277321
39919
488756
50030
655945
Sum131

Check digit = (10 - (131 % 10)) % 10 = (10 - 1) % 10 = 9. Full SEDOL: 0798059

Here is what a naive Node.js implementation looks like:

// sedolCheck.js — naive implementation (format + check digit only)

/**
 * Map a SEDOL character to its numeric value.
 * 0-9 = 0-9, A-Z = 10-35
 */
function charValue(ch) {
  const code = ch.charCodeAt(0);
  if (code >= 48 && code <= 57) return code - 48;   // '0'-'9'
  if (code >= 65 && code <= 90) return code - 55;   // 'A'-'Z'
  throw new Error(`Invalid SEDOL character: ${ch}`);
}

const WEIGHTS = [1, 3, 1, 7, 3, 9];

/**
 * Compute the SEDOL check digit.
 * Input: the first 6 characters of a SEDOL.
 * Returns: the expected check digit (0-9).
 */
function computeCheckDigit(base6) {
  let sum = 0;
  for (let i = 0; i < 6; i++) {
    sum += charValue(base6[i]) * WEIGHTS[i];
  }
  return (10 - (sum % 10)) % 10;
}

const SEDOL_RE = /^[A-Z0-9]{6}[0-9]$/;

function validateSedolFormat(sedol) {
  sedol = sedol.replace(/\s/g, '').toUpperCase();

  if (sedol.length !== 7 || !SEDOL_RE.test(sedol)) {
    return { valid: false, reason: 'format' };
  }

  const expected = computeCheckDigit(sedol.slice(0, 6));
  const actual = Number(sedol[6]);

  if (expected !== actual) {
    return { valid: false, reason: 'check_digit' };
  }

  return {
    valid: true,
    sedol,
    checkDigit: sedol[6],
  };
}

// ── Examples ──────────────────────────────────────────────────────────────────
console.log(validateSedolFormat('0798059'));   // valid — BP PLC
console.log(validateSedolFormat('0540528'));   // valid — HSBC Holdings
console.log(validateSedolFormat('0798051'));   // invalid check digit
console.log(validateSedolFormat('07980'));     // invalid format (too short)
⚠️This implementation catches format errors and invalid check digits — but it tells you nothing about the underlying security. A structurally valid SEDOL might refer to a delisted instrument, a fund that has been wound up, or an identifier that was reassigned after a corporate action. The check digit alone cannot tell you whether the SEDOL maps to a live, tradeable security.

4. Why manual validation isn't enough

SEDOLs are exchange-specific, not global

Unlike ISINs, which uniquely identify a security regardless of where it trades, a SEDOL identifies a specific listing. The same company can have multiple SEDOLs — one for its ordinary shares on the London Stock Exchange main market, another for its AIM-listed shares, and potentially others for depositary receipts or dual listings. Validating the format tells you nothing about which listing the SEDOL refers to.

Pre-2004 SEDOLs may contain vowels

LSEG stopped issuing SEDOLs with vowels in 2004 to avoid character ambiguity, but millions of legacy SEDOLs with vowels in positions 1–6 remain in circulation. A validator that rejects vowels will incorrectly discard valid legacy codes. A validator that allows vowels passes the structural test but still cannot determine whether the code is active.

Corporate actions and delistings invalidate SEDOLs

When a company is acquired, merges, or delists, its SEDOL may be retired or reassigned. A structurally correct SEDOL might refer to a company that ceased to exist years ago. For any production use case — order routing, portfolio management, regulatory reporting — you need a live data source to confirm the SEDOL is active.

No free public SEDOL database

The authoritative SEDOL Masterfile is a commercial product maintained by LSEG. There is no freely downloadable complete database of all valid SEDOLs. Maintaining your own lookup table is impractical; using an API that integrates OpenFIGI is the practical alternative for most applications.


5. The right solution: one API call

Instead of implementing the check digit algorithm yourself and trying to maintain a reference dataset, use the IsValid SEDOL API. A single GET /v0/sedol request handles format validation, check digit verification, and instrument lookup via OpenFIGI — all in one call.

Full
Validation
Format + weighted check digit
Live
Enrichment
Name, ticker, FIGI, sector & more
100/day
Free tier
no credit card

Get your free API key at isvalid.dev. The free tier includes 100 calls per day — enough for most development and low-volume production use.

Full parameter reference and response schema: SEDOL Validation API docs →


6. Node.js code example

Using the @isvalid-dev/sdk package or the native fetch API (Node 18+).

// sedolValidator.js
import { createClient } from '@isvalid-dev/sdk';

const iv = createClient({ apiKey: process.env.ISVALID_API_KEY });

// ── Example usage ─────────────────────────────────────────────────────────────

const result = await iv.sedol('0798059');  // BP PLC

if (!result.valid) {
  console.log('Invalid SEDOL: failed format or check digit');
} else {
  console.log(`SEDOL       : ${result.sedol}`);
  console.log(`Check digit : ${result.checkDigit}`);
  if (result.found) {
    console.log(`Name        : ${result.name}`);
    console.log(`Ticker      : ${result.ticker}`);
    console.log(`Exchange    : ${result.exchCode}`);
    console.log(`FIGI        : ${result.figi}`);
    console.log(`Sector      : ${result.marketSector}`);
  }
}

Expected output for 0798059:

SEDOL       : 0798059
Check digit : 9
Name        : BP PLC
Ticker      : BP/
Exchange    : LN
FIGI        : BBG000BT4FC2
Sector      : Equity

In an Express.js route handler:

// routes/securities.js (Express)
app.get('/securities/validate-sedol', async (req, res) => {
  const { sedol } = req.query;

  if (!sedol) {
    return res.status(400).json({ error: 'Missing sedol parameter' });
  }

  let result;
  try {
    result = await validateSedol(sedol);
  } catch {
    return res.status(502).json({ error: 'SEDOL validation service unavailable' });
  }

  if (!result.valid) {
    return res.status(400).json({ error: 'Invalid SEDOL', sedol });
  }

  res.json({
    sedol: result.sedol,
    checkDigit: result.checkDigit,
    found: result.found ?? null,
    name: result.name ?? null,
    ticker: result.ticker ?? null,
    exchCode: result.exchCode ?? null,
    figi: result.figi ?? null,
  });
});
The API strips whitespace and uppercases the input automatically — pass the raw user input without pre-processing. Both 079 805 9 and 0798059 are handled correctly.

7. cURL example

Validate a SEDOL from the command line:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://api.isvalid.dev/v0/sedol?value=0798059"

HSBC Holdings:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://api.isvalid.dev/v0/sedol?value=0540528"

Invalid check digit — the API returns valid: false:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://api.isvalid.dev/v0/sedol?value=0798051"

8. Understanding the response

Response for a valid SEDOL found in OpenFIGI:

{
  "valid": true,
  "sedol": "0798059",
  "checkDigit": "9",
  "found": true,
  "dataSource": "openfigi",
  "name": "BP PLC",
  "ticker": "BP/",
  "exchCode": "LN",
  "securityType": "Common Stock",
  "marketSector": "Equity",
  "figi": "BBG000BT4FC2",
  "compositeFIGI": "BBG000BT4FC2"
}

Response for a valid SEDOL not found in OpenFIGI:

{
  "valid": true,
  "sedol": "0798059",
  "checkDigit": "9",
  "found": false
}

Response for an invalid SEDOL:

{
  "valid": false
}
FieldTypeDescription
validbooleanFormat + check digit validation result
sedolstringNormalised (uppercased) SEDOL
checkDigitstringThe 7th character (always a digit 0–9)
foundboolean | nulltrue — found in OpenFIGI; false — not found; null — OpenFIGI unavailable
dataSourcestringAlways openfigi when present
namestring | nullFull instrument name from OpenFIGI
tickerstring | nullExchange ticker symbol
exchCodestring | nullBloomberg exchange code (e.g. LN for London)
securityTypestring | nullSecurity type (e.g. Common Stock)
marketSectorstring | nullMarket sector (e.g. Equity)
figistring | nullFinancial Instrument Global Identifier
compositeFIGIstring | nullComposite FIGI across all exchanges

9. Edge cases to handle

found: null vs. found: false

found: false means OpenFIGI was reachable but did not recognise the SEDOL. found: null means the lookup could not be completed (network error, timeout, or API rate limit). In the null case, the SEDOL is still structurally valid — treat it as an inconclusive result and retry later rather than rejecting it.

Legacy SEDOLs with vowels

The API accepts SEDOLs with vowels in positions 1–6 and validates the check digit correctly. If your own validation layer pre-filters input, make sure it does not reject vowels — only the check digit algorithm matters for structural validity.

SEDOL vs. ISIN — know which you have

UK ISINs are built from SEDOLs: GB00 + SEDOL (7 chars) + ISIN check digit. If you receive a 12-character code starting with GB, use /v0/isin instead. If you have a 7-character code, use /v0/sedol.


10. Summary

WhatDetail
Format7 characters: 6 alphanumeric + 1 check digit
Check algorithmWeighted sum with weights [1,3,1,7,3,9], modulo 10
Issuing authorityLSEG (London Stock Exchange Group)
CoverageUK, Ireland, and globally traded instruments (100M+ in SEDOL Masterfile)
Enrichment sourceOpenFIGI (Bloomberg) via ID_SEDOL
API endpointGET /v0/sedol?value=0798059

For cross-referencing, see also: