JobTech Taxonomy API

The JobTech Taxonomy API is a REST API for the JobTech Taxonomy Database. The JobTech Taxonomy Database contains terms or phrases used at the Swedish labour market.

Build Information

{:branch nil, :built "2024-04-16T13:21:18.002527696Z[Etc/UTC]", :commit "2c64ce5"}

Endpoints

Open Source

The JobTech Taxonomy API is provided under the EPL-2.0 license.

Copyright © 2019 JobTech

Overview

This is the documentation for the JobTech Taxonomy API.

Contact has information on how to reach us with questions, suggestions and problems. It also contains information on where the project source code can be found.

Explore has information on entrypoints that enables an interactive exploration of the Taxonomy.

Understanding the Taxonomy contains information about what the Taxonomy is, what it contains and how it is supposed to work.

Using the Taxonomy contains information about the technical aspects of working with the Taxonomy, including some GraphQL examples.

Explore

The taxonomy can be found at https://taxonomy.api.jobtechdev.se or accessed via one of the entrypoints listed below.

The Taxonomy Atlas

The Taxonomy Atlas is a more human friendly way to take a look at what can be found in the Taxonomy.

There is an interactive visualisation that displays part of the graph behind the Taxonomy.

GraphiQL

An interactive GraphiQL entrypoint where GraphQL queries can be written and tested is available.

There is also a chapter on how to use GraphQL in this book.

REST API

There is a Swagger UI endpoint where the REST API can be tested.

Other things

For more software from the team who brought you the Taxonomy API, check out our other open software and APIs at taxonomy-dev.

Or take a look at what the other JobTechDev teams are up to on the JobTechDev GitLab instance.

Contact Information

Open Source

The JobTech Taxonomy API is an Open Source project and the source code can be found at https://gitlab.com/arbetsformedlingen/taxonomy-dev/backend/jobtech-taxonomy-api.

Reporting an issue

If you have found a problem or have an idea on how to improve the software create an issue.

JobTechDev Forum

For technical questions about the Taxonomy API contact us at https://forum.jobtechdev.se.

Specifically the Taxonomy forum section.

Mail

Questions about the content of the Taxonomy database, about Jobtech, about the API in general are best emailed to jobtechdev@arbetsformedlingen.se.

If you have questions about the implementation and have a mail account at Arbetsförmedlingen, you can send an email directly to taxonomy-dev@arbetsformedlingen.se.

Introduction

Exploring the Taxonomy via GraphQL

The best way to understand the Jobtech Taxonomy is to explore the data via the GraphQL endpoint. Here's a collection of example queries.

All Taxonomy Environments

graph BT
ON-->|substitutability|ON
ON(occupation-name) -->|broader| S4(ssyk-level-4)
S4 -->|broader| S3(ssyk-level-3)
S3 -->|broader| S2(ssyk-level-2)
S2 -->|broader| S1(ssyk-level-1)
S4-->|broader|OF(occupation-field)
OC(occupation-collection)-->|related|ON
I4(isco-level-4)-->|related|S4
K(keyword)-->|related|ON
S(skill)-->|related|I4
S-->|broader|SH(skill-headline)

M(municipality)-->|broader|REGION
COUNTRY(country)-->|broader|CONTINENT(continent)
REGION(region)-->|broader|COUNTRY
	

SNI2(sni-level-2)-->|broader|SNI1(sni-level-1)


SF4(sun-education-field-4)-->|broader|SF3(sun-education-field-3)
SF3-->|broader|SF2(sun-education-field-2)-->|broader|SF1(sun-education-field-1)

SL3(sun-education-level-3)-->|broader|SL2(sun-education-level-2)-->|broader|SL1(sun-education-level-1)

D(driving-license)-->D

ED(employment-duration)

ET(employment-type)

UF(unemployment-fund)

WT(wage-type)

L(language)
LL(language-level)

WTE(worktime-extent)

Related standards

Taxonomies in Sweden

  • SUN
  • SNI
  • SSYK

Taxonomies in EU

The JobTech Taxonomy is compatible with the ESCO taxonomy used in the EU Job Market.

  • ESCO

Taxonomies in UN

  • ISCO

Terminology

The Taxonomy Database contains terms or phrases used at the Swedish labour market. These are called concepts in the database. Every concept has a unique concept-ID, a preferred label and a type. We aim to use the terminology of SKOS Simple Knowledge Organization System Reference by the World Wide Web Consortium.

Here's an explanation of some of the terminology:

TermDefinitionExample
ConceptA concept can be viewed as an idea or notion, a unit of thoughtData/IT
SchemaThe top-level structure of the taxonomyOccupation
TypeThe type of a conceptOccupation field
Preferred labelThe preferred label for a conceptTorgförsäljare
Alternative labelAn alternative name of a concept, can be displayed externallyTorgknalle
Hidden labelA label of a concept that should not be displayed externallyGatumånglare
DefinitionThe explanation of a conceptWorking with system development, programming or maintenance of systems and networks

Some concepts include extra attributes like definitions and alternative labels. The concepts are connected in schemas, see the schema headlines below.

Within schemas the concepts are linked with relationships.

The content of the Taxonomy Database is constantly improved and updated by the JobTech editorial team. New versions of the database will be released at regular intervals. However the data is immutable, none of the concepts/terms are deleted in the Taxonomy Database. If a concept becomes outdated for the matching purposes, it is tagged with a deprecated flag, but it is still available in the API from some endpoints.

The Taxonomy Database contains several schemas. Some of these schemas are multilevel taxonomies with hierarchical relationships between concepts. Some schemas are merely simple collections of concepts. The following section will walk you through the schemas and relations within the database.

Relations

The concepts in the Taxonomy database may be related to each other in a number of ways. The different types of relations are in part based on this SKOS standard

The relations can be either vertical (describing a hierarchy) or horizontal.

Narrower

This relation is vertical and is used to express when one concept is on a lower level than another in a hierarchy. For example: the occupation “Beläggningsarbetare” is narrower than the occupation group “Anläggningsarbetare”.

Broader

This relation is vertical and is used to express when one concept is on a higher level than another in a hierarchy. For example: the occupation group “Anläggningsarbetare” is broader than the occupation “Beläggningsarbetare”.

Substitutability

