DEV Community

Company numbers in Sweden, Norway, Finland and France: formats, check digits, and the VAT number hiding inside

Sweden, Norway, Finland and France each give a company one number, and each number ends in a check digit. If you take company numbers in a form (onboarding, invoicing, a CRM import), you can catch most typos before you ever call a register.

This post has the format of each number, the check-digit rule, how the VAT number is built from it, and tested JavaScript for all of it.

Disclosure up front: we build a company check API at SpellzCode, and it shows up at the end. Everything before that works without it.

The four numbers at a glance

Country Name Format Check digit Example
Sweden organisationsnummer 10 digits, written NNNNNN-NNNN Luhn (mod 10) over all ten digits 556703-7485
Norway organisasjonsnummer 9 digits, the first 8 or 9 mod 11, weights 3 2 7 6 5 4 3 2 923609016
Finland Y-tunnus (business ID) 7 digits, a hyphen, a check digit mod 11, weights 7 9 10 5 8 4 2 0112038-9
France SIREN (company), SIRET (establishment) 9 digits; 14 digits Luhn (mod 10) 552032534

The examples are the public register numbers of Spotify AB, Equinor ASA, Nokia Oyj and Danone.

The check digits in code

const digits = (s) => String(s).replace(/\D/g, "").split("").map(Number);

function luhn(ds) {
  const sum = [...ds].reverse().reduce(
    (acc, n, i) => acc + (i % 2 ? (n * 2 > 9 ? n * 2 - 9 : n * 2) : n), 0);
  return sum % 10 === 0;
}

function mod11(ds, weights) {
  const rest = 11 - (weights.reduce((acc, w, i) => acc + w * ds[i], 0) % 11);
  if (rest === 10) return false; // no valid check digit exists for this body
  return (rest === 11 ? 0 : rest) === ds[weights.length];
}

// Sweden: 10 digits, Luhn over all ten.
const isSwedishOrgNumber = (s) => {
  const d = digits(s);
  return d.length === 10 && luhn(d);
};

// Norway: 9 digits, mod 11 with weights 3 2 7 6 5 4 3 2.
const isNorwegianOrgNumber = (s) => {
  const d = digits(s);
  return d.length === 9 && mod11(d, [3, 2, 7, 6, 5, 4, 3, 2]);
};

// Finland: 7 digits + check digit, mod 11 with weights 7 9 10 5 8 4 2.
const isFinnishBusinessId = (s) => {
  const d = digits(s);
  return d.length === 8 && mod11(d, [7, 9, 10, 5, 8, 4, 2]);
};

// France: SIREN (9 digits) and SIRET (14 digits), both Luhn.
const isSiren = (s) => {
  const d = digits(s);
  return d.length === 9 && luhn(d);
};

const isSiret = (s) => {
  const d = digits(s);
  return d.length === 14 && luhn(d);
};

Two details that are easy to get wrong:

  • Mod 11 can have no answer. When the remainder calls for a check digit of 10, that number body is simply never issued. Return false; do not map 10 to 0.
  • The Swedish Luhn runs over the 10-digit form. Swedish numbers are sometimes written with a century prefix (12 digits, 16 for companies). Strip it before checking.

From company number to VAT number

In three of the four countries the VAT number is the company number in a wrapper, so you can derive one from the other.

const swedishVat = (org) => `SE${digits(org).join("")}01`; // 556703-7485 -> SE556703748501
const finnishVat = (id) => `FI${digits(id).join("")}`; // 0112038-9 -> FI01120389
const norwegianVat = (org) => `NO${digits(org).join("")}MVA`; // 923609016 -> NO923609016MVA

const frenchVat = (siren) => {
  const n = Number(digits(siren).join(""));
  const key = (12 + 3 * (n % 97)) % 97; // 552032534 -> FR27552032534
  return `FR${String(key).padStart(2, "0")}${n}`;
};

Caveats:

  • Deriving a VAT number does not mean the company is registered for VAT. A Swedish company without VAT registration still has an organisationsnummer. Check the derived number before you rely on it.
  • Norway is not in the EU, so a Norwegian number cannot be checked in VIES. The Norwegian register itself says whether the company is in the VAT register; the MVA suffix on an invoice means it is.
  • French keys for newer companies can contain letters. The formula above gives the numeric key that the large majority of companies have.

What a check digit cannot tell you

A number that passes is well formed. It may still belong to nobody, or to a company that was dissolved last year. For that you need the register:

  • Sweden: Bolagsverket (and SCB for activity data)
  • Norway: BrΓΈnnΓΈysundregistrene
  • Finland: PRH, the Patent and Registration Office
  • France: INSEE's Sirene register and the national business register

All four publish their data openly, each in its own format and with its own quirks, which is the tedious part.

If you would rather not integrate four registers

This is where our own tool comes in. One GET request per country, the same shape of JSON back: names, legal form, status, bankruptcy or liquidation, registration date, industry codes and address. Register facts only: no credit scores and no personal data about owners.

curl -H "Authorization: Bearer $API_KEY" \
  "https://tools.funwords.eu/no/company?orgnr=923609016"

There is a page per country with the format, the check digit and a free lookup form: Company register lookup.

VAT numbers for every EU country are covered in the VAT number check, and the API with plans is at Company check API.

If you only need the check digits, the code above is all you need. If a rule here is wrong for some class of numbers, say so in the comments and we will fix the post.

Read on DEV Community ↗ ← Back to News

Comments

No comments yet. Start the discussion.