# IBM Jobs API

> Query IBM's postings through one API with ?source=ibm — plus the lang:'zz' trick that returns the whole board and the fields named only by number.

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

IBM is not a platform. It's one employer with a bespoke careers site, and this
adapter reaches IBM and nobody else. One [Greenhouse](/ats/greenhouse) adapter
reaches every company on Greenhouse; this one reaches IBM. `company` is ignored —
there is one.

Its jobs are worth having on their own, and a bespoke site is invisible to platform
discovery, so the only way to have them is an adapter you own. We own it: query it
with `?source=ibm`. [`/v1/meta`](/docs/api-reference/meta) is the authoritative live
vocabulary, with the current count per source.

## How IBM Careers actually works

The careers UI is backed by **Elasticsearch**, and it POSTs to a search endpoint
that returns the full job body inline — so, like [Google](/ats/google), this is a
complete-return source with no per-job N+1:

```bash
curl -X POST "https://www-api.ibm.com/search/api/v2" \
  -H "Content-Type: application/json" \
  -d '{"appId":"careers","scopes":["careers2"],"sm":{"query":"","lang":"zz"},"size":100,"from":0}'
```

`hits.hits[]._source` carries `title`, `url`, `body` (the full ~3.5k-char JD) and a
handful of keyword fields; `hits.total.value` is the board total. You page with
`from`, and `size` caps around 100.

<Tip title="`lang: 'zz'` means every locale at once">
  The magic is the empty `query` paired with `lang: "zz"`. `zz` isn't a real
  language — it's a non-locale that tells IBM's index *don't filter by locale*, so
  one query walks the entire global board instead of one country's slice. Send a
  real language code and you'd silently scope yourself to a fraction of it.
</Tip>

### The fields you need are named by number

The useful facets don't have readable names. Work arrangement, category and
location arrive as `field_keyword_17`, `field_keyword_18` and `field_keyword_19` —
Elasticsearch keyword slots — and you simply have to know which number is which:

```
field_keyword_17  →  "Hybrid" | "Remote"                              (work arrangement)
field_keyword_18  →  "Professional" | "Entry Level" | "Internship"    (career level)
field_keyword_19  →  "Pune, IN"                                       (location)
```

`field_keyword_18` does double duty — it drives employment type (only
`"Internship"` becomes an intern role) and seniority (`"Entry Level"` maps through;
`"Professional"` is deliberately left null rather than guessed). The stable id is
the requisition number in the URL (`jobId=58347`), preferred over the Elasticsearch
document hash so it survives a reindex.

## What bites you

**There is no posting date.** IBM's search endpoint exposes none, so `posted_at` is
null on this source and `?time_frame=` can't filter what isn't published — the same
gap [Trakstar Hire](/ats/recruiterbox) has.

**The body has a teaser twin.** `_source.body` is the full description;
`_source.description` is a 250-character teaser. Read the wrong one and every
posting looks populated while carrying an eighth of its text. The adapter takes
`body` and only falls back to the teaser when it's empty.

**Opaque field numbers are a standing liability.** `field_keyword_17/18/19` are
positional in spirit even though they're keyed — a reindex could renumber them, and
nothing about the name would tell you the location had moved.

## Or use ours

An Elasticsearch POST with the `lang:"zz"` whole-board trick, numbered keyword
fields decoded, the full `body` taken over its teaser, a requisition id lifted from
the URL, and a source with no posting date handled honestly — with IBM's rows in the
same [`Job`](/docs/objects/job) shape as every other
[source](/docs/reference/sources), dedup against the same role on
[LinkedIn](/ats/linkedin), and the adapter's upkeep being ours instead of yours.
Same deal as [Amazon](/ats/amazon), [Apple](/ats/apple), [Uber](/ats/uber),
[TikTok](/ats/tiktok), [Google](/ats/google) and [Microsoft](/ats/microsoft).

[Sources](/docs/reference/sources) · [Quickstart](/docs/quickstart)
