mantalest. MMXXVI

Organisationsnummer: format, checksum and company lookup

An organisationsnummer looks like a simple ten-digit string right up until you store one. Then you meet the twelve-digit form, the check digit, and the fact that one number can return two hundred rows.

Illustration: a grid of identical rectangular floor plans with one marked by a filled square.

Two forms of the same number

The human form is NNNNNN-NNNN: six digits, a hyphen, four digits. The machine form is twelve digits with a prefix — 16 for a legal entity — so 556012-5790 is stored as 165560125790.

A sole trader has no separate number at all: the organisationsnummer is the owner’s personnummer, prefixed 19 or 20. That single fact breaks most naive validators, and it means an organisationsnummer can itself be personal data.

Pick one canonical form and normalise on the way in. Ours is the ten-digit core, with the prefix reattached on the way out. Matching a mixed column with a trailing wildcard is how a lookup quietly returns the wrong entity.

The first digit is the legal form

The leading digit of the core puts the entity in a group:

  • 1 — dödsbon (estates of deceased persons).
  • 2 — state, region, municipality, parish.
  • 3 — foreign companies operating in Sweden.
  • 5 — aktiebolag.
  • 6 — enkla bolag.
  • 7 — ekonomiska föreningar, including bostadsrättsföreningar.
  • 8 — ideella föreningar and stiftelser.
  • 9 — handelsbolag and kommanditbolag.

The check digit is Luhn

Use the group to sanity-check a form field, never to decide legal status — that comes from a lookup, not from a digit.

The tenth digit of the core is a Luhn check digit, the same algorithm as a payment card. This runs client-side and rejects the typos before you spend a call:

orgnr.ts — normalise, then Luhn
/** The 10-digit core, from any of the forms people paste. */
export function orgnrCore(input: string): string | undefined {
  const d = input.replace(/\D/g, '');
  // 12-digit forms carry a prefix: 16 for a legal entity,
  // 19/20 for the personnummer of a sole trader.
  const core = d.length === 12 ? d.slice(2) : d;
  return core.length === 10 ? core : undefined;
}

export function isValidOrgnr(input: string): boolean {
  const core = orgnrCore(input);
  if (!core) return false;
  let sum = 0;
  for (let i = 0; i < 10; i++) {
    let n = Number(core[i]) * (i % 2 === 0 ? 2 : 1);
    if (n > 9) n -= 9;
    sum += n;
  }
  return sum % 10 === 0;
}

isValidOrgnr('556012-5790');   // true
isValidOrgnr('165560125790');  // true — same company, machine form
isValidOrgnr('556012-5791');   // false

One org number, many workplaces

A company is not a row. Swedish company data is collected per arbetsställe — workplace — so a large employer comes back as dozens or thousands of rows, each with its own address and switchboard, and none of them flagged as the head office.

Concretely: a property group appears as fifteen rows across five cities, a large municipality as several thousand. Dedupe on name and you lose real branches; skip deduping and you will report one company as fifteen customers.

So the grain is explicit in the response. /v1/companies/by-orgno/{orgno} returns the resolved company plus an offices array: the company is the organisationsnummer, the rows are its workplaces.

lookup by org number, and by name
curl -s "https://mantal.eu/v1/companies/by-orgno/5560125790" -H "Authorization: Bearer $KEY"

curl -s "https://mantal.eu/v1/companies/search?q=volvo" -H "Authorization: Bearer $KEY"

Validate locally, look up remotely

The split that keeps a signup form fast: run the checksum in the browser to catch typos, and call the API once the digits are internally consistent. A valid checksum is cheap; a lookup is the thing worth paying for.

Both are in the API reference, and a key is self-serve.

Questions

Is a sole trader’s org number really a personnummer?
Yes. An enskild firma has no number of its own, so the owner’s personnummer identifies the business. Treat those rows as personal data even in a B2B context.
What does the 16 prefix mean?
It marks the twelve-digit form as an organisation number, the way 19 or 20 marks a century on a personnummer. It carries no information about the company itself.
Why do I get several rows for one company?
Because the data is per workplace. One organisationsnummer can have hundreds of establishments, each with its own address and phone number, and there is no head-office flag to sort them by.
Does a valid checksum mean the company exists?
No. Luhn only proves the digits are internally consistent. Existence, status and legal form come from a lookup against the register.