Hiring Signals API

Turn a company domain into a hiring snapshot in one call

The Hiring Signals API turns a company domain into a hiring signal as clean JSON.

no credit card1,000 free credits · instant API key · live in 10 seconds
Missing a Hiring Signals endpoint, or need a source we don't have yet?Contact us real people · same-day reply.
H
/enrich-hiring/v1

3 active endpoints, on 5, 6 and 10 credit tiers.

  • POST/enrich-hiring/v1/hiring_signal
  • POST/enrich-hiring/v1/hiring_signal_rich
  • POST/enrich-hiring/v1/batch

What Hiring Signals endpoints does ReefAPI ship?

3 live read endpoints. Read-only data API: no writes, no account actions, no dashboard access on the target site.

3 endpoints

hiring_signal

6 cr

domain → company hiring snapshot.

required
optional
domain, company_name, ats_slug, ats_provider, countries

hiring_signal_rich

10 cr

everything in hiring_signal + employer firmographics (linkedin company / glassdoor employer.

required
optional
domain, company_name, ats_slug, ats_provider, countries

batch

5 cr

hiring_signal for up to 10 domains in one call (cache-first, per-item ok/error).

required
domains
optional

Every parameter, every allowed value →

Hiring Signals API

3 of 3 endpoints, ready to run

View docs ↗

One domain in, one snapshot out: which ATS the company uses, how many roles are open on it, and how those roles split by department, seniority and remote arrangement.

6 credits0 required · 3 optional
POST/enrich-hiring/v1/hiring_signal
idle
// Press "Try it" and this pane shows exactly what the
// live site returned this second — including an empty
// result, if that is the truth. No key, no account.

How the Hiring Signals API works

Hiring Signals is a normal ReefAPI surface — the same four rules that hold for every other engine on the key.

01
Authenticate
x-api-key header

No OAuth app, no request signing, no per-site account. One key covers all 185 engines.

02
Call
POST /enrich-hiring/v1/…

Every route is a POST with a JSON body. Parameters are validated against the published schema before anything is charged.

03
Pay
5 or 6 or 10 credits per call

Credits, not seats. Failed and blocked calls are never charged, and cache hits cost nothing.

04
Read
{ ok, data, meta, error }

One envelope everywhere. meta carries latency_ms, record_count and the endpoint that answered.

Score a list of accounts by whether they are actually hiring

The useful signal is not "does this company have jobs" but "is it hiring at a rate that is unusual for its size", and that needs the headcount next to the count. The rich action returns both.

01batch
POST/enrich-hiring/v1/batch
{"domains": ["stripe.com", "vercel.com", "monzo.com"]}

Ten domains a call, each returning its own coverage block, entity match and counts. Failures are per item, so one unresolvable domain does not spoil the call.

02hiring_signal_rich
POST/enrich-hiring/v1/hiring_signal_rich
{"domain": "<the interesting ones>"}

Adds the employer record and, with it, current_hiring_intensity — which writes out its own basis in words: 66 open roles against roughly 5,778 employees, a ratio of 0.0114, graded low.

A ranked list where the ranking is defensible, because every number arrives with the source it came from and the denominator it was measured against.

request
curl -X POST https://api.reefapi.com/enrich-hiring/v1/hiring_signal \
  -H "x-api-key: $REEF_KEY" \
  -H "content-type: application/json" \
  -d '{"domain":"stripe.com"}'
response envelope
{
  "ok": true,
  "data": { … },
  "meta": {
    "api": "enrich-hiring",
    "endpoint": "hiring_signal",
    "mode": "live",
    "latency_ms": …,
    "record_count": …
  },
  "error": null
}

Where each number comes from, and why the source counts do not add up

This is an aggregate: one domain fans out to an ATS board probe plus two keyword job sources, and those counts measure different things. Summing them inflates the answer, which is why the response reports them separately and gives you a deduplicated total instead. Measured on stripe.com, figma.com and shopify.com.

FieldWhat it countsMeasured
ats.direct_jobs_countthe open-role count read straight off the company's own careers boardstripe.com: greenhouse board "stripe", 580 open roles. This is the number to quote.
ats.returnedhow many of those roles came back as rows for the mix calculations50 of the 580
jobs.count_by_sourceone count per source, deliberately not summedstripe.com: {ats: 580, linkedin: 50, indeed: 0}
jobs.deduplicated_totalunique postings across sources by title + location + company99 for stripe.com. This, not direct_jobs_count, is the denominator for departments and seniority_mix.
departments[].pct / seniority_mix[].pctshare of the deduplicated samplestripe.com sales 43 of 99 = 43.4%; figma.com unspecified seniority 45 of 63 = 71.4%
entity.matchhow the company was pinned down: ats-board, name-confirmed or name-onlyfigma.com scored confidence 0.94 on two pieces of evidence (a greenhouse board and a LinkedIn company); shopify.com fell back to name-confirmed at 0.85
current_hiring_intensitya level plus the basis string that explains itfigma.com: moderate, 159 open roles against ~3,017 employees, open_to_headcount_ratio 0.0527
employer (rich only)firmographics that give the ratio a denominatorfigma.com's linkedin block carried employee_count, company_size, industry, headquarters, founded and specialties; the glassdoor block was null on both rich calls measured
coverage[]per-source status with an honest note about what was droppedindeed on stripe.com: "0/50 keyword hits passed the company-name filter (dropped 50 foreign-company rows)"
freshnessISO-8601 UTC timestamp of the snapshot itselfset per call; there is no stored history behind it
batch.domainsup to 10 domains per call11 domains returns INVALID_PARAM, not a truncated result

The ATS probe covers greenhouse, lever, ashby and workable under the domain stem. shopify.com missed all four, so ats.provider was null, direct_jobs_count was null and current_hiring_intensity came back level "unknown" with basis "no source returned an open-role count". Pass ats_slug when the board token differs from the domain stem, or ats_provider to skip the probe entirely.

What it probes, what it admits, and where the numbers are a sample

Measured on 2026-08-28 against three known companies and one domain with no board at all. Three of these lines go against us.

No accounts, and nothing about individual employees

There is no login on any of the sources underneath and no account of yours in the path. What comes back is about the company: counts, departments, seniority bands, tech mentions, firmographics. There are no employee names, no rosters and no contact details anywhere in the response, and that is a design decision rather than a gap.

⭐ It probes all four ATS providers and shows you the scorecard

The ats block returns a probed array with the result of each attempt — one provider answering with a count, two returning not_found, one returning a zero. So the answer to "which ATS does this company use" arrives with its own evidence, and a wrong guess is visible rather than silent.

⭐ Counts are reported per source and never summed

count_by_source came back with the ATS count, the LinkedIn count and the Indeed count side by side, and a note in the payload saying explicitly that summing them would inflate the figure. deduplicated_total is the cross-source unique number. One company's direct board reported 579 open roles while the keyword sources contributed 50 and 0 — three very different numbers that a naive sum would have turned into a lie.

🔴 The percentages are computed on a sample, not on the whole board

Against us, and easy to misread. For a company with 579 open roles, classified_n was 99 — the department split, the seniority mix and the remote ratio were all computed over those 99 rows, not the 579. The counts are authoritative; the proportions are a sample. classified_n is in the response so you can weigh them accordingly.

🔴 The remote ratio can rest on five rows

Against us. One snapshot returned remote_ratio 1.0, which reads as "fully remote company" — and remote_basis next to it said "5/5 roles with a known workplace flag". Five rows out of ninety-nine classified. The engine tells you the basis in plain words in every response; read it before you use the ratio, because most ATS rows simply do not carry a workplace flag.

🔴 Two sub-calls fail in the open, and the meta names them

Against us, and we would rather it be on the page than in your logs. Every response lists the sub-calls it made with a status for each. In our runs the search-engine sub-call returned HTTP 503 on every single call — that engine is deliberately out of service — and the Glassdoor employer detail used by the rich mode came back blocked on both companies we tried. The consequence is concrete: the rich mode's employer block carries the LinkedIn firmographics and nothing from Glassdoor. Nothing is faked to cover it.

An unknown company says it is unknown

We deliberately pointed it at a domain with no job board. It returned entity confidence 0.3 with match name-only, all four ATS probes not_found, and zero counts from every source — rather than an empty snapshot that looks like a real one. On a company it does recognise, the match came back at 0.9 with the evidence named as the ATS board itself.

The intensity grade writes out its own arithmetic

current_hiring_intensity returns a level, the open-roles number, the ratio against headcount where a headcount is known, and a basis string spelling out both — plus the caveat that it is a snapshot rather than a velocity. Where there is no headcount anchor it says count-band instead and grades on the raw number.

Tech signals come from the postings, and can be empty

tech_signals is a counted list of technologies mentioned across the classified roles — one company returned python 20, looker 12, aws 6 and fourteen more. Another returned an empty array, because its postings simply did not name tools. Empty means empty here; it is not a failure.

What people build with Hiring Signals

The jobs this data is most often used for.

3

endpoints

5/6/10

credits per call

01

Sales-intelligence teams call hiring_signal to flag accounts that are actively hiring (a buying signal).

02

Recruiting tools use hiring_signal_rich to see which ATS a company uses and what roles are open.

03

Go-to-market products use batch to score a whole prospect list for hiring activity at once.

What Hiring Signals data costs

The cheapest call here is 5 credits, so $15/mo (Pro) buys 2,000 of them — $1.50 per 1,000 credits. Credits roll over and never expire, and failed or blocked calls are not charged.

Full pricing →
$0.67–$1.50 / 1,000 credits
  • 1,000 free credits on signup, no card
  • One key, all 185 APIs, one credit pool
  • Failed and blocked calls are never charged
  • Credits roll over and never expire

Call it in two lines

Sign up, get 1,000 credits and one key that works on every engine. Then this is the whole protocol.

curl
curl -X POST https://api.reefapi.com/enrich-hiring/v1/hiring_signal \
  -H "x-api-key: $REEF_KEY" \
  -H "content-type: application/json" \
  -d '{"domain":"stripe.com"}'
python
import requests

r = requests.post(
    "https://api.reefapi.com/enrich-hiring/v1/hiring_signal",
    headers={"x-api-key": REEF_KEY},
    json={
  "domain": "stripe.com"
},
)
print(r.json()["data"])
FAQ

Have a question? We got answers.

The questions people actually ask before wiring up Hiring Signals.

Get a free key →
How is this different from searching a job board for the company name?

A job search gives you rows; this gives you a company-level count plus the shape of the hiring. The open-role count is read off the company's own ATS board, which is authoritative in a way a keyword search is not, and every keyword hit is then filtered against the resolved company name before it counts. On stripe.com that filter kept 50 of 50 LinkedIn hits and 0 of 50 Indeed hits, which is exactly the noise a raw keyword search would have handed you as Stripe jobs.

Why don't the source counts add up to the total?

Because they count overlapping things, and summing them double-counts every posting that appears on more than one source. stripe.com returned count_by_source {ats: 580, linkedin: 50, indeed: 0}, and deduplicated_total 99 sits beside it. Use direct_jobs_count for "how many roles are open" and deduplicated_total for "how many distinct postings did we see". The response carries a note saying the same thing.

What is the denominator behind the department and seniority percentages?

The deduplicated sample, not the full open-role count. On stripe.com, sales showed count 43 and pct 43.4, which is 43 of the 99 deduplicated postings, not 43 of the 580 roles on the board. Treat the mix as a sample profile of what the company is hiring for and the ATS count as the volume. They answer different questions, and mixing them produces numbers that do not exist.

What happens if the company does not use a supported ATS?

You still get a signal, just a weaker one, and the response tells you which. shopify.com probed greenhouse, lever, ashby and workable and matched none, so ats.provider came back null, direct_jobs_count null, and current_hiring_intensity was level "unknown" with basis "no source returned an open-role count". The ats.note names the likely reasons (an unsupported ATS, or a board slug that is not the domain stem), and ats_slug lets you force the right token.

Why is remote_ratio null?

Because it is computed from a remote flag on individual postings, and most ATS rows do not carry one. Measured on figma.com and shopify.com: remote_ratio null in both, with remote null on the job rows themselves. Null here means the sources did not state it, which is not the same as "no remote roles", so do not render it as 0%.

What does hiring_signal_rich add over hiring_signal?

Employer firmographics, and the one derived number they make possible. The rich action adds an employer block with industry, employee_count, company_size, headquarters, founded and specialties, and current_hiring_intensity then gains open_to_headcount_ratio: figma.com came back at 159 open roles against ~3,017 employees, ratio 0.0527, level moderate. Without a headcount the intensity has no denominator and reports only the raw open-role count.

How fresh is the snapshot, and does it show hiring velocity?

It is fetched at call time and stamped with an ISO-8601 UTC freshness value, and it is a snapshot rather than a trend. The intensity basis string says so in plain words: "snapshot, not velocity". If you want velocity, store the snapshots yourself and difference them. Individual postings in the jobs sample do carry their own posted date, which is the closest thing to a timeline in a single call.

Can I run a list of companies in one call?

Yes, up to 10 domains through the batch action, cache-first, with a per-item ok or error so one bad domain does not fail the run. The cap is enforced rather than trimmed: 11 domains returned INVALID_PARAM with the message "max 10 domains per batch (got 11)". Chunk longer lists on your side.

What is the Hiring Signals API?

Hiring Signals API is a ReefAPI endpoint group for hiring signals It returns live JSON through POST requests under /enrich-hiring/v1.

Is the Hiring Signals API free to try?

Yes. ReefAPI starts with 1,000 free credits, no card required. Hiring Signals calls use the same shared credit balance as every other ReefAPI engine.

Do I need a Hiring Signals login or account?

No login to Hiring Signals is needed for the API response. You call ReefAPI with your x-api-key header, and the playground can run live examples before you create a production key.

How fresh is the Hiring Signals data?

The page example is captured from a live hiring_signal call, and production requests fetch live data through ReefAPI rather than a static sample.

How many credits does the Hiring Signals API use?

Hiring Signals actions currently cost 5-10 credits per successful call. Failed or blocked calls are free, and all APIs draw from one credit pool.

Can I call Hiring Signals from an AI assistant or MCP client?

Yes. Connect ReefAPI once through MCP and your assistant can call enrich-hiring actions with the same key, credit pool and JSON envelope used by normal REST requests.

15 Jobs & Hiring APIs on the same key

One key, one credit pool, one response envelope. If you are pulling Hiring Signals, you are one call away from the rest of the category — no second contract, no second integration.

Need something this API does not do?

Name the endpoint, the field, or a source we do not carry yet. We ship new APIs every week and you would be first to get the key. Real people read every message and reply the same day.

0/4000

No account needed · we reply from [email protected]

Try it on your own data before you pay anything

The call above is the real endpoint, not a recording. A free key gives you 1,000 credits, the other 184 APIs, and the same envelope everywhere.

Endpoints, parameters and credit costs on this page are read from the live catalog and cannot drift from what the API accepts. Field notes were captured on 2026-08-28.