Skip to main content

Developers

API documentation.

FastDOL aggregates employer compliance data from every major US federal compliance source plus the UVA Corporate Prosecution Registry into a single REST API. Search by name or EIN, get risk profiles, inspection history, analytics, and structured bulk exports — all from one endpoint.

API at a glance
Base URLapi.fastdol.com/v1
AuthX-Api-Key header
FormatJSON
Rate limit10–60 req/min
Free tier50 lookups/mo

Getting started

  1. Create a free account — 50 lookups/month, no credit card required.
  2. Verify your email — your first API key is generated automatically.
  3. Create or rotate additional keys any time from your account page.
  4. Make your first API call:
curl -H "X-Api-Key: YOUR_API_KEY" \
  "https://api.fastdol.com/v1/employers?name=walmart&state=CA"

Data sources

Every employer profile is an aggregate over the data sources listed below. Source-specific fields use a consistent prefix — osha_*, whd_*, cms_* — so you can identify provenance from the field name alone.

SourceAgencyWhat's in the dataScale
OSHAOccupational Safety and Health AdministrationInspections, violations, penalties, and fatality investigations — with inspection-type and severity breakdowns.2.7M+ inspections
WHDWage and Hour DivisionDepartment of Labor wage-theft investigations with back wages owed and affected employee counts.$4.6B in back wages
MSHAMine Safety and Health AdministrationMine safety violations, inspections, and assessed penalties across all U.S. mining operations.2.5M+ violations
EPAEnvironmental Protection AgencyClean Air, Clean Water, RCRA, and SDWA compliance via EPA ECHO — inspections, formal actions, and penalties.$1.2B in EPA penalties
NLRBNational Labor Relations BoardUnfair labor practice charges and union-representation case history.1.7M+ cases
FMCSAFederal Motor Carrier Safety AdministrationDOT-regulated motor carrier registration, operation type, and safety-basic scores.107K+ DOT-registered carriers
OFLCOffice of Foreign Labor CertificationH-1B, H-2A, and H-2B labor condition applications with prevailing-wage ratios.37K+ LCAs
ITAOSHA Injury Tracking ApplicationOSHA Form 300A self-reported DART and TRIR rates by establishment — employer-submitted, refreshed annually when OSHA publishes the next year's release.162K self-reported establishments
BLSBureau of Labor Statistics (SOII)BLS Survey of Occupational Injuries and Illnesses industry-wide TRIR/DART averages for peer-percentile ranking — refreshed annually with each BLS Table 1 release.1,045 NAICS covered
SAMSystem for Award ManagementFederal debarment, suspension, and ineligibility exclusions — governs who can win federal contracts.572 excluded employers
CMSCenters for Medicare & Medicaid ServicesFive-star ratings, deficiencies, civil money penalties, and staffing hours per resident per day.14.7K nursing facilities
CPSCConsumer Product Safety CommissionConsumer product recalls tied to the responsible manufacturer or distributor.22K+ employers w/ recalls
NHTSANational Highway Traffic Safety AdministrationVehicle recalls and defect complaints tied to OEMs and upfitters.6.6K manufacturers w/ recalls
USAspendingUSAspending.govFederal contracts and assistance (grants, loans) awarded to private and non-profit entities. Refreshed monthly from the Award Data Archive. Attributed at parent-company level via name-pattern matching against our curated parent registry, so a Walmart store profile surfaces Walmart Inc.'s federal totals rather than the (usually zero) per-store number.166M+ federal award records
SECSecurities and Exchange Commission (XBRL companyfacts)Per-public-reporter financial scale — revenue, net income, employee count, total assets — from XBRL-tagged 10-K filings.9K+ public-company filers
SECSecurities and Exchange Commission (Litigation Releases)Formal civil enforcement actions filed in federal court — defendant, date, summary, and penalty amount over a 5-year window.2.5K+ enforcement actions
UVAUVA Corporate Prosecution RegistryFederal corporate prosecutions, plea agreements, DPAs and NPAs — compiled by UVA Law School.33K+ employers w/ prosecutions
Refresh cadence: Counts reflect the 17-source aggregate, refreshed weekly. Recently added fields (federal contracts, CMS, recalls, prosecutions, SAM exclusions) are backfilled historically — every employer profile reflects the full set of sources on every response.

