@pipeworx/dol-whd

Connect: https://gateway.pipeworx.io/dol-whd/mcp · Install: one-click buttons

Tools: 4

Concluded US Department of Labor Wage & Hour Division compliance actions since FY2005 — wage theft, back wages, minimum-wage and overtime findings, child labour, H-1B and H-2A violations. osha already covers the OSHA slice of DOL enforcement; this is the sibling nobody could query.

Promoted out of _incubator on 2026-09-01 (fleet #1052) once Bruce supplied the key. Built originally against a 10-row catalog preview under fleet #651, because until that key existed every row request answered 401.

Tools

ToolAnswers
whd_search”Has employer been cited for wage violations?” — filter by employer, NAICS, state, date
whd_employerFull case history and aggregate totals for one employer
whd_top_backwages”Who owes the most back wages in industry?”
whd_coverageWhat the dataset covers, its publication date and findings-date range

Auth

Platform key (PLATFORM_DOL_KEY, set on gateway and registry-api) with BYO override via _apiKey. A free key from https://dataportal.dol.gov covers every DOL dataset and works on issue — there is no approval step. _apiKey is not in any tool’s required list, because the gateway injects the platform key.

This is not the data.gov umbrella key ([[reference-datagov-key-universal]] does not apply); the DOL Open Data Portal issues its own.

The catalog is open and the rows are not, which is a trap. GET /v4/datasets and GET /v4/datasets/10362 both answer 200 with no key, so the source looks open until you ask for data — at which point a keyless row request returns 401 "The API key is either incorrect or missing from your query."

Worse, auth differs by endpoint. /v4/datasets* accepts an X-API-KEY: request header; /v4/get/... rejects it with 401 and needs the key as a query parameter. Standardise on the header because the catalog call worked and every data call 401s, which reads as a bad key rather than a wrong place to put it. The pack always uses the query parameter.

The upstream throttles per SOURCE IP, not per key. Roughly 20 calls in a few minutes returns HTTP 429 with x-amzn-errortype: ForbiddenException and no Retry-After, for about ten minutes. Measured: a bogus key from a throttled IP also gets 429 while omitting the key entirely still gets 401, which is what pins it to the IP. So this is a shared-egress hazard for us rather than a per-key quota. The pack backs off twice and then returns { found: false, reason: "upstream_rate_limited" } rather than throwing, so a throttle stays distinguishable from an employer with no cases.

Data sources

Query grammar (documented, not guessed)

data.dol.gov is a React SPA whose bundle /static/js/main.1788ccf8.js carries DOL’s own API documentation. Parameters: limit, offset, sort (asc/desc), sort_by (field name), fields, filter_object, X-API-KEY — all as query parameters. Operators, quoted from that documentation: eq, neq, gt, lt, in, not_in, like. Nothing outside that list is assumed to work.

filter_object is a JSON string of nested and / or groups over {field, operator, value}, per DOL’s worked example:

filter_object={"and":[{"or":[{"field":"industry","operator":"eq","value":"A"},
                             {"field":"industry","operator":"eq","value":"C"}]},
                      {"field":"year","operator":"eq","value":"2021"}]}

Traps this pack already handles

  • A zero-match query answers HTTP 204 with an empty body, not a 200 with {"data":[]}. res.ok is true for 204, so parsing without checking the status throws on empty input — turning “this employer has no cases”, the commonest negative result there is, into what looks like a parse bug of ours.
  • filter_object keywords must be lowercasefield, operator, value, and, or. Anything else answers 500 with a generic “check for typos” message that names no field. A wrong dataset name gives the same 500, which is why whd/whisard (the name in the original brief) read as a DOL outage rather than a typo. The dataset is whd/enforcement.
  • like needs % to behave as a substring match. DOL documents like as the substring operator but not its syntax. Measured 2026-09-01: %Walmart% and bare Walmart both return rows, but the wildcard form is a strict superset — it also matches “Subway Georgetown Walmart”, which the bare form does not. Bare like is an anchored match. Every employer search here uses %term%.
  • Trade name ≠ legal name. “Reliant Energy” vs “Reliant Energy Retail Services, LLC” are the same employer. Both are matched with like, and every hit carries matched_field saying which one landed.
  • bw_atp_amt is the TOTAL, and the FLSA columns are a trap. The statute-level columns (flsa_bw_atp_amt, sca_bw_atp_amt, cwhssa_bw_amt, dbra_…, mspa_…, h1b_…, fmla_… …) are mutually exclusive and sum to bw_atp_amt — verified on cases with two statutes (Corrections Corp of America: 7,118,609 SCA + 953,252 CWHSSA = 8,071,861; Hewlett-Packard: 4,831,719 SCA + 401,211 FLSA = 5,232,930, both exact). But flsa_ot_…, flsa_mw_…, flsa_15a3_… and the flsa_smw* set are a breakdown of flsa_bw_atp_amt, not siblings of it, so adding all the *_bw_*_amt columns double-counts. The pack returns back_wages_agreed_usd (the total), back_wages_by_statute, and flsa_breakdown separately, plus a back_wages_reconciles flag so a change in that structure surfaces in a response rather than silently inflating a number.
  • Findings dates are not case open/close dates. The dataset says so explicitly and does not carry the latter. Register freshness on a findings date.
  • But do not take the newest findings date naively. Rows with a NULL findings_end_date sort to the top of a sort=desc, so the obvious query returns null; and DOL’s own data carries typo’d future dates — the newest non-null row is stamped 3021-05-01. whd_coverage bounds the window at both ends and says so in window_note.
  • www.dol.gov HTML pages 403 a plain UA behind Akamai and need the full browser header set (BROWSER_HEADERS in workers/data-pipeline/src/datasets/dod-contracts.ts). That is a header-fingerprint block, not a CF-egress block — do not build a proxy for it. apiprod.dol.gov is a separate host and shows no such gating.

Resolved on promotion

  • Is bw_atp_amt the total of the act columns, or a separate bucket? It is the total of the statute-level columns — settled on real rows, see the trap above. This was the pack’s one open question while it had no key.
  • Reachable from a deployed Cloudflare Worker? Yes — verified live through the gateway on 2026-09-01. apiprod.dol.gov does not gate CF egress. (The www.dol.gov Akamai block noted above is a different host and still applies to HTML scraping.)
  • PLATFORM_DOL_KEY is set as a wrangler secret on both pipeworx-gateway and pipeworx-registry-api.

The other 41 DOL datasets

The same v4 API serves 42 datasets across nine agencies (MSHA 15, OSHA 11, ILAB 7, ETA 4, and one each for EBSA, TRNG, VETS, WB and WHD). The full list, with the call shape and every trap above, is recorded in docs/dol-open-data-catalog.md. Survey only — nothing there is built, and post-saturation nothing should be built from it speculatively; it exists so a demand signal has somewhere to land.

Tools

  • whd_search — Search concluded US Department of Labor Wage & Hour Division enforcement cases since FY2005 — wage theft, back wages, minimum wage and overtime violations, child labour, H-1B and H-2A findings. Filter
  • whd_employer — Full Wage & Hour enforcement history for one employer, with per-case detail and aggregate violation and back-wage figures across every concluded case. Matches the employer against both the registered
  • whd_top_backwages — Rank employers by back wages owed in concluded Wage & Hour enforcement cases, optionally within one NAICS industry or state. Returns cases ordered by the recorded back-wage amount, highest first, with
  • whd_coverage — Report what the Wage & Hour enforcement dataset currently covers: its publication date, update frequency and the findings-date range of the cases returned by a sample query. Use to check how current t

Tools

  • whd_coverage — Report what the Wage & Hour enforcement dataset currently covers: its publication date, update frequency and the findings-date range of the cases returned by a sample query. Use to check how current t
  • whd_employer — Full Wage & Hour enforcement history for one employer, with per-case detail and aggregate violation and back-wage figures across every concluded case. Matches the employer against both the registered
  • whd_search — Search concluded US Department of Labor Wage & Hour Division enforcement cases since FY2005 — wage theft, back wages, minimum wage and overtime violations, child labour, H-1B and H-2A findings. Filter
  • whd_top_backwages — Rank employers by back wages owed in concluded Wage & Hour enforcement cases, optionally within one NAICS industry or state. Returns cases ordered by the recorded back-wage amount, highest first, with

Regenerated from source · build September 1, 2026