Guide · Node.js · Compliance

EMIR & MiCA Compliance — DTI and LEI Validation for Crypto

Crypto-asset derivatives under EMIR and crypto-asset services under MiCA both require validated identifiers. Here's how to validate DTI and LEI codes for regulatory reporting — and what happens when you don't.

1. EMIR and MiCA — what crypto firms need to report

Two EU regulations now require crypto firms to submit validated identifiers with every report. If you trade crypto-asset derivatives or operate a crypto-asset service, you need both DTI and LEI — and both must pass validation before submission.

EMIR (European Market Infrastructure Regulation)

EMIR requires reporting of all derivative contracts to trade repositories (TRs). Since the EMIR Refit (2024), crypto-asset derivatives — Bitcoin futures, Ethereum options, stablecoin swaps — fall under the same reporting obligation as traditional derivatives.

Key reporting fields:

  • Underlying asset — identified by DTI (when the underlying is a crypto-asset)
  • Counterparties — both sides identified by LEI
  • UPI — the Unique Product Identifier, which incorporates the DTI for crypto underliers

MiCA (Markets in Crypto-Assets Regulation)

MiCA entered into force in June 2023 (transitional) with full application from December 2024. It requires Crypto-Asset Service Providers (CASPs) to:

  • Identify all crypto-assets they list or trade using DTI
  • Identify themselves and their clients using LEI
  • Report to NCAs with valid, unambiguous identifiers
ℹ️EMIR focuses on derivatives (futures, options, swaps) where the underlying is a crypto-asset. MiCA covers the spot crypto market — exchanges, custody, transfers. Both require DTI + LEI.

2. DTI — identifying the digital token

A Digital Token Identifier (DTI) is a 9-character code defined by ISO 24165 that uniquely identifies a crypto-asset. The DTI uses a restricted 30-character alphabet (digits 0-9 plus 20 consonants, no vowels) and includes a check character as the 9th character.

TokenDTI
Bitcoin4H95J0R2X
EthereumX9J9K872S
Tether USDTNJP1WF2Z

Two types of identifiers exist in the DTIF registry:

  • DTI (Digital Token Identifier) — identifies the token itself
  • DLI (Distributed Ledger Identifier) — identifies the blockchain/ledger

For EMIR: the underlying asset DTI must be included in the trade report. For MiCA: every crypto-asset listed on a CASP must have a valid DTI.


3. LEI — identifying the counterparty

A Legal Entity Identifier (LEI) is a 20-character alphanumeric code (ISO 17442) that uniquely identifies a legal entity. Every participant in a regulated transaction must have a valid, current LEI.

EntityLEI
Goldman Sachs784F5XWPLTWKTBV3E584
Deutsche Bank7LTWFZYICNSX8D621K86

For EMIR: both counterparties must have active LEIs. For MiCA: CASPs must have LEIs, and institutional clients should be identified by LEI.

⚠️LEIs expire annually. A LAPSED registration status means the entity failed to renew. Regulators reject reports with LAPSED LEIs — always check registrationStatus before submitting.

4. DTI validation — format + DTIF registry lookup

The IsValid DTI API performs two checks in a single call:

1

Format check

9 characters, restricted alphabet, first char ≠ 0

2

DTIF registry lookup

Confirms the DTI has been officially assigned

Response — Bitcoin DTI (found in registry)

{
  "valid": true,
  "normalized": "4H95J0R2X",
  "payload": "4H95J0R2",
  "checkChar": "X",
  "found": true,
  "identifierType": "token",
  "name": "Bitcoin",
  "shortName": "BTC",
  "dtiType": "protocol"
}

What to check for compliance

  • valid === true — format is correct
  • found === true — officially registered with DTIF
  • identifierType — tells you if it's a "token" (DTI) or "ledger" (DLI)
⚠️A DTI that passes format checks but has found: false is not registered with DTIF. Using unregistered DTIs in regulatory reports will be rejected.

5. LEI validation — MOD-97 + GLEIF lookup

The IsValid LEI API performs a multi-step verification chain:

1

