Skip to content

Waterways

National Philippines rivers, streams, canals, lakes, and related water features, derived from the HOT OSM / HDX Philippines waterways export.

This is OSM-derived volunteer mapping for maps and overlays — not NAMRIA cadastral hydrography and not a navigation chart. Completeness varies by region.

GIS.PH waterways layer list over a Philippine outline

Illustration of the layer list and map chrome. Live maps use signed PMTiles (HOT OSM), not this static outline. Keep © OpenStreetMap contributors on every map.

LicenseODbL — keep © OpenStreetMap contributors on every map
Source of truthPostGIS (gis.waterways_*). PMTiles are a simplified paint derivative
AuthAPI key required to list layers and mint a paint session. Range tile requests use a short-lived signed URL, not the API key

Waterways are not a GeoJSON list of rivers. You mint a signed PMTiles URL and the map library Range-fetches tiles (HTTP 206).

Request access if you do not have a key yet.

SlugGeometryTypical content
ph_waterways_lineslinesRivers, streams, canals, drains
ph_waterways_polygonspolygonsLakes, reservoirs, wetlands, water bodies
ph_waterways_pointspointsSprings and other waterway points

Use these slugs with the tiles endpoints. MapLibre source-layer is the same as the slug.

Your app + API key
→ POST /v1/tiles/sessions { "slug": "ph_waterways_lines" }
← signed pmtiles:// URL (exp + HMAC)
MapLibre
→ HTTP Range GETs on /tiles/pmtiles/ph_waterways_lines?exp=&sig=
→ Worker serves tiles from private storage (206)

The Worker does not query PostGIS for each map tile. Rebuilds from PostGIS to PMTiles are an offline job, not a public API.

All /v1/tiles* calls need Authorization: Bearer $API_KEY. Without a key, production returns 401.

Terminal window
curl -sS https://api.gis.ph/v1/tiles \
-H "Authorization: Bearer $API_KEY"

GET /v1/tiles sample request and JSON

{
"data": [
{
"slug": "ph_waterways_lines",
"title": "PH Waterways (lines)",
"open_access": false,
"paint_path": "/tiles/pmtiles/ph_waterways_lines"
},
{
"slug": "ph_waterways_polygons",
"title": "PH Waterways (polygons)",
"open_access": false,
"paint_path": "/tiles/pmtiles/ph_waterways_polygons"
},
{
"slug": "ph_waterways_points",
"title": "PH Waterways (points)",
"open_access": false,
"paint_path": "/tiles/pmtiles/ph_waterways_points"
}
],
"error": null
}

The array can include other allowlisted layers (for example LULC). Find the ph_waterways_* slugs in data[].slug.

Unauthenticated:

{"message":"Unauthorized"}

This is the call an app uses.

Terminal window
curl -sS -X POST https://api.gis.ph/v1/tiles/sessions \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"slug":"ph_waterways_lines","ttl_seconds":3600}'

POST /v1/tiles/sessions sample request and JSON

{
"data": {
"slug": "ph_waterways_lines",
"url": "https://api.gis.ph/tiles/pmtiles/ph_waterways_lines?exp=1724380000&sig=…",
"path": "/tiles/pmtiles/ph_waterways_lines?exp=1724380000&sig=…",
"maplibre_url": "pmtiles://https://api.gis.ph/tiles/pmtiles/ph_waterways_lines?exp=1724380000&sig=…",
"exp": 1724380000,
"expires_at": "2026-08-23T01:32:00.000Z",
"ttl_seconds": 3600
},
"error": null
}

Pass data.maplibre_url to MapLibre. That is the client output — not a FeatureCollection of rivers.

  • Default TTL is 3600 seconds (min 60, max 86400).
  • Re-mint before expires_at, or when Range requests start returning 401.
  • Unknown slug → 404. Missing key → 401. Signing not configured → 503.

GET /tiles/pmtiles/:slug?exp=&sig=

Terminal window
curl -sS -D - -o /dev/null \
-H "Range: bytes=0-16383" \
"$URL_FROM_SESSION"

206 + binary PMTiles bytes (Content-Type: application/vnd.pmtiles). No JSON geometries.

StatusMeaning
401Missing/invalid key, or expired/bad exp/sig
404Unknown slug, or object missing in storage
403GET without Range (full-file download is disabled)
206Tile / header bytes

/tmp/:slug is a deprecated alias of the same handler — use /tiles/pmtiles/:slug.

Register the pmtiles protocol, then use data.maplibre_url from the session.

import maplibregl from "maplibre-gl";
import { Protocol } from "pmtiles";
const protocol = new Protocol();
maplibregl.addProtocol("pmtiles", protocol.tile);
const session = await fetch("https://api.gis.ph/v1/tiles/sessions", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ slug: "ph_waterways_lines", ttl_seconds: 3600 }),
}).then((r) => r.json());
map.addSource("waterways", {
type: "vector",
url: session.data.maplibre_url,
attribution: "© OpenStreetMap contributors",
});
map.addLayer({
id: "waterways-line",
type: "line",
source: "waterways",
"source-layer": "ph_waterways_lines",
paint: { "line-color": "#3b82f6", "line-width": 1.25 },
});

Polygons: slug ph_waterways_polygons, layer type fill. Points: slug ph_waterways_points, layer type circle.

Do not put a long-lived API key in a public webpage. Mint sessions from your backend, or use a restricted key and still treat it as a secret.

  • Show © OpenStreetMap contributors (ODbL) on the map.
  • Data is crowd-sourced; gaps and tagging errors are expected.
  • Snapshot is a HOT export (refresh is operational, not a client-facing version pin today).
  • Geometry in tiles is simplified for paint. Server-side “waterways near X” queries are not this endpoint.