Hopp til hovedinnhold

Command Palette

Search for a command to run...

Integrer Companybook i egen kode

For utviklere og kodeagenter som skal hente selskapsdata inn i et CRM, et datavarehus eller en kundeliste.

Denne guiden er skrevet for utviklere og kodeagenter som skal hente selskapsdata fra Companybook inn i et eget system, for eksempel et CRM, et datavarehus eller en kundeliste som skal berikes hver natt. Følg stegene i rekkefølge. Alt som står her kan kontrolleres mot OpenAPI-kontrakten.

1. Hva du trenger

  • En Companybook-konto med Plus. REST API er en del av Plus (personlig) og Business Plus (team). Free-kontoer kan bruke MCP, men får 403 plan_required på REST. Kontoer opprettes i lukket beta via ventelisten.
  • En API-nøkkel. Opprett den under Agenttilgang → Ny tilgang. Er du medlem av et team med Business Plus, velg teamet under Trekk credits fra, så belastes teamets felles saldo.
  • Nøkkelen i en miljøvariabel på serveren, for eksempel COMPANYBOOK_API_KEY. Aldri i kildekode, logger, nettleserkode eller en chat.

Kontroller tilgangen før du bygger noe:

curl -s https://companybook.co/api/v1/me -H "Authorization: Bearer $COMPANYBOOK_API_KEY"

Svaret skal ha "api_access": true. Feltet credential gjelder nøkkelen du kaller med: billed_to (personal eller team), hvilken saldo som belastes (credential.credits), grensene (credential.limits) og hvor mye som er brukt i dag og denne måneden (credential.used). For en teamnøkkel er det teamets saldo og grenser som gjelder; credits på toppnivå er brukerens personlige saldo. /me og /capabilities virker på alle planer; resten krever Plus.

2. Slik er API-et bygget opp

OperasjonBruk
GET /resolve?query=…&types=["org"]&limit=5Finn et selskap fra navn eller organisasjonsnummer. Gir kandidater med id, name og score.
POST /entities/batchHent opptil 100 selskaper i ett kall (25 på Free via MCP), med valgfrie utvidelser. Dette er arbeidshesten for integrasjoner.
GET /entities/{id}Samme som over for ett selskap.
POST /searchFinn selskaper med filtre (kommune, NACE, omsetning, organisasjonsform).
POST /traversalsFølg relasjoner som eierskap, maks tre hopp.
GET /usageEget forbruk siste 30 dager.

Base-URL er https://companybook.co/api/v1. Alle svar på dataoperasjoner er en cb/v1-konvolutt med data, coverage, warnings, as_of, truncated og cost.

Selskaps-ID-er har formen cb:org:<organisasjonsnummer>, for eksempel cb:org:923609016. Et organisasjonsnummer er alltid 9 siffer.

3. Hent mange selskaper i ett kall

Har du organisasjonsnumrene, bruk POST /entities/batch med extend:

curl -s https://companybook.co/api/v1/entities/batch \
  -H "Authorization: Bearer $COMPANYBOOK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "ids": ["cb:org:923609016", "cb:org:817209882"],
    "extend": ["financial_history", "subunits", "web_identities", "group_parent"]
  }'
  • ids: 1–100 ID-er per kall. Anbefalt: 50 per kall når du bruker alle fire utvidelsene, og kall sekvensielt, ikke parallelt.
  • extend er valgfritt. Utelat utvidelser du ikke trenger; hver utvidelse øker datamengden som måles.
  • include er noe annet: relasjoner (kanter) følger bare med når du ber om dem, for eksempel ["HAS_ROLE"], eller ["*"] for alle. Uten include får du ingen kanter, men hvert selskap har active_predicates som viser hvilke relasjoner som finnes og hvor mange. Kanter teller som poster.

Felter per selskap (data.entities[].payload)

FeltBetydning
org_nr, nameOrganisasjonsnummer og navn
entity_type, parent_org_nrhovedenhet eller underenhet, og hovedenheten til en underenhet
org_form, org_form_descriptionOrganisasjonsform, f.eks. AS
nace_code, nace_description, secondary_nace_code, secondary_nace_descriptionNæringskoder
address, postal_code, city, municipality, municipality_codeForretningsadresse
postal_address, postal_address_postal_code, postal_address_cityPostadresse
latitude, longitudeKoordinater for forretningsadressen
employees, founded_date, registration_dateAnsatte og datoer
is_bankrupt, is_liquidating, is_under_forced_liquidation, is_deleted, deleted_at, cessation_dateStatus. Bruk disse til kredittvarsel
is_in_group, last_annual_report_year, registered_in_vatKonsernflagg, siste regnskapsår, MVA-registrering

Et felt som mangler i payload, er ukjent. Det betyr ikke false eller 0.

Utvidelser (data.extensions, nøklet på organisasjonsnummer)

