Central Valley Surfacewater Map

Public API

Read-only files of what the map shows: 924 measured series of canals, rivers, turnouts, reservoirs and the Delta at daily, weekly, monthly and water-year steps, the system ledgers, the tributary flow requirement verdicts and the data notes. Static JSON and CSV in a public bucket: no key, no sign-up, no rate limit of ours.

Base URL https://storage.googleapis.com/surfacewater-map-509303/api/v1/
Data 2000-10-01 to 2026-10-24, built 2026-10-28 21:34. Licensed CC BY 4.0.

Endpoints

Measured, estimated, not publicly measured

Conventions

Versioning

Releases

Each deploy is a release, named by its time (UTC), and the site is frozen at snapshots/<release>/, the API files with it. A frozen copy never changes, so a number quoted from it can be checked later. The monthly data refresh is the monthly data release. /api/v1/release.json names the release you are reading and its frozen copy (api_snapshot). The per-series files are frozen only when they change (about once a month, with the data refresh), so a release's series files can sit in an earlier release's copy: series_snapshot says where. /api/v1/releases.json lists them all.

Use from code

import pandas as pd
sha_storage = pd.read_csv("https://storage.googleapis.com/surfacewater-map-509303/api/v1/series/SHA.storage.csv")
monthly = sha_storage[sha_storage.step == "month"]

Files are served gzip-compressed to clients that ask for it (curl --compressed; browsers and pandas do). Browser pages on other sites can fetch them (CORS: GET from any origin).

Licence and citation

The series, ledgers, verdicts and notes as compiled here are licensed CC BY 4.0. Cite the release you used:

Gray, W. (2026). Central Valley Surfacewater Map, release <release>. CC BY 4.0.

The source data keep their own terms: DWR (CDEC, Dayflow, Water Data Library, SWP reports, Bulletin 132); Reclamation (CVO reports); USGS (NWIS); U.S. Army Corps of Engineers (CWMS); State Water Resources Control Board; FERC; NMFS / USFWS (biological opinions). sources.json lists every source series.

The map’s line geometry (data/network.geojson, not part of this API) is built from OpenStreetMap ways and USGS NHD and is offered under the Open Database License 1.0, © OpenStreetMap contributors, not CC BY.

Cost and limits

The files sit in a Google Cloud Storage bucket (us-west1), inside its Always Free tier (5 GB-months of storage, 100 GB a month of transfer to North America, 50,000 reads a month); beyond it about $0.02 per GB-month stored, $0.12 per GB transferred and $0.0004 per 1,000 reads (prices read 2026-10-21 from cloud.google.com/storage/pricing). There is no rate limit of ours, but please take the bulk you need once rather than polling: the data change about once a month.

GET /api/v1/index.jsonJSON

This list as JSON: every v1 endpoint, the licence, the data period and every series.

curl --compressed "https://storage.googleapis.com/surfacewater-map-509303/api/v1/index.json"
FieldType, unitsMeaning
versionstring"v1".
licencestring"CC BY 4.0".
licence_urlstringURL of the licence.
citestringCitation line without a release id; release.json has the line with it.
docsstringURL of the docs page.
data.startYYYY-MM-DDFirst day of the record.
data.endYYYY-MM-DDLast day with data.
data.builtYYYY-MM-DD HH:MMWhen the map's data were built (Pacific time).
quality_codesobject1 = measured, 2 = estimated (an approximation flagged ~ or ? in the map's network, or a stand-in series), 3 = monthly record (a published monthly table, measured); null = no record (never zero).
endpoints[]objectname, path, summary, example, format and fields (the frozen names).
series[]objectEvery series, with the fields listed under series.csv.
countsobjectNumber of series by status.

GET /api/v1/release.jsonJSON

The release these files are, where its frozen copy is and how to cite it.

curl --compressed "https://storage.googleapis.com/surfacewater-map-509303/api/v1/release.json"
FieldType, unitsMeaning
releasestringThe deploy this copy came with (UTC time, e.g. 2026-11-06T1530).
api_releasestring | nullThe release whose frozen copy holds these API files except series/ (the same as release; null when the live API has no frozen copy).
api_snapshotstring | nullURL of that frozen copy's api/v1/.
series_releasestring | nullThe release whose frozen copy holds these exact series/ files: series files are frozen only when they change, so it can be an earlier release.
series_snapshotstring | nullURL of that frozen copy's api/v1/series/ (in a frozen copy, index.json's series file paths are relative to it).
builtYYYY-MM-DD HH:MMWhen the data were built.
data_endYYYY-MM-DDLast day with data.
citestringCitation line with api_release.

Written at deploy time. A local build carries the last deploy's record.