This relation is horizontal and describes the closeness of two occupations. The relation can be expressed as both high (75) and low (25) substitutability between occupations. For example: the occupation “Beläggningsarbetare” has a high substitutability with the occupation “Väg- och anläggningsarbetare”. In the API the objects in the substitutability relations are expressed as a source occupation and a target occupation. In the example above the occupation “Beläggningsarbetare” would be the source.

The two levels can be described as following:

  • High (or 75%): very closely related with a high level of similarity in tasks
  • Low (or 25%): some tasks are similar and/or some education or training might be needed to traverse the gap

The substitutability relation may be asymmetrical, meaning that a high substitutability from one occupation to another does not necessarily mean that the reverse is true. For instance in the example above, the reversed substitutability (from Väg- och underhållningsarbetare to Beläggningsarbetare) is in fact low.

The substitutability relations are created and recommended for employers looking for candidates. If they cannot find exactly what they are looking for, they get suggestions that may work out for them instead. For example: an employer is looking for a candidate for “Förskollärare” but cannot find one. Instead they get suggestions for “Barnskötare” through the substitutability relation. In this case the substitutability from “Förskollärare” to “Barnskötare” is low.

Schema

Occupations

alt text

The occupation taxonomy is a multilevel collection, based on a national standard. The content, occupation names, synonyms and other concepts, are created and updated in cooperation with actors at the Swedish labour market. The concepts are connected to each other directly or indirectly.

Occupation schema is structured according to “SSYK, Svensk standard för yrkesklassificering" (Swedish Standard Classification of Occupations), which is based on “ISCO, International Standard Classification of Occupation”. The current version used is SSYK-2012.

All the concepts in the SSYK have external-standard codes.

Please note that the SSYK codes are not to be used as unique ID numbers for specific concepts since they are not fixed. Always use the Concept ID as identification for specific concepts. This is guaranteed to not change over time.

The external standard type at the topmost level in the schema (SSYK-1) contain nine major groups of occupations, like " Yrken med krav på fördjupad högskolekompetens". These major groups of occupations are recommended to be used for statistical purposes only.

Another “top level” groups of occupations, Occupation Field, is based on labour market sectors, created to make it easier for job seekers to find relevant jobs. Occupation Field is not an external standard.

The connections between SSYK Occupation Groups and Occupation Field is recommended to be used for statistical purposes only.

All Occupation names are also connected to at least one Occupation Field, some of them are connected to two Occupation Fields. These connections are recommended to be used for matching purposes.

The most detailed concept, Occupation Name contain terms collected by the editorial team in co-operation with employers’ organisations, professional boards and recruiters. In this level you’ll find concepts like “IT-arkitekt/Lösningsarkitekt”. Occupation names are the “official” terms for occupations.

Every concept at a lower and more detailed level is connected to one concept at the parent level, throughout the taxonomy. Example:

alt text

In the type Occupation Collections, you’ll find listings of Occupation Names grouped by variables that may span over different occupation areas: “Yrken utan krav på utbildning” and “Chefer, direktörer och föreståndare”. These collections are created to highlight a certain group of occupations, not based on SSYK.

The Keyword type contains search terms related to Occupation Names. They can be used to help candidates find job ads they are interested in even if they don’t know the exact Occupation Name. An example is the Keyword “Asfaltarbetare”, mapped to the Occupation Name “Beläggningsarbetare”. Keywords are recommended to be used as “hidden” terms, connected to one or several official Occupation Names. Keywords should not be exposed to end users.

Skills

The skills taxonomy contains two levels: Skills headlines like “Databaser” and Skills like “SQL-Base, databashanterare”. Each of the skill concepts are mapped to a parent skill headline and to one or several SSYK Occupation groups. The database of skills is created and updated in co-operation with employers’ organisations, professional boards and recruiters and includes the most relevant skills for each four-digit SSYK Occupation Group.

The skill headline named “Generella kompetenser” contains broader skills like “Projektledning, erfarenhet”. They are not mapped to any Occupation groups. They are recommended to use as optional skills for all job seekers and employers.

Swedish Retail and Wholesale Council Skills

These concepts are an example of how the requirements for skill can be made visible and what they mean in different professions.

The skills described here are intended to be helpful for employers in formulating advertisements for job vacancies and for jobseekers to create an understanding of what is required in different professional roles.

The source of the skills is Yrkeskartan, produced by the Swedish Retail and Wholesale Council in collaboration with the staffing and recruitment company Poolia.

For more info, see https://karriarihandeln.se/yrkeskartan/

Geographical Areas

The database contains a four-level taxonomy of geographical areas. Like the occupation and skill taxonomy, the concepts are related to each other in a hierarchical structure.

The top geographic type lists all continents in the world, including Antarctica. The taxonomy is based on the UN standard for continents. In this type, there is also the concept “Alla länder”, which is a list of all countries.

The second type in this taxonomy contains all countries, according to ISO standard for countries. Each country in this level has a parent continent in the top level.

The third type is simply called “regions” and contains all regions within the EU with a “NUTS code” (See Eurostat for information about NUTS). In Sweden the regions correspond to “län”. Every region is mapped to a specific parent country in the second level in the taxonomy.

The fourth type of the geographic areas contains the Swedish municipalities. Each municipality is mapped to a specific parent region in the above level.

Geographical areas are recommended to use when a vacancy is abroad or when a job seeker looks for a job abroad.

Wage

This schema only has one type. This type contains descriptions of forms of payment, like “Rörlig ackords- eller provisionslön”.

Employment

This schema only contains one type. It lists types of employment, like “Säsongsanställning” och “Behovsanställning/Timanställning”.

Employment duration

The employment duration taxonomy contains concepts describing how long an employment is meant to last. The schema contains concepts like “3 månader – upp till 6 månader”.

Occupation Experience Years

"Occupation experience year" consists of terms describing how many years a person has worked or needs to have worked in a particular occupation.

Driving License

This single type schema contains driving license categories in Sweden, according to EU standard, and the description and limitation of each license.

“Körkortskombinationer”: All but the “lowest” ranked license also contain a list of the licenses that are implicit within that level. The A2 license for example has the Implicit license attribute listing AM and A1. These are lower level licenses for scooters that you are automatically allowed to drive if you carry the A2 license.

Worktime Extent

This schema only contains the two concepts “Heltid” and “Deltid”.

Swedish Standard Classification of Education (SUN)