Authentication

Include your API key in the X-Api-Key header with every request. View existing keys (masked) and create new ones on the account page. Each account supports up to 5 active keys; rotating a key gives the old value a 48-hour grace period.

Endpoints

Search employers

GET/v1/employers?name=walmart&state=ID&zip=83669&limit=20&offset=0
ParamTypeDescription
namestringEmployer name (fuzzy match)
einstringExact EIN match
statestring2-letter state code
zipstring5-digit ZIP code
naicsstring4-digit NAICS prefix
parent_onlyboolReturns one result per parent company with aggregate stats. Default false.
limitintResults per page (1-100, default 20)
offsetintPagination offset

Get employer detail

GET/v1/employers/{employer_id}

Lookup by EIN

GET/v1/employers/ein/{ein}?state=CA

Exact EIN lookup. Dashes are optional (94-3067788 or 943067788). When multiple locations share an EIN, add state to narrow. Returns 404 if no employer is found with that EIN.

Coverage note: EIN coverage depends on OSHA ITA filings — establishments with fewer than 250 employees may not appear.

Inspection history

GET/v1/employers/{employer_id}/inspections?limit=20&offset=0

Returns inspection records for an employer, ordered by date (newest first). Counts as 1 lookup against your quota.

Violation detail for an inspection

GET/v1/inspections/{activity_nr}/violations

All citations issued on a single OSHA inspection. activity_nr is the numeric OSHA activity number returned by the inspection history endpoint.

Risk history

GET/v1/employers/{employer_id}/risk-history?limit=90

Per-employer detail records

Each profile links to its underlying per-record detail — paginated, newest-first. All take the employer_id from a search or detail response, accept limit and offset, and count as 1 lookup.

GET/v1/employers/{employer_id}/severe-injuries
GET/v1/employers/{employer_id}/whd-cases
GET/v1/employers/{employer_id}/osha-accidents
GET/v1/employers/{employer_id}/sec-enforcement
GET/v1/employers/{employer_id}/federal-contracts
GET/v1/employers/{employer_id}/peers

In order: OSHA Severe Injury Reports; per-case WHD wage enforcement; OSHA accident & fatality investigations; SEC litigation releases for the parent company; USAspending federal contract & assistance awards; and same-NAICS, same-state peer establishments for benchmarking.

Parent company rollup

GET/v1/employers/parent?name=Amazon&state=CA

Aggregate risk across all locations of a parent company. name is required; add state to disambiguate common names.

Cluster lookups (resolved entities)

Two cluster-grain endpoints surface FastDOL's entity-resolution output directly. Each returns the cluster's confidence_band (high / med / low), the weakest-link match weight, cohesion + fragility flags, and the members of the cluster. Band cutoffs are tied to measured held-out precision (≥97.5% Wilson 95% lower bound at high, ≥98.7% at med); the full methodology document is available under NDA.

GET/v1/establishments/{establishment_id}

A physical-site cluster: all records that share an establishment_id (one address, possibly aggregated across federal sources). Use this to drill from a parent (a multi-site business) to one of its locations and see the underlying records. Singletons return a single member with confidence: null — the record is the establishment by definition; no merge happened.

GET/v1/parents/{company_id}

A rolled-up-business cluster: every establishment (site) under one company_id. The response lists one row per establishment sorted by total OSHA penalty (worst first), each carrying its own establishment-level confidence and aggregated enforcement stats. Drill into a specific site via /v1/establishments/{id} or to a specific record via /v1/employers/{employer_id}.

Singleton semantics: a record with no merge has confidence: null. The cluster id is the record's own employer_id, so calling /v1/establishments/{employer_id}for a singleton returns a one-member response — useful for uniform client code that doesn't need to special-case singletons.

Batch lookup

POST/v1/employers/batch
# Up to 100 items per synchronous request
{
  "lookups": [
    {"name": "Walmart", "state": "ID", "zip": "83669"},
    {"name": "Amazon", "state": "CA"},
    {"name": "Target", "zip": "55403"}
  ]
}