ISO 17442 MOD-97 checksum

Same algorithm as IBAN — remainder must equal 1

2

GLEIF database lookup

2.3M records from GLEIF Golden Copy — dataSource: "gleif-db"

3

GLEIF API fallback

If not found locally, query GLEIF REST API — dataSource: "gleif-api"

4

LOU resolution

Entity details, registration status, and managing LOU returned

Response — Goldman Sachs (entity found)

{
  "valid": true,
  "lei": "784F5XWPLTWKTBV3E584",
  "louCode": "784F",
  "checkDigits": "84",
  "found": true,
  "dataSource": "gleif-db",
  "entity": {
    "legalName": "GOLDMAN SACHS GROUP INC",
    "country": "US",
    "entityStatus": "ACTIVE",
    "registrationStatus": "ISSUED",
    "category": null,
    "initialRegistrationDate": "2012-06-06",
    "lastUpdate": "2024-08-14",
    "nextRenewal": "2025-08-14",
    "managingLou": "EVK05KS7XY1DEII3R011"
  },
  "lou": null
}

What to check for compliance

  • valid === true — format and checksum are correct
  • found === true — entity exists in GLEIF
  • entity.registrationStatus === "ISSUED" — not "LAPSED"
  • entity.entityStatus === "ACTIVE" — entity is currently operating

6. Validating both in parallel

A crypto derivative trade report needs three validated identifiers: the underlying asset (DTI), the buyer (LEI), and the seller (LEI). Validate all three in parallel using Promise.all:

// emir-mica-validator.mjs
const API_KEY = process.env.ISVALID_API_KEY;
const BASE = 'https://api.isvalid.dev';
const headers = { Authorization: `Bearer ${API_KEY}` };

async function callApi(path, params) {
  const url = new URL(path, BASE);
  Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
  const res = await fetch(url, { headers });
  if (!res.ok) throw new Error(`${path}: ${res.status}`);
  return res.json();
}

async function validateCryptoReport({ dti, buyerLei, sellerLei }) {
  const [dtiResult, buyerResult, sellerResult] = await Promise.all([
    callApi('/v0/dti', { value: dti }),
    callApi('/v0/lei', { value: buyerLei }),
    callApi('/v0/lei', { value: sellerLei }),
  ]);

  const errors = [];

  // DTI checks
  if (!dtiResult.valid) errors.push('DTI: invalid format');
  else if (!dtiResult.found) errors.push('DTI: not registered with DTIF');

  // Buyer LEI checks
  if (!buyerResult.valid) errors.push('Buyer LEI: invalid checksum');
  else if (!buyerResult.found) errors.push('Buyer LEI: entity not found in GLEIF');
  else if (buyerResult.entity?.registrationStatus === 'LAPSED')
    errors.push('Buyer LEI: registration LAPSED — must be renewed');

  // Seller LEI checks
  if (!sellerResult.valid) errors.push('Seller LEI: invalid checksum');
  else if (!sellerResult.found) errors.push('Seller LEI: entity not found in GLEIF');
  else if (sellerResult.entity?.registrationStatus === 'LAPSED')
    errors.push('Seller LEI: registration LAPSED — must be renewed');

  return {
    valid: errors.length === 0,
    errors,
    dti: dtiResult,
    buyer: buyerResult,
    seller: sellerResult,
  };
}

// ── Example: Bitcoin futures trade ──────────────────────────────────────────
const report = await validateCryptoReport({
  dti: '4H95J0R2X',                  // Bitcoin
  buyerLei: '784F5XWPLTWKTBV3E584',  // Goldman Sachs
  sellerLei: '7LTWFZYICNSX8D621K86', // Deutsche Bank
});

if (report.valid) {
  console.log('✓ All identifiers valid — ready for TR submission');
  console.log('  Token:', report.dti.name, `(${report.dti.shortName})`);
  console.log('  Buyer:', report.buyer.entity.legalName);
  console.log('  Seller:', report.seller.entity.legalName);
} else {
  console.log('✗ Validation errors:');
  report.errors.forEach(e => console.log(' ', e));
}

