/**
* Brønnøysund Regnskapsregisteret API Client
* Fetches actual financial statements (årsregnskap) automatically
*/
export interface RegnskapData {
id: number;
journalnr: string;
regnskapstype: string;
virksomhet: {
organisasjonsnummer: string;
organisasjonsform: string;
};
regnskapsperiode: {
fraDato: string;
tilDato: string;
};
valuta: string;
resultatregnskapResultat?: {
ordinaertResultatFoerSkattekostnad?: number;
aarsresultat?: number;
driftsresultat?: {
driftsresultat?: number;
driftsinntekter?: {
sumDriftsinntekter?: number;
};
driftskostnad?: {
sumDriftskostnad?: number;
};
};
finansresultat?: {
nettoFinans?: number;
};
};
eiendeler?: {
sumEiendeler?: number;
omloepsmidler?: {
sumOmloepsmidler?: number;
};
anleggsmidler?: {
sumAnleggsmidler?: number;
};
};
egenkapitalGjeld?: {
sumEgenkapitalGjeld?: number;
egenkapital?: {
sumEgenkapital?: number;
};
gjeldOversikt?: {
sumGjeld?: number;
};
};
}
export interface ExtractedFinancials {
org_nr: string;
year: number;
revenue: number | null;
profit: number | null;
assets: number | null;
equity: number | null;
debt: number | null;
operating_profit: number | null;
currency: string;
period: {
from: string;
to: string;
};
source: string;
}
export class RegnskapClient {
private baseUrl = 'https://data.brreg.no/regnskapsregisteret/regnskap';
/**
* Fetch annual accounts for a company
* Returns the latest available financial data
*/
async getFinancialData(orgNr: string): Promise<RegnskapData[] | null> {
try {
const url = `${this.baseUrl}/${orgNr}`;
console.error(`Fetching financial data from Regnskapsregisteret: ${url}`);
const response = await fetch(url, {
headers: {
'Accept': 'application/json',
'User-Agent': 'CompanyIQ/1.0'
}
});
if (!response.ok) {
if (response.status === 404) {
console.error(`No financial data found for ${orgNr}`);
return null;
}
throw new Error(`Regnskapsregisteret API error: ${response.status}`);
}
const data = await response.json();
return Array.isArray(data) ? data : [data];
} catch (error) {
console.error('Error fetching financial data:', error);
return null;
}
}
/**
* Extract key financial figures from the API response
*/
extractFinancials(regnskapData: RegnskapData): ExtractedFinancials {
const year = new Date(regnskapData.regnskapsperiode.tilDato).getFullYear();
return {
org_nr: regnskapData.virksomhet.organisasjonsnummer,
year,
revenue: regnskapData.resultatregnskapResultat?.driftsresultat?.driftsinntekter?.sumDriftsinntekter || null,
profit: regnskapData.resultatregnskapResultat?.aarsresultat || null,
assets: regnskapData.eiendeler?.sumEiendeler || null,
equity: regnskapData.egenkapitalGjeld?.egenkapital?.sumEgenkapital || null,
debt: regnskapData.egenkapitalGjeld?.gjeldOversikt?.sumGjeld || null,
operating_profit: regnskapData.resultatregnskapResultat?.driftsresultat?.driftsresultat || null,
currency: regnskapData.valuta,
period: {
from: regnskapData.regnskapsperiode.fraDato,
to: regnskapData.regnskapsperiode.tilDato
},
source: 'regnskapsregisteret_api'
};
}
/**
* Get and extract financial data in one call
*/
async getExtractedFinancials(orgNr: string): Promise<ExtractedFinancials | null> {
const data = await this.getFinancialData(orgNr);
if (!data || data.length === 0) return null;
// Return the most recent (first in array)
return this.extractFinancials(data[0]);
}
/**
* Fetch all available years by trying each year from 2018 to current
* The open API only provides latest year, but we can try to find historical data
*/
async getAllAvailableFinancials(orgNr: string): Promise<ExtractedFinancials[]> {
const results: ExtractedFinancials[] = [];
const currentYear = new Date().getFullYear();
const startYear = 2018; // API has data from 2018+
console.error(`Fetching all available financial data for ${orgNr} (${startYear}-${currentYear})...`);
// Try current year first (most likely to have data)
const latest = await this.getExtractedFinancials(orgNr);
if (latest) {
results.push(latest);
console.error(`✅ Found data for ${latest.year}`);
// Try previous years (API might have them)
for (let year = latest.year - 1; year >= startYear; year--) {
const data = await this.getFinancialData(orgNr);
if (data && data.length > 0) {
// Check if this year is different from what we have
const extracted = this.extractFinancials(data[0]);
if (!results.find(r => r.year === extracted.year)) {
results.push(extracted);
console.error(`✅ Found data for ${extracted.year}`);
} else {
// Same year returned, API only has latest
console.error(`ℹ️ API only returns latest year (${latest.year})`);
break;
}
}
// Add small delay to be nice to the API
await new Promise(resolve => setTimeout(resolve, 100));
}
}
console.error(`Total years found: ${results.length}`);
return results.sort((a, b) => b.year - a.year); // Newest first
}
}