Downloads v1
GET · POST · PATCH · DELETE https://api.trailsplits.com/v1
Key optional · 500 credits a day without one
Prebuilt regional packages, offline map extracts (PMTiles) and outdoor places packs, as signed links valid 24 hours. Credits are charged once per request; links need no key and support range requests. Request them in the API console or with your key.
Contract
What you get
Kinds of package:
- a PMTiles extract of the basemap for a region, for an offline map in your app;
- a places pack: TrailSplits' outdoor places per country, as GeoParquet, GeoPackage and GeoJSON.
Licence: every package carries LICENSE-AND-CREDITS.txt. The data is an ODbL 1.0 derivative of OpenStreetMap. What we sell is the service and the convenience, never exclusivity. A product made from a package credits "© OpenStreetMap contributors", and a database derived from it stays under ODbL.
Authentication
As watches-v1:
-
a secret API key (publishable keys get 403
scope_denied); -
or the owner's JWT with
?project=prj_….
The download links themselves need no key. They are signed and expire.
Endpoints
| Method and path | Body | Answer |
|---|---|---|
GET /v1/downloads/catalog | — | 200 {packages: Package[]}: the finished packages, newest first |
POST /v1/downloads | {package: "<id>"} | 201 Download: credits charged once; links valid 24 h |
GET /v1/downloads | — | 200 {downloads: Download[], month: {bytes, limit_bytes}}, this UTC month |
GET /v1/downloads/<package id>/<file>?dl=…&exp=…&sig=… | — | the file. Range requests work; the answer has an ETag, and the file's sha256 is in the catalog |
{
"id": "pmtiles_extract-alps-osm_weekly_20261004",
"kind": "pmtiles_extract",
"region": "alps",
"bbox": [4.2, 43.0, 17.2, 48.9],
"area_km2": 512340,
"release": "osm_weekly_20261004",
"source_ts": "2026-10-04T00:00:00Z",
"max_zoom": 14,
"formats": ["pmtiles"],
"size_bytes": 1234568124,
"files": [{ "name": "alps.pmtiles", "format": "pmtiles", "bytes": 1234567890, "sha256": "…" }],
"license": "ODbL-1.0",
"attribution": "© OpenStreetMap contributors, © OpenMapTiles",
"credits": 537
}
Download
{
"id": "dl_…",
"package": "pmtiles_extract-alps-osm_weekly_20261004",
"credits": 537,
"bytes": 1234568124,
"created_at": "…Z",
"expires_at": "…Z",
"links": [{ "file": "alps.pmtiles", "url": "https://api.trailsplits.com/v1/downloads/…?dl=…&exp=…&sig=…", "bytes": 1234567890, "sha256": "…" }]
}
-
Links stay valid until
expires_at, 24 h after the download was made, for any number of range requests. - They are bound to the package and file, never to a key, so share them only as you would the file.
-
GET /v1/downloadslists this month's downloads without the links.
Credits and caps
Provisional: the owner sets pricing numbers. These follow the pricing target, which shows offline packs as an add-on.
- PMTiles extract: 1 credit per 1,000 km² plus 1 per 100 MB.
- Places pack: 10 credits plus 1 per 10 MB.
-
Charged once, at
POST /v1/downloads, never per request: PMTiles clients read a file in many ranges.
Downloads per UTC month, in bytes:
| Free | Starter | Pro | Business |
|---|---|---|---|
| 2 GB | 25 GB | 250 GB | 1 TB |
Free's 2 GB is sized for trying a pack, as the pricing target's "sample pack". The paid plans aren't on sale yet.
Errors
The shape is the one from api-keys-usage-v1.
| Status | error | When |
|---|---|---|
| 400 | invalid_request | an unknown field, or no package |
| 403 | scope_denied | a publishable key |
| 403 | download_link_invalid | a link with a wrong signature, or for another file |
| 403 | download_link_expired | a link past exp |
| 429 | monthly_credits_exhausted | the credits would pass the month's allowance |
| 429 | download_cap (limit: "monthly_bytes") | the bytes would pass the plan's monthly cap |