A powerful Bun API for fetching real-time train information from the UK's Realtime Trains service. Get detailed train schedules, unit numbers, stops, operators, and more. Vibecoded lol.
✨ Core Features
- 🚂 Get train unit numbers and formations
- 📍 Fetch detailed stop information with real-time updates
- 🔍 Search by station code or full station name
- 📅 Query any date (defaults to today)
- 🎯 Find services by time and destination
- ⏱️ View scheduled and real-time arrival/departure times
- 🚫 Optional non-stop passes display
- 💾 Built-in caching for better performance
- ⚡ Lazy-loaded station database (2,600+ stations)
- Bun
# Clone the repository
# Install dependencies
bun install
# Start the development server
bun run dev
# Deploy to vercel
vc --prodServer runs on http://localhost:3000
Get all trains departing from a station at a given time.
Method: POST
Request Body:
{
"stationCodeOrName": "KGX",
"date": "2026-01-01",
"fromTime": "0900"
}Parameters:
stationCodeOrName(required) - Station code (e.g.,KGX) or name (e.g.,London Kings Cross)date(optional) - Date inYYYY-MM-DDformat. Defaults to todayfromTime(optional) - Start time inHHMMformat (e.g.,0900)
Response:
{
"stationCode": "KGX",
"stationName": "London Kings Cross",
"date": "2026-01-01",
"count": 5,
"services": [
{
"time": "1003",
"destination": "Edinburgh",
"href": "/service/gb-nr:C41110/2026-01-01#allox_id=0"
}
]
}Find a service by time and optionally destination.
Method: POST
Request Body:
{
"stationCodeOrName": "KGX",
"time": "1003",
"destinationCodeOrName": "Edinburgh",
"date": "2026-01-01"
}Parameters:
stationCodeOrName(required) - Origin stationtime(required) - Departure time inHHMMformatdestinationCodeOrName(optional) - Destination station code or namedate(optional) - Date inYYYY-MM-DDformat
Response (without destination):
{
"stationCode": "KGX",
"stationName": "London Kings Cross",
"date": "2026-01-01",
"time": "1003",
"count": 1,
"services": [
{
"destination": "Edinburgh",
"href": "/service/gb-nr:C41110/2026-01-01#allox_id=0"
}
]
}Response (with destination):
{
"stationCode": "KGX",
"stationName": "London Kings Cross",
"date": "2026-01-01",
"time": "1003",
"destination": "Edinburgh",
"simpleUrl": "https://www.realtimetrains.co.uk/service/gb-nr:C41110/2026-01-01",
"detailedUrl": "https://www.realtimetrains.co.uk/service/gb-nr:C41110/2026-01-01/detailed"
}Get the train unit numbers for a specific service.
Method: POST
Request Body:
{
"stationCodeOrName": "HGS",
"time": "1850",
"destinationCodeOrName": "CHX",
"date": "2025-12-31"
}Parameters:
stationCodeOrName(required) - Origin stationtime(required) - Departure time inHHMMformatdestinationCodeOrName(required) - Destination stationdate(optional) - Date inYYYY-MM-DDformat
Response:
{
"stationCode": "HGS",
"stationName": "Hastings",
"date": "2025-12-31",
"time": "1850",
"destination": "London Charing Cross",
"unitNumbers": ["375708", "375909"],
"urls": {
"simple": "https://www.realtimetrains.co.uk/service/gb-nr:J31261/2025-12-31",
"detailed": "https://www.realtimetrains.co.uk/service/gb-nr:J31261/2025-12-31/detailed"
}
}Get comprehensive train information including all stops.
Method: POST
Request Body:
{
"stationCodeOrName": "HGS",
"time": "1850",
"destinationCodeOrName": "CHX",
"date": "2025-12-31",
"includeTimes": true,
"includeNonStops": true
}Parameters:
stationCodeOrName(required) - Origin stationtime(required) - Departure time inHHMMformatdestinationCodeOrName(required) - Destination stationdate(optional) - Date inYYYY-MM-DDformatincludeTimes(optional, default:true) - Include arrival/departure timesincludeNonStops(optional, default:false) - Include pass-through locations
Response:
{
"stationCode": "HGS",
"stationName": "Hastings",
"date": "2025-12-31",
"time": "1850",
"destination": "London Charing Cross",
"unitNumbers": ["375708", "375909"],
"operator": "Southeastern",
"carriages": 8,
"stops": [
{
"code": "HGS",
"name": "Hastings",
"platform": "3",
"scheduledDeparture": "1850",
"realtimeDeparture": "1850",
"isStop": true
},
{
"code": "SLQ",
"name": "St Leonards Warrior Square",
"platform": "1",
"scheduledArrival": "1853",
"scheduledDeparture": "1853",
"realtimeArrival": "1852¼",
"realtimeDeparture": "1853",
"isStop": true
},
{
"name": "Mountfield Tunnel",
"scheduledDeparture": "1911",
"realtimeDeparture": "1913¾",
"isStop": false
}
],
"urls": {
"simple": "https://www.realtimetrains.co.uk/service/gb-nr:J31261/2025-12-31",
"detailed": "https://www.realtimetrains.co.uk/service/gb-nr:J31261/2025-12-31/detailed"
}
}Check API status.
Method: GET
Response:
{
"status": "ok"
}# Get unit numbers using station codes
curl -X POST http://localhost:3000/train \
-H "Content-Type: application/json" \
-d '{
"stationCodeOrName": "HGS",
"time": "1850",
"destinationCodeOrName": "CHX"
}'# Works with full station names too
curl -X POST http://localhost:3000/train \
-H "Content-Type: application/json" \
-d '{
"stationCodeOrName": "Hastings",
"time": "1850",
"destinationCodeOrName": "London Charing Cross"
}'curl -X POST http://localhost:3000/services \
-H "Content-Type: application/json" \
-d '{
"stationCodeOrName": "KGX",
"fromTime": "0900"
}'curl -X POST http://localhost:3000/detailed \
-H "Content-Type: application/json" \
-d '{
"stationCodeOrName": "KGX",
"time": "1003",
"destinationCodeOrName": "EDB",
"includeTimes": true,
"includeNonStops": true
}'curl -X POST http://localhost:3000/train \
-H "Content-Type: application/json" \
-d '{
"stationCodeOrName": "KGX",
"date": "2025-12-31",
"time": "2030",
"destinationCodeOrName": "Edinburgh"
}'- Station Data: Loaded once on first request (2,600+ stations)
- Services: Cached for 5 minutes per date/time combo
- Deduplication: Multiple concurrent requests for same service reuse single fetch
- Cold Start (first request): ~500ms-2s
- Warm Cache (subsequent requests): ~100-500ms
- Detailed Info: ~2-5s (multiple page fetches)
All endpoints return appropriate HTTP status codes:
200- Success400- Bad request (validation error)500- Server error
Error Response:
{
"error": "Unknown station: \"XYZ\""
}API Request
↓
Hono Router + Zod Validators
↓
Station Code Resolver (lazy-loaded from API)
↓
Realtime Trains Scraper
↓
Cheerio HTML Parser
↓
JSON Response
↓
Client
- Input Validation - Zod validates request schema
- Station Resolution - Convert code/name to station code
- Service Lookup - Fetch services from Realtime Trains
- Service Matching - Find specific service by time/destination
- Detail Extraction - Scrape detailed train info if needed
- Response Formatting - Return structured JSON
⚠️ Scrapes website (not official API) - subject to HTML changes- 🔄 No real-time push updates (polling only)
- 📊 Historical data not available
- 🔐 No authentication required or provided
- 🌍 UK trains only (National Rail network)
- WebSocket for live updates
- Request deduplication across concurrent calls
- Historical data storage
- Train tracking by unit number
- Batch endpoints
- Analytics dashboard
Contributions welcome! Please:
- Test your changes
- Update README if needed
- Follow existing code style
- Submit PR with description
- Verify station code (e.g.,
KGXnotKG) - Try full name (e.g.,
London Kings Cross)
- Check date format (
YYYY-MM-DD) - Check time format (
HHMM, 24-hour) - Verify service exists at that time
- Normal - station data loads on first use
- Subsequent requests are cached
- No trains at that time/date combination
- Try removing
fromTimeto see all services
MIT License - feel free to use for personal/commercial projects
This API is unofficial and not affiliated with National Rail or Realtime Trains. Use at your own risk. Web scraping may violate terms of service.