“Svensk utbildningsklassifkation” SUN is used for classifying education. SUN provides the conditions for producing comparable statistics and analysis of population, education and the Swedish education system, both nationally and internationally. SUN consists of two classifications: one describing education level and another describing education orientation.

Swedish Standard Industrial Classification (SNI)

This schema will soon be updated.

“Svensk näringsgrensindelning SNI” contains terms for industries. This taxonomy follows the SCB documentation and has two levels.

The SNI-level-1 contains general area term of industries. An example is the concept “Tillverkning”.

The second level, SNI-level-2, lists the industries in more detail. It has concepts like “Livsmedelsframställning”. Every concept in this level has a parent concept in the first level.

Language

Languages

The language taxonomy lists natural languages like “Engelska” and “Nederländska”. The language taxonomy is based on ISO 639 and it’s recommended to highlight which languages are requested for a vacancy and the languages a job seeker is able to work with.

Language levels

This schema will soon be updated.

Keyword

Concepts with the type Keyword are popular terms used for referencing other types of concepts (e.g. occupation-name, skill, sun-education-field). The concepts are referenced by using the relation-type related.

Design principles

The Jobtech Taxonomy database never deletes any data. Internally it just adds all changes to the database as an ever increasing event log. Concepts that shouldn't be used anymore gets flagged with a deprecated flag and will not be exposed via the API unless specifically asked for. The API allows it's consumers to choose what version of the database they want to retrieve data from which allows the consumers to become eventually consistent, instead of forcing a big bang of the usage.

Example of changes endpoint

[  
  {
    "taxonomy/event-type": "CREATED",
    "taxonomy/new-concept": {
      "taxonomy/definition": "Big data analyst/Stordata-analytiker",
      "taxonomy/preferred-label": "Big data analyst/Stordata-analytiker",
      "taxonomy/id": "Ggze_QQS_jZi",
      "taxonomy/type": "occupation-name"
    },
    "taxonomy/version": 2
  },
  {
    "taxonomy/event-type": "DEPRECATED",
    "taxonomy/latest-version-of-concept": {
      "taxonomy/id": "3vQv_E4Q_wjK",
      "taxonomy/type": "occupation-name",
      "taxonomy/definition": "Trafikpedagog",
      "taxonomy/preferred-label": "Trafikpedagog"
    },
    "taxonomy/version": 2
  }
]

Architectural overview

Architectural overview

Systems overview

Systems overview

Introduction

The JobTech Taxonomy API gives access to different taxonomies like occupation names, skills and SSYK, SNI etc.

It's main purpose is to act as a common language for labour market related systems.

REST API

How the REST API works is described by an OpenAPI specification. This is used to generate an overview with examples for the API and this can be accessed at the JobTech Taxonomy API Swagger UI page.

GraphQL

The Taxonomy API can be accessed using GraphQL and this can be tested at the JobTech Taxonomy API GraphiQL UI.

More about how the GraphQL endpoint can be used is found in the chapter on GraphQL.

Getting started

The JobTech Taxonomy API is divided into four sections GraphQL, Main, Specific Types and Suggesters.

The GraphQL section is the most modern approach to fetch data from the API and is the recommended way of fetching data from the API. Our long term goal is to be able to replace all other endpoints with the GraphQL endpoint. With the GraphQL end point you can fetch concepts (words) and their relations to other concepts.

The Main section contains the core functionalities of the API like retrieving concepts (words) from different taxonomies. It also has endpoints helping you to track and react to changes in the taxonomies.

The Specific Types section contains typed endpoints for taxonomies that has specific fields like statistical codes for SSYK and SNI.

The Suggesters section contains endpoints that helps end users finding values from the taxonomies when they are creating structured data based on the taxonomies. There is an autocomplete endpoint that suggest concepts that can assist users creating CVs or job ads.

Status

About SLA, to see statistics on our actual uptime to get a realistic idea on our availability. See this page Uptime statistics

Our commitment is that the Jobtech Taxonomy API will be operating during office hours. If you are in need of a higher uptime you should implement a fall back solution with a local copy of the Jobtech Taxonomy.

API Changes

There are two ways to get notified when changes occur in the Taxonomy API. The first is to subscribe to our API RSS feed, and the second is to register a user on https://forum.jobtechdev.se/ and subscribing to the API changes topic.

Versions

The content of the taxonomies is constantly being updated and changes are released in a controlled manner.

Warning

In order to fetch version 1 of the Taxonomy you have to add the query parameter "version" and set it to "1".

https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/concepts?id=tHZB_LJU_8LG&version=1

[
  {
    "taxonomy/id": "tHZB_LJU_8LG",
    "taxonomy/type": "occupation-name",
    "taxonomy/definition": "Barnsjuksköterska, mottagning/vårdcentral",
    "taxonomy/preferred-label": "Barnsjuksköterska, mottagning/vårdcentral",
    "taxonomy/relations": {
      "taxonomy/broader": 2,
      "taxonomy/narrower": 0,
      "taxonomy/related": 2,
      "taxonomy/substitutability-to": 6,
      "taxonomy/substitutability-from": 7
    }
  }
]

If you don't add the query parameter "version" to your request you will always get the latest version of the Taxonomy.

https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/concepts?id=tHZB_LJU_8LG

[
  {
    "taxonomy/id": "tHZB_LJU_8LG",
    "taxonomy/type": "occupation-name",
    "taxonomy/definition": "Barnsjuksköterska, mottagning/Barnsjuksköterska, vårdcentral",
    "taxonomy/preferred-label": "Barnsjuksköterska, mottagning/Barnsjuksköterska, vårdcentral",
    "taxonomy/relations": {
      "taxonomy/broader": 2,
      "taxonomy/narrower": 0,
      "taxonomy/related": 2,
      "taxonomy/substitutability-to": 6,
      "taxonomy/substitutability-from": 7
    }
  }
]

Authentication

No authentication is needed for read access of published versions.

Endpoints

Below we only show the URLs. If you prefer the curl command, you type it like:

curl "{URL}" -H "accept: application/json"

Main Endpoints

/v1/taxonomy/main/concept/types

This endpoint will list all available types in the taxonomies

v1/taxonomy/main/relation/types

This endpoint will list all available relation types in the taxonomies.

The broader / narrower relation is for hierarchical relations.

