VALOR Validation in Python
The VALOR has no check digit — any 5-to-9 digit string passes format validation. Here's how to validate VALORs properly in Python with a single API call that confirms the identifier and enriches it with live instrument data.
In this guide
1. What is a VALOR?
A VALOR (Valorennummer — also written Valoren number or simply Valor) is the numeric identifier used to identify securities in Switzerland and Liechtenstein. Issued by SIX Financial Information (SIX Group, Zurich), VALORs appear in Swiss brokerage confirmations, bank statements, portfolio reports, and financial data feeds from SIX.
While ISIN has become the standard for cross-border and regulatory reporting, VALORs remain pervasive in Swiss private banking and asset management. Many Swiss brokers, custodians, and fund administrators expose VALORs as the primary identifier alongside ISINs — and some legacy systems expose VALORs only.
Unlike WKN (Germany), the VALOR is purely numeric — it contains only digits, never letters. Like WKN and unlike ISIN or SEDOL, the VALOR has no check digit. Confirming a VALOR requires a database lookup.
2. VALOR anatomy
A VALOR is between 5 and 9 digits long, using only decimal digits:
| Property | Detail |
|---|---|
| Length | 5–9 digits |
| Allowed characters | [0-9] only |
| Check digit | None |
| Issuing authority | SIX Financial Information (SIX Group), Zurich |
| Scope | Swiss and Liechtenstein securities (equities, bonds, funds, structured products) |
Some well-known examples:
| VALOR | ISIN | Security |
|---|---|---|
| 1213853 | CH0012138530 | UBS Group AG |
| 1222171 | CH0012221716 | ABB Ltd |
| 1200526 | CH0012005267 | Novartis AG |
| 3886335 | CH0038863350 | Nestlé SA |
3. VALOR inside a Swiss ISIN
Swiss ISINs embed the VALOR in a predictable way. The NSIN (National Securities Identifying Number) portion of a CH or LI ISIN is the VALOR zero-padded on the left to 9 characters:
# Extracting VALOR from a Swiss ISIN isin = "CH0012138530" country = isin[:2] # "CH" nsin = isin[2:11] # "001213853" check = isin[11] # "0" # The VALOR is the NSIN with leading zeros stripped valor = nsin.lstrip("0") # "1213853" print(valor) # → 1213853
4. Why format checks are not enough
No check digit — typos are invisible
Because there is no check digit, a one-digit typo (1213854 instead of 1213853) passes format validation silently. Without a database lookup there is no way to detect it. In a trading or portfolio management context, this kind of error can result in the wrong security being referenced in a position, order, or report.
Variable length — 5 to 9 digits
VALORs are not a fixed length. Early securities have 5- or 6-digit VALORs; newer issuances may use up to 9 digits. Systems that assume a fixed length will silently reject valid short VALORs. A regex like \d{7} will miss valid 5-digit and 9-digit VALORs.
Retired and superseded VALORs
When a company is acquired, merged, or delisted, its VALOR may be retired or superseded. A structurally valid VALOR might map to a company that no longer exists, a fund that was wound up, or a structured product that matured. Format validation cannot distinguish an active security from a retired one.
5. The right solution: one API call
The IsValid VALOR API combines format validation and live OpenFIGI enrichment in a single GET /v0/valor request.
Get your free API key at isvalid.dev.
Full parameter reference and response schema: VALOR Validation API docs →
6. Python code example
Using the isvalid-sdk package or the requests library directly.
# valor_validator.py import os from isvalid_sdk import IsValid iv = IsValid(api_key=os.environ["ISVALID_API_KEY"]) # ── Example usage ───────────────────────────────────────────────────────────── result = iv.valor("1213853") # UBS Group AG if not result["valid"]: print("Invalid VALOR: must be 5–9 digits (no letters)") else: print(f"VALOR : {result['valor']}") if result.get("found"): print(f"Name : {result.get('name')}") print(f"ISIN : {result.get('isin')}") print(f"Ticker : {result.get('ticker')}") print(f"Exchange : {result.get('exchCode')}") print(f"FIGI : {result.get('figi')}") print(f"Sector : {result.get('marketSector')}")
Expected output for 1213853:
VALOR : 1213853 Name : UBS Group AG ISIN : CH0012138530 Ticker : UBSG Exchange : SE FIGI : BBG000BVD464 Sector : Equity
In a FastAPI endpoint:
# router.py (FastAPI) from fastapi import APIRouter, HTTPException import requests, os router = APIRouter() API_KEY = os.environ["ISVALID_API_KEY"] @router.get("/securities/validate-valor") def validate_valor_endpoint(valor: str): if not valor: raise HTTPException(status_code=400, detail="Missing valor parameter") try: resp = requests.get( "https://api.isvalid.dev/v0/valor", params={"value": valor}, headers={"Authorization": f"Bearer {API_KEY}"}, timeout=10, ) resp.raise_for_status() result = resp.json() except requests.RequestException: raise HTTPException(status_code=502, detail="VALOR validation service unavailable") if not result["valid"]: raise HTTPException(status_code=400, detail=f"Invalid VALOR: {valor}") return { "valor": result["valor"], "found": result.get("found"), "isin": result.get("isin"), "name": result.get("name"), "ticker": result.get("ticker"), "exchCode": result.get("exchCode"), "figi": result.get("figi"), }
001213853 and 1213853 are treated identically.7. cURL example
UBS Group AG:
curl -H "Authorization: Bearer YOUR_API_KEY" \ "https://api.isvalid.dev/v0/valor?value=1213853"
Novartis AG:
curl -H "Authorization: Bearer YOUR_API_KEY" \ "https://api.isvalid.dev/v0/valor?value=1200526"
Invalid format — fewer than 5 digits:
curl -H "Authorization: Bearer YOUR_API_KEY" \ "https://api.isvalid.dev/v0/valor?value=1234"
8. Understanding the response
Response for a valid VALOR found in OpenFIGI:
{ "valid": true, "valor": "1213853", "found": true, "dataSource": "openfigi", "isin": "CH0012138530", "name": "UBS Group AG", "ticker": "UBSG", "exchCode": "SE", "securityType": "Common Stock", "marketSector": "Equity", "figi": "BBG000BVD464", "compositeFIGI": "BBG000BVD464" }
Response for an invalid VALOR:
{ "valid": false }
| Field | Type | Description |
|---|---|---|
| valid | boolean | Format validation result (5–9 digits) |
| valor | string | Normalised VALOR (whitespace-stripped, leading zeros removed) |
| found | boolean | null | true — found in OpenFIGI; false — not found; null — OpenFIGI unavailable |
| isin | string | null | Associated ISIN (e.g. CH0012138530) |
| name | string | null | Full instrument name |
| ticker | string | null | Exchange ticker symbol |
| exchCode | string | null | Bloomberg exchange code (e.g. SE for SIX Swiss Exchange) |
| securityType | string | null | Security type (e.g. Common Stock) |
| marketSector | string | null | Market sector (e.g. Equity) |
| figi | string | null | Financial Instrument Global Identifier |
| compositeFIGI | string | null | Composite FIGI across all exchanges |
9. Edge cases to handle
found: null vs. found: false
found: false means OpenFIGI responded but did not recognise the VALOR. found: null means the lookup failed (timeout, rate limit). In the null case, treat the result as inconclusive and retry — do not reject the VALOR as invalid.
10. Summary
| What | Detail |
|---|---|
| Format | 5–9 digits only [0-9], no letters, no check digit |
| Check algorithm | None — purely opaque numeric sequence |
| Issuing authority | SIX Financial Information (SIX Group), Zurich |
| Coverage | Swiss and Liechtenstein securities (equities, bonds, ETFs, structured products) |
| Enrichment source | OpenFIGI (Bloomberg) via ID_VALOR |
| API endpoint | GET /v0/valor?value=1213853 |
- ISIN validation — ISINs embed VALORs for CH/LI-prefixed codes
- WKN validation — the German equivalent (alphanumeric)
- SEDOL validation — the UK equivalent
- CUSIP validation — the North American equivalent
- VALOR Validation in Node.js
Python integration notes
Use Pydantic V2's @field_validator or the Annotated + AfterValidator pattern to embed VALOR validation in your data models. The validator calls the IsValid API and raises a ValueError if valid is False. Because there is no check digit to compute locally, the API call is the only meaningful validation step — format-only regex checks provide little protection against real-world errors.
Async batch validation
For bulk imports — portfolio data from a custodian file, for example — use asyncio.gather() with a shared httpx.AsyncClient and an asyncio.Semaphore to cap concurrency at your API rate limit. This reduces total validation time from O(n) sequential to O(1) bounded by the pool size — important when processing hundreds of VALORs at once.
- Store
ISVALID_API_KEYin a.envfile and load withpython-dotenv - Cache results in Redis with a 24h TTL — VALOR-to-instrument mappings rarely change
- Apply
.strip().lstrip('0')before validation to normalise zero-padded input from custodian files - Use
NewType('Valor', str)to distinguish validated VALORs from raw strings in type annotations - Store the
isinfield from the response — it enables downstream cross-referencing without additional API calls