Public API

Read-only JSON of what the map shows: GSA and subbasin series, stored forecasts, the kriged surfaces and the context layers. No key needed.

Base URL https://groundwater-map-175591637760.us-west1.run.app/api/v1
Data release 2026-09.5cdfad9c. Outputs licensed CC BY-NC 4.0.

Endpoints

Conventions

Versioning

Caching and limits

Bulk downloads

Each monthly refresh is frozen as a release at https://groundwater-map-175591637760.us-west1.run.app/release: per-well forecast tables (CSV, Parquet), the wells as GeoJSON, the surfaces as GeoTIFF, GSA and subbasin summaries (CSV), a README, CITATION.cff, the licence, SHA-256 checksums, and one zip. A release's files do not change after later refreshes.

Licence and citation

The app's outputs (forecasts, kriged surfaces, averages, summaries, API answers) are licensed CC BY-NC 4.0 (cite Gray, W.). Additional permission: public agencies, groundwater sustainability agencies, consultants working for them, and academic researchers may also use these outputs for commercial purposes, with the same credit. Other commercial use needs the author's written permission. Releases published before the change to CC BY-NC 4.0 remain under CC BY 4.0. Each release's page gives its own licence. Cite:

Gray, W. (2026). Central Valley Groundwater Map and Forecast, release 2026-09.5cdfad9c. CC BY-NC 4.0.

Input data keep their own terms:

The model card lists each model input and its source.

GET /api/v1

This list, as JSON: every v1 endpoint, the release id and the citation.

curl --compressed "https://groundwater-map-175591637760.us-west1.run.app/api/v1"
FieldType, unitsMeaning
versionstring"v1".
releasestring | nullRelease id of the data served now, e.g. 2026-09.c1a3d688.
licencestringThe outputs' licence, "CC BY-NC 4.0". The additional permission is under Licence and citation above.
citestringCitation line, with the release id.
docsstringURL of this page.
endpoints[]objectpath, summary, example, params (name, values) and fields (frozen names).

GET /api/v1/scenarios

The stored forecasts you can ask /api/v1/forecast for.

curl --compressed "https://groundwater-map-175591637760.us-west1.run.app/api/v1/scenarios"
FieldType, unitsMeaning
first_monthYYYY-MMFirst forecast month (the month after the last reading month).
history_endYYYY-MMLast month with readings.
presetsobjectPreset name -> precipitation, % of normal: severe 50, moderate 70, normal 100, wet 130.
horizonsint[]Forecast lengths in months a preset or the outlook can be asked for.
replays[]objectkey, label, months: a past drought year's weather and water supply from today's levels.
outlookobject | nullNOAA CPC seasonal outlook scenario: issue (YYYY-MM), water_year, central_pct (% of normal precipitation), member_pct ([dry, wet] %), temp_delta_c, max_horizon (months).

GET /api/v1/forecast

A stored forecast from today's levels: a preset, the NOAA outlook, or a drought replay.

ParameterValues
scenariosevere | moderate | normal | wet | outlookDefault normal.
horizon6 | 12 | 24 | 36Months; default 12. The outlook stops at its max_horizon.
replaya key from /api/v1/scenariosInstead of scenario; its length is fixed.
curl --compressed "https://groundwater-map-175591637760.us-west1.run.app/api/v1/forecast?scenario=normal&horizon=12"
curl --compressed "https://groundwater-map-175591637760.us-west1.run.app/api/v1/forecast?scenario=outlook&horizon=12"
curl --compressed "https://groundwater-map-175591637760.us-west1.run.app/api/v1/forecast?replay=WY2015"
FieldType, unitsMeaning
monthsYYYY-MM[]Forecast months.
grids[month][row][col] number | nullKriged depth to groundwater, ft below ground. Rows run north to south, columns west to east; cell centres are evenly spaced from the bounds' edges. null outside the valley and in grayed subbasins.
boundsobjectGrid extent: lat_min, lat_max, lon_min, lon_max (degrees, WGS84), nrows, ncols.
gsa.<id>number[] (ft below ground)Area-weighted average of the grid per month. Keyed by GSA id (DWR i03 GSA id, as a string).
basins.<code>number[] (ft below ground)The same per subbasin; null for a grayed subbasin. Keyed by Bulletin 118 subbasin code, e.g. 5-022.09.
gsa_elev.<id>number[] (ft, NAVD88)Water-table elevation average per month (ground minus depth). null when the ground grid is not loaded.
basins_elev.<code>number[] (ft, NAVD88)The same per subbasin.
thresholds.<id>objectn: the GSA's RMS wells with a recent reading; past[]: how many of them are forecast deeper than their minimum threshold (MT), per month.
scenarioobjecthorizon_months, precip_pct (% of normal), inputs (other settings; {} for presets). Replays add analog (key), label, source_months; the outlook adds outlook (as in /api/v1/scenarios).