The related relation is a non specific relation like a keyword that is related to an occupation name.

The substitutability relation is for showing related occupations that can substitute one another. For example, if an employer wants to hire a “Barnmorska, förlossning" but can't find any they can do a search for a "Barnmorska, vårdavdelning/BB-avdelning" instead. The substitutability-percentage will show how well the occupation can substitute another occupation.

/v1/taxonomy/main/concepts

This endpoint will let you retrieve concepts from different taxonomies.

Example List all Skill headlines
https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/concepts?type=skill-headline

This request will fetch all concepts of type skill headline.

Example Relations
https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/concepts?related-ids=xAWr_WYq_JPP%20Uj5W_dft_Ssg&relation=narrower

This request will fetch concepts that has a narrower relation from the concepts “Databaser” and “Operativsystem”.

Example 2. Multiple types
https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/concepts?type=ssyk-level-1%20ssyk-level-2%20ssyk-level-3

This request will fetch concepts of types ssyk-level-1 ssyk-level-2 and ssyk-level-3

/v1/taxonomy/main/graph

This endpoint will list relations between two types of concepts in the taxonomies. It’s main use case is to be able to build tree views of the taxonomy. It will also list extra metadata on the relations.

Example Tree view Occupation Field, ssyk-level-4, occupation-name
https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/graph?edge-relation-type=broader&source-concept-type=occupation-name&target-concept-type=ssyk-level-4

https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/graph?edge-relation-type=broader&source-concept-type=ssyk-level-4&target-concept-type=occupation-field

With the help of these two request you can build a tree view bottom up of the occupation-name -> ssyk-level-4 -> occupation-field hierarchy

Example Occupation name substitutability
https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/graph?edge-relation-type=substitutability&source-concept-type=occupation-name&target-concept-type=occupation-name&limit=10

This request will fetch occupation names that has a substitutability relation to each other. For example, if an employer wants to hire a “Barnmorska, förlossning" but can’t find any they can instead use information from this endpoint to search for a "Barnmorska, vårdavdelning/BB-avdelning". The substitutability-percentage will show how well the occupation can substitute another occupation.

/v1/taxonomy/main/changes

This endpoint will list all changes that have occurred to the taxonomies. It’s a list of events of the types CREATED, DEPRECATED and UPDATED.

You can use it to be able to react to changes in the taxonomies. For example if a job seeker is subscribing to job recommendations based on a specific occupation name and that occupation name becomes deprecated, this endpoint will contain information that the deprecation occurred so you can inform the job seeker to update their search profile.

/v1/taxonomy/main/replaced-by-changes

This endpoint will list all deprecated concepts that has been replaced by another newer concept.

/v1/taxonomy/main/versions

This endpoint will list all published versions of the taxonomies.

GraphQL endpoint

GraphQL is a modern query language for APIs that is especially useful for fetching multiple related resources at once in a single request. Since this taxonomy consists of highly inter-related concepts, GraphQL is a naturally fitting instrument for building complex queries that require only a single round-trip to server.

GraphiQL is an interactive GraphQL explorer that helps you browse the taxonomy and build queries interactively. It is accessible on this page.

GraphiQL

You can learn GraphQL, as well as taxonomy dataset and terms, using interactive Explorer UI that shows all available options and allows to build queries by selecting from them. You can read Docs to learn about our schema and meanings of different concept fields.

GraphQL endpoint for programmatic access — /v1/taxonomy/graphql — is also documented on the Swagger API page, so once you've finished building your GraphQL query in GraphiQL, you can use query's text as a query parameter to see how curl commands or urls will look like, for example:

https://taxonomy.api.jobtechdev.se/v1/taxonomy/graphql?query=query%20SwedishMunicipalities%20%7B%20%20%20concepts%28id%3A%20%22i46j_HmG_v64%22%29%20%7B%20%20%20%20%20id%20%20%20%20%20preferred_label%20%20%20%20%20regions%3A%20narrower%20%7B%20%20%20%20%20%20%20id%20%20%20%20%20%20%20type%20%20%20%20%20%20%20preferred_label%20%20%20%20%20%20%20municipalities%3A%20narrower%20%7B%20%20%20%20%20%20%20%20%20id%20%20%20%20%20%20%20%20%20type%20%20%20%20%20%20%20%20%20preferred_label%20%20%20%20%20%20%20%7D%20%20%20%20%20%7D%20%20%20%7D%20%7D

Example Fetch Swedish regions and municipalities (län and kommuner) in one request

query MyQuery {
  concepts(id: "i46j_HmG_v64") {
    id
    preferred_label
    type
    narrower {
      id
      preferred_label
      type
      narrower {
        id
        preferred_label
        type
      }
    }
  }
}

Example Fetch ssyk-level-4 and occupation-name based on occupation-field Data/IT

query MyQuery {
  concepts(type: "occupation-field", id: "apaJ_2ja_LuF") {
    id
    preferred_label
    type
    narrower(type: "ssyk-level-4"){
      id
      preferred_label
      type
      narrower(type: "occupation-name") {
        id
        preferred_label
        type
      }
    }
  }
}
query MyQuery {
  concepts(id: "rQds_YGd_quU") {
    id
    preferred_label
    type
    broader(type: "ssyk-level-4") {
      id
      preferred_label
      type
      related(type: "skill"){
          id
          preferred_label
          type
      }
    }
  }
}

Example Fetch Standard för svensk näringsgrensindelning (SNI) taxonomy

query MyQuery {
  concepts(type: "sni-level-1"){
    id
    preferred_label
    type
    sni_level_code_2007
    narrower(type: "sni-level-2"){
      id
      preferred_label
      type
      sni_level_code_2007
    }
  }
}

Specific Endpoints

These endpoint acts like the /v1/taxonomy/main/concepts but will also display specific metadata on the concepts like ssyk or country codes.

Example Fetch SSYK codes for all levels

https://taxonomy.api.jobtechdev.se/v1/taxonomy/specific/concepts/ssyk?type=ssyk-level-1%20ssyk-level-2%20ssyk-level-3%20ssyk-level-4

Suggesters Endpoints

/v1/taxonomy/suggesters/autocomplete

This endpoint is to help end users to find concepts in the taxonomies.

Example Autocomplete programming languages starting on “sc”

