1. Check the format with modulus 11
A CVR number has 8 digits and doesn't start with 0. Multiply each digit by the weights 2, 7, 6, 5, 4, 3, 2, 1 and add up the results. The sum must be divisible by 11.
For 10403782: 1·2 + 0·7 + 4·6 + 0·5 + 3·4 + 7·3 + 8·2 + 2·1 = 77, and 77 / 11 = 7, so the number is valid.
WEIGHTS = (2, 7, 6, 5, 4, 3, 2, 1)
def is_valid_cvr(cvr: str) -> bool:
cvr = cvr.replace(" ", "")
if len(cvr) != 8 or not cvr.isdigit() or cvr[0] == "0":
return False
return sum(int(d) * w for d, w in zip(cvr, WEIGHTS)) % 11 == 0
is_valid_cvr("10403782") # True (Vestas Wind Systems A/S)
is_valid_cvr("12345678") # False2. Confirm the company exists
A number can have a correct check digit without being assigned. Look it up:
curl https://apicvr.dk/api/v1/10403782{
"vat": 10403782,
"name": "VESTAS WIND SYSTEMS A/S",
"status": "NORMAL",
"startdate": "...",
"enddate": null,
"bankrupt": false,
"companydesc": "Aktieselskab",
...
}If the number doesn't exist, the API responds with HTTP 404:
{"detail": {"error": "NOT_FOUND", "status": 404, "message": null}}3. Check that it's active
A company can exist in CVR even though it has ceased or gone bankrupt. Look at enddate (set once the company has ceased), bankrupt and status. Here's the whole flow in JavaScript:
const WEIGHTS = [2, 7, 6, 5, 4, 3, 2, 1];
function isValidCvr(input) {
const cvr = String(input).replace(/\s/g, "");
if (!/^[1-9]\d{7}$/.test(cvr)) return false;
const sum = [...cvr].reduce((acc, d, i) => acc + Number(d) * WEIGHTS[i], 0);
return sum % 11 === 0;
}
async function checkCvr(cvr) {
if (!isValidCvr(cvr)) return { valid: false, reason: "checksum" };
const res = await fetch(`https://apicvr.dk/api/v1/${cvr}`);
if (res.status === 404) return { valid: false, reason: "not_found" };
const company = await res.json();
const active = !company.enddate && !company.bankrupt;
return { valid: true, active, name: company.name };
}Tips
- Run the modulus 11 check in the browser so users get instant feedback – and you save the API call on obvious typos.
- Strip spaces and any
DKprefix (from VAT numbers) before validating. - Rely on
enddateandbankruptrather than matching text instatus, which can take many different values.
Frequently asked questions
Is every CVR number that passes modulus 11 assigned?
No. Modulus 11 catches typos, but only a CVR lookup can confirm that the number belongs to a company.
Is a CVR number the same as a Danish VAT number?
For Danish companies, the VAT number is usually the CVR number prefixed with DK, e.g. DK10403782.
What does the API return for an invalid format?
If the number contains anything but digits, the API responds with HTTP 422. If it doesn't exist, it responds with HTTP 404 and the error code NOT_FOUND.