The 80 % range of a GSA or subbasin average is in /api/v1/gsa and /api/v1/basins (uncertainty).

Months 1–24 are tested; later months are a what-if.

Per-well forecasts are in the bulk downloads.

GET /api/v1/gsa

GSA polygons, each GSA's depth history, its forecast range and its plan's MT.

curl --compressed "https://groundwater-map-175591637760.us-west1.run.app/api/v1/gsa"
FieldType, unitsMeaning
layerGeoJSON FeatureCollectionSimplified GSA polygons (WGS84). properties: id, name, subbasin_code, subbasin, gsp_id, n_wells.
series.monthsYYYY-MM[]Months of every series below, from 2005-01.
series.gsas.<id>.avgnumber[] (ft below ground)Area-weighted average of the kriged surface per month.
series.gsas.<id>.mediannumber[] | null (ft below ground)Median of the readings inside the GSA that month.
series.gsas.<id>.n_readingsint[]Main-aquifer wells inside the GSA with a reading that month.
series.gsas.<id>.n_wellsintMain-aquifer wells inside the GSA.
series.gsas.<id>.coverage0–1Share of the GSA's area the kriged surface covers.
uncertainty.level0–1Coverage the band is built for (0.8).
uncertainty.horizonsintMonths the band covers (12); later months have none.
uncertainty.gsas.<id>[lower[], upper[]] (ft)Offsets added to the forecast average per month: the 80 % range is [avg + lower[k], avg + upper[k]]. From held-out backtests.
uncertainty.default[lower[], upper[]] (ft)Offsets for a GSA without its own.
thresholds.<id>objectFrom the GSP: n_sites (RMS wells), mt_depth_median, mo_depth_median (ft below ground), pct_past_mt_now (share past MT in the latest readings, 0–1), gsp_id.

Keyed by GSA id (DWR i03 GSA id, as a string). GSAs that overlap each hold their own wells.

GET /api/v1/basins

Bulletin 118 subbasins: polygons, depth history, forecast range.

curl --compressed "https://groundwater-map-175591637760.us-west1.run.app/api/v1/basins"
FieldType, unitsMeaning
layerGeoJSON FeatureCollectionSubbasin polygons (WGS84). properties: id (subbasin code), name, basin, area_sqmi, critically_overdrafted, gsas (GSA ids).
series.monthsYYYY-MM[]Months of every series below.
series.basins.<code>.avgnumber[] (ft below ground)Area-weighted average of the kriged surface per month.
series.basins.<code>.mediannumber[] | null (ft below ground)Median of the readings inside that month.
series.basins.<code>.n_readingsint[]Main-aquifer wells with a reading that month.
series.basins.<code>.n_wellsintMain-aquifer wells inside.
uncertainty.basins.<code>[lower[], upper[]] (ft)80 % range offsets, as for GSAs.
uncertainty.default[lower[], upper[]] (ft)Offsets for a subbasin without its own.

GET /api/v1/summary_now