https://taxonomy.api.jobtechdev.se/v1/taxonomy/suggesters/autocomplete?query-string=sc&type=skill&relation=narrower&related-ids=ShQw_McG_oti

With this request you can autocomplete programming languages starting on the letter “sc”

https://taxonomy.api.jobtechdev.se/v1/taxonomy/suggesters/autocomplete?query-string=lastb&type=occupation-name%20keyword

https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/concepts?related-ids=d68E_e74_a59&relation=related

Let's say a user wants to find jobs as a “Lastbilsförare” and starts typing the word “lastb”.

We make a first request to this endpoint also limiting the result to occupation-name and keyword. The response contains the concept “Lastbilsförare” but not as an occupation-name but as a keyword.

If the user show interest in the word “Lastbilsförare” we can make another request for related occupation names with the /v1/taxonomy/main/concepts endpoint.

Results

The results of your queries will be in edn, transit+messagepack or transit+json or JSON.

Successful queries will have a response code of 200 and give you a result set that consists of:

...

Errors

Unsuccessful queries will have a response code of:

HTTP Status codeReasonExplanation
400Bad RequestSomething wrong in the query
401UnauthorizedYou are not using a valid API key (private endpoints only)
500Internal Server ErrorSomething wrong on the server side

Diagrams

Here is a diagram over the types in the taxonomies and what relations they have to each other. The "broader" relation always has an implicit "narrower" relation in the opposite direction. The "related" relation always has an implicit "related" relation in the opposite direction.

Taxonomy Types and Relations

Convert between Old and New Taxonomy ids

If you need to convert data that contains ids from the old taxonomy service you can use these APIs to convert between old and new Taxonomy ids:

Please be aware of that occupation-group, municipality, region are not using the legacyDatabase id but statistical codes, like SSYK, länskod, kommunkod.

Also note that "driving license", is named "driving licence", in the the new taxonomy API

Taxonomy + Ontology

The Job market Ontology is being merged with the JobTech Taxonomy. This is an ongoing task. The values of the Ontology will become either new concepts, alternative labels or keywords and all identifiers will be replaced with Jobtech Taxonomy identifiers where it's applicable.

Ontology files

A file dump of the Ontology can be downloaded here: Ontology Files

Tutorials

Under this section, we collect tutorials for using the Taxonomy API in various ways.

Using the Taxonomy from Python

This is a tutorial on how to use the Taxonomy API from Python. We will be using the Requests library to make HTTP requests. Start by installing it, and then, in a new script, import it:

import requests

The GraphQL API is arguably the easiest API to use. You may want to have a look at the GraphQL documentation along with this tutorial.

We will be talking against a server at the following address:

host = "https://taxonomy.api.jobtechdev.se"

and in order to display results, we will import a pretty printing module.

import pprint
pp = pprint.PrettyPrinter(width=41, compact=True)

Querying versions using GraphQL

The taxonomy has several versions. Let's start by querying what versions there are:

response = requests.get(host + "/v1/taxonomy/graphql", params={"query": """query MyQuery {
  versions {
    id
  }
}"""})

version_data = response.json()["data"]["versions"]
print("Last three versions:")
pp.pprint(version_data[-3:])

Output:

Last three versions:
[{'id': 20}, {'id': 21}, {'id': 22}]

Let's pick out the latest version:

latest_version = max([x["id"] for x in version_data])

pp.pprint(latest_version)

Output:

22

Querying concepts using GraphQL

If we want to, we can modify our query to include concept data from every version. To keep things concise, we will limit ourselves to the latest version and only pick two concepts. Note that we pass in a separate json-coded map with variables.

import json

query = """query MyQuery($version:VersionRef) {
  versions(from: $version, to: $version) {
    id
    concepts(limit: 2) {
      id
      preferred_label
    }
  }
}"""

variables = json.dumps({"version": "21"})

response = requests.get(
    host + "/v1/taxonomy/graphql",
    params={"query": query, "variables": variables})
    
pp.pprint(response.json())

and we get

Output:

{'data': {'versions': [{'concepts': [{'id': 'ghs4_JXU_BYt',
                                      'preferred_label': 'Planeringsarkitekt/Fysisk '
                                                         'planerare'},
                                     {'id': 'GPNi_fJR_B2B',
                                      'preferred_label': 'Inredningsdesigner'}],
                        'id': 21}]}}

We could also have approached this by directly querying the concepts:

query = """query MyQuery($version: VersionRef) {
  concepts(version: $version, limit: 2) {
    id
    preferred_label
  }
}"""

response = requests.get(
    host + "/v1/taxonomy/graphql",
    params={"query": query, "variables": variables})

pp.pprint(response.json())

and we get

Output:

{'data': {'concepts': [{'id': 'ghs4_JXU_BYt',
                        'preferred_label': 'Planeringsarkitekt/Fysisk '
                                           'planerare'},
                       {'id': 'GPNi_fJR_B2B',
                        'preferred_label': 'Inredningsdesigner'}]}}

What concepts are returned differ from query to query.

Querying concept types using GraphQL

To see what concept types there are in the latest version we can do

query = """query MyQuery {
  concept_types {
    id
    label_en
  }
}"""

response = requests.get(host + "/v1/taxonomy/graphql", params={"query": query})
concept_types = response.json()["data"]["concept_types"]
n = len(concept_types)
print(f"There are {n} concept types in the latest version")
print("Here are some:")
pp.pprint(concept_types[0:3])

We only print three concept types.

Output:

There are 52 concept types in the latest version
Here are some:
[{'id': 'occupation-experience-year',
  'label_en': 'Occupation experience '
              '(time)'},
 {'id': 'forecast-occupation',
  'label_en': 'Forecast occupation'},
 {'id': 'occupation-field',
  'label_en': 'Occupation field'}]

but we can also look at the concept types for a specific version:

query = """query MyQuery($version:VersionRef) {
  concept_types(version: $version) {
    id
    label_en
  }
}"""

variables = json.dumps({"version": "1"})
response = requests.get(host + "/v1/taxonomy/graphql", params={"query": query, "variables": variables})
n = len(response.json()["data"]["concept_types"])
print(f"There are {n} concepts in the first version.")

Output:

There are 36 concepts in the first version.

Understanding versions with GraphQL and Python

The taxonomy has multiple versions to help track changes and maintain backward compatibility. We can start by retrieving all the version ids. Just as in the introduction, we use the Requests library. We start with some imports and some definitions:

import json
import requests
import pprint
pp = pprint.PrettyPrinter(width=41, compact=True)
host = "https://taxonomy.api.jobtechdev.se"

def graphql_get(query, variables):
    response = requests.get(host + "/v1/taxonomy/graphql",
                            params={"query": query, "variables": json.dumps(variables)})
    return response.json()

The function graphql_get is a helper function to keep the rest of this code concise.

We can use it to get all versions:

version_data = graphql_get("""query MyQuery {
  versions {
    id
  }
}""", {})

versions = [x["id"] for x in version_data["data"]["versions"]]
versions.sort()

pp.pprint(versions)

Output:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]

Let's query the number of concepts per version:

query = """query MyQuery($version: VersionRef) {
  concepts(include_deprecated: true, version: $version) {
    id
    deprecated
    preferred_label
    replaces {
      id
    }
    replaced_by {
      id
    }
  }
}"""

version_concepts = {}

for v in versions:
    cdata = graphql_get(query, {"version": v})
    concepts = cdata["data"]["concepts"]
    version_concepts[v] = {c["id"]:c for c in concepts}
    n = len(concepts)

print(f"Loaded {len(version_concepts)} versions.")
print("Number of concepts per version: ")
pp.pprint([len(version_concepts[v]) for v in versions])

Output:

Loaded 22 versions.
Number of concepts per version: 
[14715, 18227, 18361, 18406, 18418,
 21365, 24291, 26352, 26352, 26546,
 28560, 41130, 41179, 41436, 41816,
 41960, 41960, 41998, 42227, 42584,
 44942, 45647]

We see that the number of concepts increase with every version if we count both deprecated and non-deprecated concepts. We would expect that the set of concepts in the last version is the set of all concepts ever seen:

all_ids = {k for concepts in version_concepts.values()
           for k in concepts.keys()}
last_ids = {k for k in version_concepts[versions[-1]].keys()}

print("Equal" if last_ids == all_ids else "Not equal")

Output:

Equal

It would be interesting to study the history of every concept. We will create a map from every concept id to its value in every version:

concept_histories = {concept_id:{v:cs[concept_id]
                                 for v,cs in version_concepts.items()
                                 if concept_id in cs}
                     for concept_id in all_ids}

There are for sure going to be some concepts that have been deprecated. We will start by looking at concepts that have not been replaced by any other concepts. To filter the concepts, we write two helper functions has_deprecated and has_replaced_by.


def map_has_value(m, pred):
    for k, v in m.items():
        if pred(v):
            return True
    return False


def has_deprecated(history):
    return map_has_value(history, lambda concept: concept["deprecated"])

def has_replaced_by(history):
    return map_has_value(history, lambda concept: 0 < len(concept["replaced_by"]))
    
histories_of_interest = [(concept_id, history)
                         for concept_id, history in concept_histories.items()
                         if has_deprecated(history) and not(has_replaced_by(history))]

(concept_id, history) = histories_of_interest[0]

exist_versions = [v for v in versions if v in history]
deprecated_in_versions = [v for v in exist_versions if history[v]["deprecated"]]

label = history[exist_versions[0]]["preferred_label"]

print(f"Have a look at concept {concept_id} with first label {label}")
print(f"It exists in versions {exist_versions}")
print(f"It is marked as deprecated in {deprecated_in_versions}")

Output:

Have a look at concept Tgsx_o7B_Tpo with first label Musik
It exists in versions [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]
It is marked as deprecated in [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]

The above concept does not have any replacements (as its replaced_by value is always empty). Let's look at an example where replaced_by has a value:

histories_of_interest = [(concept_id, history)
                         for concept_id, history in concept_histories.items()
                         if has_deprecated(history) and has_replaced_by(history)]

(concept_id, history) = histories_of_interest[0]

exist_versions = [v for v in versions if v in history]
deprecated_in_versions = [v for v in exist_versions if history[v]["deprecated"]]

import itertools

replaced_by_id_version_pairs = [(r["id"],v) for v,concept in history.items() for r in concept["replaced_by"]]
groups = itertools.groupby(replaced_by_id_version_pairs, lambda kv: kv[0])
replaced_by_id_version_map = {id:[p[1] for p in pairs]
                              for id, pairs in groups}

label = history[exist_versions[0]]["preferred_label"]

print(f"Have a look at concept {concept_id} with first label {label}")
print(f"It exists in versions {exist_versions}")
print(f"It is marked as deprecated in {deprecated_in_versions}")
print("It has been replaced by")
for id, versions in replaced_by_id_version_map.items():
    print(f" * Concept {id} in versions {versions}")

Output:

Have a look at concept AWt8_idw_DYJ with first label Odlare av trädgårds- och jordbruksväxter, frukt och bär
It exists in versions [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]
It is marked as deprecated in [13, 14, 15, 16, 17, 18, 19, 20, 21, 22]
It has been replaced by
 * Concept Wv97_wRL_3LS in versions [13, 14, 15, 16, 17, 18, 19, 20, 21, 22]

It would be interesting to take a look at a replacement concept.

(rid, rversions) = next(iter(replaced_by_id_version_map.items()))
rconcept = concept_histories[rid][rversions[0]]
pp.pprint(rconcept)

Output:

{'deprecated': False,
 'id': 'Wv97_wRL_3LS',
 'preferred_label': 'Odlare av '
                    'trädgårds- och '
                    'jordbruksväxter '
                    'samt djuruppfödare '
                    'blandad drift',
 'replaced_by': [],
 'replaces': [{'id': 'AWt8_idw_DYJ'}]}

Let's also see if it does indeed replace the previous concept:


replaces_id_set = {c["id"] for c in rconcept["replaces"]}
print(f"Is it true that {rid} replaces {concept_id}? {concept_id in replaces_id_set}")

Output:

Is it true that Wv97_wRL_3LS replaces AWt8_idw_DYJ? True

Hopefully, you will understand how versions and deprecation works now.

Using the main API

In addition to the GraphQL API previously shown, there are also several endpoints under the HTTP path /v1/taxonomy/main. This tutorial will show you how you can access them from Python.

Let's start with some imports and definitions:

import json
import requests
import pprint
pp = pprint.PrettyPrinter(width=41, compact=True)
host = "https://taxonomy.api.jobtechdev.se"