Each item can include name, ein, employer_id, state, zip, and city. The response wraps each input in an object with query, match (the employer profile or null), and confidence, plus top-level matched / unmatched counts. For batches over 100 items, use CSV upload (below), which supports up to 500 rows.

CSV upload

POST/v1/employers/upload-csv

Upload a CSV with employer names. Returns a CSV with risk profiles appended. Max 500 rows, 5MB. Content-Type: multipart/form-data, field name file.

Industry benchmarks

GET/v1/industries/{naics_code}
GET/v1/industries/naics-codes

BLS SOII industry TRIR/DART benchmarks by NAICS. The code must be exactly 4 digits (e.g. 2361); call /v1/industries/naics-codes for the list of covered codes.

Bulk export Enterprise

Pull up to 100,000 employer records matching a structured query — filter, threshold, and sort in a single request. Runs async: submit a job, poll for status, download the file. Requires the export:bulk scope. Contact sales to enable.

Want the entire dataset rather than a filtered slice? Bulk export is capped at 100,000 rows — for a full local copy use Full dataset (snapshots) below.

Request

POST/v1/export
{
  "format": "csv",              // "csv" or "json" (NDJSON)
  "max_rows": 50000,            // 1 - 100,000
  "sort_by": "fatalities",
  "sort_dir": "desc",           // "asc" or "desc" (default desc)
  "filters": {
    "states": ["CA", "TX", "FL"],
    "naics_codes": ["2361", "2362"],
    "min_penalties": 100000,
    "has_fatalities": true
  }
}

→ 202 { "job_id": "...", "status": "queued", "poll_url": "..." }

At least one filter is required. An unfiltered export would scan 2M+ rows and is refused.

Polling

GET /v1/export/{job_id}
→ {
    "job_id": "...",
    "status": "queued" | "running" | "finished" | "failed",
    "row_count": 42187,
    "file_size_bytes": 52428800,
    "download_url": "...",        // present only when status=finished
    "expires_at": "2026-04-23T11:00:00Z"
  }

GET /v1/export/{job_id}/download
→ streams the CSV or NDJSON file (24h retention)
Limits: 3 concurrent jobs per key; 100,000 rows per export; files expire 24 hours after creation. One lookup is charged per submission regardless of row count. Failed exports are refunded automatically.

Full dataset — weekly snapshots Enterprise

The complete dataset as point-in-time Parquet — one file per table, republished every week. This is the path for a full local copy (the bulk export above is for filtered slices up to 100,000 rows). Two calls get you everything: fetch the manifest, then download each file from its presigned URL. Requires the snapshot:read scope.

1. Fetch the manifest

GET/v1/snapshots/latest
curl -s -H "X-Api-Key: $KEY" \
  https://api.fastdol.com/v1/snapshots/latest

→ {
    "snapshot_id": "2026-W22",
    "asof_date": "2026-05-29",
    "total_rows": 180000000,
    "total_size_bytes": 1500000000,
    "files": [
      {
        "table": "employer_profile",
        "format": "parquet",
        "rows": 2250197,
        "size_bytes": 344789695,
        "sha256": "4855575e0c07...",
        "download_url": "https://<r2-host>/...employer_profile.parquet?X-Amz-...",
        "download_url_expires_in_seconds": 21600,
        "status": "ready"
      }
      // ...one entry per table (13 in total)
    ]
  }

Omit the path for the latest snapshot, or pass an id — GET /v1/snapshots/2026-W22 — to pin a specific week. Every call mints fresh presigned URLs.

2. Download every table

Each file carries a presigned download_url (no auth header on the download itself). Loop the manifest with jq:

KEY="your_api_key"

# Pull the manifest, then download each table's Parquet to <table>.parquet
curl -s -H "X-Api-Key: $KEY" \
  https://api.fastdol.com/v1/snapshots/latest > manifest.json

jq -r '.files[] | select(.status == "ready")
       | [.table, .download_url] | @tsv' manifest.json \
| while IFS=$'\t' read -r table url; do
    echo "downloading $table"
    curl -fSL -o "$table.parquet" "$url"
  done

3. Verify integrity (optional)

