# Hazardous Waste Manifests - EPA e-Manifest (All States) (`j0401/pa-hazwaste`) Actor

Hazardous waste shipment manifests from the EPA e-Manifest register (public open data, 15.5M waste lines, 1991-2026): tracking number, status, generator and receiving site, waste code and description, DOT description, container, quantity, unit and management method. Filter by state, site or code.

- **URL**: https://apify.com/j0401/pa-hazwaste.md
- **Developed by:** [Wenhao Yang](https://apify.com/j0401) (community)
- **Categories:** Business
- **Stats:** 2 total users, 1 monthly users, 94.4% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.03 / 1,000 hazardous waste manifest 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

## Hazardous Waste Manifests - EPA e-Manifest

Hazardous waste shipment manifests from the EPA e-Manifest register, published
by the Pennsylvania Department of Environmental Protection. **15.55 million
waste lines**, from 1991 through June 2026.

### Low cost

**From $0.00005 per record, down to $0.00003 at Gold.** Pay only for the
records you actually receive - the whole register stays queryable, you are
never billed for the scan behind it.

### What you get

One row per waste line on a shipment, with the full chain of custody attached:

- **The shipment** - the manifest tracking number and handling status
- **Who shipped** - the generator or receiving site, by EPA site id and name,
  and the site's state
- **What waste** - the waste code and description, and the DOT shipping
  description (UN number, hazard class)
- **How much** - the quantity and its unit of measure (pounds, gallons,
  kilograms, cubic yards)
- **What happened to it** - the management method (incineration, fuel blending,
  storage, landfill) and the container type
- **When** - the shipped, received and certified dates

#### Two things to know up front

- **This is a national register, not a Pennsylvania-only one.** 8,876,642 of
  the 15,553,852 lines (57.1%) carry a Pennsylvania site; the rest are OH, NJ,
  NC, MD, VA and others. Each row's site state is derived from the EPA site id
  and is filterable - set `state="PA"` to narrow to Pennsylvania, or leave it
  blank to read the register as a whole.
- **A row is a waste line, not a shipment.** One tracking number covers about
  10.35 lines; there are **1,502,166 distinct manifests** behind the 15.5M
  lines. The line count is what you receive; the tracking number is the
  shipment key.

### Filter it

- **State** - `state="PA"` for Pennsylvania sites, `state="OH"` for Ohio.
- **Site** - `siteName="Cycle Chem"`, `epaSiteId="PAD000000554"`.
- **Waste** - `wasteCode="D001"` (ignitable), `wasteCode="D002"` (corrosive),
  `wasteDescription="SOLVENT"`. 514 codes in total.
- **Shipment** - `trackingNumber="028219191JJK"` returns every line on one
  manifest (22 lines on this one).
- **Status** - Signed, Corrected, UnderCorrection.
- **Site type** - generator or designated facility.
- **Management method** - incineration, fuel blending, storage and more.
- **Date range** and **last-N-days**; **quantity range**.

### Example inputs

**Pennsylvania shipments of one waste** - the headline query.

```json
{ "state": "PA", "wasteCode": "D001", "maxResults": 50 }
```

**Every line on one manifest** - a tracking number is the shipment key.

```json
{ "trackingNumber": "028219191JJK" }
```

**What happens to the waste** - `mode=aggregate` returns one count row per
management method; every group comes back.

```json
{ "state": "PA", "mode": "aggregate", "groupBy": "managementMethod" }
```

### Or roll it up

Set `mode=aggregate` and get a rolled-up count by **state**, **status**,
**origin type**, **submission type**, **site type**, **management method** or
**waste code**. Every group comes back - not cut off by `maxResults`.

### Then follow the waste

- Where a state's hazardous waste is generated, and where it goes.
- Every manifest a facility handled, line by line.
- Waste codes by volume - what is shipped, in what quantity.
- Incineration vs. landfill vs. fuel blending, by state.

### Example output

**One waste line** - `state=PA`, `wasteCode=D001`:

```json
{
 "platform": "pa-hazwaste",
 "source": "epa-e-manifest-pa",
 "mode": "rows",
 "groupKey": "",
 "groupCount": "",
 "groupBy": "",
 "trackingNumber": "028219191JJK",
 "status": "Corrected",
 "submissionType": "DataImage5Copy",
 "originType": "Web",
 "dateShipped": "2026-06-23T00:00:00.000",
 "dateReceived": "2026-06-24T00:00:00.000",
 "dateCertified": "2026-07-07T00:00:00.000",
 "siteType": "designatedFacility",
 "epaSiteId": "PAD000797548",
 "siteName": "FIELDING ENVIROMENTAL LLC",
 "wasteLineNumber": "3",
 "dotCode": "UN1950",
 "dotDescription": "UN1950, WASTE AEROSOLS (NOT EXCEEDING 1 LITER CAPACITY) 2.1",
 "containerTypeDescription": "Metal drums, barrels, kegs",
 "wasteQuantity": "55",
 "wasteUomDescription": "GALLONS",
 "wasteCode": "D001",
 "wasteDescription": "IGNITABLE WASTE",
 "managementMethodDescription": "STORAGE, BULKING AND/OR TRANSFER OFF SITE",
 "state": "PA",
 "sourceUpdatedAt": "2026-07-30"
}
```

**`mode=aggregate`, `groupBy=state`** - one count row per site state:

```
PA                          8,876,642
OH                          1,146,194
NJ                            889,089
NC                            778,997
MD                            538,419
VA                            455,415
```

### Notes on the data, from the source

- **Line, not shipment.** See above - the manifest is the tracking number.
- **Quantity unit varies per row.** `wasteQuantity` is measured in the row's
  own `wasteUomDescription` (POUNDS 13.25M, GALLONS 1.95M, KILOGRAMS, CUBIC
  YARDS), so a quantity range compares across units.
- **Some columns are intentionally blank on parts of the register.**
  `dotDescription` is empty on the 5,998,392 non-DOT lines, and
  `managementMethodDescription` on 5,985,821. They are returned as the source
  holds them.
- **`dateReceived` is not used** - the source carries a bad future value there.
  `dateShipped` is fully populated and clean, and is the sort axis.
- **The register is updated periodically**, not daily; `sourceUpdatedAt`
  carries the dataset's own refresh date.

# Actor input Schema

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

Two-letter EPA site-id state code, e.g. 'PA', 'OH', 'NJ'. Derived from the site identifier: PA covers 8,876,642 of 15,553,852 lines (57.1%) - the rest are other states. Blank = any.

## `trackingNumber` (type: `string`):

Substring match on the manifest tracking number, e.g. '028219191JJK'. One tracking number covers several waste lines. Blank = any.

## `siteName` (type: `string`):

Substring match on the site name, e.g. 'CYCLE CHEM', 'SPS TECHNOLOGIES'. Blank = any.

## `epaSiteId` (type: `string`):

Substring match on the EPA site identifier, e.g. 'PAD000000554'. Blank = any.

## `wasteCode` (type: `string`):

Substring match on the EPA waste code, e.g. 'D001' (ignitable), 'D002' (corrosive), 'F003'. 514 codes in total. Blank = any.

## `wasteDescription` (type: `string`):

Substring match on the waste description, e.g. 'IGNITABLE', 'SOLVENT'. Blank = any.

## `dotDescription` (type: `string`):

Substring match on the DOT shipping description. Note this is empty on the non-DOT waste lines (5,998,392 rows). Blank = any.

## `managementMethod` (type: `string`):

Substring match on the management method, e.g. 'INCINERATION', 'FUEL BLENDING', 'STORAGE'. 30 methods in total. Blank = any.

## `containerType` (type: `string`):

Substring match on the container type, e.g. 'Metal drums', 'Tank'. Blank = any.

## `status` (type: `string`):

Exact manifest handling status. Blank = any.

## `originType` (type: `string`):

How the manifest entered the system. Blank = any.

## `siteType` (type: `string`):

Which side of the shipment this row's site is: the generator or the designated receiving facility. Blank = any.

## `shippedFrom` (type: `string`):

Earliest shipment date, YYYY-MM-DD. Blank = any.

## `shippedTo` (type: `string`):

Latest shipment date, YYYY-MM-DD. Blank = any.

## `minQuantity` (type: `number`):

Smallest waste quantity. Note the unit varies per row (see wasteUomDescription) - pounds, gallons, kilograms, cubic yards - so a quantity range compares across units. Blank = no lower bound.

## `maxQuantity` (type: `number`):

Largest waste quantity (same unit caveat). Blank = no upper bound.

## `recentDays` (type: `integer`):

Only lines whose shipment date falls within the last N days. Ignored when 'Shipped on or after' is set. 0 = off.

## `mode` (type: `string`):

rows = waste lines matching your filters (default). aggregate = one count row per group (see groupBy).

## `groupBy` (type: `string`):

Which dimension to aggregate over (mode=aggregate). Blank = state. Every group is returned - aggregate mode is not cut off by maxResults. Some dimensions are source-side heavy on 15.5M rows.

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

Cap the number of records pushed in rows mode (0 = default 50; up to 2,000 per run). Each record is metered individually, so there is no per-run charge cap. Aggregate mode returns every group.

## Actor input object example

```json
{
  "state": "",
  "trackingNumber": "",
  "siteName": "",
  "epaSiteId": "",
  "wasteCode": "",
  "wasteDescription": "",
  "dotDescription": "",
  "managementMethod": "",
  "containerType": "",
  "status": "",
  "originType": "",
  "siteType": "",
  "shippedFrom": "",
  "shippedTo": "",
  "recentDays": 0,
  "mode": "rows",
  "groupBy": "",
  "maxResults": 50
}
```

# Actor output Schema

## `recordsUrl` (type: `string`):

Hazardous waste manifest records - as JSON

## `datasetUrl` (type: `string`):

No description

## `runUrl` (type: `string`):

No description

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("j0401/pa-hazwaste").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("j0401/pa-hazwaste").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 '{}' |
apify call j0401/pa-hazwaste --silent --output-dataset

```

## MCP server setup

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

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/gMHnS2HX1kOEao5Dh/builds/8FuNqFeoKJcyQMO69/openapi.json
