emission-factors.com API reference

Base URL https://emission-factors.com. Free and keyless: no API key, no signup. Rate limit 2,000 requests/hour per IP (HTTP 429 with retryAfter seconds). Errors are JSON: {"error": "...", "message": "..."}. Full spec: /openapi.json. Summary for agents: /llms.txt. MCP: /mcp-setup.

GET /api/lookup

Look up emission factors for a ZIP code

Query parameters:

  • zip (required) - 5-digit ZIP; ZIP+4 accepted e.g. 94105
  • year - 2024 = eGRID2024 from Cornerstone (EPA code, 2024 inputs; CC-BY-4.0); residual mix only with 2023

Responses:

  • 200: Emission factors for the ZIP code. A well-formed ZIP with no eGRID mapping (PO box, territory) returns 200 with candidates: [] and the reason in notes.
  • 400: Malformed ZIP (not 5 digits or ZIP+4) or invalid year
  • 429: Rate limit exceeded

GET /api/lookup/by-coordinates

Look up emission factors by latitude/longitude

Query parameters:

  • lat (required) e.g. 37.7749
  • lon (required) e.g. -122.4194

Responses:

  • 200: Resolved ZIP and emission factors
  • 400: Invalid coordinates
  • 404: No ZCTA at these coordinates
  • 503: Census Geocoder unavailable; retry

POST /api/lookup/batch

Look up emission factors for up to 100 ZIP codes

Responses:

  • 200: A bare array of lookup results (default), or {edition, *_source fields, results} with compact or envelope. Always eGRID2023; use /api/lookup?year=2024 for eGRID2024.
  • 400: Not an array or {zips}, empty, over 100, a non-string/number entry, or an unknown field

POST /api/calculate

Calculate Scope 2 CO₂e for a ZIP + kWh, location-based and market-based candidates[].co2e_kg is location-based (eGRID). candidates[].market_based.co2e_kg applies the Green-e residual mix to kWh not covered by contractual instruments (renewable_kwh).

JSON body:

  • zip (string) e.g. "94105"
  • kwh (number) e.g. 500
  • year (string) - eGRID edition (default 2023); market-based needs 2023
  • renewable_kwh (number) - kWh covered by RECs, PPAs or green tariffs (market-based method). Default 0, max kwh. e.g. 100

Responses:

  • 200: CO₂e calculation result (location- and market-based)
  • 400: Missing or invalid fields, malformed ZIP, invalid year, or unknown fields (e.g. "unit"; kwh is always kWh)
  • 404: Well-formed ZIP with no eGRID subregion (PO box, unique ZIP)

POST /api/bulk

Process a CSV file of ZIP codes

Responses:

  • 200: Enriched CSV with emission factor columns. Delimiter (comma, semicolon, tab) is detected from the header; the ZIP and kWh columns are detected by name (X-kWh-Column-Detected header).
  • 400: No CSV, or no ZIP column
  • 413: Over 1 MB

GET /api/rate

Latest monthly average retail electricity rate by sector

Query parameters:

  • zip (required) - 5-digit ZIP or ZIP+4 e.g. 94105

Responses:

  • 200: Residential, commercial, industrial, transportation, all-sectors prices from EIA Form 861 (sectors with no sales are omitted)
  • 400: Malformed ZIP
  • 404: No state mapping (e.g. Puerto Rico, territories)
  • 503: EIA API temporarily unavailable; retry (Retry-After header)

GET /api/intensity

Hourly grid carbon intensity (EIA-930 fuel mix derived, data lags up to ~1 day)

Query parameters:

  • zip
  • ba - Balancing authority code (CISO, ERCO, PJM, NYIS, MISO, etc.) e.g. CISO
  • hours
  • aggregate - Return 24-hour averaged profile across window + cleanest/dirtiest hour + swing ratio

Responses:

  • 200: Hourly intensity array or aggregated profile
  • 400: Missing ZIP/BA or unknown BA
  • 404: ZIP not in EIA-930 coverage (AK, HI, PR)
  • 503: EIA-930 API temporarily unavailable; retry (Retry-After header)

GET /api/plant-emissions

Unit-level emissions from EPA CAMD (fossil units >25 MW): per-facility summary from daily data, or raw unit-hour records CAMD publishes by quarter; the default window ends on latest_published_date (last day of the latest quarter that ended 45+ days ago). Queries over the record limit are rejected with the count, never truncated. NOx/SO2 in the summary are lb.