We will start by quering the versions:

version_data = requests.get(host + "/v1/taxonomy/main/versions").json()
version_data.sort(key=lambda x: x["taxonomy/timestamp"])

def disp_version(v):
    version = v["taxonomy/version"]
    timestamp = v["taxonomy/timestamp"]
    print(f"Version {version} published at {timestamp}")

print("First version:")
disp_version(version_data[0])

print("Last version:")
disp_version(version_data[-1])

version_ids = [v["taxonomy/version"] for v in version_data]

print("Version ids:")
pp.pprint(version_ids)

Output:

First version:
Version 1 published at 2021-03-05T13:38:02.440Z
Last version:
Version 22 published at 2024-02-21T16:16:00.195Z
Version ids:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]

There is also a /v1/taxonomy/main/concepts endpoint. Let's look at one of the concepts from that endpoint. We put the limit parameter to one.

Many endpoints accept a version parameter to specify a version and if it is omitted, the endpoint will default to delivering data from the latest version. In the following example, we omit the version parameter:

concepts = requests.get(host + "/v1/taxonomy/main/concepts",
                        params={"limit": 1}).json()
pp.pprint(concepts)

Output:

[{'taxonomy/alternative-labels': ['Fysisk '
                                  'planerare',
                                  'Planeringsarkitekt'],
  'taxonomy/definition': 'Planeringsarkitekt/Fysisk '
                         'planerare',
  'taxonomy/id': 'ghs4_JXU_BYt',
  'taxonomy/preferred-label': 'Planeringsarkitekt/Fysisk '
                              'planerare',
  'taxonomy/type': 'occupation-name'}]

We can also pick out exactly one concept at a specific version:

concept_id = concepts[0]["taxonomy/id"]
latest_version_id = version_ids[-1]

concept = requests.get(host + "/v1/taxonomy/main/concepts",
                       params={"id": concept_id, "version": latest_version_id}).json()

pp.pprint(concept)

Output:

[{'taxonomy/alternative-labels': ['Fysisk '
                                  'planerare',
                                  'Planeringsarkitekt'],
  'taxonomy/definition': 'Planeringsarkitekt/Fysisk '
                         'planerare',
  'taxonomy/id': 'ghs4_JXU_BYt',
  'taxonomy/preferred-label': 'Planeringsarkitekt/Fysisk '
                              'planerare',
  'taxonomy/type': 'occupation-name'}]

We can list all the types. By default

types_data = requests.get(host + "/v1/taxonomy/main/concept/types",
                          params={"version": latest_version_id}).json()

print("The first 5 types:")
pp.pprint(types_data[0:5])

Output:

The first 5 types:
['barometer-occupation', 'continent',
 'country', 'driving-licence',
 'employment-duration']

That's it. We have now seen some of the most useful endpoints of the main taxonomy API.

REST API

REST API Examples

The Swagger page of the REST API can be found here:

https://taxonomy.api.jobtechdev.se/v1/taxonomy/swagger-ui/index.html

It is a good starting point for exploring the capabilities of the REST API.

Requesting all Swedish regions

In this example, we want to use the legacy API to obtain all regions in Sweden. We will be using two endpoints to accomplish that:

In the first step, we will figure out the concept id of Sweden using the first endpoint. In the second step, we will use the second endpoint to query regions in Sweden.

Start by visiting the Swagger page of the API at

https://taxonomy.api.jobtechdev.se/v1/taxonomy/swagger-ui/index.html

Step 1: Obtaining the concept id of Sweden

The specific endpoint that we are going to use to obtain the concept id of Sweden has the following Swagger URL:

https://taxonomy.api.jobtechdev.se/v1/taxonomy/swagger-ui/index.html#/Specific%20Types/get_v1_taxonomy_specific_concepts_country

Click on the Try it out button. Then click execute. You will see a long list of all countries in the latest version of the taxonomy. The URL of the request is

https://taxonomy.api.jobtechdev.se/v1/taxonomy/specific/concepts/country

In order to only obtain Sweden in the result list, set the preferred-label parameter to be Sverige. The corresponding URL is

https://taxonomy.api.jobtechdev.se/v1/taxonomy/specific/concepts/country?preferred-label=Sverige

and we obtain the result

[
  {
    "taxonomy/type": "country",
    "taxonomy/definition": "Sverige",
    "taxonomy/id": "i46j_HmG_v64",
    "taxonomy/iso-3166-1-alpha-3-2013": "SWE",
    "taxonomy/iso-3166-1-alpha-2-2013": "SE",
    "taxonomy/preferred-label": "Sverige"
  }
]

with Sweden having the concept id i46j_HmG_v64.

Step 2: Obtaining all regions in Sweden

Visit the Swagger page for regions and click on the button Try it out:

https://taxonomy.api.jobtechdev.se/v1/taxonomy/swagger-ui/index.html#/Specific%20Types/get_v1_taxonomy_specific_concepts_region

Then click on the button Execute which will return all regions in the world. For instance, we will obtain the following region in the result set:

{
  "taxonomy/type": "region",
  "taxonomy/definition": "Erzincan",
  "taxonomy/id": "CsrW_6th_DKs",
  "taxonomy/preferred-label": "Erzincan"
}

The corresponding URL can be found under Request URL in the Swagger UI: https://taxonomy.api.jobtechdev.se/v1/taxonomy/specific/concepts/region

We want to restrict the set of regions to the set of concepts being narrower to the concept with id i46j_HmG_v64 that represents Sweden. In order to do that, set the relation parameter to be narrower and the related-ids parameter to be i46j_HmG_v64. Then execute the request. The corresponding URL is

https://taxonomy.api.jobtechdev.se/v1/taxonomy/specific/concepts/region?related-ids=i46j_HmG_v64&relation=narrower

and the results will now only contain Swedish regions, such as

{
  "taxonomy/type": "region",
  "taxonomy/definition": "Kalmar län",
  "taxonomy/id": "9QUH_2bb_6Np",
  "taxonomy/national-nuts-level-3-code-2019": "08",
  "taxonomy/nuts-level-3-code-2013": "SE213",
  "taxonomy/preferred-label": "Kalmar län"
}

Requesting all occupations fields

To request all concepts of type occupation-field from the REST API, start by taking a look at the Swagger page:

https://taxonomy.api.jobtechdev.se/v1/taxonomy/swagger-ui/index.html

