Government — entry 026 of 90
EPA
EPA's Envirofacts platform exposes the agency's environmental compliance and monitoring databases — air quality, drinking water systems, the Toxics Release Inventory, hazardous waste, and Superfund sites — through a keyless REST API at `data.epa.gov/efservice`. Any of the underlying tables can be queried by building a URL from the table name, filter columns, and an output format, with results returned as JSON, XML, CSV, or Excel. EPA's Developer Central site separately documents smaller topic widgets built on the same data.
EPA's Envirofacts platform exposes environmental compliance and monitoring data — including the Toxics Release Inventory (TRI) — through a keyless REST API whose query grammar lives entirely in the URL path rather than query-string parameters: /{table}/{column}/{operator-or-value}/.../rows/{start}:{end}/{format}. A live GET this run against /tri_facility/state_abbr/DE/rows/0:0/JSON returned a genuine 200, 1,507 B single-facility record at content-type: application/json, with access-control-allow-origin reflecting the request's own Origin header rather than a wildcard — confirmed live by an explicit Origin: https://greatapis.com probe, which got that exact value echoed back.
GreatAPIs Score
Auth quickstart
- No API key, signup, or credit card required — a live GET this run against
/tri_facility/state_abbr/DE/rows/0:0/JSONreturned real facility data on the first anonymous try. Filters chain as path segments in{column}/{value}pairs (or a word operator likeBEGINNINGin place of an exact value — confirmed live against/tri_facility/state_abbr/BEGINNING/D/rows/0:1/JSON), not as?column=valuequery parameters.
Your key is stored only in this browser (localStorage) and sent directly to the API — never to greatapis.
Look up a Toxics Release Inventory facility by state
GEThttps://data.epa.gov/efservice/tri_facility/state_abbr/DE/rows/0:0/JSON
[
{
"tri_facility_id": "19701CMPST3310W",
"facility_name": "COMPOSITES USA INC",
"street_address": "3310 WRANGLE HILL RD, BLDG 111",
"city_name": "BEAR",
"county_name": "NEW CASTLE",
"state_abbr": "DE",
"zip_code": "197011846",
"region": "3",
"fac_closed_ind": "1",
"pref_latitude": 39.5886,
"pref_longitude": 75.691859,
"epa_registry_id": "110001135227",
"asgn_public_contact": "JOHN F. MCCLOSKEY",
"asgn_public_phone": "4102872700",
"...": "34 more fields omitted (mail_*, parent_co_*, asgn_technical_*, frs_id, bia_code, etc, mostly null) -- full record is 1,507 B"
}
]/tri_facility/state_abbr/DE/count/JSON returned 200 with [{"TOTALQUERYRESULTS": 168}] — Delaware has 168 TRI facilities in total; a larger state proves the same grammar scales, live this run /tri_facility/state_abbr/CA/count/JSON returned [{"TOTALQUERYRESULTS": 5110}].
Try it
Developer reference
https://data.epa.gov/efservice- GET/{table}/rows/{start}:{end}/JSON
- GET/{table}/{column}/{value}/JSON
- GET/{table}/count/JSON
Gotchas & limits
rows/{start}:{end}is an inclusive range on both ends, not the usual exclusive-end slice — confirmed live this run:rows/0:0returns exactly 1 record,rows/0:1returns 2 records, androws/0:2returns 3. Code ported from a language where slice ends are exclusive (Python'slist[0:1], for instance) will silently fetch one extra row per request.- Omitting
/rows/entirely returns the whole table, with no default page size or cap of any kind — confirmed live this run:/tri_facility/state_abbr/CA/JSON(no/rows/segment) returned all 5,110 California facilities in a single 7.7 MB response, matchingCA's own/count/JSONtotal exactly. Code that assumes an unpaginated request is safely small by default can pull megabytes it didn't ask for. /count/JSONwraps its single number in an array containing one object, not a bare integer — confirmed live above: the literal response body is[{"TOTALQUERYRESULTS": 168}], so the count itself isbody[0].TOTALQUERYRESULTS, one level deeper than a naivebody.countorbody[0]read would expect.- An unrecognised table name is a real HTTP 404 with a descriptive JSON error, not a silent empty result — confirmed live this run against
/not_a_table/rows/0:1/JSON, which returned exactly{"error": "not_a_table/rows/0:1: The table is not available."}(62 B), echoing the full requested path back inside the message.