Guide · Python · SDK · REST API

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.

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:

PropertyDetail
Length5–9 digits
Allowed characters[0-9] only
Check digitNone
Issuing authoritySIX Financial Information (SIX Group), Zurich
ScopeSwiss and Liechtenstein securities (equities, bonds, funds, structured products)

Some well-known examples:

VALORISINSecurity
1213853CH0012138530UBS Group AG
1222171CH0012221716ABB Ltd
1200526CH0012005267Novartis AG
3886335CH0038863350Nestlé SA
ℹ️Unlike WKN (Germany), which can contain letters A–Z, a VALOR is always purely numeric. If an identifier contains letters, it is not a VALOR — it may be a WKN or another national securities identifier.

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
If you already have a CH or LI ISIN, use /v0/isin directly — it validates the full ISIN and returns all instrument enrichment. Use /v0/valor only when you have a standalone VALOR number.

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.

Format
Validation
5–9 digit numeric check
Live
Enrichment
Name, ISIN, FIGI, exchange & more
100/day
Free tier
no credit card

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"),
    }
The API strips whitespace and leading zeros automatically — no pre-processing needed. Both 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
}
FieldTypeDescription
validbooleanFormat validation result (5–9 digits)
valorstringNormalised VALOR (whitespace-stripped, leading zeros removed)
foundboolean | nulltrue — found in OpenFIGI; false — not found; null — OpenFIGI unavailable
isinstring | nullAssociated ISIN (e.g. CH0012138530)
namestring | nullFull instrument name
tickerstring | nullExchange ticker symbol
exchCodestring | nullBloomberg exchange code (e.g. SE for SIX Swiss Exchange)
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 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.

VALOR vs. ISIN — know which you have

If you receive a 12-character code starting with CH or LI, it is a Swiss or Liechtenstein ISIN — use /v0/isin instead. A 5–9 digit code is a VALOR — use /v0/valor.


10. Summary

WhatDetail
Format5–9 digits only [0-9], no letters, no check digit
Check algorithmNone — purely opaque numeric sequence
Issuing authoritySIX Financial Information (SIX Group), Zurich
CoverageSwiss and Liechtenstein securities (equities, bonds, ETFs, structured products)
Enrichment sourceOpenFIGI (Bloomberg) via ID_VALOR
API endpointGET /v0/valor?value=1213853

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_KEY in a .env file and load with python-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 isin field from the response — it enables downstream cross-referencing without additional API calls