jq -r '.files[] | "\(.sha256)  \(.table).parquet"' manifest.json | sha256sum -c -
# employer_profile.parquet: OK
# inspection_detail.parquet: OK
# ...
Presigned URLs expire after 6 hours and are minted fresh on every manifest call — if a long download outlives the window, re-fetch the manifest and resume. Subscribe a webhook to snapshot.ready to be notified the moment each weekly snapshot publishes, instead of polling for a new snapshot_id.

Response format

Each employer result includes flat fields plus nested objects for benchmarks, self-reported data, accident details, and analytics. The full response shape includes ~80 fields; the OpenAPI spec linked above has the complete schema.

{
  "results": [
    {
      "employer_id": "uuid",
      "employer_name": "WALMART",
      "city": "STAR",
      "state": "ID",
      "naics_code": "452112",
      "naics_description": "Discount Department Stores",
      "svep_flag": false,
      "parent_name": "Walmart Inc.",
      "location_count": 140,

      "osha_inspections": 3,
      "osha_violations": 7,
      "osha_total_penalties": 15000.00,
      "whd_cases": 1,
      "whd_backwages_total": 5000.00,
      "nlrb_cases": 2,
      "epa_compliance_status": "Significant Violation",
      "is_sam_excluded": false,
      "agency_violation_count": 3,
      "peer_violation_percentile": 87,
      "peer_group_size": 342,

      "industry_benchmark": { "avg_trir": 3.2, "avg_dart": 1.8, "source": "BLS SOII 2024" },
      "self_reported": { "trir": 3.5, "dart_rate": 2.1, "source": "OSHA ITA Form 300A" },
      "accident_summary": { "fatalities": 0, "hospitalizations": 1 },
      "analytics": {
        "agencies_with_activity": ["OSHA", "WHD", "EPA"],
        "total_penalties_all_agencies": 22000,
        "peer_penalty_percentile": 72
      }
    }
  ],
  "total_count": 1,
  "limit": 20,
  "offset": 0
}

Analytics object

The analytics object contains computed insights derived from raw enforcement data. All fields are optional — they appear only when the underlying data exists.

FieldTypeDescription
years_of_historynumberYears between first and most recent enforcement activity
days_since_last_activitynumberDays since the most recent inspection or enforcement case
inspection_velocitynumberAverage OSHA inspections per year over history span
violation_velocitynumberAverage violations per year over history span
osha_willful_pctnumberPercentage of violations classified as willful
osha_serious_pctnumberPercentage of violations classified as serious
osha_complaint_pctnumberPercentage of inspections triggered by complaints
osha_penalty_per_violationnumberAverage OSHA penalty dollars per violation
whd_backwages_per_employeenumberAverage WHD back wages per affected employee
agencies_with_activitystring[]List of agencies with enforcement records
total_penalties_all_agenciesnumberSum across OSHA + WHD + MSHA + EPA
trir_vs_industrynumberSelf-reported TRIR minus industry average (positive = worse)
peer_penalty_percentilenumberPenalty rank vs same NAICS + state peers (0-100)
peer_inspection_percentilenumberInspection frequency rank vs same NAICS + state peers (0-100)

Risk scoring

Risk scores range from 0–100 and combine:

  • OSHA violations — willful (30 pts), repeat (15 pts), serious (3 pts)
  • OSHA penalties — up to 15 pts based on dollar amount
  • WHD enforcement — back wages (up to 8 pts), cases (up to 4 pts), employees violated (up to 3 pts)

Scores decay over time: full weight for last 3 years, 80% at 4 years, 60% at 5 years, 40% for older activity.

Risk tiers are derived from the score plus a few hard override conditions:

  • HIGH: score ≥ 50, or any willful violation within 5 years, or 3+ repeat violations within 5 years.
  • ELEVATED: score 20–49, or any workplace fatality investigation on record.
  • MEDIUM: score 5–19, or any OSHA violations in the last 3 years, or enforcement actions across 2+ agencies.
  • LOW: score 0–4 with no recent enforcement activity.

See methodology for the full per-component weighting and the time-decay table.

Data enrichment

Each employer profile aggregates data from every major US federal compliance source plus the UVA Corporate Prosecution Registry. Refresh cadence by source:

