The Sydney transit API you'll actually enjoy using
The TfNSW API can't be called from a browser. TransitKit can. Clean JSON, real bus departures, full CORS support. Live in 5 minutes.
Free to start. No credit card required.
{
"realtimeStatus": ["MONITORED"],
"isRealtimeControlled": true,
"location": {
"id": "204238",
"name": "Newtown Station, King St, Stand B",
"type": "platform",
"coord": [-33.898167, 151.178277],
"properties": {
"occupancy": "MANY_SEATS",
"stopId": "10101214",
"platform": "B",
"platformName": "Newtown Station, King St, Stand B"
},
"parent": {
"id": "204210",
"name": "Newtown Station, King St, Stand B, Newtown",
"type": "stop"
}
},
"departureTimePlanned": "2026-04-03T16:59:00Z",
"departureTimeBaseTimetable": "2026-04-03T16:59:00Z",
"departureTimeEstimated": "2026-04-03T17:05:24Z",
"transportation": {
"id": "nsw:31N10: :R:sj2",
"name": "Sydney Buses Network N10",
"number": "N10",
"description": "Sutherland to City Town Hall",
"product": { "class": 5, "name": "Sydney Buses Network" },
"operator": { "id": "2510", "name": "U-Go Mobility" },
"destination": {
"id": "10101101",
"name": "Town Hall Station",
"type": "stop"
}
},
"properties": {
"WheelchairAccess": "true",
"RealtimeTripId": "2197798"
}
}
// ...and you still need to infer isLive yourself,
// filter out trains, fix the coordinate order,
// and handle 200 OK "errors" in systemMessages{
"stop": "Newtown Station, King St, Stand B",
"departures": [
{
"route": "N10",
"destination": "Town Hall Station",
"scheduled": "2026-04-03T16:59:00Z",
"realtime": "2026-04-03T17:05:24Z",
"minutesAway": 6,
"isLive": true,
"wheelchairAccessible": true,
"occupancy": "MANY_SEATS"
}
]
}Everything the raw API should have been
TransitKit handles the painful parts so you can focus on building.
Works from the browser
The raw API doesn't
TfNSW has zero CORS support. Every OPTIONS preflight returns HTTP 500 with a SOAP XML fault. TransitKit has full CORS support — call it directly from any frontend.
No more type inference
Clean boolean fields
TfNSW has no isLive boolean. You have to compare timestamps and handle null values. TransitKit returns a clean is_live: true/false.
Buses only, guaranteed
No more filtering
TfNSW returns all transport modes together. Central Station dumps trains, metro, light rail and buses in one response. TransitKit filters to buses only.
Ghost stop protection
No phantom results
The TfNSW nearby API returns decommissioned stops with no flag. They claim to serve buses but return zero departures forever. TransitKit silently filters them.
Fixed coordinates
Consistent lat, lng everywhere
TfNSW query params take lng:lat, responses return [lat, lng]. TransitKit uses lat, lng consistently everywhere.
Real HTTP status codes
No more 200 OK errors
TfNSW returns HTTP 200 for errors, burying them in systemMessages. TransitKit returns proper 4xx/5xx codes with consistent JSON error shapes.
Future departures
Built-in timezone handling
Pass date and time to get departures at any future point. TransitKit handles the Sydney timezone conversion so you don't have to.
Clean disruption alerts
Plain text, no HTML parsing
TransitKit exposes disruption summaries as plain text — no HTML parsing required. e.g. "Buses replace trains between Waterfall and Sutherland".
Free tier
1,000 requests/day
Get started with 1,000 requests per day free. No credit card required. Upgrade when you need more.
Live in 5 minutes
Three steps. No SDK needed.
# 1. Get your free API key at transitkit.dev
# 2. Make your first request
curl https://api.transitkit.dev/v1/departures?stop=200060 \
-H "Authorization: Bearer YOUR_API_KEY"
# 3. Get clean JSON back instantlyWho builds with TransitKit
Mobile apps
iOS, Android, React Native transit apps
Property listings
Show transit scores for real estate
Hotel & venue displays
Real-time transport info for guests
Campus wayfinding
University and campus transit boards
Internal dashboards
Operations and monitoring tools
Ready to build?
Get your free API key and make your first request in under a minute.