Skip to main content
Search, the feeds, company jobs and single-job lookup all return this shape. Use id, a stable UUID, as your primary key for upserts.

Fields

Datetimes are ISO 8601.

Null, empty, and omitted values

Every job carries every key in the table except external_id:
  • Nullable fields are null, never absent. Handle null on every field marked Yes.
  • Array fields (locations, responsibilities, benefits) are [] when empty, never null.
  • external_id is omitted, not null, when unavailable.
Search can drop non-core fields with include_fields (see Shrinking the response). An excluded field keeps its key with an empty value: The feed and GET /api/jobs/{id} always return the full job.

External ID

external_id is the posting’s ID on the platform named by source. It’s returned whenever available, including on searches that request only core fields with include_fields: []. Store it as a string: it can have leading zeros, letters or punctuation. It may differ from the employer’s requisition number and isn’t guaranteed to be globally unique, so keep id as your key for upserts and single-job lookups.

Description format

description is Markdown by default. Jobo converts the employer’s HTML: tags are stripped, line breaks kept, and lists, bold text and links become Markdown (- item, **bold**, [text](url)). Render it as Markdown or show it as plain text. If you render the Markdown to HTML in a web UI, run the output through a sanitizer such as DOMPurify. For HTML, set description_format to html (the default is markdown): In the HTML, raw HTML from the source is escaped, and only http(s), mailto and relative URLs are kept.
The feed cursor doesn’t carry description_format. Send it with every page, or later pages come back as Markdown.

Enums

Responses carry display values (Full-time, On-site, Entry Level), but the employment_type, work_model and experience_level filters accept only the lowercase filter values below. Filtering on a display value matches nothing and returns 200 with total: 0.
  • Facet buckets are keyed by the filter value, so a facet key works as a filter.
  • The workplace filter is work_model (work_models in the POST /api/jobs/search and feed bodies); the job field is workplace_type. There is no is_remote parameter or field.
  • A filter on one of these fields leaves out jobs where the field is null. The feed’s exclude_employment_types, exclude_work_models and exclude_experience_levels are the exception: they keep jobs whose value is unknown.

Employment type

Workplace type

Experience level

Source

source is the provider_id of the platform the posting came from, one of 200+ listed on Source platforms. Unlike the enums, the value is the same on input and output: pass it to the sources filter, and facets.sources buckets use it. New platforms are added regularly, so treat the set as open. Don’t hard-code it as a closed enum.

Nested objects

Company

A slim preview of the employer. For the full profile, follow details_url or call GET /api/companies/{id}, which returns the company object.

Location

Compensation

Amounts are as the employer published them. Salary filters compare a USD-annualized value that Jobo derives from them; that value isn’t returned.

Occupation

A job has at most one occupation, and occupation is null when the job isn’t classified. It describes the kind of work, not the posting: the employer’s title stays in title and normalized_title, and seniority in experience_level. “Senior Backend Engineer” and “Backend Engineer II” get the same occupation. onet_soc_codes usually holds one code, several where O*NET splits the occupation, and [] when O*NET has no equivalent (as for jobo: occupations). The first seven characters of a code are its SOC 2018 code: 15-1252.00 is SOC 15-1252. Search and POST /api/jobs/feed filter on the taxonomy: GET /api/occupations lists every category, subcategory and occupation; Search recipes has examples. Occupations come from the ESCO classification and O*NET-SOC codes from the O*NET database; see Open data licenses and attribution.

Qualifications

qualifications always has two buckets, must_have and preferred, each with these fields:

Skill type

Complete example

A fully populated job object:

Returned by