# Texas Stormwater Construction Permits Scraper (`usta/texas-stormwater-noi-scraper`) Actor

Texas sites holding an active TXR15 stormwater construction permit. One row per site: permit number, site name, county, city, ZIP, EPA's permit name, and the date EPA recorded it issued. Read live from EPA's national ICIS-NPDES download.

- **URL**: https://apify.com/usta/texas-stormwater-noi-scraper.md
- **Developed by:** [US Tech Automations](https://apify.com/usta) (community)
- **Categories:** Real estate, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$5.00 / 1,000 result rows

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?

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

## Texas Stormwater Permit Leads for Contractors

Erosion-control and building-materials sales reps get active Texas stormwater construction-permit coverages from EPA's own database, ready to call before a competitor does.

### Introduction

Any construction site in Texas that disturbs an acre of ground or more has to
hold coverage under the state's general stormwater permit, TXR150000, before
the first shovel goes in. That single fact is a signal buyers care about:
general contractors, erosion-control and silt-fence crews, aggregate and
building-materials suppliers, and site-development lenders all want to know
where new active coverages are showing up, because a fresh permit is one of
the earliest public signs that a construction job is about to start.

Texas's own environmental agency, TCEQ, runs the permit program, but its
public query tool does not answer a plain request for a machine to read. The
same coverages are re-published nationally by the EPA in its own ICIS-NPDES
compliance database, which EPA's own data-licensing page states is public
domain by default. This Actor reads that EPA file directly, live, on every
run, and keeps only the Texas TXR15 stormwater coverages that are currently
active (status EFF) and were recorded by EPA as issued inside the window you
ask for.

### Tutorial

1. Open the Actor and set **County** to a Texas county name (for example
   `Harris` or `Travis`), or leave it as `All` to search every county.
2. Set **Days back** to how far back you want to look for a permit's
   EPA-recorded issue date. EPA refreshes its download on its own schedule,
   not daily, so a wider window (30-90 days) is more useful than 1-2 days.
3. Set **Maximum rows** to your spend cap. Every row returned bills, so this
   number is also the most a single run can cost.
4. Click **Start** and open the resulting dataset once the run finishes.

### Pricing

This Actor charges **$0.005 per row** returned to the dataset, with no start
fee and no charge for a run that returns zero rows. A run that returns 80
rows costs $0.40. The price reflects that each row is a specific, dated,
government-recorded construction permit, not a generic directory listing:
finding this yourself means downloading and parsing a roughly 350MB national
EPA file by hand.

### Input and output examples

Input:

```json
{"county": "Harris", "daysBack": 60, "maxItems": 100}
```

Output (one row):

```json
{
  "permit_id": "TXR15XXXX",
  "site_name": "EXAMPLE SITE NAME",
  "county": "Harris",
  "city": "Houston",
  "zip": "77002",
  "permit_name": "EXAMPLE PERMIT NAME",
  "permit_issue_date": "2026-08-14",
  "status": "EFF",
  "source_url": "https://echo.epa.gov/files/echodownloads/npdes_downloads.zip",
  "fetched_at": "2026-09-15T12:00:00Z"
}
```

`permit_name` is EPA's own facility-name field for the permit, not a
contractor or operator name — EPA publishes no operator field, and none is
invented here. `permit_issue_date` is when EPA recorded the coverage as
issued, not a ground-breaking date.

### Recommendations

Run this weekly or monthly with a 30-90 day window rather than daily; EPA's
own download does not change every day. Use the **County** filter to focus
on a metro area you cover instead of pulling every Texas county each time.

### FAQ

**Does this include contractor or site-plan details?** No. EPA's public
dataset has no such field, so none is added or guessed.

**Where does the data come from?** EPA's national ICIS-NPDES download, which
is public and free to access directly from EPA; this Actor automates the
download, filtering, and county lookup so you do not have to.

**What happens if EPA's file can't be read on a run?** The run ends with a
status message and an empty dataset. No row is ever invented, and you are
never charged for a row that was not produced.

### Refunds and support

Refunds: if a run returns zero rows for a valid input, email operations@ustechautomations.com within 7 days and we refund that run. Support: same address, replies within 2 business days.

# Actor input Schema

## `county` (type: `string`):

Texas county to search, by name (for example 'Harris' or 'Travis'). 'All' searches every county.

## `daysBack` (type: `integer`):

How many days before today to look for a permit's EPA-recorded issue date. Coverages are added to EPA's download on EPA's own refresh schedule, not daily.

## `maxItems` (type: `integer`):

Hard cap on the number of rows this run produces, and therefore on what it can cost. Every row bills at the listed price from row one; there is no start fee.

## Actor input object example

```json
{
  "county": "All",
  "daysBack": 30,
  "maxItems": 200
}
```

# Actor output Schema

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

No description

## `report` (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 = {
    "county": "All",
    "daysBack": 30,
    "maxItems": 200
};

// Run the Actor and wait for it to finish
const run = await client.actor("usta/texas-stormwater-noi-scraper").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 = {
    "county": "All",
    "daysBack": 30,
    "maxItems": 200,
}

# Run the Actor and wait for it to finish
run = client.actor("usta/texas-stormwater-noi-scraper").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 '{
  "county": "All",
  "daysBack": 30,
  "maxItems": 200
}' |
apify call usta/texas-stormwater-noi-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,usta/texas-stormwater-noi-scraper"
        }
    }
}
```

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/ba2rwIaNPYjHG2slf/builds/lhhclP5fDwZod8BqG/openapi.json