A frozen copy (snapshots/<release>/api/v1/) holds every file but series/ when its series files are the same as an earlier release's; series_snapshot says where they are.

GET /api/v1/releases.jsonJSON

Every release of the site and where its frozen copy is.

curl --compressed "https://storage.googleapis.com/surfacewater-map-509303/api/v1/releases.json"
FieldType, unitsMeaning
[].releasestringRelease id.
[].builtstringWhen its data were built.
[].data_startYYYY-MM-DDFirst day of its record.
[].data_endYYYY-MM-DDLast day with data.
[].deployedstringWhen it went live (UTC).
[].pathstringIts frozen site: snapshots/<release>/index.html.
[].apistring | nullIts frozen API: snapshots/<release>/api/v1/; null before the API existed.
[].seriesstring | nullWhere its series files are frozen: snapshots/<release>/api/v1/series/, an earlier release's when the series did not change; null before the API existed.

GET /api/v1/series.csvCSV

Every series as one table, one row each (the catalog of index.json).

curl --compressed "https://storage.googleapis.com/surfacewater-map-509303/api/v1/series.csv"
ColumnType, unitsMeaning
idstringSeries id: a map line (e.g. swp_nba), a reservoir role (SHA.storage, SHA.inflow, SHA.release) or a Delta term (DELTA.inflow.Yolo_Bypass).
namestringName as on the map.
groupstringline, reservoir or delta.
kindstringcanal, river, turnout, checkpoint, delivery, tunnel, pump; reservoir_storage, reservoir_inflow, reservoir_release; delta_inflow, delta_exports, delta_use, delta_outflow, delta_channels.
systemstringSWP, CVP, Friant, Delta, River or Local.
mapstringdelivery (the Delivery Map) or tributaries (drawn on the Tributaries Map only).
unitstringcfs (a flow: the mean over the period) or af (reservoir storage: the last day of the period).
aggregationstringmean or end_of_period.
statusstringmeasured, not publicly measured (drawn on the map, no published measurement; no value files) or no record (a published source exists but holds no value in the period).
approximationboolSome values come from an expression flagged ~ or ?: those values carry quality 2 (estimated).
daily_recordstringHow a day's value is made: published series ids added or subtracted, tried in order ("|" = else). Empty when there is none.
monthly_recordstringThe published monthly table a month's value comes from where there is no daily record. Empty when there is none.
sourcesstring[]Ids of the published source series used (see sources.json).
data_notesstring[]Ids of the data notes about this series (see notes.json).
steps.<step>objectFor each step with a value (day, week, month, wy): first, last (periods) and n (values).
filesobjectjson and csv: paths of the series' files, relative to api/v1/. Absent when the status is not measured.
notestring | nullThe map's note on the line.

Lists are joined with spaces; steps.<step> becomes <step>_first, <step>_last and <step>_n columns; files becomes json and csv columns.

GET /api/v1/series/<id>.jsonJSON

One series at every step: daily, weekly, monthly and water-year values with a quality per value.