Per GSA, now: record lows and the plan's rule.

curl --compressed "https://groundwater-map-175591637760.us-west1.run.app/api/v1/summary_now"
FieldType, unitsMeaning
history_endYYYY-MMLast month with readings.
monthsintWindow for "now" (months up to history_end).
gsa.<id>.subs_nintMain-aquifer wells with a long enough record to judge a record low.
gsa.<id>.subs_nowintOf those, wells whose deepest reading since 2005 falls in the window.
gsa.<id>.subs_sitesstring[]Their site codes.
gsa.<id>.ur_nowbool | nullThe plan's undesirable-result rule is met in the latest readings; null when it cannot be judged.

GET /api/v1/changes

What changed at each monthly refresh, per GSA.

ParameterValues
gGSA idOne GSA's lines in every kept edition. Unknown id: 404.
curl --compressed "https://groundwater-map-175591637760.us-west1.run.app/api/v1/changes"
curl --compressed "https://groundwater-map-175591637760.us-west1.run.app/api/v1/changes?g=40"
FieldType, unitsMeaning
editions[].history_endYYYY-MMLast reading month of that refresh.
editions[].previousYYYY-MM | nullThe refresh it is compared with.
editions[].builtISO 8601 timeWhen it was built (UTC).
editions[].outlookobject | nullThe NOAA outlook used: issue, water_year, central_pct, member_pct.
editions[].notableobjectWithout g: GSA id -> count of notable items.
gsastringWith g: the GSA id.
namestringWith g: the GSA name.
editions[].items[]objectWith g: kind (a code such as level, rms_state, forecast; more may be added), text (one sentence), notable (bool).

GET /api/v1/hindcast

Per GSA: what the model forecast a year ago, and its record.

curl --compressed "https://groundwater-map-175591637760.us-west1.run.app/api/v1/hindcast"
FieldType, unitsMeaning
originYYYY-MMMonth the year-ago forecast starts from.
last_history_monthYYYY-MMLast month with readings.
trained_throughYYYY-MMThe tested model saw data up to this month only.
leadsint[]Lead times in months (1, 6, 12).
gsas.<id>.path[YYYY-MM, number][] (ft below ground)The 12-month forecast from origin.
gsas.<id>.ahead.<lead>[YYYY-MM, number][] (ft below ground)For each month, the forecast made lead months before.
gsas.<id>.stats.<lead>objectn, mae (ft), bias (ft; + = forecast too deep), against the GSA's kriged average.

Given the weather and water supply that came, not a scenario.

GET /api/v1/normal_low

Deepest month of a normal year per grid cell.

ParameterValues
horizon1–36Months; default 12.
curl --compressed "https://groundwater-map-175591637760.us-west1.run.app/api/v1/normal_low?horizon=12"
FieldType, unitsMeaning
horizonintMonths covered.
monthsYYYY-MM[]Those months.
grid[row][col] number | null (ft below ground)Deepest forecast depth over the months, normal-year preset; the same grid as /api/v1/history.

GET /api/v1/history

Monthly kriged surfaces of depth to groundwater since 2005.

curl --compressed "https://groundwater-map-175591637760.us-west1.run.app/api/v1/history"
FieldType, unitsMeaning
monthsYYYY-MM[]Months, from 2005-01.
grids[month][row][col] number | null (ft below ground)Kriged from main-aquifer wells. A well's reading is held up to 12 months. Rows north to south, columns west to east.
boundsobjectGrid extent: lat_min, lat_max, lon_min, lon_max (degrees, WGS84), nrows, ncols.
valley_mask[row][col] 0 | 11 inside the Central Valley.

Large: about 13 MB, 1.4 MB with gzip.

GET /api/v1/wells

The map's wells, one list record each.

