Guides / Skills & taxonomies

Skills & taxonomies

The two classification vocabularies — how they're tokenised, how aliasing breaks round-tripping, and how to query them.

Postings carry two independent classification vocabularies, and they answer different questions:

  • skills — specific, granular capabilities. python, kubernetes, cpp. About 84% of postings have at least one (504,787 of 603,335).
  • taxonomies — the job family. Software, Healthcare, Finance & Accounting. 28 fixed values, on about 64% of postings (385,246).

They're orthogonal. A posting can be Software with no skills, carry kubernetes with no taxonomy, or have both. Neither is guaranteed, which matters more than it sounds: filtering on either one silently excludes the postings that were never classified.

BASH
curl -G https://api.hyperjobs.io/v1/jobs \
  -H "Authorization: Bearer $HYPERJOBS_KEY" \
  --data-urlencode "skill=kubernetes" \
  --data-urlencode "taxonomies=Software"

The token model#

Skills are stored as canonical lower-case tokens with no spaces and no punctuation. Not free text, not the words that appeared in the posting — a normalised token drawn from a fixed vocabulary. Machine Learning in a job description becomes the token machinelearning.

skill= is a token match, not a substring match. skill=java does not match javascript, and skill=py matches nothing at all. Contrast with title= and description=, which are Google-style searches — see filtering.

Two alias tables, pointing opposite ways#

There are two separate translation layers, and conflating them is the source of almost every "but I can see that skill in the response" bug.

Query aliases (input)
7 tokens

Applied to the value you send in ?skill=. Lets you write the punctuated form of a few well-known names and have it resolved to the stored token.

Display aliases (output)
one-way

Applied to the skills array on the way out, to render a token as something a human wants to read. Has no reverse mapping.

The full query-alias table:

You sendResolves toRows
c++cpp9,586
c#csharp6,309
.netdotnet4,912
node.js, nodejsnode
react.jsreact
vue.jsvue
golanggo

The punctuated forms are not storedc++ as a stored token is 0 rows, and c# is 0. They work only because the input alias rewrites them before the query runs. That's the whole table; anything not on it is sent through untranslated.

The round-trip problem#

A skill you can see in a response often won't work as a filter

Display aliases are one-way. There is no reverse mapping, so a value the API showed you is not necessarily a value the API will accept. Feed it back and you get zero rows — not an error, not a warning, just an empty set that looks exactly like "no jobs match".

You seeActually stored as?skill= with what you saw?skill= with the token
Machine Learningmachinelearning0 rows22,269
CI/CDcicd0 rows4,178
Quality Assurancequalityassurance0 rows
C++cpp✓ — input-aliased

Only the query-alias entries above survive the round trip. Everything else that gets display-formatted does not.

The rule: if a displayed skill contains a space or a slash, strip them and lower-case it before filtering.

JS
// Turns a displayed skill back into a queryable token.
const toToken = (displayed) => displayed.replace(/[\s/]/g, "").toLowerCase();
 
toToken("Machine Learning"); // → "machinelearning"
toToken("CI/CD");            // → "cicd"

This is a heuristic, not the inverse function — no such function exists. It covers the space-and-slash cases, which is the whole observed failure mode.

Comma means AND — but only for skill#

Comma means OR on every multi-value filter, with one exception: skill, where each value is another required condition, not an alternative.

BASH
# Tagged BOTH python AND aws. Not "either" — skill is the AND exception.
curl "…/v1/jobs?skill=python,aws"
 
# Either family — taxonomies is OR (overlap match).
curl "…/v1/jobs?taxonomies=Software,Healthcare"

skill's AND is exactly right when you mean it: skill=react,typescript,graphql finds roles that need all three, which is what a skill list usually means. Just don't carry the habit elsewhere — every other comma list in the API reads as OR now, and vice versa: a comma in skill= narrows where a comma anywhere else widens.

Getting OR across skills#

taxonomies no longer needs this — taxonomies=Software,Data & Analytics is a native union. skill still does: run one request per value and merge client-side.

JS
const key = process.env.HYPERJOBS_KEY;
 
// The union of single-skill queries — the OR that `skill=` won't express.
async function anyOf(param, values) {
  const pages = await Promise.all(
    values.map((v) =>
      fetch(
        `https://api.hyperjobs.io/v1/jobs?${param}=${encodeURIComponent(v)}&limit=200`,
        { headers: { Authorization: `Bearer ${key}` } },
      ).then((r) => r.json()),
    ),
  );
 
  // Dedupe by id — a posting can legitimately carry several of the values.
  const byId = new Map(pages.flatMap((p) => p.data).map((j) => [j.id, j]));
  return [...byId.values()];
}
 
const rustOrGo = await anyOf("skill", ["rust", "go"]);

N values costs N requests against your rate limit. To mix AND with OR, put the AND terms in each request's comma list and vary the OR term across requests — skill=rust,kubernetes and skill=go,kubernetes unions to "(Rust or Go) and Kubernetes".

The 28 taxonomies#

Exact, Title-Case values. A casing miss or a value off this list is a 400 naming the allowed values — never a silent zero-row response.

SoftwareTechnologyEngineering
Data & AnalyticsHealthcareFinance & Accounting
ConsultingLegalHuman Resources
MarketingCreative & MediaSales
Art & DesignEducationManufacturing
EnergyConstructionScience & Research
Customer Service & SupportLogisticsAdministrative
Management & LeadershipTradesTransportation
HospitalitySecurity & SafetySocial Services
Agriculture

Software and Technology are separate families, as are Software and Engineering. If you're after technical roles broadly, ask for all three in one request — ?taxonomies=Software,Technology,Engineering is a native OR (overlap match) — rather than assuming one subsumes the others. The full list also lives in the enums reference.

Which one should you filter on?#

UseWhenCoverageCost
taxonomiesYou want a whole job family — "all healthcare roles"64%Coarse; misses the 36% unclassified
skillYou want a specific capability — "roles needing Rust"84%Misses postings that never listed skills
titleYou want a named role — "SRE", "Staff Engineer"100%Google-style search; broad, still noisy

The practical guidance:

  • Start with skill for anything technology-shaped. It's the highest-signal filter and has the best coverage of the three classifiers.
  • Use taxonomies to scope, not to find. It's good for narrowing a broad query to a sector and bad as the only filter, because a third of postings carry no taxonomy and are invisible to it.
  • Reach for title when the concept isn't a skill or a family. "Staff" and "Principal" are seniority signals in the title that no vocabulary captures — though note seniority is its own exact-match filter.
  • Don't combine all three defensively. Every classifier you add is another AND, and each one drops the postings it never classified. Three filters at 84%, 64%, and 100% coverage intersect to a much smaller set than you expect, and it won't be obvious that's what happened.

Next#

Was this page helpful?