Query parameters:

  • facility_id - EPA CAMD/ORIS facility code (facility_id or state is required) e.g. 3
  • state - US state, 2-letter code or full name (TX or Texas), for a state-wide aggregate e.g. TX
  • days - Counted back from latest_published_date
  • begin - Custom window start (with end; overrides days; max 366 days)
  • end - Custom window end (with begin)
  • format - hourly returns raw CAMD unit-hour records (large: use facility_id and a short window)
  • limit - Facilities returned in summary mode, largest CO2 first

Responses:

  • 200: Per-facility emissions summary or raw hourly records
  • 400: Invalid or missing parameters, an ID or date CAMD rejects, or a query over the record limit
  • 503: EPA CAMD API temporarily unavailable (Retry-After header), or the server key is not configured

GET /api/utility-rate

Utility-specific electricity tariff from OpenEI URDB (upgrade from state-average /api/rate)

Query parameters:

  • zip e.g. 94105
  • utility e.g. Pacific Gas & Electric Co
  • eiaid - EIA utility ID e.g. 14328
  • sector - Case-insensitive; RES/COM/IND codes accepted
  • limit

Responses:

  • 200: Currently-active default tariffs with effective rate, tiers, TOU flag, and source PDF
  • 400: No zip, utility, or eiaid provided, or an invalid sector or limit
  • 404: Unknown ZIP code
  • 503: OpenEI URDB API temporarily unavailable; retry (Retry-After header)

POST /api/compare

Rank 2-25 candidate sites on grid carbon, retail $/kWh and cleanest daily window

JSON body:

  • zips (array) e.g. ["20147","79601","97058"]
  • annual_kwh (number) - Optional; adds annual tCO2e and cost per site e.g. 87600000
  • sector (string)
  • duration (integer) - Cleanest-window length in hours

Responses:

  • 200: Sites with factors, rates, cleanest window and rank_carbon / rank_cost / rank_combined
  • 400: Fewer than 2 or more than 25 ZIPs, or invalid input
  • 429: Rate limit reached while fetching per-site data (compare costs about 1 + sites + states + BAs requests)

GET /api/cleanest-hours

Cleanest contiguous N-hour window of the day to run a flexible load (EIA-930, last ~7 days)

Query parameters:

  • zip e.g. 94105
  • ba - Balancing authority code instead of zip, e.g. CISO
  • duration
  • between - Optional local hours the window must fall in (start-end, wrapping past midnight), e.g. 20-06 for overnight EV charging e.g. 20-06

Responses:

  • 200: cleanest_window and dirtiest_window (UTC and the ZIP's local time), savings %, hours ranked. For a nearly carbon-free or flat grid both windows are null and no_window_reason says why.
  • 400: Invalid duration or input
  • 404: ZIP not covered by EIA-930 (AK, HI, PR)
  • 503: EIA-930 API temporarily unavailable; retry (Retry-After header)

GET /api/fuel-emissions

Scope 1 stationary combustion CO₂e for one fuel (GHG Emission Factors Hub 2026, Cornerstone, AR6; edition=2025 for EPA's, AR5); no fuel lists fuels

Query parameters:

  • fuel e.g. natural_gas
  • quantity e.g. 1000
  • unit - Required with fuel: mmBtu, therm, Dth, scf, ccf, mcf, gallon, liter, barrel, short_ton, lb, tonne e.g. therm
  • edition - 2026: Cornerstone Hub (AR6 GWPs); 2025: EPA Hub (AR5)

Responses:

  • 200: CO2, CH4, N2O and CO2e (GWPs of the chosen edition)
  • 400: Unknown fuel, unit or edition

POST /api/fuel-emissions

Scope 1 CO₂e for several fuels with a total

JSON body:

  • items (array)
  • edition (string)

Responses:

  • 200: Per-item results and total_co2e_kg
  • 400: Invalid item

POST /mcp

MCP server (JSON-RPC 2.0 over Streamable HTTP, stateless, keyless): initialize, tools/list, tools/call. 11 tools mirroring these REST endpoints. Setup: https://emission-factors.com/mcp-setup

JSON body:

  • jsonrpc (string) e.g. "2.0"
  • id (integer) e.g. 1
  • method (string) e.g. "tools/list"
  • params (object)

Responses:

  • 200: JSON-RPC response
  • 204: Notification accepted

GET /health

Health check

Responses:

  • 200: OK

GET /status

Edition, ZIP coverage (counted from the mapping) and the startup self-check result

Responses:

  • 200: Status object

GET /methodology

Methodology, data sources, licenses and edition policy (JSON; browsers get the page)

Responses:

  • 200: Methodology document

GET /openapi.json

This OpenAPI specification

Responses:

  • 200: OpenAPI 3.0 document