curl --compressed "https://storage.googleapis.com/surfacewater-map-509303/api/v1/series/SHA.storage.json"
FieldType, unitsMeaning
idstringSeries id.
namestringName.
unitstringcfs or af.
aggregationstringmean or end_of_period.
quality_codesobject1 = measured, 2 = estimated (an approximation flagged ~ or ? in the map's network, or a stand-in series), 3 = monthly record (a published monthly table, measured); null = no record (never zero).
steps.day.startYYYY-MM-DDFirst day; values run one per day from it.
steps.<step>.periodsstring[]week: the Monday the week starts (YYYY-MM-DD); month: YYYY-MM; wy: WYyyyy (October of the year before to September).
steps.<step>.valuesnumber | null []One per day or period; null = no record.
steps.<step>.qualityint | null []One per value, codes as in quality_codes.
licencestring"CC BY 4.0".
citestringCitation line (see release.json for the release id).

A week, month or water year has a value only when enough days have one (weekly 5 of 7, monthly 20 days, water year 330 days for flows; storage needs a reading in the last week). A monthly-only delivery line has month and water-year values only.

Values are rounded: daily and weekly to 1 cfs, monthly and water-year means to 0.1 cfs.

GET /api/v1/series/<id>.csvCSV

One series as a long table: every step, one row per period with a value.

curl --compressed "https://storage.googleapis.com/surfacewater-map-509303/api/v1/series/swp_nba.csv"
ColumnType, unitsMeaning
stepstringday, week, month or wy.
periodstringAs in the JSON: the day (YYYY-MM-DD), the Monday a week starts (YYYY-MM-DD), the month (YYYY-MM) or the water year (WYyyyy, October of the year before to September).
valuenumberThe value; rows without one are left out.
unitstringcfs or af.
qualitystringmeasured, estimated or monthly record.

GET /api/v1/sources.jsonJSON

The published series the map is built from: gauges, plants and report tables.

curl --compressed "https://storage.googleapis.com/surfacewater-map-509303/api/v1/sources.json"
FieldType, unitsMeaning
[].series_idstringSource series id, as used in daily_record.
[].sourcestringcdec, cdec_h, usgs, dayflow, cvo_dout, swpops, wdl, cwms, ... (agency and system).
[].stationstringStation or site code at that source.
[].paramstringSensor or parameter code.
[].kindstringflow or storage.
[].namestringName.
[].notesstringNotes on the series.

GET /api/v1/accounting/index.jsonJSON

The system ledgers: which systems have one.

curl --compressed "https://storage.googleapis.com/surfacewater-map-509303/api/v1/accounting/index.json"
FieldType, unitsMeaning
[].systemstringswp, cvp, friant, sac: the <system> of the ledger paths.
[].namestringName.
[].shortstringShort name.
[].estimatesboolWhether estimates/ holds loss estimates for it.

GET /api/v1/accounting/<system>.jsonJSON

A system's annual ledger: per reach and water or calendar year, the measured terms and the unmeasured gain / loss.

curl --compressed "https://storage.googleapis.com/surfacewater-map-509303/api/v1/accounting/swp.json"
FieldType, unitsMeaning
systemstringSystem id.
namestringName.
unitstring"af" (acre-feet per period).
sourcestringWhere the numbers come from.
incompletestringWhat the record lacks.
reaches[]objectid, name, note, gaps and the other descriptions of each reach.
annual[].reachstringReach id.
annual[].periodstringWYyyyy or CYyyyy.
annual[].basisstringdaily, monthly or b132 (DWR Bulletin 132).
annual[].headaf | nullFlow measured into the reach at its head.
annual[].inflowaf | nullMeasured inflows along the reach.
annual[].deliveryaf | nullMeasured deliveries (turnouts, diversions).
annual[].branchaf | nullMeasured branch and spill outflows.
annual[].storage_changeaf | nullChange in the storage of reservoirs or pools on the reach.
annual[].tailaf | nullFlow measured at the reach's end.
annual[].residual_totalaf | nullUnmeasured gain (+) or loss (−): what the measured terms leave unexplained (evaporation, seepage, unlisted users, ungauged inflow, measurement error). null when a term is missing.
annual[].operator_lossaf | nullThe operator's own booked losses, as printed, for comparison (negative = loss).
annual[].qualitystringmeasured, estimated (a term is an approximation), incomplete (a term is missing) or suspect.
annual[].subs[]objectSub-reaches: from, to, residual (af).

Rows carry only the terms that apply to the reach; other measured terms (inflow_unlisted, delivery_federal, residual_cdec, points_dwr, combined) are described in the reach notes.

Nothing in a ledger is modelled. Estimated loss ranges are in estimates/.

GET /api/v1/accounting/<system>.csvCSV

The annual ledger as a table, one row per reach and period (sub-reaches left out).

curl --compressed "https://storage.googleapis.com/surfacewater-map-509303/api/v1/accounting/cvp.csv"
ColumnType, unitsMeaning
systemstringSystem id.
reachstringReach id.
reach_namestringReach name.
periodstringWYyyyy or CYyyyy.
basisstringAs in the JSON.
headafAs in the JSON; blank = no record or does not apply.
inflowaf
deliveryaf
branchaf
storage_changeaf
tailaf
residual_totalaf
operator_lossaf
qualitystring

Further columns follow for the terms only some reaches have (inflow_unlisted, delivery_federal, residual_cdec, points_dwr, combined, combined_quality, note).

GET /api/v1/accounting/<system>_monthly.jsonJSON

A system's ledger by month: the same terms per reach and month.

curl --compressed "https://storage.googleapis.com/surfacewater-map-509303/api/v1/accounting/friant_monthly.json"
FieldType, unitsMeaning
systemstringSystem id.
unitstring"af".
monthsYYYY-MM[]Months of every list below.
reaches.<reach>.v.<term>af | null []head, inflow, delivery, branch, storage_change, tail and gain (the unmeasured gain (+) or loss (−)), per month.
reaches.<reach>.qstring[]Quality per month: measured, estimated, incomplete.
annual_extraobjectAnnual-only figures some reaches have (af).

GET /api/v1/accounting/<system>_monthly.csvCSV

The monthly ledger as a table, one row per reach and month.

curl --compressed "https://storage.googleapis.com/surfacewater-map-509303/api/v1/accounting/swp_monthly.csv"
ColumnType, unitsMeaning
systemstring
reachstring
monthYYYY-MM
headafTerms as in the JSON; blank = no record or does not apply.
inflowaf
deliveryaf
branchaf
storage_changeaf
tailaf
gainafUnmeasured gain (+) or loss (−).
qualitystring

GET /api/v1/estimates/index.jsonJSON

Estimates, not measurements: loss and open-term ranges, in their own files.

curl --compressed "https://storage.googleapis.com/surfacewater-map-509303/api/v1/estimates/index.json"
FieldType, unitsMeaning
layerstring"estimate".
labelstringWhat an estimate is here.
files[]objectname, path, system, about: one file per estimate set; every file says layer: "estimate" at its top.

Estimates are modelled from published inputs (reference evapotranspiration, rain, canal geometry, dry-year analogues). They are never added into a series, a ledger row or a total, and they are not part of the measured files.

The file layouts are the map's own (as the map loads them) and may change; the top-level layer, system and label fields are frozen.

GET /api/v1/tributaries/index.jsonJSON

Tributary flow requirements: the rivers, compliance points, instruments and requirements the Tributaries Map judges.

curl --compressed "https://storage.googleapis.com/surfacewater-map-509303/api/v1/tributaries/index.json"
FieldType, unitsMeaning
monthsYYYY-MM[]Months the verdict counts cover.
data_endYYYY-MM-DDLast day judged.
rivers[]objectid (the <river> of the river paths), name, basin, upper (an upper-watershed system), points (id, name, reach, gauge, reqs), files.
requirements.<id>objecttitle, instrument, section (judged, listed, proposed, reference), judge_label, reason (why it is not judged), gauge, compliance_point, mode (min, band, ramp, rmean, volume, event), effective (from, to), cite, data_notes.
instruments.<id>objectlabel, name, agency, kind.
gauges.<key>objectlabel, series (the source series id), operator.
excusestringWhat a shortfall means here: the requirement as written; it may have been excused or varied.

A requirement is judged against the daily mean at its compliance gauge, as written. A shortfall can have been excused or varied (a FERC order, a temporary urgency change); the event markers on the map show the ones on record.

GET /api/v1/tributaries/<river>.csvCSV

One river: per judged requirement and month, the day counts behind the verdict.

curl --compressed "https://storage.googleapis.com/surfacewater-map-509303/api/v1/tributaries/mokelumne.csv"
ColumnType, unitsMeaning
riverstringRiver id.
compliance_pointstringPoint id.
requirementstringRequirement id.
monthYYYY-MM
days_in_forceintDays the requirement applied.
days_metint
days_below_as_writtenintDays below the minimum as written.
days_above_bandintDays above a maximum or band.
days_nd_year_type_unknownintNot determinable: the year type was not published.
days_nd_no_gauge_valueintNot determinable: no gauge value.
days_nd_not_yet_publishedintNot determinable: the data are not yet published.
days_nd_other_clauseintNot determinable: a clause of the rule (see the requirement).
days_nd_temporary_varianceintNot determinable: a FERC-approved temporary variance.
days_provisionalintDays judged on provisional data.
days_usgs_estimatedintDays whose gauge value USGS marks estimated.
days_exceptedintDays inside an exception period of the rule.
days_above_written_range_notedintDays above the written range, noted.
lowestcfs | afLowest daily mean (a volume requirement: af to date; an event requirement, mode event: the highest mean over its stated hours in the window, judged once on the window's last day).
lowest_dayintDay of the month of the lowest value.
requirement_lowcfs | afLowest required value in the month (the lowest year type it could be).
requirement_highcfs | afHighest required value in the month.
largest_shortfall_pctnumberLargest shortfall of a day below, % of the minimum.

Only judged requirements have rows; the rest are listed in index.json with the reason.

api/v1/tributaries/<river>.json has the same counts as lists per requirement (months, and one list per column above).

GET /api/v1/notes.jsonJSON

The data notes: every source defect and pipeline fix found, with evidence, resolution and live status.

curl --compressed "https://storage.googleapis.com/surfacewater-map-509303/api/v1/notes.json"
FieldType, unitsMeaning
builtYYYY-MM-DDWhen the notes were built.
issues[].idstringNote id, as in the series' data_notes.
issues[].titlestring
issues[].kindstringsource_defect, pipeline_bug, ...
issues[].sourcestringThe source it is about.
issues[].affectsstring[]What it affects.
issues[].periodsstring[]Periods affected.
issues[].evidencestring
issues[].resolutionstring
issues[].statusstring
issues[].livestringWhether the fix is on the public site.
issues[].featuresstring[]Series ids it is about.
issues[].reachesstring[]Ledger reaches it is about.
issues[].requirementsstring[]Tributary requirement ids it is about.