# OSHA Inspections by Company + EPA Enforcement Report (`owlabee/osha-epa-enforcement-report`) Actor

Look up OSHA inspections, violations and penalties (DOL Data API) and EPA ECHO enforcement cases by company name, facility ID, state or ZIP. One normalized record per inspection or case, a per-company summary, name-match confidence, and new-record monitoring. Pay per record.

- **URL**: https://apify.com/owlabee/osha-epa-enforcement-report.md
- **Developed by:** [Owlabee](https://apify.com/owlabee) (community)
- **Categories:** Lead generation, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 enforcement records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## OSHA Inspections by Company + EPA Enforcement Report

Look up **OSHA inspections by company**: enter a company name, facility ID, state or ZIP and get every OSHA inspection with its violations and penalties (DOL Data API) and the company's **EPA ECHO enforcement cases**, one normalized JSON record each, plus a per-company summary and a name-match confidence. Schedule it to watch suppliers or contractors for new records.

### What it does

| Source | Agency data | How it is queried | Key |
|---|---|---|---|
| `osha` | OSHA inspections, citations (violations) and penalties from the U.S. Department of Labor's enforcement data | DOL Data API v4 (`apiprod.dol.gov`), datasets `OSHA/inspection` and `OSHA/violation` | **Your own free DOL API key is required** (see below) |
| `epa` | EPA and state enforcement cases recorded in ECHO (Enforcement and Compliance History Online): case number and name, category, status, primary law (CAA, CWA, RCRA, …), filing and settlement dates, federal and state/local penalties, outcome | ECHO web services (`echodata.epa.gov`): facility search, then the case lists of matched facilities | None |

**OSHA needs a DOL API key.** The Department of Labor's Data API does not answer without one. Keys are free: sign in at [dataportal.dol.gov](https://dataportal.dol.gov), open your account's API keys page, and paste the key into the `dolApiKey` input (stored as an encrypted secret and only sent to `apiprod.dol.gov`). Without a key the Actor still runs EPA and writes one `DOL_API_KEY_MISSING` item for OSHA.

Typical uses: due diligence on a company or facility before a deal or loan, supplier and contractor vetting, insurance underwriting, and monitoring a list of companies for new inspections or cases on a schedule. Records describe what the agencies published; they are not a rating of any company.

Checking contractors too? [License Verification API — TDLR, DBPR, DORA, WA DOH, NPI](https://apify.com/owlabee/us-license-verifier) verifies their professional licenses.

### Why this Actor

| | This Actor | Typical Actor in this category | Do it yourself |
|---|---|---|---|
| Agencies | OSHA and EPA in one run, one output shape | One agency per Actor | Two APIs with different query models (DOL filter objects; ECHO query ids) |
| Matching | Every record carries `matchBasis` and `matchConfidence` (high, medium, low); different firms are never merged | Raw name search results | Your own fuzzy matching |
| Penalties | OSHA citations summed per inspection (current and initial penalty, counts by violation type); EPA federal plus state/local penalties | Often the inspection list only | Join the violation table yourself |
| Company view | Optional summary record per company: counts, penalties, most recent action, matched names | None | Spreadsheet work |
| Monitoring | `monitor` mode writes only new or changed records since the last run, with a webhook | Re-run and diff by hand | Your own state store |
| Pricing unit | Per record, per company search and per extra agency page; nothing per minute | Per result | Server time and upkeep |
| Keys and proxies | No proxy; EPA needs no key; OSHA uses your free DOL key | Varies | Same keys |

- **One shape across agencies.** `actionDate`, `status`, `penaltyUsd` and `sourceUrl` mean the same thing on an OSHA inspection and an EPA case, so a vetting or underwriting workflow has one rule set.
- **Honest matching.** Agencies index establishments and facilities by name, not by a company id. The Actor tells you how each record matched instead of guessing.
- **Monitoring built in.** Schedule a list of suppliers and receive only what is new.

### How to use

1. Enter one or more **company names** (and optionally a **state** or **ZIP** to narrow common names), or exact **identifiers** (`osha:<inspection number>`, `frs:<12-digit EPA FRS id>`).
2. Choose the **sources**; for OSHA paste your free **DOL API key**. Optionally set a **date range** and the **minimum match confidence**.
3. Click **Start**. Records appear in the dataset as each company finishes; download them as JSON, CSV or Excel, or read them through the API.

#### How name matching works

| `matchConfidence` | `matchBasis` | Meaning |
|---|---|---|
| `high` | `name-exact`, `osha-activity-nr`, `epa-frs-id` | Names equal after removing case, punctuation and suffixes such as Inc, LLC, Corp; or an exact identifier lookup |
| `medium` | `name-prefix`, `facility-name` | Your name is a whole-word prefix of the agency's name ("Tesla" → "TESLA MOTORS INC") |
| `low` | `name-tokens`, `name-substring`, `facility-name` | Your words appear elsewhere in the name ("10045 TESLA ROAD") or only as part of a word; or an EPA case at a matched facility that is filed under another party's name (`matchNote` says so) |

`minMatchConfidence` (default `medium`) drops weaker matches before they are written or charged. "DBA" names are matched on each part. The summary record lists every distinct matched name with its own count, so two firms with similar names stay visibly separate.

#### Quick start input

```json
{
  "companies": ["Tesla"],
  "state": "CA",
  "sources": ["epa"]
}
```

This is the prefilled input: no key needed, about 5 seconds, three EPA cases and a summary record.

#### Ready-to-run inputs

Supplier vetting across both agencies for the last five years (needs your DOL key):

```json
{
  "companies": ["Acme Roofing", "Mistras Group"],
  "state": "TX",
  "dateFrom": "2021-01-01",
  "sources": ["osha", "epa"],
  "dolApiKey": "<your free DOL API key>",
  "minMatchConfidence": "medium"
}
```

One facility and one inspection by identifier:

```json
{
  "identifiers": ["frs:110000482898", "osha:316113513"],
  "dolApiKey": "<your free DOL API key>"
}
```

Weekly monitor of a supplier list with a webhook:

```json
{
  "companies": ["Tesla", "Rivian"],
  "sources": ["epa"],
  "monitor": true,
  "stateStoreName": "supplier-enforcement-watch",
  "webhookUrl": "https://example.com/hooks/enforcement"
}
```

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `companies` | array of strings | — | Company or establishment names, one per line |
| `identifiers` | array of strings | — | `osha:<inspection activity number>` or `frs:<12-digit EPA FRS registry id>` |
| `state` | string | — | Two-letter state code for the site or facility |
| `zip` | string | — | Five-digit ZIP code |
| `dateFrom`, `dateTo` | date | — | Action date window (OSHA: inspection opened; EPA: case filed, else settled) |
| `sources` | array | `["osha","epa"]` | Agencies to query |
| `dolApiKey` | secret string | — | Your free DOL Data API key; required for OSHA |
| `minMatchConfidence` | `high` / `medium` / `low` | `medium` | Weakest name match to keep |
| `includeSummary` | boolean | `true` | One `company-summary` record per company |
| `includeViolations` | boolean | `true` | OSHA citations and penalties per inspection |
| `epaAllFacilities` | boolean | `false` | Check every matched EPA facility, not only those ECHO flags with formal actions or penalties |
| `maxRecordsPerCompany` | integer | 100 | Most recent records kept per company and agency (max 5,000) |
| `maxFacilitiesPerCompany` | integer | 25 | EPA facilities checked per company (max 500) |
| `maxResults` | integer | 1,000 | Items written across the run (max 50,000) |
| `timeBudgetSecs` | integer | 300 | Wall time per agency over the run (30–1,800) |
| `monitor` | boolean | `false` | Write only new or changed records since the last run |
| `stateStoreName` | string | `osha-epa-enforcement-report-state` | Key-value store for monitor snapshots |
| `webhookUrl` | string | — | POST a JSON run summary and the items written |

### Output example

An EPA case (from the quick-start run on 2026-11-01; `raw` shortened):

```json
{
  "recordType": "enforcement-case",
  "agency": "EPA",
  "recordId": "epa:09-2019-0029",
  "query": "Tesla",
  "entityName": "Tesla Motors, Inc.",
  "facilityName": "TESLA MOTORS INC",
  "facilityRegistryId": "110000482898",
  "address": "45500 FREMONT BLVD",
  "city": "FREMONT",
  "state": "CA",
  "zip": "94538",
  "naicsCode": "336111",
  "actionDate": "2019-03-28",
  "closedDate": null,
  "actionType": "Administrative - Formal",
  "status": "Final Order Issued",
  "penaltyUsd": 31000,
  "lawOrProgram": "RCRA",
  "outcome": "Final Order With Penalty",
  "sourceUrl": "https://echo.epa.gov/enforcement-case-report?id=09-2019-0029",
  "matchBasis": "facility-name",
  "matchConfidence": "medium",
  "matchedName": "TESLA MOTORS INC",
  "fetchedAt": "2026-11-01T13:01:08.211Z",
  "raw": {
    "case": { "CaseNumber": "09-2019-0029", "CourtDocketNumber": "RCRA(3008)-09-2019-0029", "SEPCost": "$55,000.00", "Lead": "EPA", "...": "..." },
    "facility": { "RegistryID": "110000482898", "FacFormalActionCount": "1", "FacTotalPenalties": "$275,000", "...": "..." }
  }
}
```

An OSHA inspection has the same top-level fields plus `initialPenaltyUsd`, `violationCount` and `violationsByType` (`serious`, `willful`, `repeat`, `other`, `unclassified`); `status` is `open` until OSHA records a closing date, `actionType` is the inspection type (Complaint, Planned, Accident, Referral, Fatality/catastrophe, …), `sourceUrl` points to the OSHA inspection detail page, and `raw` holds the `inspection` row and its `violations`.

The per-company summary record:

```json
{
  "recordType": "company-summary",
  "query": "Tesla",
  "sources": ["epa"],
  "recordCount": 3,
  "countsByAgency": { "EPA": 3 },
  "penaltiesByAgencyUsd": { "EPA": 581000 },
  "totalPenaltiesUsd": 581000,
  "openCount": 0,
  "countsByConfidence": { "high": 0, "medium": 3, "low": 0 },
  "mostRecentAction": { "recordId": "epa:09-2022-3503", "agency": "EPA", "actionDate": "2022-02-17", "actionType": "Administrative - Formal", "entityName": "Tesla Motors CAFO" },
  "earliestActionDate": "2010-01-11",
  "matchedNames": [
    { "name": "TESLA MOTORS INC", "agency": "EPA", "confidence": "medium", "records": 2 },
    { "name": "TESLA MOTORS", "agency": "EPA", "confidence": "medium", "records": 1 }
  ],
  "incomplete": false,
  "errors": []
}
```

Error items look like `{ "recordType": "error", "query": "Acme", "source": "osha", "error": "DOL_API_KEY_REJECTED", "errorMessage": "…" }`. Codes: `DOL_API_KEY_MISSING`, `DOL_API_KEY_REJECTED`, `QUERY_TOO_BROAD` (ECHO refuses a name matching too many facilities; add a state or ZIP), `TIME_BUDGET`, `INVALID_IDENTIFIER`, `SOURCE_ERROR`.

### Alerts and delivery

- **Schedules.** Create a schedule in the Apify Console (weekly is typical for vendor lists) with `monitor: true`; each run writes only records that are new or whose status, penalty or closing date changed (`changeType: "new"` or `"changed"`, with `changedFields` and the `previous` values). The first run is a baseline that writes, and charges for, every current record.
- **The Actor's own `webhookUrl`.** After every run the Actor POSTs one JSON document: `actor`, `runId`, counts (`produced`, `records`, `summaries`, `errors`, `newOrChanged`, `searches`, `extraPages`), per-source `requests`, `mbReceived`, `seconds` and `abandoned`, `monitor`, `baseline`, `charges`, `limitReached`, `finishedAt`, and `items`, up to 500 of the items written in this run without their `raw` fields. Delivery has a 10 s timeout and two retries; a failing endpoint never fails the run and is recorded as `webhookDelivered: false` in the `SUMMARY` record.
- **Apify integrations.** The Actor's **Integrations** tab connects Slack, Make, Zapier, Google Sheets, email or a generic webhook on run events (`ACTOR.RUN.SUCCEEDED`, `ACTOR.RUN.FAILED`).
- **API.** `POST https://api.apify.com/v2/acts/owlabee~osha-epa-enforcement-report/run-sync-get-dataset-items?token=<APIFY_TOKEN>` with the input as the body returns the items in one call; the run's `SUMMARY` record is at `GET /v2/key-value-stores/{storeId}/records/SUMMARY`.

### Pricing

Pay per event. Set a **maximum cost per run** in the run options to cap spend.

| Event | Price | Charged for |
|---|---|---|
| Enforcement record | $0.005 | Each inspection or case record written, each company summary record and each error item |
| Company search | $0.01 | Each company name or identifier per agency queried, whatever it returns |
| Extra agency page | $0.002 | Each further agency request for that search: next OSHA result pages, OSHA violation batches, ECHO facility pages, per-facility case lists and case batches |
| Actor start | $0.00005 | Apify platform event |

**Example:** 1,000 records ≈ **$5.00**, plus $0.01 per company and agency searched and $0.002 per extra page. The quick-start run (one company, EPA only: 1 search, 5 extra pages, 3 cases and a summary) costs $0.04. A company with 20 OSHA inspections and 5 EPA cases across both agencies costs about $0.16. A weekly monitor of 50 companies on both agencies with nothing new costs the searches and pages only, about $1.50 per run.

Store pricing discounts: Scale plan (Silver) users pay 10% less per event, Business plan (Gold) users 20% less.

### Limits and fair use

- Requests to each agency are spaced at least 0.5 s apart; each request has a 30 s deadline including two retries, and a `Retry-After` wait is capped at 10 s.
- Each agency has a time budget for the run (`timeBudgetSecs`, default 300 s, max 1,800 s; at roughly 1–3 s per company per agency, raise it for lists over about 100 companies); one that returns nothing usable for 60 s in a row is abandoned for the rest of the run, and the companies still waiting for it get a charged `TIME_BUDGET` item. A rejected DOL key stops OSHA for the run with a single error item. Default run memory is 512 MB.
- ECHO's company-name filter for cases is not usable, so EPA cases are found through facilities: by default only facilities that ECHO flags with formal enforcement actions or penalties are checked (`epaAllFacilities` checks all), up to `maxFacilitiesPerCompany`. Very broad names can exceed ECHO's query limit (`QUERY_TOO_BROAD`); add a state or ZIP.
- OSHA inspections are returned newest first; the name filter matches anywhere in the establishment name and the Actor then grades each match, so a short or generic name scans more rows. Federal OSHA and State Plan inspections are both in the DOL data as published.
- Agency data lag the agencies' internal systems; dates, statuses and penalties can change after an inspection or case is first published.

### Related Actors

Other pay-per-event Actors from the same account, all limited-permission and agent-friendly:

- [License Verification API — TDLR, DBPR, DORA, WA DOH, NPI](https://apify.com/owlabee/us-license-verifier) — verify contractor and professional licenses.
- [PACER RSS Docket Monitor — New Federal Court Filings](https://apify.com/owlabee/federal-court-docket-monitor) — watch federal courts for new filings naming a company.
- [Building Permits Scraper — Roofing & Construction Leads](https://apify.com/owlabee/building-permits-scraper) — permits with contractor names to vet.
- [Grants.gov API & SAM.gov Scraper — Federal Grants Feed](https://apify.com/owlabee/gov-opportunity-feed) — federal contract and grant opportunities.

### Use from AI agents (MCP)

Pin this Actor in the Apify MCP server with `https://mcp.apify.com?tools=owlabee/osha-epa-enforcement-report`, or let the agent find it with `search-actors`. It is pay-per-event with limited permissions. Prompts that map onto the input:

1. "List every EPA enforcement case for Tesla facilities in California with penalties and dates."
2. "Pull OSHA inspections, violations and penalties for Mistras Group in North Carolina since 2015 and summarize them."
3. "Every Monday, check my 50 suppliers for new OSHA inspections or EPA cases and POST only the new ones to my webhook."

```json
{
  "tool": "call-actor",
  "arguments": {
    "actor": "owlabee/osha-epa-enforcement-report",
    "input": { "companies": ["Tesla"], "state": "CA", "sources": ["epa"] }
  }
}
```

### FAQ

**Does this need proxies or an API key?** No proxies. EPA ECHO needs no key. OSHA data comes from the DOL Data API, which requires a free key from dataportal.dol.gov in `dolApiKey`; nothing else is needed.

**How is cost controlled?** Set `maxRecordsPerCompany`, `maxFacilitiesPerCompany`, `maxResults` and the run's maximum total charge. Every item is charged when it is saved, and the run stops cleanly at any limit. `minMatchConfidence` drops weak matches before they are charged.

**Why did I get records for a different company?** Agencies record establishment and facility names, not company ids. Check `matchConfidence`, `matchBasis` and `matchNote`; raise `minMatchConfidence` to `high`, add a state or ZIP, or look up exact identifiers. The Actor never merges two names into one company; the summary lists each matched name separately.

**Does it cover state OSHA plans and state environmental agencies?** OSHA data includes State Plan inspections that DOL publishes. EPA ECHO includes state-led and locally-led cases that states report to EPA (`raw.case.Lead`); state agencies' own systems are not queried.

**How does monitor mode work?** Each company's records are fingerprinted (status, penalty, closing date) in the named key-value store. Later runs write only new or changed records and charge the same searches and pages as a normal run. A source that fails during a run keeps its earlier snapshot, so nothing is reported twice when it recovers.

**Can I try it for free?** Yes. The Apify free plan includes monthly platform credit, and the quick-start input costs about four cents.

### Changelog

- **2026-11-01** — First release: OSHA inspections, violations and penalties (DOL Data API, user key) and EPA ECHO enforcement cases, name and identifier lookups, match confidence, per-company summary, monitor mode with webhook.

### Legal

This Actor reads public enforcement records from two official United States government APIs: the Department of Labor's Data API (OSHA inspections and violations, using the DOL API key you supply under DOL's terms of use) and the EPA's Enforcement and Compliance History Online (ECHO) web services. It does not log in, bypass access controls or use proxies, and it sends your company list only to those two agencies. Use the data in compliance with each agency's terms and applicable law.

The output reproduces agency records as published. An inspection, citation or enforcement case is not a finding that a company broke the law or operates unsafely: OSHA citations can be contested, reduced or withdrawn, EPA cases are often settled without an admission, and both agencies publish corrections and disclaimers about the completeness and timeliness of their data. The Actor makes no claim about any company's legality, safety or compliance; it does not score or rank companies.

Records are matched to the names and identifiers you enter by fuzzy name matching, and every record carries a match-confidence flag. Establishments with similar names, franchisees, subsidiaries and unrelated companies can share a name, so verify the match (address, state, EPA registry ID, OSHA establishment ID) before relying on a record.

Establishment names in OSHA data can be the names of individuals (sole proprietors and small contractors). This Actor is not a consumer reporting agency and its output is not a consumer report: do not use it, in whole or in part, to decide an individual's eligibility for employment, credit, insurance, housing or any other purpose covered by the Fair Credit Reporting Act or similar laws. Commercial due diligence on companies, such as underwriting a business policy or vetting a vendor, is your responsibility to conduct in line with the law that applies to you.

# Actor input Schema

## `companies` (type: `array`):

Company or establishment names to look up, one per line. Agencies index records by establishment or facility name, so every match carries a matchBasis and a matchConfidence (high, medium, low) and different firms are never merged. Add a state or ZIP to narrow common names.

## `identifiers` (type: `array`):

Exact lookups, one per line: "osha:<inspection activity number>" (OSHA) or "frs:<12-digit EPA FRS registry id>" (EPA ECHO facility). Matched with high confidence.

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

Two-letter USPS code (for example CA). Restricts OSHA inspections to the site state and EPA facilities to the facility state.

## `zip` (type: `string`):

Five-digit ZIP code of the inspected site or EPA facility.

## `dateFrom` (type: `string`):

Only records whose action date (OSHA inspection opening date; EPA case filing date, or settlement date when no filing date is published) is on or after this date. YYYY-MM-DD.

## `dateTo` (type: `string`):

Only records whose action date is on or before this date. YYYY-MM-DD.

## `sources` (type: `array`):

Which agencies to query. OSHA needs your free DOL Data API key (below); EPA ECHO needs no key.

## `dolApiKey` (type: `string`):

Required for OSHA records. The U.S. Department of Labor gives these keys free at dataportal.dol.gov (sign in, then API keys). Stored encrypted and only sent to apiprod.dol.gov. Without it, OSHA is skipped with one error item and EPA still runs.

## `minMatchConfidence` (type: `string`):

high = names equal after removing punctuation and suffixes such as Inc or LLC; medium = your name is a whole-word prefix of the agency's name ("Tesla" → "TESLA MOTORS INC"); low = the words appear elsewhere in the name or only as a substring, including EPA cases filed under another party's name at a matched facility.

## `includeSummary` (type: `boolean`):

After each company, write one recordType "company-summary" item: counts and penalties per agency, open records, the most recent action, and every matched agency name listed separately.

## `includeViolations` (type: `boolean`):

Fetch OSHA citations for the inspections found (one extra request per 100 inspections) to fill violationCount, violationsByType, penaltyUsd and initialPenaltyUsd.

## `epaAllFacilities` (type: `boolean`):

By default only facilities that ECHO flags with formal enforcement actions or penalties are checked for cases. Turn on to request the case list of every matched facility (slower; one extra request per facility).

## `maxRecordsPerCompany` (type: `integer`):

Most recent records kept per company for each agency.

## `maxFacilitiesPerCompany` (type: `integer`):

Matched EPA facilities checked for enforcement cases per company, those with the most formal actions first.

## `maxResults` (type: `integer`):

Upper bound on items written across the run (records, summaries and error items). Use it with the run's maximum cost to control spend.

## `timeBudgetSecs` (type: `integer`):

Wall time each agency may take over the whole run. A source with 60 s in a row without a usable response is abandoned earlier. Raise it for long company lists.

## `monitor` (type: `boolean`):

For schedules: remember every record seen per company in the state store and write only records that are new, or whose status, penalty or closing date changed (changeType new / changed). The first run is a baseline and writes, and charges for, everything.

## `stateStoreName` (type: `string`):

Named key-value store that holds the monitor snapshots. Use a different name per schedule if two schedules share companies.

## `webhookUrl` (type: `string`):

After the run, the Actor POSTs one JSON document here: run counts, charges, and up to 500 of the items written (in monitor mode, only the new and changed records), without the nested raw fields. Failures are logged, never fatal.

## Actor input object example

```json
{
  "companies": [
    "Tesla"
  ],
  "state": "CA",
  "sources": [
    "epa"
  ],
  "minMatchConfidence": "medium",
  "includeSummary": true,
  "includeViolations": true,
  "epaAllFacilities": false,
  "maxRecordsPerCompany": 100,
  "maxFacilitiesPerCompany": 25,
  "maxResults": 1000,
  "timeBudgetSecs": 300,
  "monitor": false,
  "stateStoreName": "osha-epa-enforcement-report-state"
}
```

# Actor output Schema

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

One item per record: agency, recordId, entityName, address, actionDate, actionType, status, penaltyUsd, lawOrProgram, sourceUrl, matchBasis, matchConfidence and the agency's raw fields under raw; recordType company-summary items carry counts and penalty totals; error items carry error and errorMessage.

## `summary` (type: `string`):

SUMMARY record in the run's default key-value store: counts of records, summaries, errors, searches and extra pages, per-source requests and time, charges, and webhookDelivered.

# 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 = {
    "companies": [
        "Tesla"
    ],
    "state": "CA",
    "sources": [
        "epa"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("owlabee/osha-epa-enforcement-report").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 = {
    "companies": ["Tesla"],
    "state": "CA",
    "sources": ["epa"],
}

# Run the Actor and wait for it to finish
run = client.actor("owlabee/osha-epa-enforcement-report").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 '{
  "companies": [
    "Tesla"
  ],
  "state": "CA",
  "sources": [
    "epa"
  ]
}' |
apify call owlabee/osha-epa-enforcement-report --silent --output-dataset

```

## MCP server setup

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

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/XovswMhEAn65WLSae/builds/VZHZWbexWOzcHa4q3/openapi.json
