This is an end-to-end tutorial on finding, retrieving, downloading, and reusing Bureau of Reclamation RISE data through the Western Water Datahub (WWDH) EDR interface.
It is written for USBR staff who are comfortable with computers but
are not web developers. You do not need to install anything or write any
code. Every step works by opening a URL in a normal web browser. Where a
command-line alternative is useful, a curl version is shown
too, but it is always optional.
Key example URLs in this tutorial were checked against the live service on June 10, 2026. The Datahub evolves, so if an example ever surprises you, start again from the discovery steps in sections 3 and 4 — those are the durable part.
RISE (data.usbr.gov) is Reclamation’s public data catalog: reservoir storage, elevations, releases, canal flows, weather observations, and more, organized by location and parameter.
EDR (OGC API - Environmental Data Retrieval) is an open standard for asking environmental data questions with plain URLs: “what do you have?”, “what stations are in this box?”, “give me parameter X at location Y between these dates.”
WWDH is a server that republishes RISE (and several
other federal water datasets) through that standard. The collection you
will use is called rise-edr.
Why go through WWDH instead of RISE directly? Two reasons:
rise-edr, you can query SNOTEL snowpack, USACE reservoir,
and PRISM climate collections on the same server with the same
URL grammar (section 10).Every request in this tutorial is just a URL with this shape:
https://api.wwdh.internetofwater.app / collections/rise-edr/locations/3514 ? f=json & parameter-name=3
└──────────────── base ─────────────┘ └───────────── path ──────────────┘ └───────── query ────────┘
https://api.wwdh.internetofwater.app.?, with
pieces separated by &) refines the request: format,
dates, parameters, bounding box.f=Almost every URL accepts an f parameter that picks the
response format. This is the single most useful thing to remember:
f= |
What you get | When to use it |
|---|---|---|
html |
A readable web page, often with a map or table | Browsing, orienting yourself, sharing a link with a colleague |
json |
Structured data (GeoJSON or CoverageJSON) | Downloads, scripts, GIS, Excel Power Query |
csv |
A spreadsheet-ready table (location/feature lists) | Direct download into Excel |
If you leave f= off, your browser usually gets the HTML
page and tools like curl usually get JSON. Being explicit
avoids surprises.
The HTML pages are genuinely useful — the locations page renders a
map, and the items page renders a sortable table — but they are a
window onto the data, not the data itself. When you want to
keep or analyze the numbers, switch the same URL to f=json
or f=csv.
Open these three pages in order, just to look around:
The RISE collection page shows the description (“a proxy of the RISE API into the OGC API EDR format”), the spatial extent, the list of parameters, and links to the four query types RISE supports. For the complete technical reference of every route and parameter, see the Swagger/OpenAPI page.
Here is the live collection page, embedded from the service (this and the other embedded views below require an internet connection; open in its own tab):
The machine-readable version of the collection page is the anchor for everything else:
https://api.wwdh.internetofwater.app/collections/rise-edr?f=json
Two blocks in that document matter most.
data_queries lists the query types this
collection supports. As of June 10, 2026, rise-edr
advertises four:
| Query type | URL path | Question it answers |
|---|---|---|
locations |
/collections/rise-edr/locations |
Where are the monitoring locations? What data does one location have? |
items |
/collections/rise-edr/items |
Feature catalog: searchable, filterable list of RISE locations with their attributes |
cube |
/collections/rise-edr/cube |
Give me data for everything inside this bounding box |
area |
/collections/rise-edr/area |
Give me data for everything inside this polygon |
Do not assume other EDR routes (like /position or
/radius) work for RISE — a route that is not advertised in
data_queries will return an error. Other collections on the
server advertise different sets.
parameter_names lists every data
variable you can request, keyed by RISE’s numeric parameter ids. Each
entry carries a human-readable name, description, and unit.
RISE parameters are identified by numbers, not names. The URL takes the number; the name and unit are there so humans can pick the right number. A few examples from the live metadata:
| Parameter id | Name | Unit |
|---|---|---|
3 |
Lake/Reservoir Storage (daily) | af |
1830 |
Lake/Reservoir Release - Total | cfs |
1834 |
Lake/Reservoir Elevation | ft |
1811 |
Precipitation | in |
1777 |
Water Temperature | °F |
There are hundreds more. Two ways to find the one you need:
In the browser: open https://api.wwdh.internetofwater.app/collections/rise-edr and use your browser’s find-in-page (Ctrl+F / Cmd+F) on the parameter list.
With curl and jq: pull just the id/name/unit triples:
curl -sS 'https://api.wwdh.internetofwater.app/collections/rise-edr?f=json' |
jq '.parameter_names | to_entries[] | {id: .key, name: .value.name, unit: .value.unit.symbol.value}'Note that the same concept (for example “Lake/Reservoir Storage”) may appear under several ids that differ by timestep or computation method. Read the description text before committing to an id, and remember: labels are for humans; ids go in URLs.
You will usually start from a place, not a parameter: “what does RISE monitor near here?” There are two complementary tools.
Open the locations page in a browser and you get a map of RISE locations:
https://api.wwdh.internetofwater.app/collections/rise-edr/locations
Constrain it with a bounding box. A bbox is four
comma-separated numbers — longitude and latitude, in this
order:
min_lon,min_lat,max_lon,max_lat
(Remember that longitudes in the western U.S. are negative, and the minimum longitude is the westernmost edge.) For example, the area around the lower Colorado River near Lake Mead and Lake Havasu:
https://api.wwdh.internetofwater.app/collections/rise-edr/locations?bbox=-115,33,-113,37
The live map (open in its own tab):
Switch the same URL to f=json to get the locations as a
GeoJSON FeatureCollection — each feature has an
id (the RISE location id you will use in section 6), a
point geometry, and properties such as locationName,
locationTypeName, elevation,
timezone, and projectNames.
The /items route serves the same locations as a
searchable feature catalog. In a browser it renders as a table
with one row per location:
https://api.wwdh.internetofwater.app/collections/rise-edr/items?f=html&bbox=-115,33,-111,35&locationTypeName=Lake%2FReservoir&limit=20
That request — checked live on June 10, 2026 — returns seven
lake/reservoir locations in a Lower Colorado bounding box, including
3515 (Lake Havasu Parker Dam and Powerplant) and several
Apache Lake sites. The live view (open
in its own tab):
Three things are happening in that URL:
bbox=-115,33,-111,35 limits the spatial window.locationTypeName=Lake%2FReservoir filters on a feature
property. The %2F is a URL-encoded / (the
value is literally Lake/Reservoir; a raw slash would
confuse the URL).limit=20 caps the number of rows. Start generous: some
filters are applied after the limit, so a small limit can hide
matches that a larger one finds.Which property names can you filter on? Ask the queryables route:
https://api.wwdh.internetofwater.app/collections/rise-edr/queryables?f=json
Any property listed there (such as locationTypeName or
projectNames) can be used as a query parameter on
/items.
Download the catalog as a spreadsheet: change
f=html to f=csv and the same filtered table
downloads as a CSV file that opens directly in Excel — including useful
engineering attributes like Total Capacity, Active Capacity, and
vertical datum notes where RISE has them:
https://api.wwdh.internetofwater.app/collections/rise-edr/items?f=csv&bbox=-115,33,-111,35&locationTypeName=Lake%2FReservoir&limit=20
Inspect one location: every row links to a
single-feature page, e.g. Lake Mead is location 3514:
https://api.wwdh.internetofwater.app/collections/rise-edr/items/3514
Once you know a location id and a parameter id, the data request is
one URL: /locations/{locationId} plus a date range and
parameter. Lake Mead (3514), daily storage
(3), January 2023:
https://api.wwdh.internetofwater.app/collections/rise-edr/locations/3514?f=json&datetime=2023-01-01/2023-01-31¶meter-name=3
Or as curl, saving to a file:
curl -sS -o lake-mead-jan2023.json \
'https://api.wwdh.internetofwater.app/collections/rise-edr/locations/3514?f=json&datetime=2023-01-01/2023-01-31¶meter-name=3'The two query parameters:
datetime= takes an ISO date, or a range with a slash:
2023-01-01/2023-01-31. Some providers accept an open end:
2023-01-01/... Without datetime, you may get
the full period of record — fine for some series, enormous for others.
Start narrow.parameter-name= takes one or more parameter ids,
comma-separated: parameter-name=3,1834.Data queries return CoverageJSON, a compact format that keeps the time axis and the values in parallel arrays:
{
"type": "Coverage",
"domain": {
"domainType": "PointSeries",
"axes": {
"x": {"values": [-114.7]},
"y": {"values": [36.0]},
"t": {"values": ["2023-01-01T07:00:00Z", "2023-01-02T07:00:00Z"]}
}
},
"ranges": {
"3": {
"type": "NdArray",
"axisNames": ["t"],
"values": [8730345, 8732112]
}
}
}To turn this into a table, pair them up positionally: the first time
in domain.axes.t.values goes with the first number in
ranges.{parameter}.values, the second with the second, and
so on. axisNames tells you which axis(es) the values run
along — for a single station it is just ["t"].
| t | value of parameter 3 (af) |
|---|---|
| 2023-01-01T07:00:00Z | 8730345 |
| 2023-01-02T07:00:00Z | 8732112 |
A note on CSV here: the server advertises f=csv on data
queries, but in testing the EDR data routes returned empty CSV bodies.
For time series, treat f=json as the dependable format and
convert it yourself (section 9), or use the /items CSV for
catalog tables.
/cubeWhen you want every matching series inside a bounding box, use the
cube route instead of looping over locations. All RISE
storage (3) series in a small box around Lake Havasu, for
calendar 2024:
https://api.wwdh.internetofwater.app/collections/rise-edr/cube?f=json&bbox=-114.3,34.1,-113.5,34.4&datetime=2024-01-01/2024-12-31¶meter-name=3
This returns a CoverageCollection: a
coverages array in which each entry is one location’s
series, with its own domain (the x/y coordinates and time
axis) and ranges (the values). The example above returns
one coverage — Lake Havasu, 365 daily storage values.
Practical guidance for cube:
/items (section 5b), then request each
one via /locations/{id} (section 6)./areaIf your area of interest is a watershed or management boundary rather
than a box, the area route accepts a polygon in WKT
(well-known text) via coords=. A readable WKT polygon:
POLYGON((-115 35,-113 35,-113 37,-115 37,-115 35))
URLs cannot contain spaces, so each space becomes
%20:
https://api.wwdh.internetofwater.app/collections/rise-edr/area?f=json&coords=POLYGON((-115%2035,-113%2035,-113%2037,-115%2037,-115%2035))&datetime=2024-01-01/2024-01-31¶meter-name=3
Two rules save most of the grief here: the polygon ring must close
(first coordinate repeated last), and every space must be encoded. For
complex boundaries, simplify the polygon first or use a tool that
encodes URLs for you — very long URLs can exceed browser and server
limits. If a box is close enough, prefer cube; it is
simpler and faster.
You now know how to build the URLs. Getting the results into your tools:
Browser: open the f=json URL and use
Save Page As (Ctrl+S / Cmd+S), or right-click a link and Save Link As.
The /items?f=csv URLs download directly as spreadsheet
files.
curl:
curl -sS -o output.json '<URL>'.
Excel: open /items CSV files directly.
For JSON time series, Data → Get Data → From Web in Excel’s Power Query
accepts the f=json URL and can unpivot
domain.axes.t.values against
ranges.{id}.values, though this takes some Power Query
comfort — many people find it easier to ask a script-writing colleague
(or an AI assistant) for a five-line converter from CoverageJSON to
CSV.
GIS: QGIS and ArcGIS read GeoJSON natively. In QGIS,
Layer → Add Layer → Add Vector Layer, choose Protocol: HTTP, and paste a
/locations?f=json or /items?f=json URL to map
RISE locations directly — no download step needed.
R: this package (edr4r) wraps all of
these routes; edr_locations(), edr_cube(), and
covjson_to_tibble() reproduce this tutorial in a few lines.
See the companion vignette, Western Water Datahub collection field
guide.
Python: requests plus the
covjson-pydantic or plain json module; the
axis/range pairing logic in section 6 is a five-line loop.
Everything above transfers. The same server hosts sibling collections that answer to identical URL grammar — only the collection id, the parameter ids, and the advertised query types change:
| Collection id | Source | Example use |
|---|---|---|
snotel-edr |
USDA NRCS SNOTEL | Snow water equivalent above your reservoir |
awdb-forecasts-edr |
USDA AWDB | Seasonal water supply forecasts |
usace-edr |
USACE Access2Water | Corps reservoir storage and outflow |
usgs-prism |
PRISM | Monthly precipitation and temperature grids |
Check each collection’s data_queries before assuming a
route exists (for example, usgs-prism supports
position and cube, not
locations).
parameterGroupsParameter ids differ across agencies: RISE storage is 3,
USACE storage is Flood Storage or
Conservation Storage. WWDH publishes a crosswalk in the
top-level collections document:
https://api.wwdh.internetofwater.app/collections?f=json
Its parameterGroups array maps a shared concept to each
collection’s ids. As checked on June 4, 2026, the
Lake/Reservoir Storage group included:
{
"name": "Lake/Reservoir Storage",
"members": {
"rise-edr": ["1470", "56", "51", "47", "3"],
"usace-edr": ["Flood Storage", "Conservation Storage",
"Percent Flood Pool", "Percent Conservation Pool"]
}
}So a cross-agency comparison of 2024 storage near Parker Dam is two parallel cube requests over the same bbox:
https://api.wwdh.internetofwater.app/collections/rise-edr/cube?f=json&bbox=-114.3,34.1,-113.5,34.4&datetime=2024-01-01/2024-12-31¶meter-name=3
https://api.wwdh.internetofwater.app/collections/usace-edr/cube?f=json&bbox=-114.3,34.1,-113.5,34.4&datetime=2024-01-01/2024-12-31¶meter-name=Flood%20Storage
(The %20 encodes the space in Flood Storage
— USACE uses worded ids.) When verified, the first returned Lake
Havasu’s 365 daily RISE storage values and the second returned Alamo
Dam’s Corps storage record for the same year. Expect timestep
differences across agencies: RISE returned daily values; the USACE
series was irregular. Aligning them is an analysis step, not an API
option.
1. ORIENT /collections/rise-edr (browser, f=html)
2. PARAMETERS /collections/rise-edr?f=json -> parameter_names: pick exact ids
3. LOCATIONS /collections/rise-edr/items?f=html&bbox=...&{queryable}=...&limit=...
-> browse table; switch to f=csv to download; note location ids
4. ONE SERIES /collections/rise-edr/locations/{id}?f=json&datetime=...¶meter-name=...
5. MANY SERIES /collections/rise-edr/cube?f=json&bbox=...&datetime=...¶meter-name=...
6. CROSSWALK /collections?f=json -> parameterGroups, then repeat 3-5 on the sibling collection
Start small — one location, one parameter, one month. Widen one dimension at a time once the small request works.
| Symptom | Likely cause | Fix |
|---|---|---|
| 404 on a query route | Route not advertised for this collection | Re-check data_queries in
/collections/rise-edr?f=json |
400 on /area |
WKT not URL-encoded or ring not closed | Encode spaces as %20; repeat the first coordinate at
the end |
| 204 / empty body | Valid request, but nothing matched | Try a different parameter id, location, or a shorter date range |
| Empty CSV from a data query | CSV not populated for EDR data routes | Use f=json for time series; f=csv works on
/items |
500 or very slow on /cube |
Upstream RISE could not satisfy a broad query | Shrink bbox, shorten dates, request one parameter |
Empty features on /items |
Filter too narrow, or limit too small |
Raise limit, drop filters one at a time, check the
f=html view |
| Wrong or empty data for a parameter | Parameter id not collected at that location | Open the location in the items table; try a sibling id from section 4 |
| Shell error before any response | URL not quoted in the terminal | Wrap the whole URL in single quotes |
| Numbers but no meaning | Units unknown | Look up the id under parameter_names — units are in the
metadata |
If you get stuck on what a route accepts, the OpenAPI page
documents every route and query parameter interactively, and every JSON
document on the server contains a links section pointing to
its related pages — when in doubt, follow the links.
/cube/area