# Changelog

> API changes, the compatibility policy, and how you'll hear about them.

Source: https://hyperjobs.io/docs/changelog

## Compatibility policy

`/v1` is stable. These changes can happen at any time and are considered
**backwards-compatible** — your client must tolerate them:

- **New fields** on the Job or Company object.
- **New optional query parameters.**
- **New enum values** — new `taxonomies`, new `source` values as ATS platforms
  are added, new `data_tier` values.
- **New endpoints.**
- **Changes to counts, ordering within equal sort keys, and dataset coverage.**

These would be **breaking**, and won't happen inside `/v1`:

- Removing or renaming a field or parameter.
- Changing a field's type.
- Changing the meaning of an existing parameter.
- Removing an endpoint.

If a breaking change becomes necessary it ships as `/v2`, and `/v1` keeps
working. You'd get notice by email at the address on your account before `/v1`
was ever retired.

<Warning title="Write a tolerant client">
  The single most important consequence: **don't fail on an unknown enum value
  or an unrecognised field.** New `source` values appear whenever an ATS
  integration lands, and new `taxonomies` appear as the classifier improves. A
  client with an exhaustive `switch` that throws on the default case will break
  on a change that is, by policy, not breaking.

  Parse defensively, ignore what you don't recognise, and log rather than throw.
</Warning>

## Versioning

There is one version, `/v1`. There's no version header, no date-pinning, and no
per-account version — every caller is on the same `/v1`. The running release is
reported as `version` on [`/v1/meta`](/docs/api-reference/meta) and
[`/v1/health`](/docs/api-reference/health) — currently `1.0.0`.

## Changes

<Note>
  This is a new API and its published change history starts here. Dataset
  contents change continuously and aren't itemised — call
  [`/v1/meta`](/docs/api-reference/meta) for live counts and freshness rather
  than tracking them here.
</Note>

### v1 — 2026-07-16 (current)

The launch release. It replaced a pre-release draft that was documented on this
site but never had production consumers — so where the draft's design was
wrong, v1 fixed it rather than inheriting it, and the compatibility policy
above applies from this release forward. If you read these docs before
2026-07-16, the differences below are what changed.

**The contract:**

- **Strict validation.** An unknown parameter, empty value, bad enum member,
  unrecognised ISO code, or malformed search syntax is a
  [`400`](/docs/errors) naming the parameter — never a silent drop. (The draft
  coerced or ignored bad input, so a typo could masquerade as an empty result
  set.)
- **Comma means OR** on every multi-value filter — except `skill`, which is
  AND (required skills). The draft ANDed commas everywhere. See
  [filtering](/docs/guides/filtering#comma-means-or--except-skill).
- **Salary filters are range-overlap:** `salary_gte` (`annual_max >= X`,
  "could pay this much"), `salary_lte`, and `salary_currency`. The draft's
  `salary_min` is gone. See [salary](/docs/guides/salary).
- **Geo parameters** are `country` (full name or ISO-2), `city`, `region`,
  `continent`; **time parameters** are `time_frame` and `posted_gte`/`_lt`.
  The draft's `location` and `posted_since` aliases are gone.
- **`time_frame` / `since`: `m` means minutes** (`15m`). Units are `m`, `h`,
  `d` only — the draft's m-for-months trap didn't survive.
- **`employment_type`, `education_requirements`, and `benefits` are real JSON
  arrays** on the Job object — the draft returned raw JSON strings.
- **`/v1/meta` requires an API key** and counts toward rate limit and quota.

**The surface:**

- **Ten endpoints**, including [`/v1/jobs/count`](/docs/api-reference/jobs-count)
  (a count for any filter set),
  [`/v1/jobs/expired`](/docs/api-reference/jobs-expired) (the purge feed),
  [`/v1/jobs/modified`](/docs/api-reference/jobs-modified) (the update feed,
  with `modified_fields` on each row), and `/openapi.json` (the generated
  OpenAPI 3.1 spec, no key needed).
- **Cursor pagination everywhere.** Every list endpoint returns `next_cursor`;
  pass it back as `?cursor=` for drift-free paging at any depth.
- **The full filter set**, including `title_advanced`/`description_advanced`
  boolean search, the company axis (`company_industry`, `company_size`,
  `employee_count_gte`/`_lt`, `funding_gte`/`_lt`, `company_country`,
  `domain`), exclusions (`exclude_organization`, `exclude_source`), absolute
  date bounds (`posted_gte`/`_lt`, `created_gte`/`_lt`),
  `source_type=ats|jobboard|aggregator` provenance, and
  `visa_sponsorship=only|exclude`.
- **`title` and `description` are Google-style searches** — words AND,
  `"quoted phrases"`, `OR`, `-exclusions` — not plain substrings.
- **One vocabulary for sources:** the `?source=` filter, the `/v1/meta` keys,
  and the `source` field on every payload all use the public slug
  (`source=lever` works). `country`/`company_country` accept ISO-2 codes,
  `language` accepts ISO-639-1.
- **`/v1/companies` is a real search** — `q`, `industry`, `country`, `size`,
  employee-count bounds, `has_jobs` — returning `total`, with a live
  `jobs_count` on every company.
- **`/v1/meta` reports `coverage_pct`** (measured per-field fill rates),
  `full_text_search`, and `version`.
- **Rate-limit headers** (`X-RateLimit-Limit` / `-Remaining` / `-Reset`) on
  every authenticated response, and `Retry-After` on per-minute 429s. Monthly
  quotas are enforced and synced to plan limits, with a distinct `429` body
  when a quota runs out.
- [`/v1/jobs/feed`](/docs/api-reference/jobs-feed) excludes expired postings
  and duplicates, same as `/v1/jobs` — the draft's feed served expired rows.
  `/v1/health` counts live jobs only, matching `/v1/meta`.

## Known gaps

Documented so you can design around them rather than discover them:

| Gap | Workaround |
| --- | --- |
| No webhooks or streaming | Poll [`/v1/jobs/feed`](/docs/guides/feed-sync) |
| No bulk jobs export | Page `/v1/jobs` with `cursor`, or [contact us](mailto:hello@hyperjobs.io) for flat-file delivery |
| No geo/radius search | Filter on `country` / `city` / `region`; `location.coords` is on the Job object for client-side distance |
| No configurable sort | Fetch the filtered set and sort client-side |

If one of these blocks you, say so — [support](/docs/support). Knowing what
people actually hit is how this list gets shorter.