The /v1/taxonomy/main/concepts endpoints can be used to obtain concepts of a specific type. Click on the Try it out button and fill in the type parameter to be occupation-field. Then click Execute. You will obtain a list of occupation fields from the latest version, such as

{
  "taxonomy/type": "occupation-field",
  "taxonomy/definition": "Exempel på arbetsuppgifter: \r\n\r\nKlipper och behandlar hår.\r\n\r\nUtför ansikts-, spa- och kroppsbehandlingar eller fotvård. \r\n\r\nMasserar kroppens mjukdelsvävnader.",
  "taxonomy/id": "Uuf1_GMh_Uvw",
  "taxonomy/preferred-label": "Kropps- och skönhetsvård"
}

The corresponding URL is https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/concepts?type=occupation-field .

In order to obtain the occupation fields for a specific version, set the version parameter to the version you want, e.g. 22. The corresponding URL is https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/concepts?type=occupation-field&version=22.

Requesting specific sun-education-level concepts

Assume we want to request specific concepts of type sun-education-level that have the attribute sun-education-level-code-2000 being either 1, 2, 3, 4, 5 or 6 for version 1 of the Taxonomy. Start by visiting the Swagger page:

https://taxonomy.api.jobtechdev.se/v1/taxonomy/swagger-ui/index.html

Go to the endpoint /v1/taxonomy/specific/concepts/sun-education-level and click on Try it out. Fill in the the following fields:

  • version should have value 1.
  • sun-education-level-code-2000 should have either 1, 2, 3, 4, 5 or 6.

The API does not support comma-separated values for the sun-education-level-code-2000 field. You will have to make a separate query for each of the possible values. For the value sun-education-level-code-2000 being 1, we have the URL

https://taxonomy.api.jobtechdev.se/v1/taxonomy/specific/concepts/sun-education-level?version=1&sun-education-level-code-2000=1

and the results

[
  {
    "taxonomy/type": "sun-education-level-1",
    "taxonomy/definition": "Förgymnasial utbildning kortare än 9 år",
    "taxonomy/id": "hxDt_SD3_1qX",
    "taxonomy/sun-education-level-code-2000": "1",
    "taxonomy/preferred-label": "Förgymnasial utbildning kortare än 9 år"
  }
]

All URL for sun-education-level-code-2000 being either 1, 2, 3, 4, 5 or 6 are:

GraphQL

Using curl it is quite easy to query the GraphQL endpoints of the taxonomy and save the response in a JSON document. Save the query in a file (in the example below example.graphql is chosen) and call the desired endpoint.

# Get 5 occupation names.
query occupation_names {
  concepts(type: "occupation-name", limit: 5) {
    preferred_label
  }
}
curl --data-urlencode query@example.graphql --get https://taxonomy.api.jobtechdev.se/v1/taxonomy/graphql

The command above should produce output similar to the following JSON.

{
  "data": {
    "concepts": [
      { "preferred_label": "Planeringsarkitekt/Fysisk planerare" },
      { "preferred_label": "Inredningsdesigner" },
      { "preferred_label": "Utvecklingsingenjör, elkraft" },
      { "preferred_label": "Beräkningsingenjör, el-tele" },
      { "preferred_label": "Mjukvaruutvecklare" }
    ]
  }
}

Examples

Fetch tree of occupation-field -> ssyk-level-4 -> occupation-name in version 1.

query occupations {
  concepts(type: "occupation-field", version: "1") {
    id
    preferred_label
    type
    narrower(type: "ssyk-level-4") {
      id
      preferred_label
      type
      narrower(type: "occupation-name") {
        id
        preferred_label
        type
      }
    }
  }
}

Playground

GraphiQL

Libraries

To reduce application complexity, improve stability and availability it can be useful to access the Taxonomy using one of the provided libraries. These libraries are build by performing standard queries against the default production endpoint and packaging the result into libraries that are deployed into the appropriate package managers.

Here is an overview of the queries used for the platforms concerned.

.NET

The .NET Taxonomy contains a subset of the taxonomy presented in library form consumable from .NET.

Country

Country

query region_country_continent {
  concepts(type: "country", include_deprecated: true) {
    id
    deprecated
    preferred_label
    iso_3166_1_alpha_3_2013
    iso_3166_1_alpha_2_2013
  }
}

Language

Language

query language {
  concepts(type: "language", include_deprecated: true) {
    id
    type
    deprecated
    preferred_label
    iso_639_1_2002
    iso_639_2_1998
    iso_639_3_2007
  }
}

Region

Region

query region_country_continent {
  concepts(type: "region", include_deprecated: true) {
    id
    deprecated
    preferred_label
    nuts_level_3_code_2021
    national_nuts_level_3_code_2019
    broader(type: "country", include_deprecated: true) {
      id
    }
  }
}

Occupation name to ESCO ID

Occupation name to ESCO ID

# This needs to confirm to the ESCO ID Selection algorithm to be valid.
query occupation_name_to_esco {
  concepts(type: "occupation-name", include_deprecated: true) {
    id
    preferred_label
    type
    no_esco_relation
    exact_match {
      id
      esco_uri
      preferred_label
      type
    }
    broad_match {
      id
      esco_uri
      preferred_label
      type
    }
    broader {
      id
      esco_uri
      preferred_label
      type
    }
    narrow_match {
      id
      esco_uri
      preferred_label
      type
    }
    close_match {
      id
      esco_uri
      preferred_label
      type
    }
  }
}

Skill to ESCO ID

Skill to ESCO ID

query skill_to_esco {
  concepts(type: "skill", include_deprecated: true) {
    id
    preferred_label
    type
    no_esco_relation
    exact_match {
      id
      esco_uri
      preferred_label
      type
    }
    broad_match {
      id
      esco_uri
      preferred_label
      type
    }
    broader {
      id
      esco_uri
      preferred_label
      type
    }
    narrow_match {
      id
      esco_uri
      preferred_label
      type
    }
    close_match {
      id
      esco_uri
      preferred_label
      type
    }
  }
}

A Taxonomy of One's Own

Should you wish to experiment with the content of the taxonomy or set up a private local copy go to https://gitlab.com/arbetsformedlingen/taxonomy-dev/backend/jobtech-taxonomy-api and take a look at the development documentation under /docs/development.