A lightweight, stateless API that wraps the official MobilityData GTFS Validator and exposes it as a single /validate
endpoint.
Upload a GTFS .zip
or provide a URL, receive a validation report in your chosen format.
Feature | Notes |
---|---|
Serverless-ready | Designed for Google Cloud Run (default) but can run wherever Docker can. |
Fast cold-starts | One-shot Java CLI lives in a slim image; typical cold-start ≤ 3 s. |
Zero persistence | No database to manage (other than API keys...and those are optional). |
API-key & quota support | Optionally uses Firestore to manage users and API keys in order to impose rates based on keys. |
User registration & verification | Auto-issues API keys to emails which are verified. Currently leverages Mailjet's free usage tier to send verification emails. |
Language binding | Pure REST (OpenAPI 3.0 spec included) → generate clients for Python, JS/TS, Go, etc. |
Cost @ 100 feeds/day | Currently fits well inside Cloud Run's free tier. |
Full documentation of endpoints is at https://validategtfs.urbanlabs.io/docs
Note: you can also use the API directly from the docs by clicking "try out".
Method | Path | Body | Query Params | Response |
---|---|---|---|---|
POST |
/validate |
multipart/form-data field file (GTFS .zip ) or url (GTFS .zip URL) |
format (optional: json (default), html , errors ) |
200 OK JSON, HTML, or errors-only JSON report. 400 if neither or both file and url are provided.500 if validator fails. |
.zip
file upload. Use this for local files..zip
file. Use this to validate a remote file.json
(default): Full JSON validation report.html
: HTML validation report (as text/html
).errors
: Only errors (notices with severity ERROR
) as JSON.Note: You must provide either file
or url
, but not both.
Validate gtfsfeed.zip
curl -X POST \
-F "file=@gtfsfeed.zip" \
https://validategtfs.urbanlabs.io/validate
Use your API key in the header to increase your rate limits:
curl -X POST \
-F "file=@feed.zip" \
-H "x-api-key: <YOUR_API_KEY>" \
https://validategtfs.urbanlabs.io/validate
Validate a feed hosted remotely at mobilitydata.org:
curl -X POST \
-F "url=https://download.mobilitydata.org/gtfs/mdb/gtfs-2245.zip" \
-H "x-api-key: <YOUR_API_KEY>" \
https://validategtfs.urbanlabs.io/validate
Validate a feed and get returned the HTML report:
curl -X POST \
-F "url=https://download.mobilitydata.org/gtfs/mdb/gtfs-2245.zip" \
-H "x-api-key: <YOUR_API_KEY>" \
"https://validategtfs.urbanlabs.io/validate?format=html"
import requests
api_url = "https://https://validategtfs.urbanlabs.io/validate"
api_key = "<YOUR_API_KEY>"
gtfs_zipfile = "gtfsfeed.zip"
with open(gtfs_zipfile, "rb") as f:
response = requests.post(
api_url,
params={"format": "html"}, # <--- Optional. can be json (default), html or errors (which is also json)
files={"file": (gtfs_zipfile, f, "application/zip")}, # use this to validate a local feed
# url = "https://download.mobilitydata.org/gtfs/mdb/gtfs-2245.zip", # use this if you want to validate a feed at a URL
headers={"x-api-key": api_key}
)
print(response.status_code)
print(response.json())
const axios = require('axios');
const fs = require('fs');
const FormData = require('form-data');
const apiUrl = 'https://https://validategtfs.urbanlabs.io/validate';
const apiKey = '<YOUR_API_KEY>';
const form = new FormData();
form.append('file', fs.createReadStream('gtfsfeed.zip'));
axios.post(apiUrl, form, {
headers: {
...form.getHeaders(),
'x-api-key': apiKey
}
})
.then(res => {
console.log(res.data);
})
.catch(err => {
console.error(err.response ? err.response.data : err);
});
This hosted service is provided by UrbanLabs LLC and is provided "as is" without any warranty.
This service does not collect any personal data. It is provided by UrbanLabs LLC and is provided "as is" without any warranty.
Please provide feedback via GitHub Issues.
Already have a key? Use it in the x-api-key
header for higher limits.