# Breezy HR Jobs API

> Query jobs from Breezy HR boards through one API — and why Breezy's posting pages 403 your client no matter which IP you come from.

Source: https://hyperjobs.io/ats/breezy

Breezy HR is a visual, pipeline-first hiring tool aimed at small companies. Boards
live at `<tenant>.breezy.hr`, and there's a public per-tenant JSON feed that
returns the whole board in one call. It also returns no descriptions, and the
place they live is behind a WAF that doesn't care what IP you use. Breezy is the
only platform in this pool besides one other where a browser-fingerprint fetch tier
is **mandatory** rather than a fallback.

## Try it

```bash
curl -G https://api.hyperjobs.io/v1/jobs \
  -H "Authorization: Bearer $HYPERJOBS_KEY" \
  --data-urlencode "source=breezy" \
  --data-urlencode "time_frame=7d" \
  --data-urlencode "limit=2"
```

```json title="Illustrative — the shape, not a live response"
{
  "data": [
    {
      "id": "breezy:brightpath_customer-success-manager",
      "title": "Customer Success Manager",
      "company": {
        "slug": "brightpath",
        "name": "BrightPath",
        "domain": "brightpath.co.za",
        "website": "https://brightpath.co.za",
        "logo": "https://media.licdn.com/dms/image/…",
        "industry": "Financial Services",
        "employee_count": 45
      },
      "location": {
        "remote": false,
        "countries": ["South Africa"],
        "cities": ["Cape Town"],
        "regions": ["Western Cape"],
        "raw": ["Cape Town, Western Cape, South Africa"]
      },
      "employment_type": ["FULL_TIME"],
      "work_arrangement": "Hybrid",
      "salary": {
        "min": 8000,
        "max": 10000,
        "currency": "ZAR",
        "unit": "MONTH",
        "annual_min": 96000,
        "annual_max": 120000,
        "summary": "R8,000 – R10,000 / month"
      },
      "skills": ["account management", "onboarding"],
      "taxonomies": ["Customer Service"],
      "apply_url": "https://brightpath.breezy.hr/p/a1b2c3d4e5f6-customer-success-manager",
      "url": "https://brightpath.breezy.hr/p/a1b2c3d4e5f6-customer-success-manager",
      "source": "breezy",
      "posted_at": "2026-07-08T00:00:00.000Z",
      "expires_at": null,
      "updated_at": "2026-07-13T14:20:07.000Z"
    }
  ],
  "total": 2,
  "limit": 2,
  "offset": 0
}
```

## How Breezy boards actually work

One GET for the list, no auth, no pagination:

```bash
curl "https://<tenant>.breezy.hr/json"
```

`<tenant>` is the subdomain. The response is a bare JSON **array**. Per job:
`friendly_id`, `name`, `url`, `published_date`, `type`, `location`, `locations[]`,
`department`, `salary`, and `company.logo_url`.

And no description. The body exists only on the HTML posting page — one fetch per
posting, which is the entire cost of this platform.

### The posting page is where it gets interesting

```bash
curl "https://<tenant>.breezy.hr/p/<friendly_id>"
```

Most posting pages carry a JobPosting JSON-LD block, and that's the clean path.
Some tenants ship **none** — there the body exists only as a `<div class="description">`
in the page HTML, and you have to walk the div nesting to find the matching close
tag, because the body is rich HTML full of nested divs and a lazy
`.*?</div>` truncates it at the first one. Two templates, two parsers, no way to
know which you'll get until you fetch.

<Warning title="Breezy's WAF fingerprints your client, not your IP">
  The posting pages 403 a plain HTTP client on **both** direct and residential
  proxy egress. Rotating IPs does nothing, because the IP was never the problem —
  it's the TLS and HTTP/2 fingerprint. This is the one wall in this pool that a
  proxy budget cannot buy its way past.

  The fix is a fetch tier that reproduces a real browser's TLS and h2 fingerprint
  (we use impit). Without it, every posting page fails, the catch swallows it, and
  you get a full board of rows with `description: null` — a `200`-shaped success
  containing nothing worth having.
</Warning>

That last sentence is the whole reason Breezy is worth writing about. The failure
isn't loud. It's a complete-looking board of description-less jobs, which under a
no-description-no-job rule means a board of nothing.

## What bites you

**`is_remote` is true for hybrid roles.** Same trap as [Ashby](/ats/ashby), same
consequence. Verified live on a tenant whose hybrid jobs all carried
`is_remote: true`. The bool alone mislabels every hybrid job as fully remote.

`remote_details.value` is the authoritative field — `remote` or `hybrid` — and it
can express the difference. Hybrid has to win first; only then does an explicit
`remote` mean remote, and only an explicit `is_remote: false` means on-site.

**`friendly_id` repeats across tenants.** They're human-readable — `accountant`,
`sales-manager` — so a key of `breezy:<friendly_id>` collides across boards and
one company's accountant overwrites another's. Ours is scoped:
`breezy:<tenant>_<friendly_id>`.

**The display location drops the country.** `location.name` gives `Cape Town, ZA`;
the structured `city` / `state.name` / `country.name` gives
`Cape Town, Western Cape, South Africa`. Prefer the structured fields.

**`salary` is free text.** `R8,000 – R10,000 / month` — a currency symbol you have
to recognise, an en dash, and a period suffix. It parses, but it's a string, not a
number, and it's often absent.

**There's no expiry field.** `published_date` is the only date. A pulled job is
only detectable by re-fetching the board.

## Or use ours

Breezy is a request per posting, through a browser-fingerprint tier, against two
different page templates, keyed on ids that collide across tenants.

We pay that N+1 on every new posting — a description-less row is worthless, so
there's no cheap mode worth having — and skip it for postings already in the pool,
so a re-scrape of an unchanged board costs one call. When a posting page 403s, we
climb to the impersonation tier rather than record an empty row. When the JSON-LD
is missing, we walk the div nesting. We track 1,385 Breezy boards.

Then the usual: `remote_details` read instead of the hybrid-inclusive bool,
tenant-scoped ids, structured locations preferred over the display string, the
free-text salary parsed and normalised, dedup, and the [company
join](/docs/objects/company).

Breezy is in the fast refresh tier, attempted every cycle, despite the N+1 — see
[coverage](/docs/reference/coverage).

[Quickstart](/docs/quickstart) · [Pricing](/pricing)
