# Exporting company and persons to CSV

This is an example of how Proff API can be used to produce a CSV with information about beneficial owners and persons with important roles. All nordic countries are supported (NO,DK,SE,FI), but only NO and DK have information about beneficial owners.

  • One line is printed for every person found
  • If the company is not found a line is still printed with just the business id and country.
  • If the company is found, but no associated persons are found, a line is printed with the business id, country and company name

The example uses the native Fetch API in NodeJS and has been tested with NodeJS 21.7.3.

# Introduction

The program can be run like this:

node persons.mjs NO 987582715

This will print results like this:

987582715,NO,2020PARK AS,Monica Runestad,1975,Daglig leder,
987582715,NO,2020PARK AS,Rune Runestad,1954,Styrets leder,
987582715,NO,2020PARK AS,Øystein Runestad,1978,Styremedlem,
987582715,NO,2020PARK AS,Rune Runestad,1954,Beneficial owner,100

You can pipe the output to a file using the > operator (e.g. node persons.mjs NO 943545634 > 943545634.csv).

These are the column headers:

ID Country Company name Name BirthYear Role Share

Note that if there is no share value an empty value is printed.

# Full example

// List of roles that we care about - defined per country
const validRoles = {
    "NO": [ // Define important roles in Norway
        "Styrets leder",
        "Daglig leder",
        "Styremedlem"
    ],
    "DK": [ // Define important roles in Denmark
        "Adm. direktør",
        "Direktør"
    ]
}

const API_ENDPOINT = 'https://api.proff.no/companies'

// Set your API token in the environment variable API_TOKEN
const API_TOKEN = process.env.API_TOKEN
const httpOptions = {headers: {'Authorization': `Token ${API_TOKEN}`}};

// Input arguments to the program
const [, , ccTLD, id] = process.argv

const companyResponse = await fetch(`${API_ENDPOINT}/register/${ccTLD}/${id}`, httpOptions);
const company = companyResponse.ok && await companyResponse.json()

// Fetch owners only if company found
const companyOwnerResponse = company && await fetch(`${API_ENDPOINT}/owner/${ccTLD}/${id}`, httpOptions);
const companyOwners = companyOwnerResponse?.ok && await companyOwnerResponse.json()

// In DK all beneficial owners are persons, for NO only those with BirthYear are persons
const ownersFiltered = companyOwners?.Shareholders
    ?.filter?.(f => ccTLD !== 'NO' || ccTLD === 'NO' && f.BirthYear != null)
    .map?.(o => ({name: o.NameFromShareholder, birthYear: o.BirthYear, title: 'Beneficial owner', share: o.ShareInPercent})) || []

// Combine persons with important roles and beneficial owners, and map them to records
// If there are no persons we still map an entry for the company
const personRoles = company.personRoles?.filter?.(f => !validRoles[ccTLD] || validRoles[ccTLD].indexOf(f.title) !== -1) || [{}]
const records = personRoles.concat(ownersFiltered).map(p => ({
    businessId: id,
    country: ccTLD,
    name: company.name || null,
    personName: p.name,
    birthYear: p.birthYear || p.birthDate && p.birthDate.substring(4),
    title: p.title,
    share: p.share
}))

// Write all records to stdout (CSV)
for (let record of records) {
    process.stdout.write(`${(Object.values(record).join())}\n`)
}