API DOCUMENTATION / FIELD DICTIONARY
Field dictionary
Every field in a job record, with a complete real example, the states a value can be in, and the value lists behind the filters.
One complete record
A real job from the live API on October 14, 2026, requested with include=company,source_data. Only the description text is shortened, and the company.identifiers and company.industries entries are the values Headcount Labs returned for this employer. next_cursor and snapshot_watermark sit beside data on list responses; a single-job response holds only data.
{
"data": [
{
"job_id": "9f70ad16-ab51-49fe-b964-62067a7946b3",
"currentness": "current",
"stale": false,
"company_id": "3483b509-5f22-4535-a907-19c285f3b460",
"employer_name": {
"state": "known",
"value": "Cloudflare"
},
"title": {
"state": "known",
"value": "Senior Customer Engineer, Strategic - San Francisco"
},
"description": {
"state": "known",
"value": "(plain-text job description, left out here for length)"
},
"work_arrangement": {
"state": "known",
"value": "hybrid"
},
"locations": [
{
"state": "known",
"value": {
"city": "San Francisco",
"region": "US-CA",
"country": "US",
"county_fips": "06075",
"msa": {
"type": "metro",
"cbsa_code": "41860",
"cbsa_title": "San Francisco-Oakland-Fremont, CA"
}
}
}
],
"job_first_seen_at": "2026-10-07T19:31:45.114Z",
"curated_at": "2026-10-13T07:33:18.049Z",
"job_updated_at": "2026-10-14T23:30:26.947Z",
"postings": [
{
"posting_id": "79de47fa11a25e23ad485762a9a0fb1c09cca32f3ae3c108b7788734134d504c",
"source": "greenhouse",
"source_posting_id": "8246078",
"posting_status": "listed",
"posting_url": {
"state": "known",
"value": "https://boards.greenhouse.io/cloudflare/jobs/8246078?gh_jid=8246078"
},
"application_url": {
"state": "known",
"value": "https://boards.greenhouse.io/cloudflare/jobs/8246078?gh_jid=8246078"
},
"location": {
"state": "known",
"value": {
"city": "San Francisco",
"state": "CA",
"remote": false,
"country": "US"
}
},
"pay": {
"state": "known",
"value": {
"max": 336000,
"min": 214000,
"currency": "USD",
"interval": "year"
}
},
"source_posted_at": "2026-10-06T14:22:31.000Z",
"first_seen_at": "2026-10-07T19:31:45.114Z",
"last_completed_fetch_at": "2026-10-14T14:04:07.098Z",
"latest_application_check": null,
"attribution": {
"required": null,
"text": null,
"link": null
},
"source_data": {
"job_location_type": "hybrid",
"source_posted_at": "2026-10-06T14:22:31.000Z",
"source_updated_at": "2026-10-14T00:57:01.000Z",
"employment_type": null,
"source_type": "greenhouse",
"availability": "listed"
}
}
],
"company": {
"company_id": "3483b509-5f22-4535-a907-19c285f3b460",
"name": "Cloudflare",
"country": "US",
"status": "active",
"region": "CA",
"address_source": "sec",
"identifiers": [
{
"scheme": "ein",
"value": "270805829",
"exchange": null,
"source": "sec"
},
{
"scheme": "sec_cik",
"value": "0001477333",
"exchange": null,
"source": "sec"
},
{
"scheme": "ticker",
"value": "NET",
"exchange": null,
"source": "sec"
},
{
"scheme": "uei",
"value": "JV9YXS9MLA48",
"exchange": null,
"source": "sam_gov"
}
],
"industries": [
{
"system": "naics",
"code": "541519",
"source": "sam_gov"
},
{
"system": "sic",
"code": "7372",
"source": "sec"
}
]
}
}
],
"next_cursor": "<opaque cursor, or null on the last page>",
"snapshot_watermark": "2026-10-14T01:43:41.000Z"
}How to read a value
Most text-like fields are wrapped in a small object that says where the value came from. Read state first and only then look for value.
| state | Shape | What it means |
|---|---|---|
known | {"state":"known","value":"Engineer"} | The source gave a usable value. |
source_omitted | {"state":"source_omitted"} | The source did not publish this. There is no value key. |
source_unmapped | {"state":"source_unmapped","value":null,"evidence":["…"]} | The source published something, but it did not map to a defined value. evidence shows the source text. |
extraction_failed | {"state":"extraction_failed"} | Headcount Labs tried to read the value and could not. There is no value key. |
derived | {"state":"derived","value":"hybrid","evidence":["…"]} | Headcount Labs worked the value out from the posting text. evidence quotes what it used. |
A state is never the same as null. Treat source_omitted and extraction_failed as "unknown", and keep them apart from a known empty value.
Job fields
| Field | Type | What it holds |
|---|---|---|
job_id | UUID | The combined job. One job joins every posting of the same opening across job boards. |
merged_into_job_id | UUID | Only on the body of a 308 redirect, when this job was merged into another one. |
currentness | current, uncertain, not_current | current while a linked posting is listed and accepting applications. uncertain when that cannot be confirmed. not_current when every linked posting is no longer listed. |
stale | boolean | A label published with the job. A stale job stays in results. Filter with stale=true or stale=false. |
company_id | UUID or null | The company record for the employer. Null when the employer is not yet linked to a company record; employer_name then holds the name the source published. |
employer_name | field state (string) | The employer name as published. |
title | field state (string) | The job title as published. |
description | field state (string) | The description as plain text. |
work_arrangement | field state | remote, hybrid or in_person. A derived value carries the evidence it came from. |
locations | array of field states | Every location of the job, merged from its postings. See the location section below. |
job_first_seen_at | timestamp | When Headcount Labs first collected any posting of this job. |
curated_at | timestamp | When the job first entered the final dataset. |
job_updated_at | timestamp | When the job record last changed. sort=updated orders by this. |
postings | array | One entry for each public listing of the job on one job source. |
company | object or null | Present only when you ask for it with include=company or fields=company. See the company section below. |
Posting fields
Each entry in postings is one listing of the job on one source.
| Field | Type | What it holds |
|---|---|---|
posting_id | string | Headcount Labs ID for this posting. |
source | string | The job-board platform, for example greenhouse, lever or workday. The platform list shows every value. |
source_posting_id | string | The source’s own ID for the posting. |
posting_status | listed or no_longer_listed | listed while the source still shows the posting. no_longer_listed once a completed read no longer finds it. |
posting_url | field state (string) | The posting’s public page on the source. |
application_url | field state (string) | Where to apply, when the source gives an application link. |
location | field state (object) | The location exactly as the source published it. Different shape from the job-level locations. |
pay | field state (object) | Pay as published, not converted. |
source_posted_at | timestamp or null | The date the source says it published the posting. |
first_seen_at | timestamp | When Headcount Labs first collected this posting. |
last_completed_fetch_at | timestamp or null | When Headcount Labs last read the posting’s source completely. |
latest_application_check | object or null | {"result","checked_at"}, where result is available, closed, broken or inconclusive. |
attribution | object | {"required","text","link"}. What the source’s rights record says about crediting it. All three are null when the record says nothing. When required is true, show text and link with the job. |
source_data | object | Only with include=source_data. See the source data section below. |
Locations
A job has two kinds of location data, and they use different keys.
Job level (locations[].value) is cleaned and enriched. Keys: city, region (ISO 3166-2, for example US-TX), country (two letters), county_fips (a five-digit US county code as a string, or null), msa and, when the source gives them, street and postal_code. msa is {"type":"metro" or "micro","cbsa_code","cbsa_title"}, or null when the place is in no statistical area. zip is a five-digit US ZIP, present only when the posting states a real ZIP inside the stated state; the key is absent otherwise.
Posting level (postings[].location.value) is the source’s own data, so keys follow what the source publishes: city, state, remote (boolean) and country, plus, when the source gives them, latitude, longitude, postalCode, streetAddress, countryRaw, regionCode and zip. A posting that lists several places also has alternatives, an array where each entry has raw, city, state, remote, country and the same optional keys.
Pay
postings[].pay.value holds min, max, currency (ISO 4217) and interval (year, month or hour), as the source published them. When a source lists several ranges, ranges is an array of the same four keys. Pay is never converted between currencies or intervals in the response. The filters pay_min and pay_max compare yearly amounts: hourly pay is multiplied by 2,080 and monthly pay by 12 before comparing, and pay with an unknown interval never matches. When there is no pay, the state is source_omitted, or extraction_failed where a pay line could not be read.
Company object
Ask for it with include=company. Each company has company_id, name, country and status (active, retired or merged), plus:
| Field | What it holds |
|---|---|
region | State or province code from the same government address as country, or null. |
address_source | sec (SEC business address), dol_form5500 (Form 5500 plan sponsor address) or null. |
identifiers | Public registry IDs from US government sources. Each has scheme (sec_cik, ein, uei or ticker), value, exchange and source (sec, dol_form5500 or sam_gov). Empty when none is known. |
industries | Industry codes from US government sources. Each has system (naics or sic), code and source. Empty when none is known. |
Source data
With include=source_data each posting gets a source_data object with the values the source itself labels. It holds only the keys below; the raw source payload is not published.
| Key | What it holds |
|---|---|
job_location_type | The source’s own work-location label, as published. |
source_posted_at | The source’s posted date, as published. |
source_updated_at | The source’s own last-updated time, as published. |
employment_type | The source’s employment type label, as published. Free text; see the value lists below. |
source_type | The kind of source, such as an ATS board or an employer site. |
availability | Whether the source shows the posting as listed. |
Other response shapes
| Response | Fields |
|---|---|
| List and search | data (jobs), next_cursor (string or null), snapshot_watermark |
| Single job | data (one job) |
| Count | count, snapshot_watermark |
| Changes | data (events), resume_cursor, has_more, snapshot_watermark. Each event has event_id, job_id, type (created, updated or expired), occurred_at and, for created and updated events, the job. |
| Export | export_id, status, created_at, completed_at, expires_at, record_count, snapshot_watermark, request, files (each with n, records, bytes, url), error |
| Error | error.code, error.message, error.request_id |
Value lists
Counts below are current jobs from the October 14, 2026 snapshot (4,886,218 current jobs). They change daily. Run GET /v1/jobs/count with the filter to see today’s number.
| Field or filter | Values |
|---|---|
work_arrangement | remote 127,219, hybrid 167,344, in_person 780,175. Jobs where no arrangement could be read have source_omitted or extraction_failed, so these three do not add up to the catalog. |
currentness | current (the default filter), uncertain, not_current. |
posting_status | listed, no_longer_listed. |
application_check | available, closed, broken, inconclusive. |
pay_currency | ISO 4217 codes. Most common: USD 1,394,280, EUR 51,333, CAD 36,444, GBP 20,232, AUD 1,975. Jobs with pay in total: 1,601,152. |
country | Two-letter ISO 3166-1 codes, for example US, DE, CA. |
state | Subdivision codes. Alone, a US state (CA is California); with country, that country’s subdivision. |
source | Platform names such as greenhouse, lever, ashby, workday. See supported platforms. |
Employment type is free text
employment_type is the label the source printed, so the same idea appears under many spellings. A filter matches one spelling exactly, ignoring case. These are the most common ones:
| Value | Current jobs |
|---|---|
| Full time | 953,534 |
| Full-time | 568,664 |
| full_time | 269,446 |
| Part time | 209,796 |
| Part-time | 135,298 |
| part_time | 54,624 |
| contract | 48,354 |
| Regular | 29,005 |
| Permanent | 21,603 |
| Contractor | 16,989 |
| Intern | 11,800 |
| Temporary | 11,529 |
| Per diem | 8,913 |
| Seasonal | 8,176 |
| Internship | 7,351 |
There is no normalized list. To cover one idea, send several spellings in one filter: employment_type takes up to 10 values. Use GET /v1/jobs/count?employment_type=... to test a spelling before you rely on it. A count over several very common spellings with no other filter can run past the 10-second limit and return 504 query_timeout; add a country or state to narrow it.
Continue in the reference
See how the same fields are filtered and counted.
Job filters Job and posting fields