Products
HireLayer Job Criteria Extractor
HireLayer job description parsing API: send a job ad as text or a file and get its typed, weighted criteria back as JSON, for free.
The HireLayer Job Criteria Extractor reads a job description and returns its criteria in one POST /api/v4/jobs/extract-criteria call: usually 4 to 10, each with a type, a requirement, a weight and, when the ad sets one, a threshold such as 3 years minimum or B2. Send the job as text or as a PDF, DOCX, TXT or HTML file. It is free, except when a new text is sent under the job_id of a job already scored: its stored scores are evaluated again on the new criteria, 1 credit each. The job is stored under a job_id, and the Resume Scorer, Talent Pool Search and Job Recommendations reuse its criteria.
| Field | Values |
|---|---|
type | skill, experience, education, language, certification, location, soft_skill, other |
requirement | required, preferred, bonus. required: a resume that clearly lacks it loses 25 % of its score, never eliminated outright. preferred and bonus count only through their weight. |
weight | Importance. 3 essential, 2 important, 1 nice to have, 0 off: kept on the job, left out of every score, of the required-criterion penalty, of required_missing and of to_verify. Texts already written (summary, explanation) stay as they are. |
threshold | The minimum level the ad asks for, or null. |
Criteria are written in the job’s language, French or English, unless language says otherwise. Correct one with PATCH /jobs/{job_id}/criteria/{criterion_id}: a weight, requirement or type change re-ranks the stored scores for free. A job text identical to the stored job returns the job as stored: title, location and language sent with it are ignored; change them with PUT /jobs/{job_id}.
- Endpoint
POST /api/v4/jobs/extract-criteria- Input
- JSON
text(50,000 characters) or a job file - Output
- The criteria and the
job_id - Price
- Free; 1 credit per stored score evaluated again when a new text replaces a stored job
/api/v4/jobs/extract-criteriaReads a job description and returns its typed criteria (usually 4 to 10, at most 12), the job stored under a job_id.
- The same text sent again under the same id (or without an id) returns the stored job and its current criteria (
200), without a new extraction; the call'stitle,locationandlanguageare then ignored: change them withPUT /jobs/{job_id}. A different text under an existingjob_idreplaces it and extracts the criteria again, asPUT /jobs/{job_id}withrecompute_criteria: truewould; itstitle,locationandstatusstay as stored unless the call sends them. To extract again from the same text, use thatPUT.
- Authentication
X-API-Keyheader- Billing
- Free; 1 credit per stored score evaluated again when a new text replaces a stored job
- Client timeout
- Client timeout ≥ 150 s
Headers
HireLayer-WorkspacestringYour customer's workspace id. Case-insensitive, created on first use. Absent, calls use
default.
Request body
Content type application/json, or multipart/form-data with files
textstringrequiredThe full job description, as published.
1–50,000 characters
titlestring | null≤ 300 characters
locationstring | nullWhere the job is based. Read by the extraction.
≤ 300 characters
languagestring"fr""en"job_idstringLetters, digits and
. _ : ~ -, up to 200 characters.do_not_store_databooleanEnterprise plan only, else
403 enterprise_plan_required: process without storing anything. See Storage.default
false
Response
200A job was already stored under this id. The same text returns its current criteria; another text replaces it and its criteria are extracted again.
request_idstringThe call's id, also in the
HireLayer-Request-Idheader. Quote it when contacting support.job_idstring | nullnullwithout storage.storedbooleantitlestring | nulllocationstring | nulllanguagestring"fr""en"criteriaobject[]Usually 4 to 10, at most 12, numbered
crit_1,crit_2… in order.1–12 items
›Show 7 child fieldsHide child fields
criterion_idstringStable id in the job, such as
crit_2. Never reused.labelstringtypestring"skill""experience""education""language""certification""location""soft_skill""other"requirementstringrequired: a resume that clearly lacks it loses 25 % of its score, never eliminated outright.preferredandbonuscount only through their weight."required""preferred""bonus"weightintegerImportance. 3 essential, 2 important, 1 nice to have, 0 off: kept on the job, left out of every score, of the required-criterion penalty, of
required_missingand ofto_verify. Texts already written (summary,explanation) stay as they are.0–3
thresholdstring | nullsourcestringextractedby HireLayer, orcustom: sent or edited by you."extracted""custom"
credits_usedintegerCredits this call cost.
≥ 0
201Job created and criteria extracted.
request_idstringThe call's id, also in the
HireLayer-Request-Idheader. Quote it when contacting support.job_idstring | nullnullwithout storage.storedbooleantitlestring | nulllocationstring | nulllanguagestring"fr""en"criteriaobject[]Usually 4 to 10, at most 12, numbered
crit_1,crit_2… in order.1–12 items
›Show 7 child fieldsHide child fields
criterion_idstringStable id in the job, such as
crit_2. Never reused.labelstringtypestring"skill""experience""education""language""certification""location""soft_skill""other"requirementstringrequired: a resume that clearly lacks it loses 25 % of its score, never eliminated outright.preferredandbonuscount only through their weight."required""preferred""bonus"weightintegerImportance. 3 essential, 2 important, 1 nice to have, 0 off: kept on the job, left out of every score, of the required-criterion penalty, of
required_missingand ofto_verify. Texts already written (summary,explanation) stay as they are.0–3
thresholdstring | nullsourcestringextractedby HireLayer, orcustom: sent or edited by you."extracted""custom"
credits_usedintegerCredits this call cost.
≥ 0
Errors
- 400
- 400invalid_requesttitle must be a string.
param:title.text,title,location,languageorjob_idis not a string.Fix, then retry
- 400
- 400invalid_requesttitle must be 300 characters or less.
param:title.titleorlocationover 300 characters.Fix, then retry
- 400invalid_requestjob_id cannot be search: that name is reserved for POST /api/v4/jobs/search.
param:job_id.job_idis not a valid id, or is a name the paths reserve (extract-criteria,search).Fix, then retry
- 400
- 400invalid_requestThe request body is not valid JSON.
The body is not valid JSON, not an object, or not sent as
application/json.Fix, then retry
- 400invalid_requestHireLayer-Workspace must contain letters, digits and . _ : ~ -, up to 200 characters.
param:HireLayer-Workspace.HireLayer-Workspaceis not a valid id.Fix, then retry
- 401
- 401missing_api_keyAuthorization: Bearer is not accepted: send the key in the X-API-Key header.
The key sent as
Authorization: Bearer: it goes inX-API-Key.Fix, then retry
- 401missing_api_keyThe key goes in the X-API-Key header, not in the URL.
The key sent in the URL: it goes in
X-API-Key.Fix, then retry
- 401invalid_api_keyInvalid API key: it is unknown, malformed or revoked.
The key is unknown, malformed or revoked.
Fix, then retry
- 403insufficient_creditsThis call evaluates 12 scores, 1 credit each: 12 credits, and 3 are left. Nothing was processed or billed.
A new text replaces a stored job already scored, and the credits left do not cover its scores evaluated again.
Fix, then retry
- 403enterprise_plan_requireddo_not_store_data is available on the Enterprise plan only. Nothing was processed or billed.
param:do_not_store_data.do_not_store_data: truebelow the Enterprise plan.Do not retry
- 413payload_too_largetext must be 50,000 characters or less.
param:text. The text is over 50,000 characters.Fix, then retry
- 413
- 413payload_too_largeThe text of file must be 50,000 characters or less.
param:file. The text read in the file is over 50,000 characters.Fix, then retry
- 422job_unreadablefile has no text layer: it is probably a scan. Send its text instead.
param:file. The file cannot be read: a scan, a protected or damaged PDF, a PDF of more than 50 pages, an old.doc, or another type.Do not retry
- 500internal_errorInternal error: retry later. If it persists, contact support with the request_id.
An unexpected error.
Retry with backoff
- 502model_unavailableThe analysis did not complete after several attempts. Nothing was stored or billed: retry with backoff.
The analysis did not complete.
Retry with backoff
- 502internal_errorThe service could not be reached: retry later.
The service could not be reached.
Retry with backoff
- 503internal_errorThe credit service is briefly unavailable: retry in a second.
The credit service is briefly unavailable. Header
Retry-After: <seconds>.Retry with backoff
- 504internal_errorThe service did not answer in time. The change may still be applied: read it before sending it again.
No answer in time.
Retry with backoff
Behavior
- Credits
- 0. Except when a different text replaces a stored job that has scores and the extraction brings new criteria: as with
PUT /jobs/{job_id}, its stored scores are evaluated again in the background, 1 credit each, and the call is refused (403) when the credits left do not cover them.credits_usedcounts this call's extraction only. - Without storage
job_idisnull. Keep the criteria and send them back with the job toPOST /resumes/score, so that scores stay comparable from one call to the next.
curl -X POST https://hirelayer.co/api/v4/jobs/extract-criteria \
-H "X-API-Key: $HIRELAYER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Ingénieur IA / Développeur backend Node.js (H/F)",
"text": "Ingénieur IA / Développeur backend Node.js (H/F)\nLumio · Paris 9e · CDI · Hybride (2 jours de télétravail par semaine)\n- 3 ans minimum d'\''expérience en développement backend Node.js / TypeScript\n- Expérience indispensable de l'\''intégration de LLM en production\n- Vous maîtrisez AWS (Lambda, S3, DynamoDB) ; une certification AWS est un plus\n- Anglais courant (B2 minimum) obligatoire"
}'import os
import requests
response = requests.post(
"https://hirelayer.co/api/v4/jobs/extract-criteria",
headers={"X-API-Key": os.environ["HIRELAYER_API_KEY"]},
json={
"title": "Ingénieur IA / Développeur backend Node.js (H/F)",
"text": "Ingénieur IA / Développeur backend Node.js (H/F)\nLumio · Paris 9e · CDI · Hybride (2 jours de télétravail par semaine)\n- 3 ans minimum d'expérience en développement backend Node.js / TypeScript\n- Expérience indispensable de l'intégration de LLM en production\n- Vous maîtrisez AWS (Lambda, S3, DynamoDB) ; une certification AWS est un plus\n- Anglais courant (B2 minimum) obligatoire",
},
timeout=150,
)
response.raise_for_status()
data = response.json()
print(data["criteria"])const response = await fetch('https://hirelayer.co/api/v4/jobs/extract-criteria', {
method: 'POST',
headers: {
'X-API-Key': process.env.HIRELAYER_API_KEY!,
'Content-Type': 'application/json',
},
body: JSON.stringify({
title: 'Ingénieur IA / Développeur backend Node.js (H/F)',
text: 'Ingénieur IA / Développeur backend Node.js (H/F)\nLumio · Paris 9e · CDI · Hybride (2 jours de télétravail par semaine)\n- 3 ans minimum d\'expérience en développement backend Node.js / TypeScript\n- Expérience indispensable de l\'intégration de LLM en production\n- Vous maîtrisez AWS (Lambda, S3, DynamoDB) ; une certification AWS est un plus\n- Anglais courant (B2 minimum) obligatoire',
}),
signal: AbortSignal.timeout(150_000),
})
if (!response.ok) {
throw new Error(`HireLayer ${response.status}: ${await response.text()}`)
}
const data = await response.json()
console.log(data.criteria){
"request_id": "0c4a7b1e-5d2f-4e8a-b3c6-9f1d2e7a4b58",
"job_id": "job_30cfa454c97663f3e1801e5a61b87d74",
"stored": true,
"title": "Ingénieur IA / Développeur backend Node.js (H/F)",
"location": null,
"language": "fr",
"criteria": [
{
"criterion_id": "crit_1",
"label": "Développement backend Node.js / TypeScript",
"type": "skill",
"requirement": "preferred",
"weight": 3,
"threshold": "3 ans minimum",
"source": "extracted"
},
{
"criterion_id": "crit_2",
"label": "Intégration de LLM en production",
"type": "skill",
"requirement": "required",
"weight": 3,
"threshold": null,
"source": "extracted"
},
{
"criterion_id": "crit_3",
"label": "AWS (Lambda, S3, DynamoDB)",
"type": "skill",
"requirement": "preferred",
"weight": 2,
"threshold": null,
"source": "extracted"
},
{
"criterion_id": "crit_4",
"label": "Diplôme d'ingénieur ou Bac+5 en informatique",
"type": "education",
"requirement": "preferred",
"weight": 2,
"threshold": "Bac+5",
"source": "extracted"
},
{
"criterion_id": "crit_5",
"label": "Anglais",
"type": "language",
"requirement": "required",
"weight": 2,
"threshold": "B2 minimum",
"source": "extracted"
},
{
"criterion_id": "crit_6",
"label": "Encadrement technique",
"type": "experience",
"requirement": "bonus",
"weight": 1,
"threshold": null,
"source": "extracted"
},
{
"criterion_id": "crit_7",
"label": "Certification AWS",
"type": "certification",
"requirement": "bonus",
"weight": 1,
"threshold": null,
"source": "extracted"
},
{
"criterion_id": "crit_8",
"label": "Astreinte",
"type": "other",
"requirement": "required",
"weight": 1,
"threshold": "1 semaine sur 6",
"source": "extracted"
}
],
"credits_used": 0
}{
"error": {
"code": "invalid_request",
"message": "text or file is required.",
"param": "text",
"doc_url": "https://hirelayer.co/api-docs/errors#invalid_request"
},
"request_id": "6f1c2a4e-1d2b-4c3a-9e8f-0a1b2c3d4e5f"
}From a file. Send the job description as a PDF, DOCX, TXT or HTML file in the multipart field file.
curl -X POST https://hirelayer.co/api/v4/jobs/extract-criteria \
-H "X-API-Key: $HIRELAYER_API_KEY" \
-F "file=@job.pdf;type=application/pdf"import os
import requests
with open("job.pdf", "rb") as file:
response = requests.post(
"https://hirelayer.co/api/v4/jobs/extract-criteria",
headers={"X-API-Key": os.environ["HIRELAYER_API_KEY"]},
files={"file": ("job.pdf", file, "application/pdf")},
timeout=150,
)
response.raise_for_status()
data = response.json()
print(data["criteria"])import { readFile } from 'node:fs/promises'
const form = new FormData()
form.append(
'file',
new Blob([await readFile('job.pdf')], { type: 'application/pdf' }),
'job.pdf'
)
const response = await fetch('https://hirelayer.co/api/v4/jobs/extract-criteria', {
method: 'POST',
headers: {
'X-API-Key': process.env.HIRELAYER_API_KEY!,
},
body: form,
signal: AbortSignal.timeout(150_000),
})
if (!response.ok) {
throw new Error(`HireLayer ${response.status}: ${await response.text()}`)
}
const data = await response.json()
console.log(data.criteria){
"request_id": "0c4a7b1e-5d2f-4e8a-b3c6-9f1d2e7a4b58",
"job_id": "job_30cfa454c97663f3e1801e5a61b87d74",
"stored": true,
"title": "Ingénieur IA / Développeur backend Node.js (H/F)",
"location": null,
"language": "fr",
"criteria": [
{
"criterion_id": "crit_1",
"label": "Développement backend Node.js / TypeScript",
"type": "skill",
"requirement": "preferred",
"weight": 3,
"threshold": "3 ans minimum",
"source": "extracted"
},
{
"criterion_id": "crit_2",
"label": "Intégration de LLM en production",
"type": "skill",
"requirement": "required",
"weight": 3,
"threshold": null,
"source": "extracted"
},
{
"criterion_id": "crit_3",
"label": "AWS (Lambda, S3, DynamoDB)",
"type": "skill",
"requirement": "preferred",
"weight": 2,
"threshold": null,
"source": "extracted"
},
{
"criterion_id": "crit_4",
"label": "Diplôme d'ingénieur ou Bac+5 en informatique",
"type": "education",
"requirement": "preferred",
"weight": 2,
"threshold": "Bac+5",
"source": "extracted"
},
{
"criterion_id": "crit_5",
"label": "Anglais",
"type": "language",
"requirement": "required",
"weight": 2,
"threshold": "B2 minimum",
"source": "extracted"
},
{
"criterion_id": "crit_6",
"label": "Encadrement technique",
"type": "experience",
"requirement": "bonus",
"weight": 1,
"threshold": null,
"source": "extracted"
},
{
"criterion_id": "crit_7",
"label": "Certification AWS",
"type": "certification",
"requirement": "bonus",
"weight": 1,
"threshold": null,
"source": "extracted"
},
{
"criterion_id": "crit_8",
"label": "Astreinte",
"type": "other",
"requirement": "required",
"weight": 1,
"threshold": "1 semaine sur 6",
"source": "extracted"
}
],
"credits_used": 0
}