This documents the external Shubble API (
api-shuttles.rpi.edu), not Meridian core REST. It lives under Mobile because shuttle surfaces ship primarily in campus mobile experiences.Base URL
Overview
The Shubble API provides real-time shuttle tracking data for Rensselaer Polytechnic Institute (RPI). All endpoints return JSON data and do not require authentication for GET requests.Response Headers
Some endpoints include helpful timing headers:X-Server-Time: Current server time in ISO formatX-Oldest-Data-Time: Timestamp of the oldest data point in the responseX-Data-Age-Seconds: Age of the oldest data point in seconds
Endpoints
1. GET /api/locations
Returns the latest location for each vehicle currently inside the geofence. Response: Object keyed by vehicle ID, containing location data for each active shuttle. Example Request:name(string): Vehicle name/numberlatitude(number): GPS latitude coordinatelongitude(number): GPS longitude coordinatetimestamp(string): ISO 8601 timestamp of the location readingheading_degrees(number): Vehicle heading in degrees (0-360)speed_mph(number): Vehicle speed in miles per houris_ecu_speed(boolean): Whether speed is from ECU or GPSformatted_location(string): Human-readable addressaddress_id(string): Samsara address IDaddress_name(string): Name of the location/addresslicense_plate(string): Vehicle license platevin(string): Vehicle identification numberasset_type(string): Type of asset (typically “vehicle”)gateway_model(string): Gateway device modelgateway_serial(string): Gateway device serial numberdriver(object|null): Current driver informationid(string): Driver IDname(string): Driver name
2. GET /api/velocities
Returns predicted velocity and route matching data for each vehicle currently inside the geofence. Response: Object keyed by vehicle ID, containing velocity predictions and route information. Example Request:speed_kmh(number|null): Predicted speed in kilometers per hourtimestamp(string): ISO 8601 timestamp of the velocity readingroute_name(string|null): Name of the matched route (e.g., “NORTH”, “WEST”) or null if not matchedpolyline_index(number|null): Index into the route polyline arrayis_at_stop(boolean): Whether the vehicle is currently at a stopcurrent_stop(string|null): Name of the current stop ifis_at_stopis true
3. GET /api/etas
Returns ETA (Estimated Time of Arrival) information for each vehicle currently inside the geofence. Response: Object keyed by vehicle ID, containing predicted arrival times for each stop on the route. Example Request:stop_times(object): Object keyed by stop name, containing ISO 8601 timestamps for predicted arrival timestimestamp(string): ISO 8601 timestamp when the ETA predictions were calculated
4. GET /api/routes
Returns route definitions including polylines, stops, and colors. Response: Object containing route definitions for all shuttle routes. Example Request:COLOR(string): Hex color code for the route (e.g., “#FF0000” for red)STOPS(array): List of stop identifiers in orderPOLYLINE_STOPS(array): List of stops including ghost stops for polyline rendering[STOP_NAME](object): Stop definition objects containing:COORDINATES(array): [latitude, longitude]OFFSET(number): Offset into the polyline arrayNAME(string): Human-readable stop name
ROUTES(object): Route variants keyed by route identifier, containing:POLYLINE(array): Array of [latitude, longitude] coordinate pairs
5. GET /api/schedule
Returns the shuttle schedule organized by day and route. Response: Object containing schedule data organized by day type and route. Example Request:- Day names map to day type strings (“weekday”, “saturday”, “sunday”)
- Day type objects contain route schedules keyed by route name
- Each route schedule is an array of [time, route_name] pairs
6. GET /api/today
Returns all location data and geofence events for today (campus timezone). Response: Object keyed by vehicle ID, containing historical location data and geofence entry/exit times. Example Request:entry(string|null): ISO 8601 timestamp of first geofence entry today, or null if not enteredexit(string|null): ISO 8601 timestamp of geofence exit today, or null if still in geofencedata(array): Array of location readings throughout the day, each containing:latitude(number): GPS latitudelongitude(number): GPS longitudetimestamp(string): ISO 8601 timestampspeed_mph(number): Speed in miles per hourheading_degrees(number): Heading in degreesaddress_id(string): Samsara address ID
7. GET /api/aggregated-schedule
Returns aggregated schedule data. Response: Aggregated schedule information (may return 404 if file not found). Status: May not be available on all deployments.8. GET /api/matched-schedules
Returns matched schedules with vehicle-to-stop assignments. Response: Object containing matched schedule information. Example Request:status(string): “success” or “error”matchedSchedules(object): Matched schedule data (may be empty)source(string): “computed” or “recomputed”
9. POST /api/webhook
Webhook endpoint for receiving geofence events from Samsara. Authentication: Requires Samsara webhook signature verification. Request Headers:X-Samsara-Timestamp: Timestamp of the webhookX-Samsara-Signature: HMAC signature for verification
Error Responses
All endpoints may return standard HTTP error codes:400 Bad Request: Invalid request parameters404 Not Found: Resource not found405 Method Not Allowed: HTTP method not supported500 Internal Server Error: Server error
Rate Limiting & Caching
- Most endpoints are cached with Redis (15-300 second TTLs)
- No explicit rate limiting is enforced, but excessive requests may be throttled
- Cache headers are not currently exposed in responses
Frontend Integration Examples
JavaScript/TypeScript Example
React Hook Example
Notes for Frontend Developers
-
Vehicle IDs: Vehicle IDs are large integers (e.g.,
281474977371235). Use them as keys in client-side maps keyed by vehicle id. -
Timestamps: All timestamps are in ISO 8601 format with UTC timezone (
+00:00). Convert to local time as needed. -
Route Matching: Use
/api/velocitiesto get route matching data. Theroute_namewill benullif the vehicle is not close enough to any route (< 0.050 distance threshold). -
Empty Responses: If no vehicles are in the geofence, endpoints return empty objects
{}. -
Data Freshness: Check the
X-Data-Age-Secondsheader on/api/locationsto determine how fresh the data is. - CORS: The API may have CORS restrictions. If building a frontend on a different domain, you may need to configure CORS or use a proxy.
- Polling Frequency: Recommended polling interval is 15-30 seconds to balance freshness with server load.