Tutorial: USBR RISE data through the Western Water Datahub EDR API

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.

1. The ideas you need (and none you don’t)

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:

  1. The URL patterns are a standard. Once you can query rise-edr, you can query SNOTEL snowpack, USACE reservoir, and PRISM climate collections on the same server with the same URL grammar (section 10).
  2. Every response is available in machine-friendly formats (JSON, CSV) and a human-readable HTML page, so you can browse first and automate later.

Anatomy of a request URL

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 ────────┘
  • The base is always https://api.wwdh.internetofwater.app.
  • The path says what kind of thing you want (a list of locations, data at one location, a data cube over an area, …).
  • The query (everything after ?, with pieces separated by &) refines the request: format, dates, parameters, bounding box.

The format switch: 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.

If you use curl

Always wrap the URL in single quotes, because ? and & mean something to the shell:

curl -sS 'https://api.wwdh.internetofwater.app/collections/rise-edr?f=json'

Add -o filename to save the response to a file. That is all the curl you need for this tutorial.

2. Five-minute orientation in the browser

Open these three pages in order, just to look around:

  1. The landing page: https://api.wwdh.internetofwater.app
  2. The list of all collections on the server: https://api.wwdh.internetofwater.app/collections
  3. The RISE collection page: https://api.wwdh.internetofwater.app/collections/rise-edr

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):

3. Discover what RISE offers

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.

4. Find the parameter ids you need

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.

5. Find locations

You will usually start from a place, not a parameter: “what does RISE monitor near here?” There are two complementary tools.

5a. The locations map

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.

5b. The items catalog: filter, browse, download

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

6. Get data for one location

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&parameter-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&parameter-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.

Reading the response (CoverageJSON)

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.

7. Get data for many locations at once: /cube

When 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&parameter-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:

  • Keep the bbox tight and the date range short on the first try, then widen one thing at a time. Each cube request fans out to the upstream RISE API, so big requests are slow and can time out.
  • If a broad cube fails, fall back to the discovery pattern: find candidate ids with /items (section 5b), then request each one via /locations/{id} (section 6).

8. Get data inside a polygon: /area

If 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&parameter-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.

9. Downloading and using the data

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.

10. Interoperating beyond RISE

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).

Translating concepts across agencies: parameterGroups

Parameter 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&parameter-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&parameter-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.

11. The whole workflow on one page

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=...&parameter-name=...
5. MANY SERIES /collections/rise-edr/cube?f=json&bbox=...&datetime=...&parameter-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.

12. Troubleshooting

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.