openbart / docs

overview

openbart is an open-source REST JSON API for Bay Area Rapid Transit (BART) data. it bundles the static schedule, real-time trip updates, service alerts, and rolled-up line health into a single simple API.

all endpoints are GET, return JSON, and are served from https://openbart.com. the base path is /api/v1.

CORS is enabled for all origins, so you can call the API directly from a browser.

authentication

the API is open and works with no authentication. if you want a higher rate limit, pass an API key on every request using one of:

Authorization: Bearer <your-key>
X-API-Key: <your-key>

keys look like ob_sk_.... see rate limits below for how to request one.

rate limits

every response includes these headers so you can track usage:

X-RateLimit-Limit:     <your limit per minute>
X-RateLimit-Remaining: <requests left in this window>
X-RateLimit-Reset:     <unix timestamp when the window resets>
unauthenticated — 60 requests per minute per IP
authenticated — 300 requests per minute per key (default; configurable per key)

when you exceed the limit you'll get a 429 response with a Retry-After header.

need a higher limit, or want another transit agency indexed alongside BART? reach out to @theharryet on twitter.

responses

single resources are returned directly as a JSON object:

{ "id": "DBRK", "name": "Downtown Berkeley", ... }

list endpoints use a consistent pagination envelope:

{
  "items": [...],
  "pagination": { "offset": 0, "limit": 50, "total": 234 }
}

pagination params: ?offset=0&limit=50 (default 50, max 200).

errors return a standard shape with a matching HTTP status:

{ "error": { "code": "NOT_FOUND", "message": "Stop 'FAKE' not found" } }
200 — success
400 — bad request (invalid params)
401 — invalid or disabled API key
404 — resource not found
429 — rate limited
500 — internal server error

endpoints

/stops

stations and their platforms. each BART station is a parent stop with one or more platform children.

GET /api/v1/stops
list all stops
query params:
parent_only (boolean) only return parent stations (no platforms)
offset (integer) pagination offset (default 0)
limit (integer) page size (default 50, max 200)
returns: { items: Stop[], pagination: { offset, limit, total } }
GET /api/v1/stops/:id
single stop with its platforms (if parent) or parent station (if platform)
path params:
id (string, required) stop id (e.g. DBRK)
returns: Stop & { children: Stop[], parent: Stop | null }
GET /api/v1/stops/:id/arrivals
next N arrivals at a stop (sorted by arrival time), with route info and real-time delays overlaid
path params:
id (string, required) stop id
query params:
limit (integer) number of upcoming arrivals (default 10, max 50)
route_id (string) filter by route id
returns: { stopId, date, arrivals: [{ tripId, routeId, route, headsign, directionId, stopId, platformCode, stopSequence, arrivalTime, departureTime, realtime: { delay, uncertainty, predictedArrivalUnix } | null }] }
GET /api/v1/stops/:id/departures
next N departures from a stop, with route info and real-time delays overlaid
path params:
id (string, required) stop id
query params:
limit (integer) number of upcoming departures (default 10, max 50)
route_id (string) filter by route id
returns: { stopId, date, departures: [{ tripId, routeId, route, headsign, directionId, stopId, platformCode, stopSequence, arrivalTime, departureTime, realtime: { delay, uncertainty, predictedDepartureUnix } | null }] }
GET /api/v1/stops/:id/history
on-time performance for a station over the last N days
path params:
id (string, required) stop id
query params:
days (integer) window size in days (1–30, default 7)
returns: { stopId, days, totalSamples, onTimePct, avgDelaySec, worstDelaySec, majorDelayCount }
GET /api/v1/stops/:id/schedule
full scheduled day timetable for a stop
path params:
id (string, required) stop id
query params:
date (string) YYYYMMDD (defaults to today in America/Los_Angeles)
route_id (string) filter by route id
returns: { stopId, date, items: StopTime[] }

/routes

BART lines (Red, Blue, Yellow, Green, Orange, and others). each route has a color and direction.

GET /api/v1/routes
list all routes
returns: { items: Route[], pagination }
GET /api/v1/routes/:id
single route
path params:
id (string, required) route id
returns: Route
GET /api/v1/routes/:id/trips
trips that run on this route
path params:
id (string, required) route id
query params:
direction_id (0 | 1) filter by direction
offset (integer) pagination offset
limit (integer) page size
returns: { items: Trip[], pagination }
GET /api/v1/routes/:id/stops
ordered list of stops along the route
path params:
id (string, required) route id
query params:
direction_id (0 | 1) filter by direction
returns: { routeId, directionId, stops: [{ stopId, name, lat, lon, stopSequence }] }

/trips

a trip is a single train run — one vehicle going one direction on one route at a specific time.

GET /api/v1/trips/:id
single trip with its route info
path params:
id (string, required) trip id
returns: Trip & { route: Route }
GET /api/v1/trips/:id/stop-times
all scheduled stops for a trip, with real-time delays overlaid
path params:
id (string, required) trip id
returns: { tripId, items: [StopTime & { realtime: { arrivalDelay, departureDelay, ... } | null }] }

/realtime

live trip updates from BART's GTFS-RT feed. refreshed every minute.

GET /api/v1/realtime/trip-updates
latest real-time snapshot for all trips
query params:
route_id (string) filter by route id
trip_id (string) filter by trip id
returns: { items: TripUpdate[], pagination }
GET /api/v1/realtime/trip-updates/:tripId
latest real-time update for a single trip, including per-stop delays
path params:
tripId (string, required) trip id
returns: TripUpdate & { stopTimeUpdates: StopTimeUpdate[] }
GET /api/v1/realtime/stops/:stopId
latest real-time updates affecting a specific stop
path params:
stopId (string, required) stop id
returns: { stopId, items: StopTimeUpdate[], pagination }

/alerts

service disruptions, delays, and advisories published by BART.

GET /api/v1/alerts
active alerts, optionally filtered by route or stop
query params:
route_id (string) only alerts affecting this route
stop_id (string) only alerts affecting this stop
include_expired (boolean) also include deleted/expired alerts
offset (integer) pagination offset
limit (integer) page size
returns: { items: (Alert & { informedEntities: InformedEntity[] })[], pagination }
GET /api/v1/alerts/:id
single alert with informed entities and optional version history
path params:
id (integer, required) alert id
query params:
include_history (boolean) include all past versions of this alert
returns: Alert & { informedEntities, history?: AlertVersion[] }

/status

rolled-up service health — current line status and 90-day on-time performance.

GET /api/v1/status
overall system health and per-line status summary
returns: { overallStatus, generatedAt, lines: LineSummary[], activeAlertCount }
GET /api/v1/status/lines
per-line status in a paginated envelope
returns: { items: LineSummary[], pagination }
GET /api/v1/status/lines/:color/history
hourly history for one line
path params:
color (string, required) line color (e.g. RED, BLUE)
query params:
days (integer) how many days back (1–90, default 90)
returns: { color, name, displayColor, days, hourly: HourlyPoint[], summary }
GET /api/v1/status/alerts
current active alerts (with duration)
returns: { items: ActiveAlert[], pagination }

/system

metadata about the transit agencies, the feed itself, and route geometry.

GET /api/v1/agencies
list all transit agencies
returns: { items: Agency[], pagination }
GET /api/v1/agencies/:id
single agency
path params:
id (string, required) agency id
returns: Agency
GET /api/v1/feed-info
latest feed version and freshness info
returns: FeedInfo
GET /api/v1/shapes/:shapeId
GeoJSON LineString for a route shape (useful for drawing on a map)
path params:
shapeId (string, required) shape id
returns: { shapeId, type: 'LineString', coordinates: [lon, lat][] }