CFI Code Validation in Node.js — ISO 10962 Decoded
CFI codes appear in ISIN lookups, MiFID II filings, and financial data feeds — but their 6-letter structure is rarely explained. Here's what each position encodes and how to validate and decode them in your application.
In this guide
- 1. What is a CFI code?
- 2. The 6-position structure
- 3. Position 1: the 13 asset categories
- 4. Position 2 and 3–6: groups and attributes
- 5. Decoding ESVUFR — equity share step by step
- 6. Decoding DBFAXR — bond step by step
- 7. Where CFI codes appear in practice
- 8. The production-ready solution
- 9. Node.js code example
- 10. cURL example and response
1. What is a CFI code?
A CFI code (Classification of Financial Instruments) is a standardised 6-character alphabetic identifier defined by ISO 10962:2021. It encodes what a financial instrument is — its asset class, instrument type, and key structural attributes — in a machine-readable format that is consistent across markets, countries, and regulatory regimes.
CFI codes are maintained by the Association of National Numbering Agencies (ANNA) and are included in ISIN records, MiFID II trade reporting, ESMA FIRDS regulatory filings, and most institutional-grade financial data feeds.
2. The 6-position structure
Every CFI code is exactly 6 uppercase letters. Each position has a fixed role:
| Position | Name | Meaning | Example (ESVUFR) |
|---|---|---|---|
| 1 | Category | Asset class — the top-level instrument type | ESVUFR → Equities |
| 2 | Group | Instrument type within the category | ESVUFR → Shares (common) |
| 3 | Attribute 1 | First characteristic — depends on category/group | ESVUFR → Voting right |
| 4 | Attribute 2 | Second characteristic | ESVUFR → Transfer: Free |
| 5 | Attribute 3 | Third characteristic | ESVUFR → Partly paid |
| 6 | Attribute 4 | Fourth characteristic | ESVUFR → Registered form |
F at position 3 means Fixed rate for a bond but Partly paid for an equity share. Always resolve attributes in the context of positions 1 and 2.3. Position 1: the 13 asset categories
The first letter narrows the instrument down to one of 13 top-level asset classes defined by ISO 10962:2021. Any 6-letter string starting with an unrecognised letter is invalid.
| Code | Category | Typical instruments |
|---|---|---|
| E | Equities | Common shares, preferred shares, ETF units, convertibles, ADRs |
| D | Debt instruments | Bonds, convertible bonds, MTNs, money market, ABS, MBS |
| R | Entitlements (rights) | Subscription rights, allotment rights, warrants, mini-futures |
| O | Listed options | Exchange-traded call and put options |
| F | Futures | Financial futures (rates, FX, equity) and commodity futures |
| S | Swaps | Interest rate, FX, credit, equity, commodity swaps |
| H | Non-listed & complex options | OTC options, exotic options, swaptions |
| I | Spot | FX spot, commodity spot |
| J | Forwards | FRAs, FX forwards, forward equity, forward commodity |
| K | Strategies | Multi-leg combinations — straddles, spreads, mixed strategies |
| L | Financing | Repo agreements, securities lending |
| T | Referential instruments | Currencies, indices, interest rates used as underlyings |
| M | Others | Combined and miscellaneous instruments not covered above |
4. Position 2 and 3–6: groups and attributes
Position 2 selects a group within the category — for example, within E (Equities) the group letter distinguishes common shares (S), preferred shares (P), convertible shares (C), ETF units (U), and so on.
Once category and group are fixed, each of the four attribute positions maps to a named characteristic. For ES (Equities — Shares common) the four attributes are:
| Position | Attribute name | Possible values |
|---|---|---|
| 3 | Voting right | V Voting · N Non-voting · R Restricted · E Enhanced · X N/A |
| 4 | Ownership / transfer restrictions | T Restrictions · U Free · X N/A |
| 5 | Payment status | O Fully paid · P Nil paid · F Partly paid · X N/A |
| 6 | Form | B Bearer · R Registered · N Bearer & registered · M Others · X N/A |
X to mean "not applicable or undefined" regardless of attribute type. When you see ESVUXR, position 5 is not meaningful for that particular share.5. Decoding ESVUFR — equity share step by step
ESVUFR is the CFI code returned by the IsValid ISIN API for PKN ORLEN SA, Poland's largest energy company. Here is what each position means:
Equities
Asset class — this is an equity instrument
Shares (common / ordinary)
Regular voting shares, not preferred or convertible
Voting
Each share carries a voting right at shareholders' meetings
Free
No restrictions — shares can be freely bought and sold
Partly paid
Shares have not been fully paid up by shareholders
Registered
Owner's name is recorded in the issuer's share register
// What ESVUFR tells you about the instrument: const result = { category: 'E', categoryName: 'Equities', group: 'S', groupName: 'Shares (common / ordinary)', attributes: [ { position: 3, code: 'V', name: 'Voting right', value: 'Voting' }, { position: 4, code: 'U', name: 'Ownership / transfer', value: 'Free' }, { position: 5, code: 'F', name: 'Payment status', value: 'Partly paid' }, { position: 6, code: 'R', name: 'Form', value: 'Registered' }, ], };
6. Decoding DBFAXR — bond step by step
DBFAXR is a typical CFI code for a plain-vanilla government or corporate bond:
Debt instruments
This is a fixed-income instrument
Bonds
Classic bond — not a convertible, ABS, or money-market instrument
Fixed rate
Coupon is a fixed percentage of face value — predictable cash flows
Annual
Coupon is paid once per year
Not applicable
No external guarantor — backed solely by the issuer
Registered
Holder is recorded in the issuer's register
F means Fixed rate in the bond context (DB), but means Partly paid in the equity context (ES). This is why you cannot decode positions 3–6 without first knowing positions 1 and 2.7. Where CFI codes appear in practice
ISIN lookup responses
Financial data APIs that resolve ISIN codes typically include the CFI code in the response. The IsValid ISIN API returns a cfiCode field — you can feed it directly into the CFI endpoint to get a structured breakdown.
// Example: enrich an ISIN lookup with CFI decoding const isinResult = await fetch('/v0/isin?value=PL0000503135', { headers }); const { cfiCode } = await isinResult.json(); // → "ESVUFR" const cfiResult = await fetch(`/v0/cfi?value=${cfiCode}`, { headers }); const cfi = await cfiResult.json(); console.log(cfi.categoryName); // → "Equities" console.log(cfi.groupName); // → "Shares (common / ordinary)" console.log(cfi.attributes[0].value); // → "Voting"
MiFID II trade reporting (ESMA FIRDS)
Under MiFID II, investment firms must report trades with instrument reference data including the CFI code. The ESMA FIRDS database — which the IsValid ISIN endpoint queries — stores CFI codes for all ~700 000 instruments registered for EU trading.
Portfolio analytics and risk systems
Risk engines and portfolio management systems use CFI codes to determine instrument type for margin calculations, asset allocation bucketing, and regulatory capital treatment. Parsing the category letter alone is often enough to route instruments through the correct calculation path.
Data validation at ingestion time
When importing financial instrument data from third-party feeds, validating the CFI code catches malformed or truncated records before they corrupt your database. A valid CFI must be exactly 6 characters, all uppercase letters, and start with a recognised category letter.
// Quick structural check before sending to the API function isCfiCandidate(value) { return typeof value === 'string' && /^[A-Z]{6}$/.test(value); } // Filter out obviously invalid entries in a batch const validCandidates = instruments.filter(i => isCfiCandidate(i.cfi));
8. The production-ready solution
The IsValid CFI API validates a CFI code against the full ISO 10962:2021 definition and returns a structured breakdown of all 6 positions — category name, group name, and the label and decoded value of each attribute. Because attribute mappings vary by category and group, maintaining the full lookup table yourself is error-prone; the API handles it for you.
Full parameter reference and response schema: CFI Validation API docs →
9. Node.js code example
import { createClient } from '@isvalid-dev/sdk'; const iv = createClient({ apiKey: process.env.ISVALID_API_KEY }); // ── Example usage ───────────────────────────────────────────────────────────── const result = await iv.cfi('ESVUFR'); if (!result.valid) { console.log('Invalid CFI code'); } else { console.log('Category:', result.categoryName); // → 'Equities' console.log('Group:', result.groupName); // → 'Shares (common / ordinary)' for (const attr of result.attributes) { console.log(`Position ${attr.position} (${attr.name}): ${attr.value}`); } // Position 3 (Voting right): Voting // Position 4 (Ownership / transfer restrictions): Free // Position 5 (Payment status): Partly paid // Position 6 (Form): Registered }
In a portfolio analytics pipeline — routing instruments to the correct calculation path based on asset class:
// Classify a batch of instruments by CFI category async function classifyInstruments(instruments) { const results = []; for (const inst of instruments) { if (!inst.cfi) { results.push({ ...inst, assetClass: 'unknown' }); continue; } const cfi = await validateCfi(inst.cfi); if (!cfi.valid) { results.push({ ...inst, assetClass: 'invalid' }); continue; } // Route by category for downstream processing const assetClass = { E: 'equity', D: 'fixed-income', O: 'option', F: 'future', S: 'swap', J: 'forward', }[cfi.category] ?? 'other'; results.push({ ...inst, assetClass, instrumentType: cfi.groupName, cfiAttributes: cfi.attributes, }); } return results; }
10. cURL example and response
Validate and decode an equity share CFI:
curl -H "Authorization: Bearer YOUR_API_KEY" \ "https://api.isvalid.dev/v0/cfi?value=ESVUFR"
Validate a bond CFI:
curl -H "Authorization: Bearer YOUR_API_KEY" \ "https://api.isvalid.dev/v0/cfi?value=DBFAXR"
Valid CFI response (ESVUFR):
{ "valid": true, "cfi": "ESVUFR", "category": "E", "categoryName": "Equities", "group": "S", "groupName": "Shares (common / ordinary)", "attributes": [ { "position": 3, "code": "V", "name": "Voting right", "value": "Voting" }, { "position": 4, "code": "U", "name": "Ownership / transfer restrictions","value": "Free" }, { "position": 5, "code": "F", "name": "Payment status", "value": "Partly paid" }, { "position": 6, "code": "R", "name": "Form", "value": "Registered" } ] }
Invalid CFI response:
{ "valid": false }
| Field | Type | Description |
|---|---|---|
| valid | boolean | 6 uppercase letters, recognised category letter |
| cfi | string | Normalised (uppercase) input |
| categoryName | string | Human-readable asset class (e.g. Equities) |
| groupName | string | null | Instrument type within the category, or null if group letter is unrecognised |
| attributes | array[4] | Decoded positions 3–6 — each object has position, code, name, value |
Summary
Node.js integration notes
When handling CFI Code in a TypeScript codebase, define a branded type to prevent accidental mixing of financial identifier strings at compile time:type CfiCode = string & { readonly __brand: 'CfiCode' }. The IsValid SDK ships with full TypeScript definitions covering all response fields, including country-specific and instrument-specific data, so your editor provides autocomplete on the parsed result without manual type declarations.
In financial data pipelines — payment processors, reconciliation engines, or KYC workflows — CFI Code validation sits at the ingestion boundary. Pair the IsValid SDK with decimal.js orbig.js for any monetary amounts tied to the identifier, and usepino for structured logging that attaches the validation result to the transaction reference in every log line, making audit trails straightforward.
Express.js and Fastify middleware
Centralise CFI Code validation in a request middleware rather than repeating it in every route handler. The middleware calls the IsValid API, attaches the parsed result toreq.validated, and callsnext() on success. Layer in a Redis cache keyed by the normalised identifier with a 24-hour TTL to avoid redundant API calls for the same value across multiple requests in the same session.
Error handling should distinguish between a 422 response from IsValid (the CFI Code is structurally invalid — return this to the caller immediately) and 5xx or network errors (transient failures — retry once after a short delay before surfacing a service-unavailable error). Never swallow validation failures silently; they indicate bad data that could propagate into financial records downstream.
- Assert
process.env.ISVALID_API_KEYis present at server startup, not lazily at first request - Use
Promise.allSettled()for batch validation — it collects all results without aborting on the first failure - Mock the IsValid client with
jest.mock()in unit tests; keep CI pipelines free of real API calls - Store the full parsed API response alongside the raw CFI Code in your database — country code, institution data, and check-digit status are useful for downstream logic
When making HTTP calls to the IsValid API directly (without the SDK), the choice between fetch and axios is largely a matter of preference. The native fetch API is available in Node.js 18+ without any additional dependency and is sufficient for simple request/response flows. axios adds automatic JSON parsing, request/response interceptors, and a cleaner timeout API (axios.create({ timeout: 5000 })), which makes it easier to centralise the Authorization header and retry logic in one place. For high-throughput services that make many concurrent API calls, consider undici — the HTTP client underlying Node.js fetch — used directly for its connection pooling and lower overhead.
See also
Validate CFI codes instantly
Free tier includes 100 API calls per day. No credit card required. Full ISO 10962:2021 attribute decoding for all 13 asset categories.