Field dictionary
What does every field mean, how is it derived, and what do providers call it?
Every field BetterJobs returns, in one table. Field names are dotted paths as they appear in the API response: salary.min is min inside salary, and sources[].url is url inside each item of sources. The OpenAPI spec is the source of truth; this page is built from the same field list.
All fields
Section titled “All fields”Filter by name, for example salary or seen. Each row has a stable anchor you can link to, such as #field-job-last_verified_at or #field-company-is_hiring-value.
| Field | Type | Description | null / [] means | Derivation | Example |
|---|---|---|---|---|---|
id | string | Canonical job id (job_...). Stable across sources and requests. | Never null | normalized | "job_01JC8X4M2Q7RV3T9KD5W6YH0AB" |
title | string | Job title as posted. | Never null | raw | "Head of Revenue Operations" |
company.id | string | Canonical company id (cmp_...). | Never null | normalized | "cmp_4Rk7TzP1aQ" |
company.name | string | Company name. | Never null | normalized | "Acme Robotics" |
company.domain | string | null | Primary web domain of the company. | Unknown. No source reported it. | normalized | "acme-robotics.example" |
location.city | string | null | City. | Unknown. No source reported it. | normalized | "Berlin" |
location.region | string | null | State, province or region. | Unknown. No source reported it. | normalized | "Berlin" |
location.country_code | string | null | ISO 3166-1 alpha-2 country code. | Unknown. No source reported it. | normalized | "DE" |
location.remote | boolean | null | true remote, false on-site or hybrid. | Unknown. Not the same as false. | normalized | false |
employment_type | full_time | part_time | contract | internship | temporary | null | Employment type. | Unknown. No source reported it. | normalized | "full_time" |
seniority | intern | junior | mid | senior | lead | director | vp | c_level | null | Seniority level. | Unknown. No source reported it. | inferred | "lead" |
job_family | string | null | Job family, e.g. engineering, sales, operations. | Unknown. No source reported it. | inferred | "operations" |
salary | Salary | null | Pay range. See the salary.* fields. | Unknown. No source reported pay. | normalized | {"min":110000,"max":135000,"currency":"EUR","period":"year","origin":"declared"} |
salary.min | number | null | Lower bound in salary.currency per salary.period. | Unknown lower bound. | normalized | 110000 |
salary.max | number | null | Upper bound in salary.currency per salary.period. | Unknown upper bound. | normalized | 135000 |
salary.currency | string | ISO 4217 currency code. | Never null | normalized | "EUR" |
salary.period | year | month | hour | Pay period. | Never null | normalized | "year" |
salary.origin | declared | inferred | declared = stated in the posting. inferred = estimated by a source. | Never null | normalized | "declared" |
description | string | null | Plain-text job description. | Unknown. No source reported it. | raw | "Acme Robotics is hiring a Head of Revenue Operations..." |
apply_url | string | null | Where a candidate applies. | Unknown. No source reported it. | raw | "https://jobs.acme-robotics.example/revops-lead/apply" |
posted_at | date-time | null | Date the employer posted the job. | Unknown. Use first_seen_at instead. | raw | "2026-10-08T00:00:00Z" |
first_seen_at | date-time | Earliest time any source saw the job. | Never null | normalized | "2026-10-08T06:40:00Z" |
last_seen_at | date-time | Latest time any source saw the job. | Never null | normalized | "2026-10-11T06:10:00Z" |
last_verified_at | date-time | null | Latest time the job was confirmed live at its origin. | Never verified at origin. | normalized | "2026-10-11T06:10:00Z" |
status | open | closed | Lifecycle status. | Never null | normalized | "open" |
closed_reason | filled | expired | removed | unknown | null | Why the job closed. | The job is open. | normalized | null |
repost_count | integer | Times the same job was re-listed. | Never null | normalized | 0 |
p_real | number (0-1) | Probability the job is a real open req, from cross-source corroboration. | Never null | inferred | 0.94 |
sources | Source[] | Every provider that saw this job, with what it contributed. | Never null | raw | [{"provider":"theirstack",...}] |
sources[].provider | ProviderSlug | Provider slug. | Never null | raw | "theirstack" |
sources[].provider_job_id | string | The provider's own id for this posting. | Never null | raw | "ts_88213377" |
sources[].url | string | null | Posting URL as this provider saw it. | The provider did not report a URL. | raw | "https://jobs.acme-robotics.example/revops-lead" |
sources[].first_seen_at | date-time | When this provider first saw the job. | Never null | raw | "2026-10-08T07:12:00Z" |
sources[].last_seen_at | date-time | When this provider last saw the job. | Never null | raw | "2026-10-11T04:02:00Z" |
sources[].fields | string[] | Job fields this source contributed to the canonical record. | [] = the source corroborated the job but contributed no field. | raw | ["salary","seniority"] |
license.display | boolean | You may show this job to your end users. | Never null | normalized | true |
license.resale | boolean | You may resell or redistribute this job as data. | Never null | normalized | false |
company | Company | Company reference: id, name, domain. | Never null | normalized | {"id":"cmp_4Rk7TzP1aQ","name":"Acme Robotics","domain":"acme-robotics.example"} |
open_jobs_count | integer | Open canonical jobs right now. | Never null | normalized | 42 |
is_hiring.value | boolean | null | Whether the company is hiring. | Unknown. Never treat null as false. | inferred | true |
is_hiring.confidence | number (0-1) | Confidence in is_hiring.value. | Never null | inferred | 0.96 |
is_hiring.basis | string | Plain-English reason for the value. | Never null | inferred | "42 open jobs corroborated by 4 sources in the last 30 days" |
hiring_pulse.direction | up | flat | down | Direction of open jobs over the last 30 days. | Never null | inferred | "up" |
hiring_pulse.open_jobs_30d_change | integer | Change in open jobs over the last 30 days. | Never null | normalized | 9 |
top_job_families | {job_family, open_jobs}[] | Job families with the most open jobs. | [] = no open jobs found. | inferred | [{"job_family":"engineering","open_jobs":18}] |
sources | {provider, open_jobs, last_seen_at}[] | Open jobs per provider for this company. | [] = no source sees this company. | raw | [{"provider":"theirstack","open_jobs":31,"last_seen_at":"2026-10-11T04:02:00Z"}] |
No field matches.
For the same fields grouped with a record sample and coverage notes, see Jobs and Companies. Enum values are listed in Taxonomies.
Derivation
Section titled “Derivation”The Derivation column tells you how much BetterJobs changed the value before returning it.
| Derivation | Meaning | Trust it as |
|---|---|---|
raw |
Passed through from a source as posted. | What the posting says. |
normalized |
Mapped to one format: ISO codes, BetterJobs enums, merged timestamps, canonical ids. | The posting’s data in a consistent shape. |
inferred |
Estimated from other data, for example seniority from the title or p_real from cross-source corroboration. |
A best estimate. Check it before you rely on it for hard filtering. |
salary.origin adds a second layer for pay. declared means the posting stated it. inferred means a source estimated it.
Null semantics
Section titled “Null semantics”The rule is the same for every field:
| You see | It means |
|---|---|
null |
Unknown. No source reported it. |
[] |
Verified none. For example top_job_families: [] means no open jobs found. |
| Field missing | Not part of this payload, for example the lifecycle-only job in a job.closed event. |
Fields marked Never null in the table always carry a value.
How often a field is non-null in your results is reported live in metadata.field_coverage. See Coverage.
Provider field names
Section titled “Provider field names”Each partner provider names the same data differently. This table maps BetterJobs fields to the names each provider uses in its own documentation. Only fields with at least one confident equivalent are shown.
| BetterJobs | Reqbeat | SignalsAPI | TheirStack | JobsPipe | Coresignal | Techmap |
|---|---|---|---|---|---|---|
title | — | — | job_title | job_title | — | — |
company.domain | — | — | company_domain | — | — | — |
location.remote | — | — | remote | — | — | — |
employment_type | — | — | — | — | — | contractType |
seniority | — | — | seniority | seniority | — | — |
salary | — | — | salary_string | salary_usd | — | — |
salary.min | — | — | min_annual_salary_usd | — | — | — |
posted_at | — | — | date_posted | date_posted | — | — |
first_seen_at | — | — | discovered_at | discovered_at | — | — |
last_seen_at | — | — | — | last_seen_at | — | — |
last_verified_at | — | — | — | verified_at | — | — |
closed_reason | — | — | — | closed_reason | — | — |
sources[].url | — | — | url | url | — | — |
sources[].first_seen_at | — | — | discovered_at | discovered_at | — | — |
sources[].last_seen_at | — | observed_at | — | last_seen_at | — | — |
Notes on the mapping:
- One field, different units. TheirStack
min_annual_salary_usdand JobsPipesalary_usdare in US dollars. BetterJobs keeps the posting’s currency insalary.currencyand its period insalary.period. - Inverse scores. JobsPipe publishes a
ghost_score, a measure of how likely a posting is a ghost job. BetterJobsp_realruns the opposite way: higher = more likely a real open req. Do not copy thresholds across. - Per-source vs canonical timestamps. A provider’s
discovered_atmaps tosources[].first_seen_atfor that provider. The top-levelfirst_seen_atis the earliest across all sources. - No equivalent (—) means we found no confident one-to-one match in the provider’s published names. It does not mean the provider lacks the data.
Moving from one provider? The migration guides translate queries as well as fields: TheirStack, JobsPipe, Coresignal, Techmap.