UtvidelseInnhold
financial_historyAlle regnskapsår, nyeste først. Kun selskapsregnskap (ikke konsern). Ett år per rad; er året både fra Proff og Brønnøysund, vinner Proff. Felter: fiscal_year, revenue, operating_costs, operating_result, result_before_tax, net_result, total_assets, total_equity, total_debt, source. Maks 30 år.
subunitsUnderenheter registrert på hovedenheten, med adresse, næring, ansatte og koordinater. Maks 50 per selskap i en batch. Ber du om ett selskap alene (GET /entities/{id}), får du opptil 1000. Er en liste avkortet, står organisasjonsnummeret i data.extensions_truncated.subunits. Underenhetene har de samme feltnavnene som selskapet (nace_code, nace_description, address, postal_code, city, municipality_code). De gamle registernavnene (industry_code, address_street osv.) følger med til v2, men ny kode bør bruke de nye.
web_identitiesNettsted og sosiale profiler: identity_type, full_url, is_primary, og for nettsteder site_kind og site_status (skill et aktivt nettsted fra et parkert domene).
group_parentØverste eier i eierkjeden (org_nr, name, depth), fulgt gjennom aksjonærregisteret, eller null hvis ingen eier over selskapet er registrert. Ikke det samme som registrert konsern: group_parent finnes også for selskaper som ikke er i et konsern i Brønnøysund (is_in_group er false). Vil du bare ha konsernmor i registerets forstand, bruk group_parent kun når is_in_group er true.

Kontaktinformasjon som e-post og telefon leveres ikke via API-et.

Utvidelsene gjelder selskapet du ber om. For en underenhet ligger regnskap, konsern og ofte nettsted på hovedenheten: hent parent_org_nr i samme eller neste kall.

4. SDK for TypeScript og JavaScript (beta)

@companybook/sdk pakker stegene over: nøkkelkontroll, batcher på 50, sekvensielle kall, Retry-After ved 429 og typede feil. Ingen avhengigheter; krever Node 20 eller nyere.

import { Companybook } from '@companybook/sdk';

const cb = new Companybook({ apiKey: process.env.COMPANYBOOK_API_KEY });
const { entities, extensions, missing, units } = await cb.entities.batchAll(orgNumbers, {
  extend: ['financial_history', 'web_identities', 'group_parent'],
});
const { subunits, truncated } = await cb.entities.subunits('817209882');
const left = await cb.remaining(); // poster og kall igjen i dag og denne måneden

Feil kommer som CompanybookError med status, code, retryAfter og fatal (401, 402, 403: stopp kjøringen).

5. Når du bare har et navn

Bruk GET /resolve og kontroller treffet før du lagrer koblingen:

curl -s -G https://companybook.co/api/v1/resolve \
  -H "Authorization: Bearer $COMPANYBOOK_API_KEY" \
  --data-urlencode 'query=Vinmonopolet' \
  --data-urlencode 'types=["org"]' \
  --data-urlencode 'limit=5'

score rangerer kandidatene, men er ikke en sannsynlighet. Godta et treff automatisk bare når navnet og postnummeret eller poststedet stemmer med det du har fra før. Ellers: legg det til manuell kontroll.

6. Forbruk og grenser

  • All bruk måles, også gratis data. Grunndata koster 0 credits, men teller mot volumgrensene: på Plus 120 kall i minuttet, 10 000 kall og 50 000 poster per døgn. Utvidelser teller som poster.
  • API-et reserverer plass før kallet og avregner faktisk mengde etterpå. Et kall med 100 ID-er og alle utvidelser reserverer mye, men belaster bare det som leveres.
  • Sjekk credential.used og credential.limits i GET /me før en stor kjøring; tellerne er de samme som grensene håndheves mot, og credential.resets sier når døgnet og måneden nullstilles (UTC).
  • Følg eget forbruk i bruksoversikten eller med GET /usage. Teamnøkler vises under teamet i bruksoversikten.

7. Feil og hva du skal gjøre

Status og kodeBetydningGjør dette
401 authentication_required / invalid_tokenNøkkelen mangler, er feil eller er tilbakekaltStopp. Ikke prøv igjen med samme nøkkel.
403 plan_requiredPlanen dekker ikke operasjonen; svaret har required_tier og upgrade_urlStopp og si fra til eieren av kontoen.
400 invalid_argumentsFor mange ID-er, ukjent utvidelse eller feil formatRett forespørselen; ikke prøv igjen uendret.
402 credits_exhaustedSaldoen er brukt oppStopp til neste måned eller til saldoen er økt.
429 volume_limit / expense_limitVolumgrensen er nåddVent minst Retry-After sekunder. Ikke lag flere nøkler for å komme rundt grensen.
503 data_unavailable / metering_unavailableMidlertidig feil hos ossPrøv igjen senere med samme forespørsel.

8. Anbefalt oppsett for en nattlig synk

  1. Les listen over organisasjonsnumre fra ditt eget system og fjern duplikater.
  2. Del opp i grupper på 50 og kall POST /entities/batch sekvensielt med de utvidelsene du trenger.
  3. Lagre as_of sammen med dataene. Hent ikke samme selskap oftere enn én gang i døgnet: registerdata endrer seg sjelden raskere.
  4. Ved 429: vent Retry-After og fortsett der du slapp. Ved 403 eller 401: avbryt hele kjøringen og varsle.
  5. Logg antall selskaper, antall mangler (coverage.missing) og cost.units per kjøring. Logg aldri nøkkelen.

9. Slik vet du at integrasjonen virker

  • GET /me gir api_access: true.
  • Et batch-kall med cb:org:923609016 (Equinor ASA) gir entity_type: "hovedenhet" og flere år i data.extensions.financial_history["923609016"].
  • Et kall med en ID som ikke finnes gir ID-en i coverage.missing, ikke en feil.
  • Forbruket vises i bruksoversikten innen et minutt.

Mer