# GET /v1/facts

> Index: https://kartpunkt.se/llms.txt

operationId: `listFacts`. The facts catalog.
Tag: `registries`.

Every fact a path, a trace or a road can report, with its kind, unit, values, NVDB layers and whether a path can be kept off it. Read it before you hard-code a fact key. It costs a request and no calculation.

## Request

`GET https://api.kartpunkt.se/v1/facts` with `Authorization: Bearer $KARTPUNKT_API_KEY`, from your backend (never browser code: the key would leak, and CORS is not enabled).

## Response 200

Example:

```json
{
  "facts": [
    {
      "key": "speed_limit",
      "kind": "category",
      "description": "The posted speed limit in the direction travelled, in km/h; metres where none is recorded (or gångfart) are under \"none\".",
      "unit": "km/h",
      "values": null,
      "avoidable": "range",
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_48_Hastighetsgrans"
        ]
      }
    },
    {
      "key": "road_owner",
      "kind": "category",
      "description": "Who maintains the road (väghållare): the state, a municipality or a private owner.",
      "unit": null,
      "values": [
        "state",
        "municipal",
        "private",
        "unknown"
      ],
      "avoidable": "values",
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_2_Vaghallare"
        ]
      }
    },
    {
      "key": "surface",
      "kind": "category",
      "description": "The wearing course (slitlager): paved or gravel.",
      "unit": null,
      "values": [
        "paved",
        "gravel",
        "unknown"
      ],
      "avoidable": "values",
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_30_Slitlager"
        ]
      }
    },
    {
      "key": "road_class",
      "kind": "category",
      "description": "Trafikverket's functional road class (funktionell vägklass), 0 (most important) to 9.",
      "unit": null,
      "values": null,
      "avoidable": "range",
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_38_FunkVagklass"
        ]
      }
    },
    {
      "key": "network",
      "kind": "category",
      "description": "The network the path is on: the road network (bil), a cycle path (cykel) or a footpath (gang).",
      "unit": null,
      "values": [
        "bil",
        "cykel",
        "gang"
      ],
      "avoidable": null,
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_88_Vagtrafiknat"
        ]
      }
    },
    {
      "key": "gcm_type",
      "kind": "category",
      "description": "The kind of walk or cycle way NVDB records (GCM-vägtyp), e.g. walk_and_cycle_path (gång- och cykelbana), footway (gångbana), cycle_lane (cykelfält), pedestrian_crossing (övergångsställe), cycle_crossing (cykelpassage), cycle_priority_crossing (cykelöverfart), unmarked_crossing (gatupassage utan utmärkning), steps (trappa), square (torg/öppen yta); metres with none recorded, as on most roads, are under \"none\", and a value the catalog does not map under \"unknown\".",
      "unit": null,
      "values": [
        "walk_and_cycle_path",
        "walk_and_cycle_path_divided",
        "mandatory_cycle_path",
        "cycle_lane",
        "footway",
        "pedestrian_crossing",
        "cycle_crossing",
        "cycle_and_pedestrian_crossing",
        "cycle_priority_crossing",
        "cycle_priority_and_pedestrian_crossing",
        "unmarked_crossing",
        "steps",
        "lift",
        "square",
        "other_cycleable",
        "other_not_cycleable",
        "none",
        "unknown"
      ],
      "avoidable": null,
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_99_GCM_vagtyp"
        ]
      }
    },
    {
      "key": "municipality",
      "kind": "category",
      "description": "The kommun the road lies in, by its four-digit code.",
      "unit": null,
      "values": null,
      "avoidable": null,
      "source": {
        "source": "nvdb",
        "layers": [
          "AGGREGAT_O_5_KommunLanReg"
        ]
      }
    },
    {
      "key": "road_name",
      "kind": "category",
      "description": "The road's name: its gatunamn, else its övrigt vägnamn; metres on roads with neither are under \"none\".",
      "unit": null,
      "values": null,
      "avoidable": null,
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_20_Gatunamn",
          "NVDB_DK_O_21_Ovrigt_vagnamn"
        ]
      }
    },
    {
      "key": "road_number",
      "kind": "category",
      "description": "The road's number as signed (vägnummer), e.g. E4 or 364; metres on unnumbered roads are under \"none\".",
      "unit": null,
      "values": null,
      "avoidable": null,
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_111_Vagnummer"
        ]
      }
    },
    {
      "key": "traffic_safety_class",
      "kind": "category",
      "description": "Trafikverket's traffic safety class for the stretch (TS-klass), as delivered.",
      "unit": null,
      "values": null,
      "avoidable": "range",
      "source": {
        "source": "nvdb",
        "layers": [
          "VIS_DK_O_62_Trafiksakerhet_Stracka"
        ]
      }
    },
    {
      "key": "built_up",
      "kind": "flag",
      "description": "Metres inside a built-up area (tättbebyggt område).",
      "unit": "m",
      "values": null,
      "avoidable": "flag",
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_40_TattbebyggtOmrade"
        ]
      }
    },
    {
      "key": "lit",
      "kind": "flag",
      "description": "Metres on a lit walk or cycle path (GCM belyst); roads carry no lighting record.",
      "unit": "m",
      "values": null,
      "avoidable": "flag",
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_97_GCM_belyst"
        ]
      }
    },
    {
      "key": "separated",
      "kind": "flag",
      "description": "Metres on a walk or cycle path NVDB records as separated from motor traffic (GCM-separation). NVDB records separation on the path's own link, so it says whether the link walked or cycled is separated; it never says whether a road has a path beside it, so metres along a road's carriageway are not counted because a separate path runs beside it.",
      "unit": "m",
      "values": null,
      "avoidable": null,
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_98_GCM_separation"
        ]
      }
    },
    {
      "key": "ferry",
      "kind": "flag",
      "description": "Metres on a ferry route (färjeled).",
      "unit": "m",
      "values": null,
      "avoidable": "flag",
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_23_Farjeled"
        ]
      }
    },
    {
      "key": "motorway",
      "kind": "flag",
      "description": "Metres on a motorway or a motortrafikled.",
      "unit": "m",
      "values": null,
      "avoidable": "flag",
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_19_Motorvag",
          "NVDB_DK_O_18_Motortrafikled"
        ]
      }
    },
    {
      "key": "fast_road",
      "kind": "flag",
      "description": "Road exposure: metres along the carriageway of a road whose limit is 70 km/h or more in either direction, functional road class 9 left out; a separate walk or cycle path beside it does not count.",
      "unit": "m",
      "values": null,
      "avoidable": "flag",
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_48_Hastighetsgrans",
          "NVDB_DK_O_38_FunkVagklass"
        ]
      }
    },
    {
      "key": "speed_limit_varies",
      "kind": "flag",
      "description": "Metres where NVDB records a deviating limit (by time, season or vehicle) beside the base one.",
      "unit": "m",
      "values": null,
      "avoidable": null,
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_48_Hastighetsgrans"
        ]
      }
    },
    {
      "key": "unlit_outside_built_up",
      "kind": "metres",
      "description": "Road exposure: exact metres outside a built-up area (tättbebyggt område); on a road every such metre, on a walk or cycle path only those not lit.",
      "unit": "m",
      "values": null,
      "avoidable": "flag",
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_40_TattbebyggtOmrade",
          "NVDB_DK_O_97_GCM_belyst"
        ]
      }
    },
    {
      "key": "traffic_volume",
      "kind": "measure",
      "description": "Annual average daily traffic (ÅDT) of the road travelled or crossed, in vehicles a day.",
      "unit": "vehicles/day",
      "values": null,
      "avoidable": null,
      "source": {
        "source": "nvdb",
        "layers": [
          "TRAFIK_DK_O_105_Trafik"
        ]
      }
    },
    {
      "key": "crossings_without_refuge",
      "kind": "count",
      "description": "Road exposure: crossings of a road whose limit is 60 km/h or more where NVDB records no refuge (refug); a crossing counts where the path covers at least half the edge it lies on.",
      "unit": null,
      "values": null,
      "avoidable": null,
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_27_GCM_passage"
        ]
      }
    },
    {
      "key": "crossings_unknown_refuge",
      "kind": "count",
      "description": "Road exposure: crossings of a road whose limit is 60 km/h or more where NVDB records the refuge as unknown, or not at all; a crossing counts where the path covers at least half the edge it lies on.",
      "unit": null,
      "values": null,
      "avoidable": null,
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_27_GCM_passage"
        ]
      }
    },
    {
      "key": "level_crossings",
      "kind": "count",
      "description": "Level crossings of a railway (plankorsning).",
      "unit": null,
      "values": null,
      "avoidable": null,
      "source": {
        "source": "nvdb",
        "layers": [
          "AGGREGAT_O_76_Plankorsning_vag_jarnvag"
        ]
      }
    },
    {
      "key": "max_weight",
      "kind": "measure",
      "description": "The lowest gross-weight limit on the path (Begränsat bruttovikt, or a ForbudTrafik row with a Totalvikt), in tonnes.",
      "unit": "t",
      "values": null,
      "avoidable": null,
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_*_BegrBruttovikt",
          "NVDB_DK_O_12_ForbudTrafik"
        ]
      }
    },
    {
      "key": "max_axle_load",
      "kind": "measure",
      "description": "The lowest axle-load limit on the path (Begränsat axeltryck), in tonnes.",
      "unit": "t",
      "values": null,
      "avoidable": null,
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_*_BegrAxelBoggiTryck"
        ]
      }
    },
    {
      "key": "max_height",
      "kind": "measure",
      "description": "The lowest free height under an obstacle on the path (Höjdhinder), in metres.",
      "unit": "m",
      "values": null,
      "avoidable": null,
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_*_Hojdhinder45dm"
        ]
      }
    },
    {
      "key": "max_width",
      "kind": "measure",
      "description": "The lowest vehicle-width limit on the path, in metres.",
      "unit": "m",
      "values": null,
      "avoidable": null,
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_*_BegrFordBredd"
        ]
      }
    },
    {
      "key": "max_length",
      "kind": "measure",
      "description": "The lowest vehicle-length limit on the path, in metres.",
      "unit": "m",
      "values": null,
      "avoidable": null,
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_*_BegrFordLangd"
        ]
      }
    },
    {
      "key": "bearing_class",
      "kind": "category",
      "description": "Bärighetsklass (BK1-BK4): metres per class. A class limits gross weight through axle-spacing tables (Trafikförordningen 4 kap.), so it is reported, never turned into one weight.",
      "unit": null,
      "values": [
        "BK1",
        "BK2",
        "BK3",
        "BK4",
        "unknown"
      ],
      "avoidable": null,
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_1_Barighet"
        ]
      }
    },
    {
      "key": "hgv_banned",
      "kind": "flag",
      "description": "Metres where NVDB's traffic bans close the road to a lorry (lastbil, tung lastbil) in the direction travelled: closed, or closed but to line traffic. A road closed to a lorry's through traffic only is not counted: a lorry may drive it to or from an end there.",
      "unit": "m",
      "values": null,
      "avoidable": null,
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_12_ForbudTrafik"
        ]
      }
    },
    {
      "key": "hazmat_banned",
      "kind": "flag",
      "description": "Metres where transport of dangerous goods (farligt gods) is banned.",
      "unit": "m",
      "values": null,
      "avoidable": null,
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_*_InskrTranspFarligtGods"
        ]
      }
    },
    {
      "key": "hazmat_route",
      "kind": "flag",
      "description": "Metres on a recommended route for dangerous goods.",
      "unit": "m",
      "values": null,
      "avoidable": null,
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_*_RekomVagFarligtGods"
        ]
      }
    },
    {
      "key": "timed_restriction",
      "kind": "flag",
      "description": "Metres under a traffic ban with a time window (ForbudTrafik): routes are not kept off these; the caller checks the window.",
      "unit": "m",
      "values": null,
      "avoidable": null,
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_12_ForbudTrafik"
        ]
      }
    },
    {
      "key": "structure",
      "kind": "category",
      "description": "Whether the path is on a bridge (överfart), passes under something (underfart) or is in a tunnel (Bro och tunnel): metres per value, \"none\" off any.",
      "unit": null,
      "values": [
        "bridge",
        "underpass",
        "tunnel",
        "none"
      ],
      "avoidable": null,
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_25_Bro_och_tunnel"
        ]
      }
    },
    {
      "key": "barriers",
      "kind": "count",
      "description": "Barriers across the road (Väghinder: a bollard, a gate, a cycle barrier, blocks) the path passes; one that stops the profile is never on its route.",
      "unit": null,
      "values": null,
      "avoidable": null,
      "source": {
        "source": "nvdb",
        "layers": [
          "NVDB_DK_O_37_Vaghinder"
        ]
      }
    }
  ],
  "provenance": {
    "synthetic": true,
    "sources": []
  }
}
```