AgencyDataRefresh
OSHAInspections, violations, penalties, fatalities, inspection-type breakdownWeekly
WHDWage enforcement cases, back wages, employees affectedWeekly
MSHAMine safety violations and assessed penaltiesWeekly
EPA ECHOEnvironmental compliance, quarters noncompliant, formal actionsDaily
FMCSADOT number, carrier registration, operation typeDaily
NLRBUnfair labor practice charges, union representation casesDaily
SAM.govFederal exclusion / debarment listDaily
OFLCH-1B / H-2 visa applications, approval rates, wage ratiosMonthly
ITAOSHA Form 300A self-reported DART / TRIR ratesAnnual (OSHA release)
BLSSOII industry benchmark TRIR / DART by NAICSAnnual (BLS release)
CMSNursing-home five-star ratings, deficiencies, civil money penaltiesMonthly
SECEnforcement actions + XBRL financial disclosures (revenue, employees, assets)Monthly
CPSCConsumer product recallsWeekly
NHTSAVehicle and equipment recallsWeekly
USAspendingFederal contracts and assistance awards, parent-rollup attributionMonthly
UVAFederal corporate prosecutions, plea agreements, DPAs / NPAsMonthly

Rate limits & quotas

Two limits apply on top of each other:

  1. Monthly quota. Your per-key allowance. Free keys get 50 lookups/month; higher tiers are per-contract. Every authenticated request that reaches a query handler counts as 1 lookup against the quota — including empty-result searches. Batch lookups count as 1 per item submitted. Current usage is visible on your account page and on every response via the X-RateLimit-* headers.
  2. IP-based request rate. 60 requests/minute per IP on the main search endpoints (/v1/employers, /v1/employers/parent); 30/minute on inspection detail and per-state / per-NAICS aggregates; 10/minute on the industry metadata endpoints. Protects against scraping; applies before the monthly quota is checked.

When you exceed the rate limit you receive a 429 with {"error": "rate_limited"}. When you exceed the monthly quota you receive a 429 with {"error": "monthly_quota_exceeded"}. Both responses include a Retry-After header.

Errors

{
  "detail": {
    "error": "error_code",
    "message": "Human-readable description"
  }
}
StatusMeaning
400Bad request — missing required parameter or invalid value (malformed UUID, invalid NAICS)
401Missing or invalid API key
403API key lacks the required scope for this endpoint
404Direct lookup by ID/EIN not found (search returns 200 with empty list)
422Parameter out of range (limit > 100, offset < 0)
429Rate limit or monthly quota exceeded
503Service degraded — pipeline freshness check or database unavailable
Zero-result searches return HTTP 200 with results: [] and a suggestions array — they are a normal response, not an error.

Code examples

Python

import requests

API_KEY = "your_api_key"
BASE = "https://api.fastdol.com/v1"

# Search
r = requests.get(f"{BASE}/employers",
    headers={"X-Api-Key": API_KEY},
    params={"name": "Walmart", "state": "ID"})
print(r.json()["results"][0]["osha_total_penalties"])

# Batch
r = requests.post(f"{BASE}/employers/batch",
    headers={"X-Api-Key": API_KEY},
    json={"lookups": [
        {"name": "Walmart", "zip": "83669"},
        {"name": "Amazon", "state": "CA"},
    ]})
for item in r.json()["results"]:
    print(item["query"]["name"], "->",
          item["match"]["employer_id"] if item["match"] else "no match")

JavaScript

const API_KEY = "your_api_key";
const BASE = "https://api.fastdol.com/v1";

const res = await fetch(
  `${BASE}/employers?name=walmart&zip=83669`,
  { headers: { "X-Api-Key": API_KEY } }
);
const data = await res.json();
console.log(data.results[0].osha_total_penalties);

curl

# Search
curl -H "X-Api-Key: YOUR_KEY" \
  "https://api.fastdol.com/v1/employers?name=walmart&zip=83669"

# CSV upload
curl -H "X-Api-Key: YOUR_KEY" \
  -F "file=@employers.csv" \
  "https://api.fastdol.com/v1/employers/upload-csv" \
  -o results.csv

Higher quotas

Need bulk export, custom integration, or commercial licensing?

Free tier covers 50 lookups / month from any IP. For programmatic access at scale or licensed redistribution of the underlying dataset, FastDOL offers commercial terms — email ben@fastdol.com.

View licensing →