fetchthing Get in touch

CVR · BBR · DMR · one API

Danish public data, one request away.

A company's details, its buildings and its vehicles all sit in Denmark's public registers, behind three very different interfaces. BBR alone takes a dozen nested requests for one property. fetchthing does it once, behind one API.

Act I

Three registers, three worlds.

An insurance broker wants to know what a business customer owns: its buildings and its vehicles. The data is public. Getting it is another matter.

01 · CVR

The company: a search engine.

The business register answers through an Elasticsearch query you write yourself, with its own nesting and its own idea of which address is current.

~
$ curl -u "$CVR_USER:$CVR_PASS" "$CVR/cvr-permanent/virksomhed/_search" -d @query.json
{"hits": {"hits": [{"_source": {"Vrvirksomhed": {"cvrNummer": 12345678,
"virksomhedMetadata": {"nyesteNavn": {"navn": "Example Transport ApS", …
# the address you want is three levels down, in a list, with validity dates

02 · BBR

The buildings: a dozen nested requests.

Address to plot, plot to buildings, buildings to units, units to floors, and the owner somewhere else entirely. The fields are codes you look up in a table.

bbr.ts lines 1–16
// one property's basic facts, from BBR. by hand.
const addr = await get(`${DAWA}/adresser?q=${query}`); // 1
const plot = await get(`${BBR}/grund?husnummer=${addr[0].adgangsadresseid}`); // 2
for (const g of plot) {
const buildings = await get(`${BBR}/bygning?grund=${g.id_lokalId}`); // 3..n
for (const b of buildings) {
const units = await get(`${BBR}/enhed?bygning=${b.id_lokalId}`); // n..m
for (const u of units) {
const floors = await get(`${BBR}/etage?id=${u.etage}`); // m..k
// and the owner is somewhere else again: ejendomsrelation,
// then the land registry, then CVR if the owner is a company.
}
}
}
// status codes are strings, dates are three different formats,
// and "byg021BygningensAnvendelse = 120" means a detached house.

03 · DMR

The vehicles: a dump.

The motor register comes as one enormous XML file of every vehicle in Denmark. You download it, stream it, and index it before you can ask anything.

~/dmr
$ lftp -e "mirror /ESStatistikListeModtag; quit" "$DMR_FTP"
ESStatistikListeModtag-20260927.zip 3.9 GB
$ unzip -l ESStatistikListeModtag-20260927.zip
84 213 440 512 ESStatistikListeModtag.xml

04 · And glue

Then join it all, in every project.

Match the company to its addresses, the addresses to buildings, the CVR number to vehicle owners. Every project that needs this writes the joins again.

~/src
$ grep -rl "BBRPublic" ~/src --include=*.ts | cut -d/ -f5 | sort -u
broker-portal
crm-sync
quote-tool
# three projects, three slightly different joins

That was one customer.

requests and downloads
3
formats to parse
3
ways it breaks
3
requests for one BBR property
~12

Here's the same customer, through fetchthing.

Act II

The fetchthing way.

The requests, the dump and the joins are written once, behind one API that returns only what a consumer needs.

01 · One request

A company, and what it owns.

Ask for a CVR number and get the company, its properties with their BBR facts in plain words, and its vehicles. The codes are decoded; the dates are one format.

~
curl https://fetchthing.example/v1/company/12345678 \
-H "Authorization: Bearer $FETCHTHING_KEY"
{
"cvr": "12345678",
"name": "Example Transport ApS",
"address": "Eksempelvej 12, 8000 Aarhus C",
"properties": [
{ "address": "Eksempelvej 12", "use": "warehouse", "built": 1987, "area_m2": 1240 }
],
"vehicles": [
{ "plate": "AB 12 345", "kind": "truck", "first_registered": "2019-04-02" }
]
}

02 · Just a property

Or one address.

The dozen BBR requests become one. fetchthing walks plot, buildings and units, and answers with the building as a person would describe it.

~
$ curl "fetchthing.example/v1/property?address=Eksempelvej+12,+8000"
{ "use": "warehouse", "built": 1987, "area_m2": 1240, "floors": 2,
"roof": "fibre cement", "heating": "district heating" }

03 · Written once

Every consumer uses the same answer.

The joins, the code tables and the dump indexing live in one service. When a register changes its API, one place changes.

~/src
$ grep -rl "BBRPublic" ~/src --include=*.ts | wc -l
1 # fetchthing itself

Act III

The bigger picture.

fetchthing is half of an idea: get Denmark's hard-to-reach business data into the CRM a broker already works in.

  1. 1

    Fetch

    fetchthing turns CVR, BBR and DMR into one clean API, so the data arrives in a shape a person understands.

  2. 2

    Shape the CRM

    twentything gives every CRM workspace the objects and fields to hold that data, declared once and installed the same everywhere.

  3. 3

    Use it

    A broker opens a customer and sees their buildings and vehicles, without anyone having written a request to a register.

Wrestling with BBR?

You have my sympathy, and probably some of the answers. Get in touch.

Get in touch