NAV
cURL Ruby Python JavaScript

Introduction

Trendence exposes parts of its architecture for integrational use, intended to fuel your custom applications and systems with data and proper exports. This system is what we call our Talent Intelligence API. These documentation pages are intended to help you getting started.

Base URL: https://api.trendence.com/v1/

API Version: 1.1.0

Authentication

To authorize, use this code:

# With Bearer Token (recommended)
curl "https://api.trendence.com/v1/talents" \
  -H "Authorization: Bearer YOUR_API_KEY"
require 'net/http'
require 'uri'

uri = URI.parse("https://api.trendence.com/v1/talents")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_KEY"
request["Content-Type"] = "application/json"
import requests

headers = {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
}

response = requests.post(
    'https://api.trendence.com/v1/talents',
    headers=headers
)
const fetch = require('node-fetch');

fetch('https://api.trendence.com/v1/talents', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});

Make sure to replace YOUR_API_KEY with your actual API key.

The Trendence API uses API keys for authentication. Every request must include a valid API key.

Authentication Methods

You can provide your API key in two ways:

Send the API key in the Authorization header as a Bearer token:

Authorization: Bearer YOUR_API_KEY

X-API-Key Header

Alternatively, you can use the X-API-Key header:

X-API-Key: YOUR_API_KEY

Content-Type Required

Otherwise, you will receive a 415 Unsupported Media Type error.

Security Recommendations

  1. Keep your API key secret: Never share your API key publicly or in version control systems.
  2. Use environment variables: Store API keys in environment variables instead of source code.
  3. Use HTTPS: All API requests are required to be made over HTTPS.
  4. Rotate keys regularly: Request a new API key when needed.

Understanding the Endpoints

The API offers two endpoints — Talents and Professions — that serve different use cases and are optimized for different types of input.

Talents Professions
Designed for CV / resume-style text Job posting / role description text
Input field talent_text.description profession_text.title + profession_text.description (or profession_taxonomy)
Perspective Candidate-centric (what someone has done) Role-centric (what a position requires)

Both endpoints return the same categories of data (salary, scarcity, vacancies, skills, etc.), but the underlying analysis pipelines are tailored to the semantics of their respective input types. This means that sending the same text to both endpoints may produce slightly different results — this is expected and by design.

Recruitment Complexity Index

Both endpoints return a Recruitment Complexity Index as part of their labour market analytics. This section explains what the index measures, what the individual dimensions mean, and how to interpret them.

What the Index Measures

Example scarcity response:

{
  "scarcity": {
    "scarcity_index": 7.8,
    "job_ads_people_available_ratio": "high",
    "campaigns_repeated": "moderate",
    "avg_postings_per_campaign": "low",
    "vacancy_duration": "high",
    "foreign_employee_share_change": "very high",
    "median_earnings_change": "very high",
    "job_change_reluctance": "very low"
  }
}

The Recruitment Complexity Index answers a single question: How difficult is it to recruit for a given profession in a given location right now?

It produces a composite score from 0 to 10, where:

Score Category Meaning
0–2 very low Easy to recruit — large candidate pool, low competition
2–4 low Below-average hiring difficulty
4–6 moderate Average hiring difficulty
6–8 high Challenging to recruit — consider competitive offers
8–10 very high Very difficult — expect longer hiring timelines and above-average compensation

The index is not a single metric. It is computed from seven dimensions, each capturing a different signal of labour market tension. The dimensions are weighted differently — some are considerably more influential than others in the final score. This gives you a detailed breakdown of why a profession is easy or hard to recruit.

The Seven Dimensions

The scarcity index is built from three categories of data: job market behaviour (derived from job postings data), official government statistics, and workforce survey data.

Job Market Behaviour

These dimensions are derived from real-world job posting patterns and carry the most weight in the index. They reflect what employers actually do in the market.

job_ads_people_available_ratio — Supply-demand balance

Are there more open positions than available candidates? This is the single most influential dimension. A high value means there are significantly more vacancies than jobseekers for this profession — a clear signal of scarcity.

campaigns_repeated — Reposting frequency

Do employers keep re-posting the same vacancy? When the same position is re-advertised shortly after a previous attempt expired, it indicates that the employer struggled to fill it. A high value is a strong signal of recruitment difficulty.

avg_postings_per_campaign — Recruitment effort

How many individual ads does it take to fill one position? When employers need to publish the same vacancy on many platforms simultaneously, it signals that finding the right candidate requires significant effort.

Official Government Statistics

These dimensions come from the German Federal Employment Agency (Bundesagentur für Arbeit) and provide structural context. They are based on official Engpass data matched by occupation code.

vacancy_duration — Time to fill

How long do vacancies for this profession stay open on average? Longer vacancy durations confirm that positions are harder to fill.

foreign_employee_share_change — International recruitment trend

Is the share of foreign employees in this profession increasing? A rising share often indicates that the domestic talent pool is insufficient, driving employers to recruit internationally.

median_earnings_change — Salary pressure

Are salaries for this profession rising above average? When demand for a profession exceeds supply, market pressure pushes wages up. Rising earnings are a classic economic indicator of scarcity.

Workforce Survey Data

job_change_reluctance — Worker mobility

Are workers in this profession willing to change jobs? This dimension is based on Trendence's proprietary survey data. When workers are reluctant to change positions, the effective talent pool for recruiters shrinks — even if the total number of professionals is large.

How to Interpret the Results

A practical example — Software Developer in Germany:

{
  "scarcity_index": 7.8,
  "job_ads_people_available_ratio": "high",
  "campaigns_repeated": "moderate",
  "vacancy_duration": "high",
  "median_earnings_change": "very high",
  "foreign_employee_share_change": "very high",
  "avg_postings_per_campaign": "low",
  "job_change_reluctance": "very low"
}

Reading this: The overall score of 7.8 ("high") is primarily driven by a high vacancy-to-candidate ratio and long vacancy durations. Salaries are rising fast and international recruitment is increasing — both confirming market pressure. However, workers are very willing to change jobs ("very low" reluctance), which partially offsets the scarcity.