curl --compressed "https://groundwater-map-175591637760.us-west1.run.app/api/v1/wells"
FieldType, unitsMeaning
[][0]numberLatitude (WGS84).
[][1]numberLongitude.
[][2]number | nullWell depth, ft.
[][3]stringCounty.
[][4]stringDWR site code: the key in /api/v1/well_timeseries.
[][5]stringZone: aquifer, or upper (perched or shallow; left out of the surfaces).
[][9]number | nullGround elevation, ft NAVD88.
[][11]stringPosition relative to the Corcoran Clay: above, below, spans, no_clay, unknown, or "".

Positions not listed are the app's own. New fields are added at the end.

GET /api/v1/well_timeseries

Each well's monthly readings.

ParameterValues
sitesite codes, comma-separated (up to 100)Without it: every well.
curl --compressed "https://groundwater-map-175591637760.us-west1.run.app/api/v1/well_timeseries?site=361737N1194798W001"
FieldType, unitsMeaning
monthsYYYY-MM[]Months of every series, from 2005-01.
wells.<site>number | null [] (ft below ground)The well's reading per month; null = no reading.

GET /api/v1/isw

Interconnected surface water: monitoring wells near rivers.

curl --compressed "https://groundwater-map-175591637760.us-west1.run.app/api/v1/isw"
FieldType, unitsMeaning
fieldsstring[]Names of the positions in each wells record (site, lat, lon, kind, river, dist_km, median_ft, last_depth, last_month, mt_depth, gsas, name, zone). New names are added at the end. mt_depth is always null here.
wells[]listOne record per well, in the order of fields. Depths ft below ground; river = index into rivers; dist_km to that reach.
rivers[][name, [[lon, lat], ...]]River reaches.
near_kmnumberDistance that counts as near a river, km.
shallow_ftnumberDepth that counts as shallow, ft.
history_endYYYY-MMLast month with readings.
sourcestringData sources.

GET /api/v1/insar

Measured land subsidence per GSA (InSAR).

curl --compressed "https://groundwater-map-175591637760.us-west1.run.app/api/v1/insar"
FieldType, unitsMeaning
sourcestringDWR / TRE ALTAMIRA InSAR, vertical displacement.
firstYYYY-MMFirst month of the record.
lastYYYY-MMLast month of the record.
last12_fromYYYY-MMStart of the last-12-months window.
gsa.<id>.last12ftMedian vertical change over the last 12 months; negative = sinking.
gsa.<id>.last12_p10ftThe most-subsided tenth of the GSA's pixels (10th percentile).
gsa.<id>.sinceftMedian change since 2015-06-13.
gsa.<id>.since_p10ft10th percentile since 2015-06-13.
gsa.<id>.wy.<year>ftMedian change in each water year (Oct–Sep).
gsa.<id>.valid_frac0–1Share of the GSA's area with InSAR pixels.

GET /api/v1/recharge

Recharge opportunity: soils that take water, near a canal.

curl --compressed "https://groundwater-map-175591637760.us-west1.run.app/api/v1/recharge"
FieldType, unitsMeaning
boundsobjectGrid extent: lat_min, lat_max, lon_min, lon_max (degrees, WGS84), nrows, ncols.
cells[][cell, good, fair, km, sy]Per grid cell (index = row × ncols + col): acres of good and fair soils, km to a canal, specific yield.
gsa.<id>.acresacresGSA area.
gsa.<id>.goodacresGood soils.
gsa.<id>.fairacresFair soils.
gsa.<id>.good_nearacresGood soils within params.near_km of a canal.
gsa.<id>.fair_nearacresFair soils near a canal.
paramsobjectThresholds: ksat_good_um_s, ksat_fair_um_s, resdept_min_cm, near_km.
sourcestringData sources.

GET /api/v1/grayed

Subbasins with no forecast or a low-confidence note.

curl --compressed "https://groundwater-map-175591637760.us-west1.run.app/api/v1/grayed"
FieldType, unitsMeaning
<code>.namestringSubbasin name.
<code>.statusstringgrayed (no forecast) or low_confidence.
<code>.messagestringWhy.