- `facts` (array of object): Every fact in the catalog.
  - `key` ("speed_limit" | "road_owner" | "surface" | "road_class" | "network" | "gcm_type" | "municipality" | "road_name" | "road_number" | "traffic_safety_class" | "built_up" | "lit" | "separated" | "ferry" | "motorway" | "fast_road" | "speed_limit_varies" | "unlit_outside_built_up" | "traffic_volume" | "crossings_without_refuge" | "crossings_unknown_refuge" | "level_crossings" | "max_weight" | "max_axle_load" | "max_height" | "max_width" | "max_length" | "bearing_class" | "hgv_banned" | "hazmat_banned" | "hazmat_route" | "timed_restriction" | "structure" | "barriers"): The fact's key, as facts and avoid.facts take it.
  - `kind` ("category" | "measure" | "flag" | "metres" | "count"): How the fact is summed over a path: 'category' as metres per value, 'measure' as its min and max, 'flag' and 'metres' as metres, 'count' as a count.
  - `description` (string): What NVDB records for the fact.
  - `unit` (string | null): The value's unit, e.g. 'km/h'; null where the value has none.
  - `values` (array of string | null): The values the fact can take, where the catalog fixes them; null otherwise.
  - `avoidable` ("flag" | "range" | "values" | null): How avoid.facts keeps a path off the fact: 'flag' as { fact }, 'range' as { fact, min, max }, 'values' as { fact, values }. A flag can also be preferred against in prefer. null where a path cannot be kept off it (ADR-0021 §5).
  - `source` (object): Where the fact is read from.
    - `source` ("nvdb"): The source the fact is read from: always 'nvdb'.
    - `layers` (array of string): The NVDB layers the fact is read from.
