API Documentation

Programmatic access to satellite-based construction detection data across Pennsylvania.

Overview

The SubGrade API provides access to construction and land disturbance detections derived from Sentinel-2 satellite imagery. All responses are JSON. Public endpoints require no authentication; the authenticated endpoint provides higher rate limits and additional query options.

Base URL: https://subgrade.io/api/v1

Authentication

Authenticated endpoints require a Bearer token in the Authorization header. API keys are prefixed with subgrade_.

# Include your API key in the Authorization header Authorization: Bearer subgrade_your_api_key_here

Free Trial: 100 API calls — sign up on the homepage.
Pro ($49/month): 5,000 API calls per month.

Rate Limits

Rate limits are applied per IP address for public endpoints and per API key for authenticated endpoints.

Public Search 20 requests / hour per IP
Public Imagery 10 requests / hour per IP

When rate limited, the API returns a 429 status code. Wait and retry after the window resets.

Endpoints

GET /api/v1/public/search Public

Search for detected construction activity near an address or statewide. Returns paginated results with map points for visualization.

Parameters
NameTypeDefaultDescription
addressstring""Address or city to search (required unless statewide=true)
radius_milesfloat10.0Search radius in miles (1–150)
statewideboolfalseReturn all PA detections (ignores address and radius)
tiersstringnullComma-separated tier filter: HIGH, MEDIUM, LOW
min_acresfloatnullMinimum detection area in acres
max_acresfloatnullMaximum detection area in acres
offsetint0Pagination offset
limitint50Page size (1–500)
Example Request
curl "https://subgrade.io/api/v1/public/search?address=Lancaster,PA&radius_miles=10&tiers=HIGH,MEDIUM"
Example Response
{ "changes": [ { "id": "a1b2c3d4-...", "tier": "HIGH", "lat": 40.0456, "lon": -76.3012, "area_sqm": 2450.0, "confidence": 0.95, "detected_date": "2025-11-01", "baseline_date": "2025-04-01", "current_date": "2025-10-01", "tile_id": "T18TUK" } ], "map_points": [ ... ], "total": 142, "summary": { "total": 142, "by_tier": { "HIGH": 38, "MEDIUM": 64, "LOW": 40 }, "date_range": { "earliest": "2025-06-01", "latest": "2025-10-01" } }, "center_lat": 40.0379, "center_lon": -76.3055, "address": "Lancaster, PA" }
GET /api/v1/public/imagery Public

Fetch before/after satellite imagery for a detection site. Returns base64-encoded JPEG crops from Sentinel-2 Cloud Optimized GeoTIFFs. Response time: 5–15 seconds.

Parameters
NameTypeDefaultDescription
latfloatrequiredDetection latitude
lonfloatrequiredDetection longitude
tile_idstringrequiredMGRS tile ID (e.g. T17TNE)
baseline_datestringrequiredBaseline date (YYYY-MM-DD)
current_datestringrequiredComparison date (YYYY-MM-DD)
Example Request
curl "https://subgrade.io/api/v1/public/imagery?lat=40.05&lon=-76.30&tile_id=T18TUK&baseline_date=2025-04-01¤t_date=2025-10-01"
Example Response
{ "before": { "image": "/9j/4AAQSkZJRg...", // base64 JPEG "date": "2025-04-03" // actual image date }, "after": { "image": "/9j/4AAQSkZJRg...", "date": "2025-09-28" } }
POST /api/v1/public/signup Public

Create a free trial account. Returns an API key for use with authenticated endpoints. Free trial includes 100 API calls.

Request Body (JSON)
NameTypeDefaultDescription
emailstringrequiredYour email address
Example Request
curl -X POST "https://subgrade.io/api/v1/public/signup" \ -H "Content-Type: application/json" \ -d '{"email": "you@company.com"}'
Example Response
{ "api_key": "subgrade_abc123...", "message": "Free trial activated. 100 API calls included." }
GET /api/v1/changes Auth Required

Query detected land changes near a geographic point. Requires a valid API key in the Authorization header.

Parameters
NameTypeDefaultDescription
latfloatrequiredLatitude (39.5–42.5)
lonfloatrequiredLongitude (-80.6 to -74.5)
radius_milesfloat5.0Search radius in miles (0.1–50)
min_tierstringnullMinimum tier: HIGH, MEDIUM, or LOW
start_datestringnullFilter changes after this date (YYYY-MM-DD)
end_datestringnullFilter changes before this date (YYYY-MM-DD)
limitint100Max results (1–1000)
Example Request
curl "https://subgrade.io/api/v1/changes?lat=40.44&lon=-79.99&radius_miles=10" \ -H "Authorization: Bearer subgrade_your_api_key"
Example Response
{ "changes": [ { "id": "a1b2c3d4-...", "tier": "HIGH", "lat": 40.4456, "lon": -79.9912, "area_sqm": 3200.0, "confidence": 0.95, "detected_date": "2025-11-01", "baseline_date": "2025-04-01", "current_date": "2025-10-01", "tile_id": "T17TNE" } ], "total": 87, "summary": { "total": 87, "by_tier": { "HIGH": 22, "MEDIUM": 35, "LOW": 30 }, "date_range": { "earliest": "2025-06-01", "latest": "2025-10-01" } } }

Response Models

ChangeOut

FieldTypeDescription
idstringUnique detection UUID
tierstringConfidence tier: HIGH, MEDIUM, or LOW
latfloatDetection latitude
lonfloatDetection longitude
area_sqmfloatDetected area in square meters
confidencefloatConfidence score (HIGH=0.95, MEDIUM=0.80, LOW=0.65)
detected_datedateDate the detection was processed
baseline_datedateBaseline image date
current_datedateComparison image date
tile_idstringMGRS tile identifier (e.g. T18TUK)

SummaryOut

FieldTypeDescription
totalintTotal matching detections
by_tierobjectCount per tier: {"HIGH": n, "MEDIUM": n, "LOW": n}
date_rangeobjectEarliest and latest detection dates

Error Codes

StatusMeaningCommon Causes
400Bad RequestInvalid parameters, missing required fields, invalid date format
401UnauthorizedMissing or invalid API key on authenticated endpoints
404Not FoundAddress could not be geocoded
409ConflictEmail already registered (signup endpoint)
429Rate LimitedToo many requests — wait for the rate limit window to reset

All errors return JSON with a detail field describing the issue.

{ "detail": "Rate limit exceeded. Maximum 20 searches per hour." }