For high-volume reporting, validate a batch of trades before submission:

// Validate a batch of crypto derivative reports
const trades = [
  { dti: '4H95J0R2X', buyerLei: '784F5XWPLTWKTBV3E584', sellerLei: '7LTWFZYICNSX8D621K86' },
  { dti: 'JW7SD9THP', buyerLei: '784F5XWPLTWKTBV3E584', sellerLei: 'HWUPKR0MPOU8FGXBT394' },
];

const results = await Promise.all(trades.map(validateCryptoReport));

const failed = results.filter(r => !r.valid);
console.log(`${results.length} trades validated, ${failed.length} failed`);
failed.forEach((r, i) => {
  console.log(`Trade ${i + 1}:`, r.errors.join(', '));
});
For high-volume reporting, validate the batch before submission. A single invalid identifier in a batch can delay the entire file at the trade repository.

7. cURL examples

Validate a DTI (Bitcoin):

curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://api.isvalid.dev/v0/dti?value=4H95J0R2X"

Validate a LEI (Goldman Sachs — buyer):

curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://api.isvalid.dev/v0/lei?value=784F5XWPLTWKTBV3E584"

Validate a LEI (Deutsche Bank — seller):

curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://api.isvalid.dev/v0/lei?value=7LTWFZYICNSX8D621K86"

8. Regulatory edge cases

LAPSED LEI

The most common EMIR/MiCA rejection. LEIs expire annually — if registrationStatus is "LAPSED", the entity must renew before the report can be accepted. Flag and notify the counterparty.

const result = await callApi('/v0/lei', { value: lei });

if (result.valid && result.found && result.entity?.registrationStatus === 'LAPSED') {
  console.warn(`LEI ${lei} is LAPSED — renewal required before reporting`);
  // Notify the counterparty: their LEI must be renewed
  // Do NOT submit to the trade repository
}

Unregistered DTI

A crypto-asset that has no DTI assigned by DTIF. This can happen with newly launched tokens or tokens on niche blockchains. For EMIR Refit, the DTI must be registered — an unregistered DTI will be rejected by the trade repository.

const result = await callApi('/v0/dti', { value: dti });

if (result.valid && !result.found) {
  console.warn(`DTI ${dti} is not in the DTIF registry`);
  // The token may exist but has no official DTI
  // Contact DTIF to request registration before reporting
}

DLI vs DTI confusion

The DTIF registry contains both Digital Token Identifiers (DTI) and Distributed Ledger Identifiers (DLI). Bitcoin the token (4H95J0R2X) and the Bitcoin blockchain are different identifiers. Check the identifierType field — use "token" for asset reporting, "ledger" for infrastructure reporting.

const result = await callApi('/v0/dti', { value: dti });

if (result.valid && result.found) {
  if (result.identifierType === 'ledger') {
    console.warn(`${dti} is a DLI (ledger), not a DTI (token)`);
    // For EMIR/MiCA asset reporting, you need a token identifier
    // This DLI identifies the blockchain, not the asset
  }
}

Cross-regulation: EMIR + MiCA overlap

A CASP that trades crypto-asset derivatives falls under both EMIR (for derivatives) and MiCA (for the spot crypto business). Both validations apply. The same LEI is used for both, but DTI usage may differ — EMIR requires it for the underlying asset in a derivative contract, MiCA requires it for the listed asset on the exchange. Both regulations reject invalid or unregistered identifiers, so validate once and use the result for both reporting obligations.


9. Summary checklist

Do not use unregistered DTIs in trade reports — only found: true is accepted
Do not submit reports with LAPSED LEIs — renew first
Do not confuse DTI (token) and DLI (ledger) — check identifierType
Validate both DTI and LEI before submission to the trade repository
Check registrationStatus for LEI — only "ISSUED" is regulatory-compliant
Use batch validation for high-volume reporting — catch errors before the TR rejects them

See also

Start validating for EMIR & MiCA

Free tier includes 100 API calls per day. No credit card required. DTI registry lookup and LEI validation included.