The composite scarcity_index gives you the headline, but the individual dimensions tell the story. Here's how to use them:

For workforce planning: Focus on job_ads_people_available_ratio and vacancy_duration. Together they show whether the talent pool is sufficient and how long filling a position will take.

For compensation strategy: Look at median_earnings_change alongside the overall index. Rising earnings in a scarce market mean you may need to offer above-average compensation to attract talent.

For recruitment strategy: campaigns_repeated and avg_postings_per_campaign reveal how much effort other employers invest. High values suggest you should differentiate your job posting strategy or consider alternative sourcing channels.

For long-term trends: foreign_employee_share_change indicates structural shifts. A consistently increasing share signals that domestic supply alone may not meet demand in the medium term.

Talents Endpoint

Create Talent Analysis

curl --request POST \
  --url "https://api.trendence.com/v1/talents" \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "talent_text": {
      "description": "This Curriculum Vitae outlines the professional background of a Project Owner with extensive experience in project management, digital transformation, and business consulting..."
    },
    "location": {
      "country": "DE"
    }
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI.parse("https://api.trendence.com/v1/talents")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_KEY"
request["Content-Type"] = "application/json"
request.body = JSON.dump({
  "talent_text" => {
    "description" => "This Curriculum Vitae outlines the professional background of a Project Owner with extensive experience in project management, digital transformation, and business consulting..."
  },
  "location" => {
    "country" => "DE"
  }
})

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end
import requests
import json

url = "https://api.trendence.com/v1/talents"
headers = {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
}
data = {
    'talent_text': {
        'description': 'This Curriculum Vitae outlines the professional background of a Project Owner with extensive experience in project management, digital transformation, and business consulting...'
    },
    'location': {
        'country': 'DE'
    }
}

response = requests.post(url, headers=headers, json=data)
const fetch = require('node-fetch');

const url = 'https://api.trendence.com/v1/talents';
const data = {
  talent_text: {
    description: 'This Curriculum Vitae outlines the professional background of a Project Owner with extensive experience in project management, digital transformation, and business consulting...'
  },
  location: {
    country: 'DE'
  }
};

