The REST API
Everything the site displays — 15-minute flow readings, statistics,
analytics, comparisons, your tracked gages — is available programmatically
under /api/v1/. This page is the orientation: who gets access,
how authentication works, and what the rate limits mean. The
endpoint-by-endpoint detail — parameters, response schemas, copy-paste curl
and Python samples — lives in the
interactive API reference, and this page won't
duplicate it.
GET
requests against your own data right in the page, no key required.
Who gets access
Programmatic API access is a Research plan feature. On Research, the API console lets you provision named API keys, reveal or revoke them, watch today's usage, try requests live, and connect to the hosted MCP server. On other plans the console link shows current plans — and the entire reference is browsable without any plan at all, so you can evaluate the API before upgrading.
A key carries exactly the access your account has: the gages you can read through the API are the gages you track on the site, and plan limits (tracked-gage count, export formats) apply identically.
Authentication, in detail
Three credentials work; all of them are sent the same way on every request (except sessions, which ride the browser's cookie):
Authorization: Bearer <token>
API keys — for scripts, notebooks, and data pipelines
Long-lived tokens provisioned from the API console. Each key has a name, can be re-revealed later, and can be revoked individually — revocation takes effect on the next request. This is the right credential for anything unattended: cron jobs, notebooks, dashboards, MCP clients.
JWT access tokens — for short-lived, user-interactive tools
POST /api/v1/auth/token/ with a JSON body of
{"username": "you@example.com", "password": "…"} — the
username field accepts your email address, and the account
must have a verified email — returns an access/refresh token pair.
Access tokens expire after a few minutes; refresh via
POST /api/v1/auth/token/refresh/. Useful when you'd rather
not mint a durable key — but for anything that runs while you're not
watching, prefer an API key.
Browser session — for the interactive reference
Same-origin requests from a signed-in browser authenticate with the
session cookie automatically. This is what powers the try-it panel in the
reference. Writes (POST/PATCH/DELETE)
additionally require Django's CSRF header — the reference page handles
that for you; your own same-origin JavaScript must send
X-CSRFToken.
Quickstart
List the gages your account can read, then pull a month of readings:
curl -H "Authorization: Bearer $GAGELOG_API_KEY" \
"https://gagelog.com/api/v1/sources/"
curl -H "Authorization: Bearer $GAGELOG_API_KEY" \
"https://gagelog.com/api/v1/gages/?gage_key=USGS&start=2026-07-01&end=2026-08-01"
The same in Python, with pagination handled:
import os, requests
BASE = "https://gagelog.com/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['GAGELOG_API_KEY']}"}
def readings(gage_key, start, end):
rows, url = [], f"{BASE}/gages/"
params = {"gage_key": gage_key, "start": start, "end": end, "page_size": 5000}
while url:
resp = requests.get(url, headers=HEADERS, params=params, timeout=30)
resp.raise_for_status()
data = resp.json()
rows += [r for r in data["results"] if not r["flagged"]]
url, params = data.get("next"), None # "next" carries the query string
return rows
july = readings("USGS", "2026-07-01", "2026-08-01")
print(f"{len(july)} readings, mean {sum(r['cfs'] for r in july)/len(july):.1f} cfs")
Conventions that apply everywhere:
- Timestamps are UTC ISO-8601; flows are cubic feet per second (CFS).
- Exclude
"flagged": truereadings from any statistic — they're sensor errors (negative flows and the like), and the site's own analytics skip them too. - List endpoints paginate with
page/page_size(default 100, max 5000); follow thenextlink until null. - A water year runs Oct 1 – Sep 30 and is named for the year it ends in.
Rate limits & cost tiers
API-key traffic shares one daily quota (10,000 units/day by default), and every endpoint belongs to a cost tier that sets how many units a call consumes and how many calls per minute it allows:
| Tier | Per-minute cap | Quota cost / call | Endpoints |
|---|---|---|---|
| light | 120 / min | 1 unit | Readings, sources, monitors, exports — everything not listed below |
| medium | 30 / min | 2 units | Sensor analytics: summary, rolling, threshold, volume, data quality |
| heavy | 10 / min | 5 units | Multi-gage summary |
Those are the defaults — your plan's live numbers, today's count, and the
reset time come from GET /api/v1/developer/usage/ (which is
quota-exempt, so it still answers when you're over). Each endpoint's tier
is badged in the reference and shown on the
console's Usage tab. Over a limit you get 429 with a
Retry-After header; the daily counter resets at midnight UTC.
Browser-session and JWT calls don't count against the key quota.
What's in the API
The reference groups endpoints the same way:
| Family | What it covers |
|---|---|
| Flow data | Tracked sources and what's available to track; 15-minute readings; server-side analytics (window stats, rolling averages, threshold compliance, volumes, trends, data quality). |
| Alerts & jobs | Threshold/anomaly monitors and their events; async spreadsheet export builds; cold-storage archive state and restores. |
| Account & access | JWT minting, profile and preferences, your plan and its limits, API keys and usage. |
Errors you'll meet
| Status | Meaning |
|---|---|
401 | Bad, expired, or revoked credential — check the console. |
403 | Your plan doesn't include that capability, or the gage isn't tracked. |
429 | A per-minute cap or the daily quota was hit — the tier table above
says which limit applies; wait out Retry-After. |
The MCP server
Alongside REST, GageLog hosts a Model Context Protocol server — an open, vendor-neutral protocol for exposing an API as discoverable, self-describing tools. It mirrors the REST interface: readings, sources, and the full server-side analytics suite (window statistics, rolling averages, threshold compliance, volumes, trends, data quality, multi-gage comparisons) are callable as MCP tools, which makes it a natural fit for heavy analytics, research, and data-science workflows that orchestrate many queries.
https://gagelog.com/mcp
Authentication is the same Bearer API key you use for REST — sent as an
Authorization: Bearer header by your MCP client. There is
nothing separate to provision, and nothing separate to meter: MCP calls
are executed against the REST API on your behalf, so they draw from the
same daily quota and per-minute tiers described above, and
GET /api/v1/developer/usage/ reports both. The transport is
streamable HTTP (stateless), so any MCP-compatible client can connect
with a URL and a header:
{
"mcpServers": {
"gagelog": {
"url": "https://gagelog.com/mcp",
"headers": { "Authorization": "Bearer <your key>" }
}
}
}
The tool set covers the same families as the reference: listing sources
and gages, pulling 15-minute readings, every analytics endpoint, usage,
and plans. Each tool documents its units (CFS), date format
(YYYY-MM-DD), and cost tier, and an
openapi resource exposes the full REST schema for anything
not surfaced as a tool. Setup details live on the console's
MCP server tab.