# SmartRecruiters Jobs API

> Query jobs from SmartRecruiters boards through one API — and how its Posting API, custom fields and remote/hybrid booleans actually behave.

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

SmartRecruiters is a hiring platform aimed at growing and enterprise companies,
with boards at `jobs.smartrecruiters.com/<Company>`. It's the largest source in
this dataset at 216,791 postings — roughly three times LinkedIn — from 2,642
tracked boards. That ratio is the whole story of the platform: comparatively few
boards, each of them big. A source's size reflects how many companies use that
ATS and how reachable its boards are, not how good the postings are; read the
live number from [`/v1/meta`](/docs/api-reference/meta) rather than this
paragraph.

## Try it

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

```json title="Illustrative — the shape, not a live response"
{
  "data": [
    {
      "id": "smartrecruiters:744000041827391",
      "title": "Restaurant General Manager",
      "company": {
        "slug": "vertex-hospitality",
        "name": "Vertex Hospitality",
        "domain": "vertexhospitality.com",
        "website": "https://vertexhospitality.com",
        "logo": "https://media.licdn.com/dms/image/…",
        "industry": "Hospitality",
        "employee_count": 8200
      },
      "location": {
        "remote": false,
        "countries": ["United States"],
        "cities": ["Denver"],
        "regions": ["Colorado"],
        "raw": ["Denver, Colorado, United States"]
      },
      "employment_type": ["FULL_TIME"],
      "work_arrangement": "On-site",
      "seniority": "Mid-Senior level",
      "salary": {
        "min": 62000,
        "max": 74000,
        "currency": null,
        "unit": "YEAR",
        "annual_min": 62000,
        "annual_max": 74000,
        "summary": null
      },
      "skills": ["p&l", "scheduling"],
      "taxonomies": ["Hospitality & Food Services"],
      "apply_url": "https://jobs.smartrecruiters.com/VertexHospitality/744000041827391",
      "url": "https://jobs.smartrecruiters.com/VertexHospitality/744000041827391",
      "source": "smartrecruiters",
      "posted_at": "2026-07-14T07:02:00.000Z",
      "expires_at": null,
      "updated_at": "2026-07-14T09:33:10.000Z"
    }
  ],
  "total": 2,
  "limit": 2,
  "offset": 0
}
```

A null `currency` next to real `min`/`max` numbers isn't a bug — see the custom
fields section below.

## How SmartRecruiters boards actually work

A public Posting API, no auth, in two steps:

```bash
# 1. List — paginated, 100 per page, no descriptions
curl "https://api.smartrecruiters.com/v1/companies/<company>/postings?limit=100&offset=0"

# 2. Detail — one per posting, the description lives here
curl "https://api.smartrecruiters.com/v1/companies/<company>/postings/<id>"
```

`<company>` is the identifier from `jobs.smartrecruiters.com/<Company>` — often
capitalised, like `Visa`. The list returns `{ content, offset, limit, totalFound }`.

The description is assembled from `jobAd.sections` on the detail: `jobDescription`,
`qualifications`, `additionalInformation` and `companyDescription`, each a
`{ title, text }` pair. Read only `jobDescription` and you drop the entire
qualifications block — the field is populated, so nothing looks wrong.

### The list is richer than most

Before you pay for a single detail call, the list gives you `location` with
structured `city` / `region` / ISO `country` **plus exact `latitude` and
`longitude`**, `typeOfEmployment`, `experienceLevel` (in LinkedIn's vocabulary —
`Mid-Senior Level`, `Entry Level`), `department`, `function`, `industry`,
`language`, `refNumber`, and `customField[]`.

Real coordinates straight from the provider are rare. Most platforms give you a
string and you geocode it and hope.

### Two remote flags, not one

`location.remote` and `location.hybrid` are **separate booleans**, and together
they give the full three-way. Read only `remote` — the obvious move — and every
hybrid job loses its arrangement entirely. `hybrid` wins when set; otherwise
`remote` true or false maps to Remote or On-site.

### Salary hides in two different places

The detail carries a `compensation` object — `{ min, max, currency, period }` —
when the employer sets one. But roughly 20% of boards publish pay in the list's
**`customField[]`** instead, even when `compensation` is empty. Surveyed across 30
boards on 2026-07-06.

Custom fields are employer-named, so there's no key to look for. You see
`Salary Range`, `Pay Range`, `Salary for Advertising`, and separate
`Salary Min` / `Salary Max` pairs. Matching them means matching labels, which
means a pile of near-misses that aren't the offered pay at all: `Salary Grade`,
`Pay Classification`, `Bonus Eligibility`, `Loan Repayment`, `Payroll Country`.
Each of those contains `salary`, `pay` or `comp` and none of them is a salary.

## What bites you

**A numeric Min/Max pair carries no currency.** When pay comes from
`Salary Min: 62000` and `Salary Max: 74000`, the employer never said which
currency. Guessing USD is how a British board's salaries end up 30% too high in
your UI. We leave `currency` null and keep the numbers — a null currency next to
real numbers is honest; a wrong currency is not.

**`department` is empty on most boards.** Around 65% of boards leave it blank
while populating `function`. Falling back to `function` fills the column; promoting
`function` to `team` as well duplicates it. We fall back, and only keep `function`
as a distinct team when it differs.

**`fullLocation` is worse than the structured fields.** It's free text and often
sparse. Build from `city` + `region` + the ISO country resolved to a canonical
name and the country is reliable; use `fullLocation` only when there's nothing
else.

**Pagination that stops early truncates a big board silently.** Page size is 100
and boards here are large. Loop to a short page or `offset + limit >= totalFound`
— a fixed cap is a data bug that returns `200` every time.

<Warning title="`?source=` is exact and case-sensitive">
  The company identifier in the URL is capitalised — `jobs.smartrecruiters.com/Visa`.
  The `source` value is not. `?source=SmartRecruiters` returns zero rows and a
  `200`, like every other [wrong filter value](/docs/errors) on this API. It's
  `smartrecruiters`, lowercase.
</Warning>

## Or use ours

SmartRecruiters is a straightforward platform with an expensive shape: a detail
call per posting, across the largest posting count of any source here.

You get the description already assembled from all four `jobAd` sections, the
hybrid boolean read rather than dropped, salary recovered from `customField[]`
when `compensation` is empty and left currency-less rather than guessed, the
provider's own coordinates, and dedup against the same role appearing on
[LinkedIn](/ats/linkedin) or a [Greenhouse](/ats/greenhouse) board — which
matters more here than anywhere, because `?source=smartrecruiters&limit=1` counts
jobs where SmartRecruiters **won** dedup, not jobs on SmartRecruiters. [The dedup
guide](/docs/guides/deduplication) has the mechanism.

SmartRecruiters is in the fast refresh tier, attempted every cycle. See
[coverage](/docs/reference/coverage) for the tiers and
[sources](/docs/reference/sources) for why board count and posting count are
close to unrelated.

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