fetch(url, {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

The above command returns JSON structured like this:

{
  "meta": {
    "tie": {
      "version": "1.1.0"
    }
  },
  "status": "pending",
  "hints": "The data is being prepared, please check talent_url for an update.",
  "talent_uuid": "fe20b273-3505-4d49-99be-8cfc260ed393",
  "talent_url": "https://api.trendence.com/v1/talents/fe20b273-3505-4d49-99be-8cfc260ed393"
}

This endpoint takes a CV or candidate description and returns labour market data for the matching roles — salary benchmarks, recruitment complexity, current vacancies, and a talent profile.

HTTP Request

POST https://api.trendence.com/v1/talents

Request Body Parameters

Parameter Type Required Default Description
talent_text.description String Yes Description of the talent in natural language (minimum 50 characters)
language String No "de" Language for profile content in the response (e.g., "de", "en"). Controls the language of fields such as hard_skills, soft_skills, responsibilities, and tools.
location.country String Yes ISO 3166-1 alpha-2 country code. Currently DE is supported.
location.region String No Region name (see Valid Region Values). Mutually exclusive with location.city — provide only one of the two.
location.city String No City name (see Valid City Values). Mutually exclusive with location.region.
location.coordinates.lat Number No Deprecated. Accepted for backward compatibility; the API rewrites it to vacancies.coordinates.lat. New integrations should use vacancies.coordinates directly.
location.coordinates.lng Number No Deprecated. Accepted for backward compatibility; the API rewrites it to vacancies.coordinates.lng. New integrations should use vacancies.coordinates directly.
vacancies Object No Vacancy-scoped filtering. See Vacancies Filter Object.

Vacancies Filter

Introduced in 1.1.0. The optional top-level vacancies object lets you scope and sort vacancy-related data. See Vacancies Filter Object for the full parameter table.

Example request with the vacancies filter (cap to 25 results, sort by similarity, 50 km around Berlin):

curl --request POST \
  --url "https://api.trendence.com/v1/talents" \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "talent_text": {
      "description": "This Curriculum Vitae outlines the professional background of a Project Owner with extensive experience in project management, digital transformation, and business consulting..."
    },
    "location": {
      "country": "DE"
    },
    "vacancies": {
      "limit": 25,
      "threshold": 0.95,
      "order_by_similarity": true,
      "coordinates": {
        "lat": 52.52,
        "lng": 13.405,
        "radius_km": 50
      }
    }
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI.parse("https://api.trendence.com/v1/talents")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_KEY"
request["Content-Type"] = "application/json"
request.body = JSON.dump({
  "talent_text" => {
    "description" => "This Curriculum Vitae outlines the professional background of a Project Owner with extensive experience in project management, digital transformation, and business consulting..."
  },
  "location" => {
    "country" => "DE"
  },
  "vacancies" => {
    "limit" => 25,
    "threshold" => 0.95,
    "order_by_similarity" => true,
    "coordinates" => {
      "lat" => 52.52,
      "lng" => 13.405,
      "radius_km" => 50
    }
  }
})

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end
import requests

url = "https://api.trendence.com/v1/talents"
headers = {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
}
data = {
    'talent_text': {
        'description': 'This Curriculum Vitae outlines the professional background of a Project Owner with extensive experience in project management, digital transformation, and business consulting...'
    },
    'location': {
        'country': 'DE'
    },
    'vacancies': {
        'limit': 25,
        'threshold': 0.95,
        'order_by_similarity': True,
        'coordinates': {
            'lat': 52.52,
            'lng': 13.405,
            'radius_km': 50
        }
    }
}

response = requests.post(url, headers=headers, json=data)
const fetch = require('node-fetch');

const url = 'https://api.trendence.com/v1/talents';
const data = {
  talent_text: {
    description: 'This Curriculum Vitae outlines the professional background of a Project Owner with extensive experience in project management, digital transformation, and business consulting...'
  },
  location: {
    country: 'DE'
  },
  vacancies: {
    limit: 25,
    threshold: 0.95,
    order_by_similarity: true,
    coordinates: {
      lat: 52.52,
      lng: 13.405,
      radius_km: 50
    }
  }
};

fetch(url, {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

For details on how location and vacancies.coordinates interact, see Filtering Scope and Backward Compatibility in the Reference section.

Query Parameters

Parameter Type Default Description
force_sync Boolean false When true, processes synchronously (max. 29 seconds)

Response

The API processes requests asynchronously by default. Upon successful acceptance, you will receive a 202 Accepted response.

Get Talent Analysis

curl --request GET \
  --url "https://api.trendence.com/v1/talents/fe20b273-3505-4d49-99be-8cfc260ed393" \
  --header "Authorization: Bearer YOUR_API_KEY"
require 'net/http'
require 'uri'

uuid = "fe20b273-3505-4d49-99be-8cfc260ed393"
uri = URI.parse("https://api.trendence.com/v1/talents/#{uuid}")
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_KEY"

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end
import requests

uuid = "fe20b273-3505-4d49-99be-8cfc260ed393"
url = f"https://api.trendence.com/v1/talents/{uuid}"
headers = {'Authorization': 'Bearer YOUR_API_KEY'}

response = requests.get(url, headers=headers)
const uuid = 'fe20b273-3505-4d49-99be-8cfc260ed393';
const url = `https://api.trendence.com/v1/talents/${uuid}`;

fetch(url, {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY'
  }
})
.then(response => response.json())
.then(data => console.log(data));

When processing is complete (200 OK):

{
  "meta": {
    "tie": {
      "version": "1.1.0"
    }
  },
  "metadata": {
    "talent_id": "54b8f264-6912-5329-a681-fb4d20974ec9"
  },
  "request": {
    "location": {
      "country": "DE"
    },
    "account_id": 123,
    "talent_text": {
      "description": "This Curriculum Vitae outlines the professional background of a Project Owner with extensive experience in project management, digital transformation, and business consulting..."
    }
  },
  "results": [
    {
      "skillset_id": "12345",
      "skillset_label": "Business Consultant / Digital Transformation Consultant",
      "vacancies": {
        "current": [
          {
            "location": "Köln",
            "similarity": 0.9043,
            "vacancy_url": "https://example.com/jobs/consultant-business-digital-strategy",
            "vacancy_title": "Consultant Business & Digital Strategy (d/w/m)",
            "organization_name": "StrategyWorks GmbH",
            "vacancy_publish_date": "2026-05-04"
          },
          {
            "location": "Paderborn",
            "similarity": 0.9070,
            "vacancy_url": "https://example.com/jobs/senior-consultant-digitalisierung",
            "vacancy_title": "Senior Consultant Digitalisierung für die Prozessindustrie (all genders)",
            "organization_name": "DigiConsult SE",
            "vacancy_publish_date": "2026-04-29"
          }
        ],
        "sources_last_12_months": [
          {"count": 163, "share": 0.222, "source": "jobportal24.example"},
          {"count": 149, "share": 0.203, "source": "careersite.example"},
          {"count": 49, "share": 0.067, "source": "hiringboard.example"}
        ],
        "employers_last_12_months": [
          {"count": 133, "share": 0.278, "employer": "DigiConsult SE"},
          {"count": 14, "share": 0.029, "employer": "GlobalAdvisory AG"},
          {"count": 13, "share": 0.027, "employer": "PublicTech GmbH"}
        ]
      },
      "labour_market": {
        "salary": {
          "q10": 69800, "q20": 73100, "q30": 75200, "q40": 76700,
          "q50": 77800, "q60": 79000, "q70": 80200, "q80": 81800, "q90": 84600
        },
        "scarcity": {
          "scarcity_index": 3.7,
          "vacancy_duration": "high",
          "campaigns_repeated": "low",
          "job_change_reluctance": "low",
          "median_earnings_change": "low",
          "avg_postings_per_campaign": "low",
          "foreign_employee_share_change": "moderate",
          "job_ads_people_available_ratio": "moderate"
        },
        "vacancies_count": [
          {"date": "2025-05-01", "vacancies": 60},
          {"date": "2025-06-01", "vacancies": 121},
          {"date": "2025-07-01", "vacancies": 164}
        ],
        "kldb_vacancies_jobseekers_ratio": [
          {"date": "2025-11-01", "vacancies": 9481, "jobseekers": 7820,
           "vacancies_jobseekers_ratio": 1.212, "vacancies_jobseekers_ratio_log": 0.794}
        ]
      },
      "matched_profession_profile": {
        "tools": ["Jira", "Confluence", "Miro", "Scrum"],
        "hard_skills": ["Agile Methoden", "Stakeholder Management", "Business Analyse", "Requirements Engineering"],
        "soft_skills": ["Kommunikation", "Teamarbeit"],
        "responsibilities": ["Strategieberatung", "Prozessoptimierung", "Change Management"],
        "similar_titles": ["Management Consultant", "Strategy Consultant", "Digital Transformation Consultant"]
      }
    },
    {
      "skillset_id": "6789",
      "skillset_label": "Senior Product Owner / Product Manager",
      "vacancies": {
        "current": [
          {
            "location": "Haren (Ems)",
            "similarity": 0.9171,
            "vacancy_url": "https://example.com/jobs/sap-inhouse-product-owner",
            "vacancy_title": "SAP Inhouse Product Owner (m/w/d)",
            "organization_name": "LogiPack GmbH",
            "vacancy_publish_date": "2026-05-04"
          }
        ],
        "sources_last_12_months": [
          {"count": 833, "share": 0.240, "source": "careersite.example"},
          {"count": 347, "share": 0.100, "source": "jobportal24.example"},
          {"count": 230, "share": 0.066, "source": "hiringboard.example"}
        ],
        "employers_last_12_months": [
          {"count": 34, "share": 0.018, "employer": "EnergieCorp AG"},
          {"count": 30, "share": 0.016, "employer": "FinTech Solutions AG"},
          {"count": 23, "share": 0.012, "employer": "GovIT GmbH"}
        ]
      },
      "labour_market": {
        "salary": {
          "q10": 65000, "q20": 70700, "q30": 74100, "q40": 76700,
          "q50": 78900, "q60": 81300, "q70": 84000, "q80": 87700, "q90": 93900
        },
        "scarcity": {
          "scarcity_index": 2.6,
          "vacancy_duration": "low",
          "campaigns_repeated": "very low",
          "job_change_reluctance": "very low",
          "median_earnings_change": "low",
          "avg_postings_per_campaign": "high",
          "foreign_employee_share_change": "high",
          "job_ads_people_available_ratio": "moderate"
        },
        "vacancies_count": [
          {"date": "2025-05-01", "vacancies": 354},
          {"date": "2025-06-01", "vacancies": 536},
          {"date": "2025-07-01", "vacancies": 596}
        ],
        "kldb_vacancies_jobseekers_ratio": [
          {"date": "2025-11-01", "vacancies": 20236, "jobseekers": 24226,
           "vacancies_jobseekers_ratio": 0.835, "vacancies_jobseekers_ratio_log": 0.607}
        ]
      },
      "matched_profession_profile": {
        "tools": ["Jira", "Confluence", "Miro", "Azure DevOps", "Figma"],
        "hard_skills": ["Product Backlog Management", "User Stories", "Scrum", "Roadmapping"],
        "soft_skills": ["Kommunikation", "Kritisches Denken"],
        "responsibilities": ["Produktvision definieren", "Sprint Planning", "Stakeholder-Koordination"],
        "similar_titles": ["Product Owner", "Product Manager", "Agile Product Owner"]
      }
    }
  ]
}

This endpoint retrieves the status or result of a talent analysis.

The results array contains matching vacancy data including job postings, similarity scores, labour market analytics (salary, scarcity index), and statistics about vacancy sources and employers.

HTTP Request

GET https://api.trendence.com/v1/talents/:uuid

URL Parameters

Parameter Description
uuid The UUID of the talent analysis to retrieve

Response Status Codes

Status Meaning
202 Accepted Analysis is still processing
200 OK Analysis is complete, result available
502 Bad Gateway Processing error occurred

Understanding Talent Responses

When you submit a CV or candidate description, the API identifies 1 to 3 distinct roles, personas, or career paths (represented as skillset) that match the person's professional background. The richer and more detailed the CV, the more roles the endpoint can distinguish.

For each identified role, the API returns three key types of information:

  1. Matching Job Vacancies - Current job opportunities with similarity scores, plus historical data on which job boards and employers posted matching vacancies over the last 12 months.

  2. Labour Market Analytics - Salary quantiles (q10-q90) and recruitment complexity metrics including the Recruitment Complexity Index (scarcity_index), helping candidates understand compensation expectations and their market value.

  3. Talent Profile - Typical skills, tools, responsibilities, and matching job titles for the matched roles.

Response Structure

Field Type Description
results Array Analysis results — contains 1 to 3 skillset entries depending on the complexity of the input. A detailed CV may yield multiple skillsets reflecting different career facets.
results[].vacancies Object Vacancy-related data
results[].labour_market Object Salary and recruitment complexity metrics
results[].matched_profession_profile Object Typical skills and profile data for the matched roles
results[].skillset_id String Internal skillset classification ID
results[].skillset_label String Human-readable skillset label

For detailed field descriptions of vacancy data, labour market metrics, and profession profiles, see the Response Field Reference section.

Polling Strategy

For asynchronous requests, we recommend using exponential backoff when polling for results.

Professions Endpoint

Create Profession Analysis

curl --request POST \
  --url "https://api.trendence.com/v1/professions" \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "profession_text": {
      "title": "Full Stack Developer (m/f/d)",
      "description": "We are looking for an experienced Full Stack Developer (m/f/d) to join our development team in Berlin..."
    },
    "location": {
      "country": "DE"
    }
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI.parse("https://api.trendence.com/v1/professions")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_KEY"
request["Content-Type"] = "application/json"
request.body = JSON.dump({
  "profession_text" => {
    "title" => "Full Stack Developer (m/f/d)",
    "description" => "We are looking for an experienced Full Stack Developer (m/f/d) to join our development team in Berlin..."
  },
  "location" => {
    "country" => "DE"
  }
})

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end
import requests

url = "https://api.trendence.com/v1/professions"
headers = {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
}
data = {
    'profession_text': {
        'title': 'Full Stack Developer (m/f/d)',
        'description': 'We are looking for an experienced Full Stack Developer (m/f/d) to join our development team in Berlin...'
    },
    'location': {
        'country': 'DE'
    }
}

response = requests.post(url, headers=headers, json=data)
const fetch = require('node-fetch');

const url = 'https://api.trendence.com/v1/professions';
const data = {
  profession_text: {
    title: 'Full Stack Developer (m/f/d)',
    description: 'We are looking for an experienced Full Stack Developer (m/f/d) to join our development team in Berlin...'
  },
  location: {
    country: 'DE'
  }
};

fetch(url, {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

The above command returns JSON structured like this:

{
  "status": "pending",
  "hints": "The data is being prepared, please check professions_url for an update.",
  "professions_uuid": "531c8cf8-77bc-4193-865d-de24158878b2",
  "professions_url": "https://api.trendence.com/v1/professions/531c8cf8-77bc-4193-865d-de24158878b2",
  "meta": {
    "tie": {
      "version": "1.1.0"
    }
  }
}

This endpoint takes a role description and returns labour market data for the matching profession — salary benchmarks, recruitment complexity, current vacancies, and a profession profile.

The API supports two input methods:

HTTP Request

POST https://api.trendence.com/v1/professions

Request Body Parameters

Text-Based Request Parameters

Parameter Type Required Default Description
profession_text.title String Yes* Job title
profession_text.description String Yes* Description of the profession in natural language (minimum 50 characters)

*Required when using text-based approach

Taxonomy-Based Request Parameters

Parameter Type Required Default Description
profession_taxonomy.taxonomy String Yes* Taxonomy system identifier: "kldb" or "berufenet"
profession_taxonomy.id String Yes* Occupation code within the taxonomy (e.g., "43413" for Software Developers in KLDB)

*Required when using taxonomy-based approach

Supported Taxonomy Systems:

Common Parameters (Both Approaches)

Parameter Type Required Default Description
language String No "de" Language for profile content in the response (e.g., "de", "en"). Controls the language of fields such as hard_skills, soft_skills, responsibilities, and tools.
location.country String Yes ISO 3166-1 alpha-2 country code. Currently DE is supported.
location.region String No Region name (see Valid Region Values). Mutually exclusive with location.city — provide only one of the two.
location.city String No City name (see Valid City Values). Mutually exclusive with location.region.
location.coordinates.lat Number No Deprecated. Accepted for backward compatibility; the API rewrites it to vacancies.coordinates.lat. New integrations should use vacancies.coordinates directly.
location.coordinates.lng Number No Deprecated. Accepted for backward compatibility; the API rewrites it to vacancies.coordinates.lng. New integrations should use vacancies.coordinates directly.
vacancies Object No Vacancy-scoped filtering. See Vacancies Filter Object.

Vacancies Filter

Introduced in 1.1.0. The optional top-level vacancies object lets you scope and sort vacancy-related data. See Vacancies Filter Object for the full parameter table.

Example request with the vacancies filter (cap to 25 results, sort by similarity, 50 km around Berlin):

curl --request POST \
  --url "https://api.trendence.com/v1/professions" \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "profession_taxonomy": {
      "taxonomy": "kldb",
      "id": "43104"
    },
    "location": {
      "country": "DE"
    },
    "vacancies": {
      "limit": 25,
      "threshold": 0.95,
      "order_by_similarity": true,
      "coordinates": {
        "lat": 52.52,
        "lng": 13.405,
        "radius_km": 50
      }
    }
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI.parse("https://api.trendence.com/v1/professions")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_KEY"
request["Content-Type"] = "application/json"
request.body = JSON.dump({
  "profession_taxonomy" => {
    "taxonomy" => "kldb",
    "id" => "43104"
  },
  "location" => {
    "country" => "DE"
  },
  "vacancies" => {
    "limit" => 25,
    "threshold" => 0.95,
    "order_by_similarity" => true,
    "coordinates" => {
      "lat" => 52.52,
      "lng" => 13.405,
      "radius_km" => 50
    }
  }
})

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end
import requests

url = "https://api.trendence.com/v1/professions"
headers = {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
}
data = {
    'profession_taxonomy': {
        'taxonomy': 'kldb',
        'id': '43104'
    },
    'location': {
        'country': 'DE'
    },
    'vacancies': {
        'limit': 25,
        'threshold': 0.95,
        'order_by_similarity': True,
        'coordinates': {
            'lat': 52.52,
            'lng': 13.405,
            'radius_km': 50
        }
    }
}

response = requests.post(url, headers=headers, json=data)
const fetch = require('node-fetch');

const url = 'https://api.trendence.com/v1/professions';
const data = {
  profession_taxonomy: {
    taxonomy: 'kldb',
    id: '43104'
  },
  location: {
    country: 'DE'
  },
  vacancies: {
    limit: 25,
    threshold: 0.95,
    order_by_similarity: true,
    coordinates: {
      lat: 52.52,
      lng: 13.405,
      radius_km: 50
    }
  }
};

fetch(url, {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

For details on how location and vacancies.coordinates interact, see Filtering Scope and Backward Compatibility in the Reference section.

Query Parameters

Parameter Type Default Description
force_sync Boolean false When true, processes synchronously (max. 29 seconds)

Taxonomy Code based input

Instead of providing a text description, you can use standardized occupation classification codes. This is useful when you already have classified occupation data or want to ensure consistent classification.

# Using KLDB occupation code instead of text description
curl --request POST \
  --url "https://api.trendence.com/v1/professions" \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "profession_taxonomy": {
      "taxonomy": "kldb",
      "id": "43413"
    },
    "location": {
      "country": "DE",
      "region": "Brandenburg / Berlin"
    }
  }'
# Using BERUFENET occupation ID
curl --request POST \
  --url "https://api.trendence.com/v1/professions" \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "profession_taxonomy": {
      "taxonomy": "berufenet",
      "id": "58965"
    },
    "location": {
      "country": "DE"
    }
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI.parse("https://api.trendence.com/v1/professions")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_KEY"
request["Content-Type"] = "application/json"

# Example with KLDB
request.body = JSON.dump({
  "profession_taxonomy" => {
    "taxonomy" => "kldb",
    "id" => "43413"
  },
  "location" => {
    "country" => "DE"
  }
})

# Or with BERUFENET
# request.body = JSON.dump({
#   "profession_taxonomy" => {
#     "taxonomy" => "berufenet",
#     "id" => "58965"
#   },
#   "location" => {
#     "country" => "DE"
#   }
# })

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end
import requests

url = "https://api.trendence.com/v1/professions"
headers = {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
}

# Example with KLDB
data = {
    'profession_taxonomy': {
        'taxonomy': 'kldb',
        'id': '43413'
    },
    'location': {
        'country': 'DE'
    }
}

# Or with BERUFENET
# data = {
#     'profession_taxonomy': {
#         'taxonomy': 'berufenet',
#         'id': '58965'
#     },
#     'location': {
#         'country': 'DE'
#     }
# }

response = requests.post(url, headers=headers, json=data)
const fetch = require('node-fetch');

const url = 'https://api.trendence.com/v1/professions';

// Example with KLDB
const data = {
  profession_taxonomy: {
    taxonomy: 'kldb',
    id: '43413'
  },
  location: {
    country: 'DE'
  }
};

// Or with BERUFENET
// const data = {
//   profession_taxonomy: {
//     taxonomy: 'berufenet',
//     id: '58965'
//   },
//   location: {
//     country: 'DE'
//   }
// };

fetch(url, {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

Returns the same response format as text-based requests.

Common Taxonomy Reference

Example KLDB Codes

KLDB Code Occupation (German) Occupation (English)
43413 Softwareentwickler/in Software Developers
51302 Krankenpfleger/in Nurses
62193 Verkäufer/in Sales Personnel

Example BERUFENET IDs

BERUFENET ID Occupation (German) Occupation (English)
58965 Fachinformatiker/in - Anwendungsentwicklung IT Specialist - Application Development
9162 Krankenschwester/Krankenpfleger Nurse
120735 Vertriebsassistent/in Sales Assistant

Get Profession Analysis

curl --request GET \
  --url "https://api.trendence.com/v1/professions/531c8cf8-77bc-4193-865d-de24158878b2" \
  --header "Authorization: Bearer YOUR_API_KEY"
require 'net/http'
require 'uri'

uuid = "531c8cf8-77bc-4193-865d-de24158878b2"
uri = URI.parse("https://api.trendence.com/v1/professions/#{uuid}")
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_KEY"

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end
import requests

uuid = "531c8cf8-77bc-4193-865d-de24158878b2"
url = f"https://api.trendence.com/v1/professions/{uuid}"
headers = {'Authorization': 'Bearer YOUR_API_KEY'}

response = requests.get(url, headers=headers)
const uuid = '531c8cf8-77bc-4193-865d-de24158878b2';
const url = `https://api.trendence.com/v1/professions/${uuid}`;

fetch(url, {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY'
  }
})
.then(response => response.json())
.then(data => console.log(data));

When processing is complete (200 OK):

{
  "meta": {
    "tie": {
      "version": "1.1.0"
    }
  },
  "metadata": {
    "taxonomy": {
      "kldb": {
        "id": "43153",
        "label": "Medieninformatik - Spezialist"
      },
      "berufenet": {
        "id": "134997",
        "label": "Web Developer"
      },
      "similarity_score": 0.8247
    },
    "extracted_attributes": {
      "tools": ["react", "typescript", "node.js", "postgresql", "mongodb", "github actions", "docker", "git"],
      "industry": "information and communication",
      "sub_industry": "computer programming, consultancy and related activities",
      "education": [
        {"level": "Bachelor's or equivalent", "fields_of_study": ["computer science"]}
      ],
      "experience": [
        {"domains": ["full-stack development"], "seniority": "Mid-level (3–5 years)"}
      ],
      "hard_skills": ["web development", "react", "typescript", "node.js", "restful apis", "microservices"],
      "soft_skills": ["collaboration", "mentoring", "agile methodologies"],
      "responsibilities": ["develop web applications", "maintain web applications", "design restful apis", "perform code reviews"]
    }
  },
  "request": {
    "location": {
      "country": "DE"
    },
    "account_id": 123,
    "profession_text": {
      "title": "Full Stack Developer (m/f/d)",
      "description": "We are looking for an experienced Full Stack Developer (m/f/d) to join our development team in Berlin..."
    }
  },
  "results": [{
    "vacancies": {
      "current": [
        {
          "location": "Berlin",
          "similarity": 0.9365,
          "vacancy_url": "https://example.com/jobs/senior-full-stack-engineer",
          "vacancy_title": "Senior Full Stack Engineer (TypeScript/Python) (m/w/d)",
          "organization_name": "CloudScale GmbH",
          "vacancy_publish_date": "2026-05-03"
        },
        {
          "location": "Düsseldorf",
          "similarity": 0.9361,
          "vacancy_url": "https://example.com/jobs/senior-fullstack-engineer",
          "vacancy_title": "Senior Fullstack Engineer (m/w/d) // Remote möglich",
          "organization_name": "RetailTech AG",
          "vacancy_publish_date": "2026-05-03"
        }
      ],
      "sources_last_12_months": [
        {"count": 1585, "share": 0.240, "source": "jobportal24.example"},
        {"count": 1415, "share": 0.214, "source": "careersite.example"},
        {"count": 484, "share": 0.073, "source": "hiringboard.example"}
      ],
      "employers_last_12_months": [
        {"count": 915, "share": 0.212, "employer": "TechCorp GmbH"},
        {"count": 146, "share": 0.034, "employer": "InnovateLabs AG"},
        {"count": 70, "share": 0.016, "employer": "Digital Solutions GmbH"}
      ]
    },
    "labour_market": {
      "salary": {
        "q10": 59300, "q20": 60500, "q30": 61200, "q40": 61600,
        "q50": 62000, "q60": 62400, "q70": 62900, "q80": 63400, "q90": 64300
      },
      "scarcity": {
        "scarcity_index": 7.3,
        "vacancy_duration": "high",
        "campaigns_repeated": "very high",
        "job_change_reluctance": "very low",
        "median_earnings_change": "very high",
        "avg_postings_per_campaign": "low",
        "foreign_employee_share_change": "high",
        "job_ads_people_available_ratio": "high"
      },
      "vacancies_count": [
        {"date": "2025-05-01", "vacancies": 614},
        {"date": "2025-06-01", "vacancies": 910},
        {"date": "2025-07-01", "vacancies": 1189}
      ],
      "kldb_vacancies_jobseekers_ratio": [
        {"date": "2025-11-01", "vacancies": 10653, "jobseekers": 14391,
         "vacancies_jobseekers_ratio": 0.740, "vacancies_jobseekers_ratio_log": 0.554}
      ]
    },
    "matched_profession_profile": {
      "tools": ["Docker", "GitHub Actions", "PostgreSQL", "React", "Git", "Kubernetes", "Node.js"],
      "hard_skills": ["CI/CD Pipelines", "RESTful APIs", "React", "Node.js", "Full-Stack Entwicklung", "API-Entwicklung"],
      "soft_skills": ["Datenqualität", "Mentoring", "Agile Methoden", "Stakeholder-Management"],
      "responsibilities": ["Webanwendungen entwickeln", "Code-Reviews durchführen", "REST-APIs entwickeln", "Nachwuchsentwickler betreuen"],
      "similar_titles": ["Senior Developer", "Developer Full Stack", "Senior Developer Full Stack", "Developer"]
    }
  }]
}

This endpoint retrieves the status or result of a profession analysis.

The results array contains matching vacancy data including job postings, similarity scores, labour market analytics (salary, scarcity index), and statistics about vacancy sources and employers.

HTTP Request

GET https://api.trendence.com/v1/professions/:uuid

URL Parameters

Parameter Description
uuid The UUID of the profession analysis to retrieve

Understanding Profession Responses

When you submit a profession description, the API analyzes the job requirements and returns three key types of information:

  1. Matching Job Vacancies - Current job opportunities with similarity scores, plus historical data on which job boards and employers posted matching vacancies over the last 12 months.

  2. Labour Market Analytics - Salary quantiles (q10-q90) and recruitment complexity metrics including the Recruitment Complexity Index (scarcity_index), providing insights into compensation benchmarks and hiring difficulty.

  3. Profession Profile - Typical skills, tools, responsibilities, and similar job titles for the matched profession.

Response Structure

Field Type Description
results Array Analysis results (typically one element)
results[].vacancies Object Vacancy-related data
results[].labour_market Object Salary and recruitment complexity metrics
results[].matched_profession_profile Object Typical skills and profile data for the matched profession

For detailed field descriptions of vacancy data, labour market metrics, and profession profiles, see the Response Field Reference section.

Reference

Valid Region Values

Both endpoints accept the following values for location.region:

Valid City Values

Both endpoints accept the following values for location.city:

City Region
Aachen Nordrhein-Westfalen
Augsburg Bayern
Berlin Brandenburg / Berlin
Bielefeld Nordrhein-Westfalen
Bochum Nordrhein-Westfalen
Bonn Nordrhein-Westfalen
Braunschweig Niedersachsen / Bremen
Bremen Niedersachsen / Bremen
Dortmund Nordrhein-Westfalen
Dresden Sachsen
Duisburg Nordrhein-Westfalen
Düsseldorf Nordrhein-Westfalen
Erfurt Thüringen
Essen Nordrhein-Westfalen
Frankfurt am Main Hessen
Freiburg im Breisgau Baden-Württemberg
Hamburg Schleswig-Holstein / Hamburg
Hannover Niedersachsen / Bremen
Karlsruhe Baden-Württemberg
Kiel Schleswig-Holstein / Hamburg
Köln Nordrhein-Westfalen
Leipzig Sachsen
Mainz Rheinland-Pfalz / Saarland
Mannheim Baden-Württemberg
München Bayern
Münster Nordrhein-Westfalen
Nürnberg Bayern
Regensburg Bayern
Stuttgart Baden-Württemberg
Wiesbaden Hessen

Vacancies Filter Object

Introduced in 1.1.0. Both the Talents and Professions endpoints accept the same optional top-level vacancies object to filter and sort vacancy-related data.

Parameter Type Required Default Description
vacancies.limit Integer No 100 Maximum number of vacancies to return (max 500).
vacancies.threshold Number No 0.9 Minimum similarity score (0–1) applied to vacancies, sources and employers.
vacancies.order_by_similarity Boolean No false When true, vacancies are sorted by similarity score descending. When false, vacancies are sorted by most recent publish date first.
vacancies.coordinates.lat Number Yes (when vacancies.coordinates is provided) Latitude of the search point. If vacancies.coordinates is provided, geographic filtering of vacancies uses it and overrides location.region / location.city.
vacancies.coordinates.lng Number Yes (when vacancies.coordinates is provided) Longitude of the search point.
vacancies.coordinates.radius_km Integer No 30 Search radius in kilometers.

Filtering Scope

The two location pathways — location and vacancies.coordinates — control different parts of the response:

The following response fields are affected by the vacancy geographic scope (i.e. controlled by location.region/location.city, or by vacancies.coordinates when provided):

In short: top-level location decides where the model thinks; vacancies.coordinates decides which job ads get listed.

Backward Compatibility

Clients that send location.coordinates (the 1.0.x shape) keep working. The API rewrites the payload to use vacancies.coordinates before forwarding the request. When this happens, the response includes two informational headers:

Header Value
Deprecation true (per RFC 9745)
X-Deprecated-Fields location.coordinates has moved to vacancies.coordinates

If a request provides both location.coordinates and vacancies.coordinates, vacancies.coordinates takes precedence and the legacy field is silently dropped.

Response Field Reference

Both endpoints return the same fields for vacancy data, labour market metrics, and profession profiles. The Talents endpoint may return 1 to 3 skillset entries in the results array (reflecting different career facets), while the Professions endpoint typically returns one.

Vacancy Fields

The vacancies object contains current job postings and historical market intelligence.

vacancies.current[] — Current matching job postings:

Field Description
location Geographic location of the vacancy
similarity Match quality (0–1). Higher values indicate a better match.
vacancy_url Direct link to the job posting
vacancy_title Job position title
organization_name Hiring organization
vacancy_publish_date Publication date (YYYY-MM-DD)

vacancies.sources_last_12_months[] — Job boards and platforms where matching vacancies were posted over the last 12 months:

Field Description
source Name of the job board or platform
count Number of postings on this source
share Proportion of total postings (0–1)

vacancies.employers_last_12_months[] — Top hiring employers for matching vacancies over the last 12 months:

Field Description
employer Employer name
count Number of postings by this employer
share Proportion of total postings (0–1)

Labour Market Data

Field Description
salary.q10salary.q90 Salary quantiles. Annual salary in local currency; q50 is the median.
scarcity.scarcity_index Recruitment Complexity Index (0–10). Higher = harder to find candidates.
scarcity.job_ads_people_available_ratio Supply-demand balance. Values: very low, low, moderate, high, very high. Most influential dimension.
scarcity.campaigns_repeated Reposting frequency. Values: very lowvery high. High = candidate scarcity.
scarcity.avg_postings_per_campaign Recruitment effort. Values: very lowvery high. High = employers invest significant effort.
scarcity.vacancy_duration Time to fill. Values: very lowvery high. High = positions harder to fill.
scarcity.foreign_employee_share_change International recruitment trend. Values: very lowvery high. Rising share signals domestic talent shortage.
scarcity.median_earnings_change Salary pressure. Values: very lowvery high. High = competitive pressure on compensation.
scarcity.job_change_reluctance Worker mobility. Values: very lowvery high. High reluctance shrinks effective talent pool.
vacancies_count[] Historical vacancy volume. Monthly time series.
kldb_vacancies_jobseekers_ratio[] Supply-demand ratio over time. Based on official occupation classification (KLDB). Higher ratio = tighter labour market.

Profession Profile

Field Description
tools Specific tools, platforms, or software most relevant for the matched profession (e.g., "React", ".NET Core")
hard_skills Core technical or domain-specific abilities (e.g., "Typescript", "Angular")
soft_skills Core interpersonal or cognitive skills (e.g., "Kommunikation", "Kritisches Denken")
responsibilities Main responsibilities, phrased as action-oriented verb phrases (e.g., "Prozessoptimierung", "Software entwickeln")
similar_titles Alternative or related job titles for the matched profession

Rate Limiting

The API is limited to 100 requests per minute for POST, PUT, and PATCH requests.

When the rate limit is exceeded, you will receive a 429 Too Many Requests status:

{
  "error": "Rate limit exceeded. Please try again later."
}

Changelog

[1.1.0] - 2026-04-24

Added

Clarified

Improved

Deprecated

When both location.coordinates and vacancies.coordinates are provided, vacancies.coordinates takes precedence and the legacy field is silently dropped.


[1.0.1] - 2026-04-02

Fixed


[1.0.0] - 2026-03-16

Changed


[0.2.2] - 2026-01-20

Added

[0.2.1] - 2026-01-06

Changed

[0.2.0] - 2025-12-16

Added

Changed

[0.1.0] - 2025-12-01

Versioning Policy

Every request includes the API version shipped in the response metadata:

{
  "meta": {
    "tie": {
      "version": "1.1.0"
    }
  }
}

Version Numbering

Deprecation Policy

When endpoints or features are deprecated:

  1. Deprecated features will be announced at least 6 months before removal
  2. Deprecation notices will appear in this changelog and API responses
  3. Migration guides will be provided for breaking changes

Errors

The Trendence API uses conventional HTTP response codes to indicate the success or failure of an API request.

HTTP Status Codes

Error Code Meaning
200 OK -- Analysis completed successfully (synchronous requests).
202 Accepted -- Request accepted and processing asynchronously.
400 Bad Request -- Your request is malformed or invalid.
401 Unauthorized -- Your API key is invalid or missing.
404 Not Found -- The requested resource could not be found.
415 Unsupported Media Type -- Content-Type header must be application/json.
422 Unprocessable Entity -- Validation failed (see error details).
429 Too Many Requests -- Rate limit exceeded. Slow down!
500 Internal Server Error -- We had a problem with our server. Try again later.
502 Bad Gateway -- The backend service is temporarily unavailable.
503 Service Unavailable -- We're temporarily offline for maintenance. Please try again later.

Validation Errors

When validation fails (422 status), the API returns a detailed error response:

{
  "error": "Validation failed",
  "missing_fields": [
    "profession_text or profession_taxonomy is required"
  ],
  "example": {
    "profession_text": {
      "title": "Full Stack Developer",
      "description": "Full Stack Developer with experience in Java, JavaScript, and modern web frameworks."
    },
    "profession_taxonomy": {
      "taxonomy": "kldb",
      "id": "12193"
    },
    "location": {
      "country": "DE"
    }
  },
  "meta": {
    "tie": {
      "version": "1.1.0"
    }
  }
}

Common Validation Errors

Error Message Cause Solution
profession_text or profession_taxonomy is required Neither text nor taxonomy provided Provide either profession_text with title/description OR profession_taxonomy with taxonomy/id
profession_taxonomy.id is required Taxonomy object missing id field Include both taxonomy and id fields in profession_taxonomy
location.country is required Missing country code Provide ISO 3166-1 alpha-2 country code (e.g., "DE", "AT", "CH")
talent_text.description is required Missing talent description Provide description in talent_text object

Insufficient Description (400)

The schema validation only checks that profession_text.description and talent_text.description are at least 50 characters long. If the text passes that check but is still too vague or generic for the underlying model to identify a meaningful profession or talent profile, the API responds with 400 Bad Request and an actionable hint:

{
  "detail": "Could not identify a profession from the provided text. Please provide a more specific job title and description.",
  "meta": {
    "tie": {
      "version": "1.1.0"
    }
  }
}
Endpoint Error Message
POST /api/v1/professions (with profession_text) Could not identify a profession from the provided text. Please provide a more specific job title and description.
POST /api/v1/talents Could not identify a talent profile from the provided description. Please provide more detail.

Solution

Taxonomy Not Found (404)

When using taxonomy-based requests, you may receive a 404 error if the specified occupation code is not found or unavailable:

{
  "error": "Upstream request failed",
  "detail": "Profession not found or embedding unavailable: 'berufenet:11510 not found'",
  "meta": {
    "tie": {
      "version": "1.1.0"
    }
  }
}

Common Causes

Solution

Verify that your taxonomy code is valid: - For KLDB: Check the official KLDB classification - For BERUFENET: Check the BERUFENET database

Rate Limiting

{
  "error": "Rate limit exceeded. Please try again later."
}

When you exceed the rate limit (100 requests per minute for POST/PUT/PATCH), you'll receive a 429 status code. Implement exponential backoff in your client to handle rate limiting gracefully.