# DOL enforcement data - OSHA inspections + WHD wage cases (CSV) (`retrainmap/dol-enforcement`) Actor

OSHA inspections and Wage and Hour Division (WHISARD) cases from the U.S. Department of Labor's open-data portal bulk files, no API key. Filter by state, city, employer name and open date; one normalised row per inspection or case: dates, NAICS, type, violations, back wages, penalties.

- **URL**: https://apify.com/retrainmap/dol-enforcement.md
- **Developed by:** [RetrainMap Team](https://apify.com/retrainmap) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## DOL enforcement data — OSHA inspections + WHD wage cases (CSV)

One row per OSHA inspection or Wage and Hour Division (WHISARD) compliance case from the
U.S. Department of Labor's Open Data Portal, filtered by state, city, employer name and
open date: id, employer, address, NAICS/SIC, open and close dates, inspection type and
scope (OSHA), violations, employees affected, back wages and civil penalties (WHD), plus
a link to the OSHA inspection page — normalised to one flat layout for both datasets,
ready for CSV or JSON. No API key needed.

**The default input (OSHA inspections, North Carolina, last 90 days, up to 300 rows)
succeeds within 5 minutes and returns rows** — Apify auto-tests it daily.

### Data source and status

| | |
|---|---|
| Publisher | U.S. Department of Labor — Occupational Safety and Health Administration (OSHA) and Wage and Hour Division (WHD), via the DOL Open Data Portal (https://data.dol.gov/) |
| Files | The portal's public "Download Complete Dataset" files: `https://data.dol.gov/data-catalog/OSHA/inspection/OSHA_inspection.zip` (1.44 GB, 104 CSV parts, ~5.2 million inspections since the 1970s) and `https://data.dol.gov/data-catalog/WHD/enforcement/WHD_enforcement.zip` (200 MB, 8 parts, ~368,000 concluded cases since FY 2005). Dataset pages: https://data.dol.gov/datasets/10334 (OSHA inspection) and https://data.dol.gov/datasets/10362 (WHD enforcement); key-free catalogue: https://apiprod.dol.gov/v4/datasets |
| What this Actor reads | The ZIP central directory, then every CSV part through HTTP Range requests, up to 6 (at most 8) in parallel; the whole file is scanned on every run because the rows are in database order, not by date. The portal catalogue is read once to confirm the dataset is still listed |
| Refresh cadence | OSHA inspection: the portal file is regenerated about weekly (the 2026-09-03 file's newest open date was 2026-08-31 — a lag of days for opened inspections; closed dates fill in later). WHD enforcement: concluded cases only, regenerated about weekly, with a lag of months to years between a case's start date and its appearance (the 2026-08-31 file had 69 cases started in 2026). `load_date` on each row and the portal's `updated_at` in `RUN_SUMMARY` say how fresh a row is |
| Copyright | Works of the United States Government are not subject to copyright in the U.S. (17 U.S.C. §105). The data are public; please cite the Department of Labor as the source |
| Known caveats | Not an API read: the former Enforcement Data API (enforcedata.dol.gov, `/api/v1/…`) now redirects to the portal, and the portal's row API (`apiprod.dol.gov/v4/get/…`) requires a registered key — so this Actor reads the public bulk files instead, which costs ~1.4 GB of transfer and 1–3 minutes per OSHA run (~200 MB, under a minute for WHD); every run scans the full file, so a wider filter costs nothing extra; the newest `max_records` matches by open date are written; rows without a parseable open date never match; OSHA `type`/`scope`/`owner_type`/`safety_or_health` labels are null for codes outside the OSHA data dictionary lists (the raw code is kept); WHD rows carry no per-case web page, so `source_url` is the bulk file; the WHD file contains a handful of impossible dates (e.g. year 3590) exactly as published |

Honesty note: the rows are the bulk files' own columns renamed to one common layout —
OSHA code letters are translated with the OSHA data dictionary's code lists (and kept
raw next to the label), WHD statute columns with non-zero values are kept under
`details.nonzero_statute_columns`, numbers are parsed only when they are plain numerals.
Nothing is inferred, summarised or classified by this Actor, and a run stops with an error
rather than guess when a file's layout changes.

Identification: the requests carry a product-token User-Agent and the operator's
contact address in the standard `From:` header (RFC 9110 §10.1.2).

### Input

| Field | Type | Meaning |
|---|---|---|
| `dataset` | string | `osha_inspection` (default) or `whd_whisard` |
| `state` | string | Optional 2-letter USPS code of the site / employer, e.g. `NC` |
| `city` | string | Optional city, exact match, case-insensitive |
| `employer_contains` | string | Optional case-insensitive substring of the establishment name (OSHA) or trade / legal name (WHD) |
| `date_from` / `date_to` | `YYYY-MM-DD` | Optional, inclusive, on the OSHA `OPEN_DATE` / WHD `FINDINGS_START_DATE`. Both empty = the last 90 days |
| `max_records` | integer | Default 300, at most 50,000 — the newest matches by open date |
| `parallel_downloads` | integer | Default 6, at most 8 |
| `contact_email` | string | Sent in the `From:` header |

Example — concluded WHD cases since 2024 whose employer name contains "restaurant":

```json
{ "dataset": "whd_whisard", "employer_contains": "restaurant", "date_from": "2024-01-01", "max_records": 100 }
```

### Output (dataset row)

`dataset`, `agency`, `activity_id` (OSHA `ACTIVITY_NR` / WHD `CASE_ID`), `employer_name`
(OSHA `ESTAB_NAME` / WHD `TRADE_NM`), `legal_name` (WHD), `address`, `city`, `state`, `zip`,
`naics`, `naics_description` (WHD), `sic` (OSHA), `open_date`, `close_date`, `type_code` /
`type` (OSHA inspection type: Accident, Complaint, Referral, Planned, Fatality/Catastrophe,
…), `scope_code` / `scope` (Complete, Partial, No Inspection, Records Only),
`safety_or_health`, `owner_type` (Private / Local / State / Federal Government),
`violations_count`, `employees_affected`, `back_wages_amount`, `employees_paid_back_wages`,
`civil_penalty_amount` (WHD; null for OSHA rows), `details` (OSHA: close-conference and
case-modified dates, owner code, advance notice, union status, employees in establishment,
reporting id, state-plan flag, mailing address, industry flags; WHD: FLSA repeat-violator
flag and the non-zero statute columns), `load_date`, `source_url`, `source_file`,
`fetched_at`.

A run summary (filters, file size and parts, the file's column list, rows scanned, rows
without an open date, the file's oldest and newest open dates, matches, requests, bytes,
seconds, the portal's catalogue entry) is stored as `RUN_SUMMARY` in the run's key-value
store.

### Pricing (pay per event)

| Event | Price |
|---|---|
| `run-start` — once per run | $0.10 |
| `record` — per row written | $0.005 |

The default pull (≤ 300 rows) costs at most $1.60; 1,000 rows cost $5.10. Rows stop when
your run's maximum charge is reached; the run summary says so.

### Operator

Steelyard Ventures LLC (RetrainMap) — info@steelyardclinical.com. Not affiliated with the
Department of Labor, OSHA or WHD. The Actor writes only to its own dataset and key-value
store; it stores no credentials and sends nothing else.

# Actor input Schema

## `dataset` (type: `string`):

osha\_inspection = OSHA inspections (portal dataset OSHA/inspection, ~5.2 million rows, 1.4 GB, refreshed weekly). whd\_whisard = Wage and Hour Division concluded compliance actions (portal dataset WHD/enforcement, ~370,000 rows, 200 MB; concluded cases only, so recent months are sparse).

## `state` (type: `string`):

Optional USPS state code of the inspected site / employer, e.g. NC. Empty = every state.

## `city` (type: `string`):

Optional city of the site / employer, matched case-insensitively and exactly (e.g. Charlotte).

## `employer_contains` (type: `string`):

Optional case-insensitive substring of the establishment name (OSHA) or the trade name / legal name (WHD), e.g. amazon, restaurant.

## `date_from` (type: `string`):

Optional. Applies to the inspection OPEN\_DATE (OSHA) or the case FINDINGS\_START\_DATE (WHD). When both dates are empty the Actor uses the last 90 days (today minus 90 days through today, UTC).

## `date_to` (type: `string`):

Optional. Inclusive upper bound on the open date.

## `max_records` (type: `integer`):

Keep the newest rows (by open date) up to this many. The whole bulk file is always scanned, so a larger cap costs no extra transfer.

## `parallel_downloads` (type: `integer`):

How many bulk-file parts are fetched at once with HTTP Range requests (the OSHA file has 104 parts of ~14 MB, the WHD file 8 parts of ~25 MB). Higher is faster; the ceiling is 8 to stay polite.

## `contact_email` (type: `string`):

Sent in the standard From: request header so the data owner can reach the operator (RFC 9110 s10.1.2).

## Actor input object example

```json
{
  "dataset": "osha_inspection",
  "state": "NC",
  "max_records": 300,
  "parallel_downloads": 6,
  "contact_email": "info@steelyardclinical.com"
}
```

# Actor output Schema

## `results` (type: `string`):

One normalised row per OSHA inspection or WHD compliance case: id, employer, address, NAICS, open/close dates, type and scope, violations, back wages and penalties where present, source URL.

## `results_csv` (type: `string`):

The same rows as a CSV file.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "state": "NC"
};

// Run the Actor and wait for it to finish
const run = await client.actor("retrainmap/dol-enforcement").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "state": "NC" }

# Run the Actor and wait for it to finish
run = client.actor("retrainmap/dol-enforcement").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "state": "NC"
}' |
apify call retrainmap/dol-enforcement --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,retrainmap/dol-enforcement"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/YMBpROeBuCOVGHymH/builds/tXZkQiNgWhAQ1bawP/openapi.json
