> ## Documentation Index
> Fetch the complete documentation index at: https://docs.canary.effectiveai.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Check an employer’s OSHA record

> Find an employer and read its injury rates, inspections and citations.

OSHA publishes its data one workplace at a time, and most of them have no FEIN. Effective groups
those rows into employers, so you can read one employer's safety history in a few calls. Use it
to check a risk before you quote, and again at renewal.

Everything here is read-only. Agents can make the same calls over MCP; see
[Use with Claude](/getting-started/claude).

## Before you start

Follow [connection setup](/guides/index#connect-once) first. Your organization also needs the OSHA
dataset turned on. Until it is, every request returns `403 dataset_not_enabled` with
`"dataset": "osha"`. Ask your Effective contact, or email
[support@effectiveailabs.com](mailto:support@effectiveailabs.com), to have it turned on.

## How employers and sites work

OSHA's datasets don't share a common key, so Effective links them in two steps:

* A **site** is one workplace. OSHA rows join a site when they share a street address, a ZIP code
  and the first word of the name.
* An **employer** is a group of sites. Sites join by FEIN when OSHA has one. Otherwise they join by
  a FEIN found under the same name in the same state, or by the same name in the same state.

Employer IDs look like `emp_8356d81fe525d4a7971c`, and site IDs look like
`site_3f9a1c27b4e8d05a6c12`. Save these IDs. A FEIN is a good way to find an employer, but it isn't
the ID.

Effective rebuilds these groups after each weekly OSHA load, and `dataVersion` changes when it
does. IDs stay the same as long as the name, address and FEIN behind them don't change. If a saved
ID ever returns `404`, match the employer again.

## The journey

| Step | Operation |
| - | - |
| Find the employer | `GET /insurance/employers/match` |
| Read its OSHA profile | `GET /insurance/employers/{employerId}/osha-profile` |
| See what happened, and when | `GET /insurance/employers/{employerId}/events` |
| Look at each workplace | `GET /insurance/employers/{employerId}/sites` |
| Compare with its industry | `GET /insurance/osha/incidence-rates` |

The examples follow Sunshine Roofing, a fictional Florida roofer with three sites.

## Find the employer

Send a FEIN, a name, or both. Dashes in the FEIN are fine. Add `address`, `city`, `state`, `zip` or
`naics` (a 2–6 digit prefix) to help rank the candidates.

```bash theme={null}
curl --request GET \
  --url "https://api.canary.effectiveai.app/api/v2/insurance/employers/match?fein=59-1234567&name=Sunshine%20Roofing&state=FL" \
  --header "Authorization: Bearer $EFFECTIVE_API_KEY"
```

```json Response theme={null}
{
  "candidates": [
    {
      "employer": {
        "id": "emp_8356d81fe525d4a7971c",
        "name": "SUNSHINE ROOFING LLC",
        "aliases": ["SUNSHINE ROOFING"],
        "feins": ["591234567"],
        "naics": "238160",
        "states": ["FL"],
        "siteCount": 3,
        "firstSeen": "2019-04-09",
        "lastSeen": "2026-09-22"
      },
      "confidence": 0.98,
      "matchedOn": ["fein", "name", "state"]
    }
  ],
  "dataVersion": "dv_20261015T230438.512Z"
}
```

* `confidence` runs from 0 to 1. Use it to rank candidates; it isn't a probability.
* `matchedOn` lists what agreed: any of `fein`, `name`, `address`, `zip`, `city`, `state` and
  `naics`.
* If the FEIN isn't on file, matching still tries the name and address.
* You get up to 5 candidates, or up to 20 with `limit`. Candidates under 0.3 are left out.
* An empty `candidates` list means nothing on file matched. It isn't a clean record.

Copy `employer.id`. To read the same summary later, call `GET /insurance/employers/{employerId}`.

## Read the OSHA profile

The profile sums up an employer's recent years in one response. `years` sets how many, from 1 to
10 (default 5):

```bash theme={null}
curl --request GET \
  --url "https://api.canary.effectiveai.app/api/v2/insurance/employers/emp_8356d81fe525d4a7971c/osha-profile?years=3" \
  --header "Authorization: Bearer $EFFECTIVE_API_KEY"
```

```json Response theme={null}
{
  "employerId": "emp_8356d81fe525d4a7971c",
  "siteId": null,
  "dataVersion": "dv_20261015T230438.512Z",
  "window": { "from": "2023-01-01", "to": "2026-10-15" },
  "years": [
    {
      "year": 2025,
      "coverage": "notOnFile",
      "sitesFiled": 0,
      "headcount": null,
      "hours": null,
      "recordableCases": null,
      "dartCases": null,
      "trcRate": null,
      "dartRate": null,
      "dafwDays": null,
      "deaths": null,
      "path": "/insurance/osha/300a-summaries?employerId=emp_8356d81fe525d4a7971c&year=2025"
    },
    {
      "year": 2024,
      "coverage": "filed",
      "sitesFiled": 2,
      "headcount": 80,
      "hours": 166400,
      "recordableCases": 9,
      "dartCases": 4,
      "trcRate": 10.82,
      "dartRate": 4.81,
      "dafwDays": 61,
      "deaths": 0,
      "path": "/insurance/osha/300a-summaries?employerId=emp_8356d81fe525d4a7971c&year=2024"
    },
    {
      "year": 2023,
      "coverage": "filed",
      "sitesFiled": 2,
      "headcount": 84,
      "hours": 174720,
      "recordableCases": 12,
      "dartCases": 6,
      "trcRate": 13.74,
      "dartRate": 6.87,
      "dafwDays": 112,
      "deaths": 1,
      "path": "/insurance/osha/300a-summaries?employerId=emp_8356d81fe525d4a7971c&year=2023"
    }
  ],
  "inspections": {
    "total": 2,
    "byType": { "fatalityOrCatastrophe": 1, "planned": 1 },
    "path": "/insurance/osha/inspections?employerId=emp_8356d81fe525d4a7971c&openDateFrom=2023-01-01"
  },
  "citations": {
    "serious": 1,
    "willful": 1,
    "repeat": 0,
    "other": 0,
    "path": "/insurance/employers/emp_8356d81fe525d4a7971c/events?types=citation&since=2023-01-01"
  },
  "penalties": {
    "initial": 177454,
    "current": 124216,
    "path": "/insurance/employers/emp_8356d81fe525d4a7971c/events?types=citation&since=2023-01-01"
  },
  "severeInjuries": {
    "reports": 0,
    "hospitalized": 0,
    "amputations": 0,
    "path": "/insurance/osha/severe-injury-reports?employerId=emp_8356d81fe525d4a7971c&eventDateFrom=2023-01-01"
  },
  "fatalities": {
    "byReportingSource": { "accidentInvestigations": 1, "annualSummaries": 1 },
    "path": "/insurance/osha/accidents?employerId=emp_8356d81fe525d4a7971c&fatality=true&eventDateFrom=2023-01-01"
  }
}
```

### Yearly injury rates

`years` runs newest first and ends at the latest year of Form 300A summaries Effective has loaded.
Form 300A is the yearly injury summary that many employers file with OSHA.

* `"coverage": "filed"` means at least one site filed for that year. `sitesFiled` says how many.
* `"coverage": "notOnFile"` means OSHA has no summary on file for that year, so the figures are
  `null`. Many small employers never have to file. It isn't a clean record.
* `trcRate` is recordable cases × 200,000 ÷ hours worked. For 2023 that's
  12 × 200,000 ÷ 174,720 = 13.74.
* `dartRate` is the same rate for cases with days away from work or restricted work.

These are OSHA's standard rates per 100 full-time workers, so you can compare employers of any
size.

### Inspections, citations and penalties

The other figures cover `window`, from 1 January of the first year to today.

* `inspections.byType` counts inspections by OSHA's reason, such as `planned`, `complaint` or
  `fatalityOrCatastrophe`.
* `citations` counts serious, willful, repeat and other citations.
* `penalties` are in US dollars. `initial` is what OSHA first proposed, and `current` reflects
  settlements.
* `fatalities.byReportingSource` keeps each OSHA source separate. The same death can appear in an
  accident investigation and in a yearly summary, so don't add them together.

Every `path` is an API path, relative to `/api/v2`, that lists the OSHA rows behind that number.
Use it to show your work. Add `siteId` to read the profile for one workplace.

## See what happened, and when

Events put an employer's OSHA activity on one timeline, newest first. Filter with `types`
(comma-separated), `since` and `until` (inclusive event dates), and `siteId`:

```bash theme={null}
curl --request GET \
  --url "https://api.canary.effectiveai.app/api/v2/insurance/employers/emp_8356d81fe525d4a7971c/events?types=inspection,citation,accident&since=2023-01-01&until=2024-12-31" \
  --header "Authorization: Bearer $EFFECTIVE_API_KEY"
```

```json Response theme={null}
{
  "events": [
    {
      "type": "citation",
      "source": "osha",
      "date": "2024-01-26",
      "siteId": "site_3f9a1c27b4e8d05a6c12",
      "title": "Cited under 19260503 A01 (serious)",
      "severity": "serious",
      "path": "/insurance/osha/inspections/1500001/violations/01001"
    },
    {
      "type": "citation",
      "source": "osha",
      "date": "2024-01-26",
      "siteId": "site_3f9a1c27b4e8d05a6c12",
      "title": "Cited under 19260501 B13 (willful)",
      "severity": "serious",
      "path": "/insurance/osha/inspections/1500001/violations/02001"
    },
    {
      "type": "inspection",
      "source": "osha",
      "date": "2023-08-01",
      "siteId": "site_3f9a1c27b4e8d05a6c12",
      "title": "OSHA inspection opened (fatality or catastrophe)",
      "severity": "fatal",
      "path": "/insurance/osha/inspections/1500001"
    },
    {
      "type": "accident",
      "source": "osha",
      "date": "2023-07-31",
      "siteId": "site_3f9a1c27b4e8d05a6c12",
      "title": "Employee killed in fall from roof",
      "severity": "fatal",
      "path": "/insurance/osha/accidents/900001"
    }
  ],
  "nextCursor": null
}
```

* `type` is `annual_summary`, `severe_injury`, `inspection`, `citation` or `accident`.
* `severity` is `fatal`, `severe`, `serious` or `other`. Willful and repeat citations count as
  `serious`.
* `path` reads the OSHA row behind the event. [Read OSHA’s own rows](/guides/osha-source-data)
  explains those rows.
* An accident that reached more than one of an employer's sites is still one event. Filter by any
  of those sites and it's there, with that `siteId`.

Lists return 25 items by default, and up to 100 with `limit`. While `nextCursor` isn't null, send
it as `cursor` with the same filters. [Pagination and recovery](/guides/pagination-and-recovery)
has the details.

## Look at each workplace

```bash theme={null}
curl --request GET \
  --url "https://api.canary.effectiveai.app/api/v2/insurance/employers/emp_8356d81fe525d4a7971c/sites?state=FL" \
  --header "Authorization: Bearer $EFFECTIVE_API_KEY"
```

```json Response (first of three sites) theme={null}
{
  "sites": [
    {
      "id": "site_3f9a1c27b4e8d05a6c12",
      "employerId": "emp_8356d81fe525d4a7971c",
      "name": "SUNSHINE ROOFING LLC",
      "address": "4410 W HILLSBOROUGH AVE",
      "city": "TAMPA",
      "state": "FL",
      "zip": "33614",
      "naics": "238160",
      "identifiers": [
        { "type": "fein", "value": "591234567" },
        { "type": "osha_establishment", "value": "3165432" },
        { "type": "osha_establishment", "value": "3398120" }
      ],
      "latestHeadcount": 46,
      "firstSeen": "2019-04-09",
      "lastSeen": "2024-12-31"
    }
  ],
  "nextCursor": null
}
```

A site can carry more than one OSHA establishment ID, because OSHA sometimes issues a new one for
the same workplace. Read one site with `GET /insurance/employers/{employerId}/sites/{siteId}`.

## Compare with its industry

Industry rates use every Form 300A filed in an industry, so you can see how an employer compares
with its peers:

```bash theme={null}
curl --request GET \
  --url "https://api.canary.effectiveai.app/api/v2/insurance/osha/incidence-rates?naics=2381&state=FL" \
  --header "Authorization: Bearer $EFFECTIVE_API_KEY"
```

For 2023, Florida employers in NAICS 2381, which includes roofing, had a `trcRate` of 4.07.
Sunshine Roofing's is 13.74. See
[Compare with industry rates](/guides/osha-source-data#compare-with-industry-rates) for the full
response.

## What OSHA data covers

* Form 300A summaries come only from workplaces OSHA requires to file online: generally those with
  20 or more employees in designated industries, or with 250 or more.
* Case detail (Forms 300 and 301) starts with 2023 filings.
* Inspections, severe injury reports and accident investigations cover employers of any size. They
  carry no EIN, so Effective places them by name and address.
* No OSHA data means nothing is on file. It isn't a clean record.

## Handle errors

| Response | Meaning and next step |
| - | - |
| 400 `invalid_request` | Fix the request: an unknown or repeated parameter, or a value out of range. |
| 400 `invalid_cursor` | The filters or limit changed since the cursor was issued. Start the list again. |
| 403 `dataset_not_enabled` | OSHA isn't turned on for your organization yet. Ask your Effective contact. |
| 404 `not_found` | The employer or site isn't on file. Match the employer again to get its current ID. |

See [Errors](/getting-started/errors) for the rest.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.