- `provenance` ([Provenance](https://api.kartpunkt.se/docs/shapes/Provenance.md))

## Errors

Every error is `{ error, message, param?, doc_url }`; `message` says what to do next. All codes: [https://api.kartpunkt.se/errors](https://api.kartpunkt.se/errors). What to do on each, with retries: [https://api.kartpunkt.se/docs/recipes/errors-and-retries.md](https://api.kartpunkt.se/docs/recipes/errors-and-retries.md).

- [`invalid_request`](https://api.kartpunkt.se/errors/invalid_request) (400): The request does not match the API schema. Fix the fields named in this message; see /openapi.json.
- [`unauthorized`](https://api.kartpunkt.se/errors/unauthorized) (401): Missing or unknown API key. Send it as 'Authorization: Bearer <key>' (or 'x-api-key'), read from the KARTPUNKT_API_KEY environment variable. The user creates a kp_test_ key on their Kartpunkt account page (https://kartpunkt.se/konto) and puts it in KARTPUNKT_API_KEY themselves; never ask them to paste a key into chat.
- [`live_access_required`](https://api.kartpunkt.se/errors/live_access_required) (403): This account is not approved for live data: kp_live_ keys are for customers under contract. Use a kp_test_ key. To ask for live access, the account holder writes to hej@kartpunkt.se, or orders a plan at https://kartpunkt.se/konto#plan.
- [`quota_exceeded`](https://api.kartpunkt.se/errors/quota_exceeded) (429): Request limit or plan quota reached (per minute, per day, or the account plan's monthly quota). Wait the number of seconds in the Retry-After header, then retry; without Retry-After, no wait helps: tell the account holder what this message says.
- [`internal_error`](https://api.kartpunkt.se/errors/internal_error) (500): Something failed on our side. Retry after a few seconds; if it keeps failing, contact hej@kartpunkt.se.
- [`live_data_unavailable`](https://api.kartpunkt.se/errors/live_data_unavailable) (503): Live data is not available yet: it opens when Kartpunkt's import of Lantmäteriet's address register completes. Use a kp_test_ key until then.

## Limits

none

## Metering

A request only: no calculations, no live call, no address limit.
