MetroHero API Reference

Welcome to MetroHero's public API documentation! Here you can browse the APIs we currently offer. To start using our APIs, you'll need to request a unique API key from us. Please email us at contact@dcmetrohero.com to get started.

All of our public APIs are available for free. In return, we require the following:

  • You must abide by WMATA's Transit Data Terms of Use; by using our APIs, you agree to these terms of service.
  • Any data returned by or derived from data returned by our APIs must be freely available to all users of your application. Any paywalled application that utilizes our APIs must also provide a free tier with access to the same data returned by or derived from our APIs.
  • Any data returned by or derived from data returned by our APIs must be prominently credited back to MetroHero. For example, if this data is being displayed to users on a website or in an application, MetroHero must always be visually credited wherever and whenever the data appears or is used.

We reserve the right to revoke API access for anyone who does not abide by the above stipulatons. In fact, we reserve the right to revoke API access for any reason at any time, and cannot make any guarantees about the availability of our APIs nor the validity of the data returned by our APIs. For more information, see WMATA's Transit Data Terms of Use; consider our SLA (service level agreement) the same as theirs.

By default, all users are limited to 10 calls to any of our APIs per second, and 50,000 calls per 24 hours. These restrictions are similar to the rate limits WMATA currently has in place for their APIs, and are subject to change in the future. If you anticipate multiple users of your application, we suggest you create your own central server as a proxy to our APIs, polling and caching our data periodically to ensure you stay below our rate limits. You can then have your clients make requests to your central server rather than our servers directly, which gives you total control over how frequently calls are made to our APIs. If you still require a higher rate limit, please email us at contact@dcmetrohero.com.

Per WMATA's Transit Data Terms of Use, as of October 12th, 2017, basic user data (name, email address, API usage) may be shared with WMATA for statistical research purposes, and you may be blocked from accessing our APIs at any time, all upon WMATA's request.


WMATA is our primary upstream data provider, but does not otherwise endorse our services nor the use of our APIs. In the event that we, MetroHero, decide to stop providing our APIs permanently or temporarily, WMATA is under no obligation to provide similar APIs.

API Endpoint
https://dcmetrohero.com/api/v1
Terms of Service: https://developer.wmata.com/license
Contact: contact@dcmetrohero.com
Schemes: https
Version: v1

Metrorail

System Metrics

GET /metrorail/metrics

Gets real-time system-wide metrics, broken down by line and direction of travel. This includes everything from the number of trains and train cars to calculations like average minimum headways, train frequencies, platform wait times, and more. Data is updated about every 30 seconds.

apiKey: string
in header

Your unique API key, provided by us. If you don't have one yet, email us at contact@dcmetrohero.com.

200 OK

System metrics successfully retrieved.

400 Bad Request

Invalid request. Make sure the required apiKey header is specified.

401 Unauthorized

You either didn't specify an API key, or the API key you specified was invalid or rejected. Please email us at contact@dcmetrohero.com for assistance.

503 Service Unavailable

You specified a valid request, but our servers aren't yet ready to accept it. This can happen if our servers have restarted recently, or if there is otherwise a problem with our servers. Please try again soon. Alternatively, you may have exceeded our rate limits: by default, all users are limited to 10 calls to any of our APIs per second, and 50,000 calls per 24 hours.

Response Content-Types: application/json
Response Example (200 OK)
{
  "lineMetricsByLine": {
    "RD": "object",
    "OR": {
      "lineCode": "OR",
      "expectedNumTrains": 22,
      "numTrains": 22,
      "numEightCarTrains": 11,
      "numDelayedTrains": 2,
      "numCars": 154,
      "averageTrainDelay": 120,
      "medianTrainDelay": 115,
      "minimumTrainDelay": 0,
      "maximumTrainDelay": 365,
      "averageMinimumHeadways": 6.12,
      "averageTrainFrequency": 6.12,
      "expectedTrainFrequency": 6,
      "averagePlatformWaitTime": 3.12,
      "expectedPlatformWaitTime": 3,
      "trainFrequencyStatus": "OK",
      "platformWaitTimeTrendStatus": "NEUTRAL",
      "averageHeadwayAdherence": 66.6,
      "averageScheduleAdherence": 66.6,
      "standardDeviationTrainFrequency": 1.9,
      "expectedStandardDeviationTrainFrequency": 1.8,
      "directionMetricsByDirection": {
        "1": {
          "lineCode": "OR",
          "directionNumber": 1,
          "direction": "Eastbound",
          "towardsStationName": "New Carrollton",
          "expectedNumTrains": 11,
          "numTrains": 11,
          "numEightCarTrains": 5,
          "numDelayedTrains": 1,
          "numCars": 76,
          "averageTrainDelay": 100,
          "medianTrainDelay": 95,
          "minimumTrainDelay": 0,
          "maximumTrainDelay": 365,
          "averageMinimumHeadways": 6.12,
          "averageTrainFrequency": 6.12,
          "expectedTrainFrequency": 6,
          "averagePlatformWaitTime": 3.12,
          "expectedPlatformWaitTime": 3,
          "trainFrequencyStatus": "OK",
          "platformWaitTimeTrendStatus": "NEUTRAL",
          "averageHeadwayAdherence": 66.6,
          "averageScheduleAdherence": 66.6,
          "standardDeviationTrainFrequency": 1.9,
          "expectedStandardDeviationTrainFrequency": 1.8,
          "date": "2017-06-12T08:24:26.655-04:00"
        },
        "2": "object"
      },
      "date": "2017-06-12T08:24:26.655-04:00"
    },
    "SV": "object",
    "BL": "object",
    "YL": "object",
    "GR": "object"
  },
  "date": "2017-06-12T08:24:26.655-04:00"
}

Trip Info

GET /metrorail/trips/{fromStationCode}/{toStationCode}

Gets real-time trip information given current conditions. The algorithms behind this API take, when available, both current conditions and conditions in the recent past into account--including any train delays and congestion--to make predictions about how long riders may be waiting or have been waiting for the next train to service the specified trip, as well as how long the trip might take once they're aboard.

Trips with station transfers are not directly supported. For example, to get trip information from Glenmont to Vienna, split the trip up into segments (e.g. Glenmont to Metro Center, then Metro Center to Vienna) and perform a separate request to this API for each segment. You can then aggregate the results across the responses of each API request however you see fit to make your own derived predictions about the trip as a whole.

apiKey: string
in header

Your unique API key, provided by us. If you don't have one yet, email us at contact@dcmetrohero.com.

fromStationCode: string
in path

The RTU station code of the origin station of the trip. For example, if you want to request trip info for the trip from Vienna (K08) to Metro Center (C01), you should specify K08 for this param. An unofficial list of valid Metrorail station codes can be found here. Only station codes for revenue stations are supported.

toStationCode: string
in path

The RTU station code of the destination station of the trip. For example, if you want to request trip info for the trip from Vienna (K08) to Metro Center (C01), you should specify C01 for this param. An unofficial list of valid Metrorail station codes can be found here. Only station codes for revenue stations are supported.

200 OK

Trip info successfully retrieved.

400 Bad Request

Invalid request. Make sure the apiKey header and all other required parameters are specified. Also make sure the trip you specified doesn't require a transfer. If it does, refer to the description of this API to learn how to handle this case.

401 Unauthorized

You either didn't specify an API key, or the API key you specified was invalid or rejected. Please email us at contact@dcmetrohero.com for assistance.

503 Service Unavailable

You have exceeded our rate limits: by default, all users are limited to 10 calls to any of our APIs per second, and 50,000 calls per 24 hours.

Response Content-Types: application/json
Response Example (200 OK)
{
  "fromStationName": "Vienna",
  "fromStationCode": "K08",
  "toStationName": "Metro Center",
  "toStationCode": "C01",
  "tripStationCodes": [
    "K08",
    "K07",
    "K06",
    "K05",
    "K04",
    "K03",
    "K02",
    "K01",
    "C05",
    "C04",
    "C03",
    "C02",
    "C01"
  ],
  "lineCodes": [
    "OR"
  ],
  "expectedRideTime": 26.12,
  "predictedRideTime": 30.3303,
  "timeUntilNextTrain": 2.02,
  "timeSinceLastTrain": 4.26,
  "fromStationTrainStatuses": [
    {
      "trainId": "155",
      "realTrainId": "901",
      "Car": "8",
      "Destination": "Vienna",
      "DestinationCode": "K08",
      "DestinationName": "Vienna",
      "Group": "1",
      "Line": "OR",
      "LocationCode": "C01",
      "LocationName": "Metro Center",
      "Min": "1",
      "parentMin": "1",
      "minutesAway": 0.89,
      "maxMinutesAway": 1.12,
      "directionNumber": 1,
      "isScheduled": false,
      "numPositiveTags": 1,
      "numNegativeTags": 3,
      "trackNumber": 1,
      "currentStationCode": "C01",
      "currentStationName": "Metro Center",
      "PreviousStationCode": "D01",
      "previousStationName": "Federal Triangle",
      "secondsSinceLastMoved": 65,
      "isCurrentlyHoldingOrSlow": true,
      "secondsOffSchedule": 145,
      "trainSpeed": 23,
      "isNotOnRevenueTrack": false,
      "isKeyedDown": false,
      "wasKeyedDown": false,
      "distanceFromNextStation": 502,
      "lat": 38.89383299999999,
      "lon": -77.02806700000001,
      "direction": 2,
      "observedDate": "Aug 11, 2017 3:51:54 PM"
    }
  ],
  "metroAlerts": [
    {
      "description": "Orange/Blue Line: Trains operate every 24 min w/ single tracking btwn Eastern Market & Stadium-Armory due to scheduled maintenance.",
      "stationCodes": [
        "D07",
        "D06",
        "D08"
      ],
      "lineCodes": [
        "OR",
        "SV"
      ],
      "keywords": [
        "long waits"
      ],
      "date": "2018-04-28T06:49:57-04:00"
    }
  ],
  "metroAlertKeywords": [
    "long waits"
  ],
  "tweets": [
    {
      "twitterId": 990273931222437900,
      "twitterIdString": "990273931222437888",
      "userId": 94625247,
      "text": "@Metrorailinfo does Silver line exist? Been waiting at Ballston, no info about next Wiehle-bound anywhere. Just had a No Passenger come through instead, that was nice",
      "stationCodes": [
        "K04"
      ],
      "lineCodes": [
        "SV"
      ],
      "keywords": [
        "long waits"
      ],
      "url": "https://twitter.com/180912906/status/990301719224573954",
      "date": "2018-04-28T06:49:57-04:00"
    }
  ],
  "tweetKeywords": [
    "long waits"
  ],
  "fromStationElevatorOutages": [],
  "fromStationEscalatorOutages": [],
  "toStationElevatorOutages": [],
  "toStationEscalatorOutages": [
    {
      "stationCode": "C01",
      "stationName": "Metro Center, G and 12th St Entrance",
      "locationDescription": "Escalator between upper and lower platforms",
      "symptomDescription": "Service Call",
      "unitName": "C01N05",
      "unitType": "ESCALATOR",
      "outOfServiceDate": "2018-04-28T09:27:00-04:00",
      "updatedDate": "2018-04-28T09:30:19-04:00",
      "estimatedReturnToServiceDate": "2018-04-29T09:00:00-04:00"
    }
  ],
  "date": "2018-04-28T06:50:34-04:00"
}

Tweets

GET /metrorail/tweets

Gets the last 30 minutes' worth of Metrorail-related tweets from Twitter. These tweets may be describing a problem with a particular station or train, a general problem on a given line, or nothing meaningful at all; while we do our best using various heuristics to only include relevant tweets, we make no guarantees.

apiKey: string
in header

Your unique API key, provided by us. If you don't have one yet, email us at contact@dcmetrohero.com.

200 OK

An ordered list of tweets by the date they were tweeted; the most recent tweet will appear first in the list. This can be null.

type
400 Bad Request

Invalid request. Make sure the required apiKey header is specified.

401 Unauthorized

You either didn't specify an API key, or the API key you specified was invalid or rejected. Please email us at contact@dcmetrohero.com for assistance.

503 Service Unavailable

You specified a valid request, but our servers aren't yet ready to accept it. This can happen if our servers have restarted recently, or if there is otherwise a problem with our servers. Please try again soon. Alternatively, you may have exceeded our rate limits: by default, all users are limited to 10 calls to any of our APIs per second, and 50,000 calls per 24 hours.

Response Content-Types: application/json
Response Example (200 OK)
[
  {
    "twitterId": 990273931222437900,
    "twitterIdString": "990273931222437888",
    "userId": 94625247,
    "text": "@Metrorailinfo does Silver line exist? Been waiting at Ballston, no info about next Wiehle-bound anywhere. Just had a No Passenger come through instead, that was nice",
    "stationCodes": [
      "K04"
    ],
    "lineCodes": [
      "SV"
    ],
    "keywords": [
      "long waits"
    ],
    "url": "https://twitter.com/180912906/status/990301719224573954",
    "date": "2018-04-28T06:49:57-04:00"
  }
]

Train Positions

GET /metrorail/trains

Gets real-time train predictions for the entire Metrorail system. These predictions are unique per train, i.e. exactly one prediction is returned per train. This API is intended to be used as an alternative to WMATA's Train Positions API, but does not return the exact same data, nor is it in the same format. We calculate our train predictions independently of WMATA by observing train movement over time.

Train predictions are returned in no particular order.

apiKey: string
in header

Your unique API key, provided by us. If you don't have one yet, email us at contact@dcmetrohero.com.

Train predictions successfully retrieved.

400 Bad Request

Invalid request. Make sure the required apiKey header is specified.

401 Unauthorized

You either didn't specify an API key, or the API key you specified was invalid or rejected. Please email us at contact@dcmetrohero.com for assistance.

503 Service Unavailable

You have exceeded our rate limits: by default, all users are limited to 10 calls to any of our APIs per second, and 50,000 calls per 24 hours.

Response Content-Types: application/json
Response Example (200 OK)
[
  {
    "trainId": "155",
    "realTrainId": "901",
    "Car": "8",
    "Destination": "Vienna",
    "DestinationCode": "K08",
    "DestinationName": "Vienna",
    "Group": "1",
    "Line": "OR",
    "LocationCode": "C01",
    "LocationName": "Metro Center",
    "Min": "1",
    "parentMin": "1",
    "minutesAway": 0.89,
    "maxMinutesAway": 1.12,
    "directionNumber": 1,
    "isScheduled": false,
    "numPositiveTags": 1,
    "numNegativeTags": 3,
    "trackNumber": 1,
    "currentStationCode": "C01",
    "currentStationName": "Metro Center",
    "PreviousStationCode": "D01",
    "previousStationName": "Federal Triangle",
    "secondsSinceLastMoved": 65,
    "isCurrentlyHoldingOrSlow": true,
    "secondsOffSchedule": 145,
    "trainSpeed": 23,
    "isNotOnRevenueTrack": false,
    "isKeyedDown": false,
    "wasKeyedDown": false,
    "distanceFromNextStation": 502,
    "lat": 38.89383299999999,
    "lon": -77.02806700000001,
    "direction": 2,
    "observedDate": "Aug 11, 2017 3:51:54 PM"
  }
]

Train Reports

GET /metrorail/trains/tags

Gets real-time rider reports, referred to as tags, for all trains. All tags are of predefined types (e.g. 'New Train', 'Crowded', 'Smooth Ride', etc) submitted by MetroHero users. These tags expire anywhere from 15 to 60 minutes after they've been created, depending on the type of tag; only current, unexpired tags are returned by this API.

Train tags are ordered by tag type in descending order by current number of active tags.

apiKey: string
in header

Your unique API key, provided by us. If you don't have one yet, email us at contact@dcmetrohero.com.

200 OK

Train tags successfully retrieved.

type
object
400 Bad Request

Invalid request. Make sure the required apiKey header is specified.

401 Unauthorized

You either didn't specify an API key, or the API key you specified was invalid or rejected. Please email us at contact@dcmetrohero.com for assistance.

503 Service Unavailable

You have exceeded our rate limits: by default, all users are limited to 10 calls to any of our APIs per second, and 50,000 calls per 24 hours.

Response Content-Types: application/json
Response Example (200 OK)
{
  "253": "object",
  "012": {
    "numTagsByType": [
      {
        "BAD_OPERATOR": 1,
        "ISOLATED_CARS": 1,
        "NEW_TRAIN": 1,
        "BROKEN_INTERCOM": 0,
        "CROWDED": 0,
        "EMPTY": 0,
        "GOOD_OPERATOR": 0,
        "GOOD_RIDE": 0,
        "NEEDS_WORK": 0,
        "RECENTLY_OFFLOADED": 0,
        "UNCOMFORTABLE_RIDE": 0,
        "UNCOMFORTABLE_TEMPS": 0,
        "WRONG_DESTINATION": 0,
        "WRONG_NUM_CARS": 0
      }
    ],
    "numPositiveTags": 1,
    "numNegativeTags": 2
  }
}

Train Report

GET /metrorail/trains/{trainId}/tags

Gets real-time rider reports about a particular train, referred to as tags. All tags are of predefined types (e.g. 'New Train', 'Crowded', 'Smooth Ride', etc) submitted by MetroHero users. These tags expire anywhere from 15 to 60 minutes after they've been created, depending on the type of tag; only current, unexpired tags are returned by this API.

Train tags are ordered by tag type in descending order by current number of active tags.

apiKey: string
in header

Your unique API key, provided by us. If you don't have one yet, email us at contact@dcmetrohero.com.

trainId: string
in path

The AIMS internal ID of the train, as returned by WMATA's Train Positions API. This should be a three-digit string anywhere from 001 to 512.

200 OK

Train tags successfully retrieved.

400 Bad Request

Invalid request. Make sure the apiKey header and all other required parameters are specified.

401 Unauthorized

You either didn't specify an API key, or the API key you specified was invalid or rejected. Please email us at contact@dcmetrohero.com for assistance.

503 Service Unavailable

You have exceeded our rate limits: by default, all users are limited to 10 calls to any of our APIs per second, and 50,000 calls per 24 hours.

Response Content-Types: application/json
Response Example (200 OK)
{
  "numTagsByType": [
    {
      "BAD_OPERATOR": 1,
      "ISOLATED_CARS": 1,
      "NEW_TRAIN": 1,
      "BROKEN_INTERCOM": 0,
      "CROWDED": 0,
      "EMPTY": 0,
      "GOOD_OPERATOR": 0,
      "GOOD_RIDE": 0,
      "NEEDS_WORK": 0,
      "RECENTLY_OFFLOADED": 0,
      "UNCOMFORTABLE_RIDE": 0,
      "UNCOMFORTABLE_TEMPS": 0,
      "WRONG_DESTINATION": 0,
      "WRONG_NUM_CARS": 0
    }
  ],
  "numPositiveTags": 1,
  "numNegativeTags": 2
}

Train Predictions

GET /metrorail/stations/trains

Gets real-time and scheduled train predictions for all stations. For each station, this API returns all of the same data as WMATA's Real-Time Rail Predictions API, but with additional real-time train predictions (including, optionally, scheduled train predictions), and additional fields for those predictions, like estimated train speed and direction of travel. We calculate our train predictions independently of WMATA by observing train movement over time.

Disclaimer: None of the above should be interpretted as a claim that our data is more accurate, more complete, or more timely than WMATA's data, we are simply stating some of the factual differences between the two datasets; as with all our APIs, we make no claims as to the accuracy of the data returned.

Each set of train predictions for each station is in ascending order by minutesAway. When the request parameter includeScheduledPredictions is set to false, our data can be used as a drop-in substitute for WMATA's Real-Time Rail Predictions API.

apiKey: string
in header

Your unique API key, provided by us. If you don't have one yet, email us at contact@dcmetrohero.com.

includeScheduledPredictions: boolean
in query

True if you want predictions made using scheduled train data to be returned in addition to predictions made using real-time data, otherwise set to false and only predictions made using real-time data will be returned. The default is false if this isn't specified.

200 OK

Train predictions successfully retrieved.

type
object
400 Bad Request

Invalid request. Make sure the required apiKey header is specified.

401 Unauthorized

You either didn't specify an API key, or the API key you specified was invalid or rejected. Please email us at contact@dcmetrohero.com for assistance.

503 Service Unavailable

You have exceeded our rate limits: by default, all users are limited to 10 calls to any of our APIs per second, and 50,000 calls per 24 hours.

Response Content-Types: application/json
Response Example (200 OK)
{
  "C01": [
    {
      "trainId": "155",
      "realTrainId": "901",
      "Car": "8",
      "Destination": "Vienna",
      "DestinationCode": "K08",
      "DestinationName": "Vienna",
      "Group": "1",
      "Line": "OR",
      "LocationCode": "C01",
      "LocationName": "Metro Center",
      "Min": "1",
      "parentMin": "1",
      "minutesAway": 0.89,
      "maxMinutesAway": 1.12,
      "directionNumber": 1,
      "isScheduled": false,
      "numPositiveTags": 1,
      "numNegativeTags": 3,
      "trackNumber": 1,
      "currentStationCode": "C01",
      "currentStationName": "Metro Center",
      "PreviousStationCode": "D01",
      "previousStationName": "Federal Triangle",
      "secondsSinceLastMoved": 65,
      "isCurrentlyHoldingOrSlow": true,
      "secondsOffSchedule": 145,
      "trainSpeed": 23,
      "isNotOnRevenueTrack": false,
      "isKeyedDown": false,
      "wasKeyedDown": false,
      "distanceFromNextStation": 502,
      "lat": 38.89383299999999,
      "lon": -77.02806700000001,
      "direction": 2,
      "observedDate": "Aug 11, 2017 3:51:54 PM"
    }
  ]
}

Station Train Predictions

GET /metrorail/stations/{stationCode}/trains

Gets real-time and scheduled train predictions for a particular station. This API returns all of the same data as WMATA's Real-Time Rail Predictions API, but with additional real-time train predictions (including, optionally, scheduled train predictions), and additional fields for those predictions, like estimated train speed and direction of travel. We calculate our train predictions independently of WMATA by observing train movement over time.

Disclaimer: None of the above should be interpretted as a claim that our data is more accurate, more complete, or more timely than WMATA's data, we are simply stating some of the factual differences between the two datasets; as with all our APIs, we make no claims as to the accuracy of the data returned.

Train predictions are returned in ascending order by minutesAway. When the request parameter includeScheduledPredictions is set to false, our data can be used as a drop-in substitute for WMATA's Real-Time Rail Predictions API.

apiKey: string
in header

Your unique API key, provided by us. If you don't have one yet, email us at contact@dcmetrohero.com.

stationCode: string
in path

The RTU station code of the station. An unofficial list of valid Metrorail station codes can be found here. Only station codes for revenue stations are supported. For transfer stations with two levels, like Metro Center, you can specify both of its two RTU station codes separated by a comma to get train predictions for both levels (e.g. "A01,C01").

includeScheduledPredictions: boolean
in query

True if you want predictions made using scheduled train data to be returned in addition to predictions made using real-time data, otherwise set to false and only predictions made using real-time data will be returned. The default is false if this isn't specified.

Train predictions successfully retrieved.

400 Bad Request

Invalid request. Make sure the apiKey header and all other required parameters are specified.

401 Unauthorized

You either didn't specify an API key, or the API key you specified was invalid or rejected. Please email us at contact@dcmetrohero.com for assistance.

503 Service Unavailable

You have exceeded our rate limits: by default, all users are limited to 10 calls to any of our APIs per second, and 50,000 calls per 24 hours.

Response Content-Types: application/json
Response Example (200 OK)
[
  {
    "trainId": "155",
    "realTrainId": "901",
    "Car": "8",
    "Destination": "Vienna",
    "DestinationCode": "K08",
    "DestinationName": "Vienna",
    "Group": "1",
    "Line": "OR",
    "LocationCode": "C01",
    "LocationName": "Metro Center",
    "Min": "1",
    "parentMin": "1",
    "minutesAway": 0.89,
    "maxMinutesAway": 1.12,
    "directionNumber": 1,
    "isScheduled": false,
    "numPositiveTags": 1,
    "numNegativeTags": 3,
    "trackNumber": 1,
    "currentStationCode": "C01",
    "currentStationName": "Metro Center",
    "PreviousStationCode": "D01",
    "previousStationName": "Federal Triangle",
    "secondsSinceLastMoved": 65,
    "isCurrentlyHoldingOrSlow": true,
    "secondsOffSchedule": 145,
    "trainSpeed": 23,
    "isNotOnRevenueTrack": false,
    "isKeyedDown": false,
    "wasKeyedDown": false,
    "distanceFromNextStation": 502,
    "lat": 38.89383299999999,
    "lon": -77.02806700000001,
    "direction": 2,
    "observedDate": "Aug 11, 2017 3:51:54 PM"
  }
]

Station Reports

GET /metrorail/stations/tags

Gets real-time rider reports, referred to as tags, for all stations. All tags are of predefined types (e.g. 'Friendly or Helpful Staff', 'Broken Escalator', etc) and are either explicitly submitted by MetroHero users, or implicitly derived from public WMATA-related tweets on Twitter by our algorithms. These tags expire anywhere from 15 to 180 minutes after they've been created, depending on the type of tag; only current, unexpired tags are returned by this API.

Station tags are ordered by tag type in descending order by current number of active tags.

apiKey: string
in header

Your unique API key, provided by us. If you don't have one yet, email us at contact@dcmetrohero.com.

200 OK

StationTags successfully retrieved.

type
object
400 Bad Request

Invalid request. Make sure the required apiKey header is specified.

401 Unauthorized

You either didn't specify an API key, or the API key you specified was invalid or rejected. Please email us at contact@dcmetrohero.com for assistance.

503 Service Unavailable

You have exceeded our rate limits: by default, all users are limited to 10 calls to any of our APIs per second, and 50,000 calls per 24 hours.

Response Content-Types: application/json
Response Example (200 OK)
{
  "A02": {
    "numTagsByType": [
      {
        "FRIENDLY_OR_HELPFUL_STAFF": 1,
        "UNCOMFORTABLE_TEMPS": 1,
        "AMPLE_SECURITY": 0,
        "BROKEN_ELEVATOR": 0,
        "BROKEN_ESCALATOR": 0,
        "CROWDED": 0,
        "EMPTY": 0,
        "LONG_WAITING_TIME": 0,
        "NEEDS_WORK": 0,
        "POSTED_TIMES_INACCURATE": 0,
        "SMOKE_OR_FIRE": 0,
        "UNFRIENDLY_OR_UNHELPFUL_STAFF": 0
      }
    ],
    "numPositiveTags": 1,
    "numNegativeTags": 1
  },
  "C05": "object"
}

Station Report

GET /metrorail/stations/{stationCode}/tags

Gets real-time rider reports about a particular station, referred to as tags. All tags are of predefined types (e.g. 'Friendly or Helpful Staff', 'Broken Escalator', etc) and are either explicitly submitted by MetroHero users, or implicitly derived from public WMATA-related tweets on Twitter by our algorithms. These tags expire anywhere from 15 to 180 minutes after they've been created, depending on the type of tag; only current, unexpired tags are returned by this API.

Station tags are ordered by tag type in descending order by current number of active tags.

apiKey: string
in header

Your unique API key, provided by us. If you don't have one yet, email us at contact@dcmetrohero.com.

stationCode: string
in path

The RTU station code of the station. An unofficial list of valid Metrorail station codes can be found here. Only station codes for revenue stations are supported.

200 OK

Station tags successfully retrieved.

400 Bad Request

Invalid request. Make sure the apiKey header and all other required parameters are specified.

401 Unauthorized

You either didn't specify an API key, or the API key you specified was invalid or rejected. Please email us at contact@dcmetrohero.com for assistance.

503 Service Unavailable

You have exceeded our rate limits: by default, all users are limited to 10 calls to any of our APIs per second, and 50,000 calls per 24 hours.

Response Content-Types: application/json
Response Example (200 OK)
{
  "numTagsByType": [
    {
      "FRIENDLY_OR_HELPFUL_STAFF": 1,
      "UNCOMFORTABLE_TEMPS": 1,
      "AMPLE_SECURITY": 0,
      "BROKEN_ELEVATOR": 0,
      "BROKEN_ESCALATOR": 0,
      "CROWDED": 0,
      "EMPTY": 0,
      "LONG_WAITING_TIME": 0,
      "NEEDS_WORK": 0,
      "POSTED_TIMES_INACCURATE": 0,
      "SMOKE_OR_FIRE": 0,
      "UNFRIENDLY_OR_UNHELPFUL_STAFF": 0
    }
  ],
  "numPositiveTags": 1,
  "numNegativeTags": 1
}

Metrobus (BETA)

Route Metrics

GET /metrobus/routes/{routeId}/metrics

Gets real-time route metrics given current conditions. This includes data like headway and schedule deviation, and can be used to assess how well a particular route is performing.

apiKey: string
in header

Your unique API key, provided by us. If you don't have one yet, email us at contact@dcmetrohero.com.

routeId: string
in path

The base bus route ID, as defined by the route IDs returned by WMATA's Bus Routes API, except we don't support variants, e.g. 10Av1 (use 10A instead).

200 OK

Route metrics successfully retrieved.

400 Bad Request

Invalid request. Make sure the apiKey header and all other required parameters are specified.

401 Unauthorized

You either didn't specify an API key, or the API key you specified was invalid or rejected. Please email us at contact@dcmetrohero.com for assistance.

503 Service Unavailable

You specified a valid request, but our servers aren't yet ready to accept it. This can happen if our servers have restarted recently, or if there is otherwise a problem with our servers. Please try again soon. Alternatively, you may have exceeded our rate limits: by default, all users are limited to 10 calls to any of our APIs per second, and 50,000 calls per 24 hours.

Response Content-Types: application/json
Response Example (200 OK)
{
  "routeId": "X2",
  "numObservedBuses": 6,
  "numExpectedBuses": 5,
  "headwayAdherence": 82,
  "scheduleAdherence": 46,
  "observedAverageHeadway": 12.04,
  "expectedAverageHeadway": 13.35,
  "numBusesAheadOfSchedule": 0,
  "numBusesBehindSchedule": 3,
  "standardDeviationFromSchedule": 5.42,
  "date": "2017-06-12T08:24:26.655-04:00"
}

Bus Positions

GET /metrobus/routes/{routeId}/buses

Gets real-time bus predictions for a particular route.

apiKey: string
in header

Your unique API key, provided by us. If you don't have one yet, email us at contact@dcmetrohero.com.

routeId: string
in path

The base bus route ID, as defined by the route IDs returned by WMATA's Bus Routes API, except we don't support variants, e.g. 10Av1 (use 10A instead).

200 OK

Bus predictions successfully retrieved.

400 Bad Request

Invalid request. Make sure the apiKey header and all other required parameters are specified.

401 Unauthorized

You either didn't specify an API key, or the API key you specified was invalid or rejected. Please email us at contact@dcmetrohero.com for assistance.

503 Service Unavailable

You have exceeded our rate limits: by default, all users are limited to 10 calls to any of our APIs per second, and 50,000 calls per 24 hours.

Response Content-Types: application/json
Response Example (200 OK)
[
  {
    "id": "6236",
    "latitude": 38.901482,
    "longitude": -77.032219,
    "destinationName": "LAFAYETTE SQUARE",
    "tripId": "922289620",
    "tripDirection": "WEST",
    "deviationFromSchedule": 2,
    "lastPositionUpdateString": "2017-08-22T13:36:22",
    "previousStopId": "1001191",
    "previousStopName": "I ST NW + 14TH ST NW",
    "nextStopId": "1001185",
    "nextStopName": "I ST NW + 15TH ST NW",
    "normalizedDistanceToNextStop": 0.952850788114076,
    "estimatedTimeToNextStop": 52,
    "estimatedDistanceFromPreviousStop": 11,
    "estimatedDistanceToNextStop": 213,
    "numStopsAway": 2,
    "scheduledArrival": "2017-08-22T13:45:30",
    "routeId": "X2",
    "timeToBusInFront": 373,
    "timeFromBusBehind": 674,
    "numPositiveTags": 1,
    "numNegativeTags": 0,
    "estimatedSpeed": 16
  }
]

Bus Reports

GET /metrobus/buses/tags

Gets real-time rider reports, referred to as tags, for all buses. All tags are of predefined types (e.g. 'Good Operator', 'Disruptive Rider', 'Skipping Stops', etc) submitted by MetroHero users. These tags expire anywhere from 15 to 180 minutes after they've been created, depending on the type of tag; only current, unexpired tags are returned by this API.

Bus tags are ordered by tag type in descending order by current number of active tags.

apiKey: string
in header

Your unique API key, provided by us. If you don't have one yet, email us at contact@dcmetrohero.com.

200 OK

Bus tags successfully retrieved.

type
object
400 Bad Request

Invalid request. Make sure the required apiKey header is specified.

401 Unauthorized

You either didn't specify an API key, or the API key you specified was invalid or rejected. Please email us at contact@dcmetrohero.com for assistance.

503 Service Unavailable

You have exceeded our rate limits: by default, all users are limited to 10 calls to any of our APIs per second, and 50,000 calls per 24 hours.

Response Content-Types: application/json
Response Example (200 OK)
{
  "5401": {
    "numTagsByType": [
      {
        "BAD_OPERATOR": 1,
        "DISRUPTIVE_RIDER": 1,
        "GOOD_OPERATOR": 1,
        "COMFORTABLE_TEMPS": 0,
        "CROWDED": 0,
        "EMPTY": 0,
        "COMFORTABLE_RIDE": 0,
        "NEEDS_WORK": 0,
        "RECENTLY_OFFLOADED": 0,
        "UNCOMFORTABLE_RIDE": 0,
        "UNCOMFORTABLE_TEMPS": 0,
        "WRONG_DESTINATION": 0,
        "SKIPPING_STOPS": 0
      }
    ],
    "numPositiveTags": 1,
    "numNegativeTags": 2
  },
  "5415": "object"
}

Bus Report

GET /metrobus/buses/{busId}/tags

Gets real-time rider reports about a particular bus, referred to as tags. All tags are of predefined types (e.g. 'Good Operator', 'Disruptive Rider', 'Skipping Stops', etc) submitted by MetroHero users. These tags expire anywhere from 15 to 180 minutes after they've been created, depending on the type of tag; only current, unexpired tags are returned by this API.

Bus tags are ordered by tag type in descending order by current number of active tags.

apiKey: string
in header

Your unique API key, provided by us. If you don't have one yet, email us at contact@dcmetrohero.com.

busId: string
in path

The unique four-digit vehicle ID of the bus. This is the same ID that can be seen inside and outside the physical bus itself.

200 OK

Bus tags successfully retrieved.

400 Bad Request

Invalid request. Make sure the apiKey header and all other required parameters are specified.

401 Unauthorized

You either didn't specify an API key, or the API key you specified was invalid or rejected. Please email us at contact@dcmetrohero.com for assistance.

503 Service Unavailable

You have exceeded our rate limits: by default, all users are limited to 10 calls to any of our APIs per second, and 50,000 calls per 24 hours.

Response Content-Types: application/json
Response Example (200 OK)
{
  "numTagsByType": [
    {
      "BAD_OPERATOR": 1,
      "DISRUPTIVE_RIDER": 1,
      "GOOD_OPERATOR": 1,
      "COMFORTABLE_TEMPS": 0,
      "CROWDED": 0,
      "EMPTY": 0,
      "COMFORTABLE_RIDE": 0,
      "NEEDS_WORK": 0,
      "RECENTLY_OFFLOADED": 0,
      "UNCOMFORTABLE_RIDE": 0,
      "UNCOMFORTABLE_TEMPS": 0,
      "WRONG_DESTINATION": 0,
      "SKIPPING_STOPS": 0
    }
  ],
  "numPositiveTags": 1,
  "numNegativeTags": 2
}

Bus Predictions

GET /metrobus/stops/{stopKey}/buses

Gets real-time and scheduled bus predictions for a particular stop.

apiKey: string
in header

Your unique API key, provided by us. If you don't have one yet, email us at contact@dcmetrohero.com.

stopKey: string
in path

The bus stop ID and the bus stop name, concatenated with a '='. For example: '4000167=DUKE ST + S WALKER ST'. This is case sensitive. Some bus stops don't have an ID or they share an ID with another stop (e.g. 0), but they _do_ have a unique name, hence this contrived "stop key" concept. To get the appropriate bus stop name to use here, you can query WMATA's Schedule at Stop API for the 'Name' element of the 'Stop' element that's returned. Be advised that bus stop names have been observed to change on occasion.

200 OK

Bus predictions successfully retrieved.

400 Bad Request

Invalid request. Make sure the apiKey header and all other required parameters are specified.

401 Unauthorized

You either didn't specify an API key, or the API key you specified was invalid or rejected. Please email us at contact@dcmetrohero.com for assistance.

503 Service Unavailable

You have exceeded our rate limits: by default, all users are limited to 10 calls to any of our APIs per second, and 50,000 calls per 24 hours.

Response Content-Types: application/json
Response Example (200 OK)
[
  {
    "id": "6236",
    "latitude": 38.901482,
    "longitude": -77.032219,
    "destinationName": "LAFAYETTE SQUARE",
    "tripId": "922289620",
    "tripDirection": "WEST",
    "deviationFromSchedule": 2,
    "lastPositionUpdateString": "2017-08-22T13:36:22",
    "previousStopId": "1001191",
    "previousStopName": "I ST NW + 14TH ST NW",
    "nextStopId": "1001185",
    "nextStopName": "I ST NW + 15TH ST NW",
    "normalizedDistanceToNextStop": 0.952850788114076,
    "estimatedTimeToNextStop": 52,
    "estimatedDistanceFromPreviousStop": 11,
    "estimatedDistanceToNextStop": 213,
    "numStopsAway": 2,
    "scheduledArrival": "2017-08-22T13:45:30",
    "routeId": "X2",
    "timeToBusInFront": 373,
    "timeFromBusBehind": 674,
    "numPositiveTags": 1,
    "numNegativeTags": 0,
    "estimatedSpeed": 16
  }
]

Stop Report

GET /metrobus/stops/{stopKey}/tags

Gets real-time rider reports about a particular stop, referred to as tags. All tags are of predefined types (e.g. 'Empty', 'Clean', 'Crowded', etc) submitted by MetroHero users. These tags expire anywhere from 15 to 180 minutes after they've been created, depending on the type of tag; only current, unexpired tags are returned by this API.

Stop tags are ordered by tag type in descending order by current number of active tags.

apiKey: string
in header

Your unique API key, provided by us. If you don't have one yet, email us at contact@dcmetrohero.com.

stopKey: string
in path

The bus stop ID and the bus stop name, concatenated with a '='. For example: '4000167=DUKE ST + S WALKER ST'. This is case sensitive. Some bus stops don't have an ID or they share an ID with another stop (e.g. 0), but they _do_ have a unique name, hence this contrived "stop key" concept. To get the appropriate bus stop name to use here, you can query WMATA's Schedule at Stop API for the 'Name' element of the 'Stop' element that's returned. Be advised that bus stop names have been observed to change on occasion.

200 OK

Stop tags successfully retrieved.

400 Bad Request

Invalid request. Make sure the apiKey header and all other required parameters are specified.

401 Unauthorized

You either didn't specify an API key, or the API key you specified was invalid or rejected. Please email us at contact@dcmetrohero.com for assistance.

503 Service Unavailable

You have exceeded our rate limits: by default, all users are limited to 10 calls to any of our APIs per second, and 50,000 calls per 24 hours.

Response Content-Types: application/json
Response Example (200 OK)
{
  "numTagsByType": [
    {
      "EMPTY": 2,
      "CLEAN": 0,
      "CROWDED": 0,
      "LONG_WAITING_TIME": 0,
      "POSTED_TIMES_INACCURATE": 0,
      "NEEDS_WORK": 0,
      "RECENTLY_SKIPPED": 0
    }
  ],
  "numPositiveTags": 2,
  "numNegativeTags": 0
}

Schema Definitions

SystemMetrics: object

lineMetricsByLine: object

Line-specific metrics by line code.

RD: object
OR: LineMetrics
SV: object
BL: object
YL: object
GR: object
date: string (date-time)

The ISO 8601-formatted datetime this data is from.

Example
{
  "lineMetricsByLine": {
    "RD": "object",
    "OR": {
      "lineCode": "OR",
      "expectedNumTrains": 22,
      "numTrains": 22,
      "numEightCarTrains": 11,
      "numDelayedTrains": 2,
      "numCars": 154,
      "averageTrainDelay": 120,
      "medianTrainDelay": 115,
      "minimumTrainDelay": 0,
      "maximumTrainDelay": 365,
      "averageMinimumHeadways": 6.12,
      "averageTrainFrequency": 6.12,
      "expectedTrainFrequency": 6,
      "averagePlatformWaitTime": 3.12,
      "expectedPlatformWaitTime": 3,
      "trainFrequencyStatus": "OK",
      "platformWaitTimeTrendStatus": "NEUTRAL",
      "averageHeadwayAdherence": 66.6,
      "averageScheduleAdherence": 66.6,
      "standardDeviationTrainFrequency": 1.9,
      "expectedStandardDeviationTrainFrequency": 1.8,
      "directionMetricsByDirection": {
        "1": {
          "lineCode": "OR",
          "directionNumber": 1,
          "direction": "Eastbound",
          "towardsStationName": "New Carrollton",
          "expectedNumTrains": 11,
          "numTrains": 11,
          "numEightCarTrains": 5,
          "numDelayedTrains": 1,
          "numCars": 76,
          "averageTrainDelay": 100,
          "medianTrainDelay": 95,
          "minimumTrainDelay": 0,
          "maximumTrainDelay": 365,
          "averageMinimumHeadways": 6.12,
          "averageTrainFrequency": 6.12,
          "expectedTrainFrequency": 6,
          "averagePlatformWaitTime": 3.12,
          "expectedPlatformWaitTime": 3,
          "trainFrequencyStatus": "OK",
          "platformWaitTimeTrendStatus": "NEUTRAL",
          "averageHeadwayAdherence": 66.6,
          "averageScheduleAdherence": 66.6,
          "standardDeviationTrainFrequency": 1.9,
          "expectedStandardDeviationTrainFrequency": 1.8,
          "date": "2017-06-12T08:24:26.655-04:00"
        },
        "2": "object"
      },
      "date": "2017-06-12T08:24:26.655-04:00"
    },
    "SV": "object",
    "BL": "object",
    "YL": "object",
    "GR": "object"
  },
  "date": "2017-06-12T08:24:26.655-04:00"
}

LineMetrics: object

Line metrics for a specific line.

lineCode: string RD, OR, SV, BL, YL, GR

The line code associated with this data.

expectedNumTrains: integer (int32)

The number of active trains scheduled to be in revenue service, calculated using WMATA's schedule data.

numTrains: integer (int32)

The number of active trains in revenue service.

numEightCarTrains: integer (int32)

The number of active 8-car trains in revenue service.

numDelayedTrains: integer (int32)

The number of active trains in revenue service with a cumulative trip time delay of 5 minutes or more, accumulated during their trip so far by holding and/or moving slowly.

numCars: integer (int32)

The number of train cars in active revenue service, as calculated using numTrains and numEightCarTrains.

averageTrainDelay: integer (int32)

The average cumulative trip time delay of trains in active revenue service. If there are no trains in active revenue service (numTrains), this will be null. (in seconds)

medianTrainDelay: integer (int32)

The median cumulative trip time delay of trains in active revenue service. If there are no trains in active revenue service (numTrains), this will be null. (in seconds)

minimumTrainDelay: integer (int32)

The minimum cumulative trip time delay of trains in active revenue service. If there are no trains in active revenue service (numTrains), this will be null. (in seconds)

maximumTrainDelay: integer (int32)

The maximum cumulative trip time delay of trains in active revenue service. If there are no trains in active revenue service (numTrains), this will be null. (in seconds)

averageMinimumHeadways: number (double)

The average predicted headways, i.e. the average travel time between each pair of back-to-back trains given their current positions, and not taking any short-term delays/congestion into account. If there are less than two trains in active revenue service (numTrains), this will be null. (in minutes)

averageTrainFrequency: number (double)

The average observed frequency of trains arriving at stations, i.e. the average time between trains. This may be null if there is not sufficient data yet. (in minutes)

expectedTrainFrequency: number (double)

The expected time between trains, as calculated using WMATA's schedule data. (in minutes)

averagePlatformWaitTime: number (double)

The average wait time on station platforms for a train, calculated by us using the following formula: (μ (1 + σ² / μ²) / 2), where μ and σ are respectively the mean and standard deviation of the time headways between observed train arrivals at stations. We optimistically assume every rider is able to board the first train they're waiting for, which is not always the case, but WMATA does not make any real-time ridership data available for us to use. This may be null if there is not sufficient data yet. (in minutes)

expectedPlatformWaitTime: number (double)

The expected platform wait time, as calculated using WMATA's schedule data plugged into the formula mentioned in the description of averagePlatformWaitTime. (in minutes)

trainFrequencyStatus: string OK, SLOW, DELAYED

The average train frequency (averageTrainFrequency) compared to the expected train frequency (expectedTrainFrequency). If the difference between the average train frequency minus the expected train frequency is less than or equal to one minute, OK is used; if the difference is greater than one minute but less than or equal to two minutes, DELAYED is used; otherwise, OK is used. This may be null if there is not sufficient data yet.

platformWaitTimeTrendStatus: string DECREASING, NEUTRAL, INCREASING

The trend of the average platform wait time (averagePlatformWaitTime) over the last 15 minutes. This may be null if there is not sufficient data yet.

averageHeadwayAdherence: number (double)

Estimated headway adherence of trains, calculated by comparing observed train arrivals at each station to WMATA's schedule data, expressed as a percentage between 0 and 100. We consider a train to be adhering to scheduled headways if the time between the last train\'s arrival and this train\'s arrival is less than or equal to one full expected headway, plus 2 minutes. This may be null if there is not sufficient data yet.

averageScheduleAdherence: number (double)

Estimated schedule adherence of trains, calculated by comparing observed train arrivals at each station to WMATA's schedule data, expressed as a percentage between 0 and 100. We consider a train as adhering to schedule if it arrives within (+/−) 2 minutes of schedule. This may be null if there is not sufficient data yet.

standardDeviationTrainFrequency: number (double)

Train spacing consistency, i.e. the observed variance in the frequency at which trains are arriving at stations. Technically, this is the standard deviation of those frequencies. This may be null if there is not sufficient data yet. (in minutes)

expectedStandardDeviationTrainFrequency: number (double)

Expected train spacing consistency, i.e. the expected variance in the frequency at which trains are arriving at stations. Technically, this is the standard deviation of those expected frequencies calculated using WMATA's schedule data. (in minutes)

directionMetricsByDirection: object

Line and direction-specific metrics by direction number.

1: DirectionMetrics
2: object
date: string (date-time)

The ISO 8601-formatted datetime this data is from.

Example
{
  "lineCode": "OR",
  "expectedNumTrains": 22,
  "numTrains": 22,
  "numEightCarTrains": 11,
  "numDelayedTrains": 2,
  "numCars": 154,
  "averageTrainDelay": 120,
  "medianTrainDelay": 115,
  "minimumTrainDelay": 0,
  "maximumTrainDelay": 365,
  "averageMinimumHeadways": 6.12,
  "averageTrainFrequency": 6.12,
  "expectedTrainFrequency": 6,
  "averagePlatformWaitTime": 3.12,
  "expectedPlatformWaitTime": 3,
  "trainFrequencyStatus": "OK",
  "platformWaitTimeTrendStatus": "NEUTRAL",
  "averageHeadwayAdherence": 66.6,
  "averageScheduleAdherence": 66.6,
  "standardDeviationTrainFrequency": 1.9,
  "expectedStandardDeviationTrainFrequency": 1.8,
  "directionMetricsByDirection": {
    "1": {
      "lineCode": "OR",
      "directionNumber": 1,
      "direction": "Eastbound",
      "towardsStationName": "New Carrollton",
      "expectedNumTrains": 11,
      "numTrains": 11,
      "numEightCarTrains": 5,
      "numDelayedTrains": 1,
      "numCars": 76,
      "averageTrainDelay": 100,
      "medianTrainDelay": 95,
      "minimumTrainDelay": 0,
      "maximumTrainDelay": 365,
      "averageMinimumHeadways": 6.12,
      "averageTrainFrequency": 6.12,
      "expectedTrainFrequency": 6,
      "averagePlatformWaitTime": 3.12,
      "expectedPlatformWaitTime": 3,
      "trainFrequencyStatus": "OK",
      "platformWaitTimeTrendStatus": "NEUTRAL",
      "averageHeadwayAdherence": 66.6,
      "averageScheduleAdherence": 66.6,
      "standardDeviationTrainFrequency": 1.9,
      "expectedStandardDeviationTrainFrequency": 1.8,
      "date": "2017-06-12T08:24:26.655-04:00"
    },
    "2": "object"
  },
  "date": "2017-06-12T08:24:26.655-04:00"
}

DirectionMetrics: object

Direction metrics for a specific line and direction. This may be null if there are no trains going in this direction.

lineCode: string RD, OR, SV, BL, YL, GR

The line code associated with this data.

directionNumber: integer (int32) 1, 2

The direction number associated with this data.

direction: string

A human-readable name for the cardinal direction trains are generally headed in.

towardsStationName: string

A human-readable name for the terminal station trains are generally headed towards.

expectedNumTrains: integer (int32)

The number of active trains scheduled to be in revenue service, calculated using WMATA's schedule data.

numTrains: integer (int32)

The number of active trains in revenue service.

numEightCarTrains: integer (int32)

The number of active 8-car trains in revenue service.

numDelayedTrains: integer (int32)

The number of active trains in revenue service with a cumulative trip time delay of 5 minutes or more, accumulated during their trip so far by holding and/or moving slowly.

numCars: integer (int32)

The number of train cars in active revenue service, as calculated using numTrains and numEightCarTrains.

averageTrainDelay: integer (int32)

The average cumulative trip time delay of trains in active revenue service. If there are no trains in active revenue service (numTrains), this will be null. (in seconds)

medianTrainDelay: integer (int32)

The median cumulative trip time delay of trains in active revenue service. If there are no trains in active revenue service (numTrains), this will be null. (in seconds)

minimumTrainDelay: integer (int32)

The minimum cumulative trip time delay of trains in active revenue service. If there are no trains in active revenue service (numTrains), this will be null. (in seconds)

maximumTrainDelay: integer (int32)

The maximum cumulative trip time delay of trains in active revenue service. If there are no trains in active revenue service (numTrains), this will be null. (in seconds)

averageMinimumHeadways: number (double)

The average predicted headways, i.e. the average travel time between each pair of back-to-back trains given their current positions, and not taking any short-term delays/congestion into account. If there are less than two trains in active revenue service (numTrains), this will be null. (in minutes)

averageTrainFrequency: number (double)

The average observed frequency of trains arriving at stations, i.e. the average time between trains. This may be null if there is not sufficient data yet. (in minutes)

expectedTrainFrequency: number (double)

The expected time between trains, as calculated using WMATA's schedule data. (in minutes)

averagePlatformWaitTime: number (double)

The average wait time on station platforms for a train, calculated by us using the following formula: (μ (1 + σ² / μ²) / 2), where μ and σ are respectively the mean and standard deviation of the time headways between observed train arrivals at stations. We optimistically assume every rider is able to board the first train they're waiting for, which is not always the case, but WMATA does not make any real-time ridership data available for us to use. This may be null if there is not sufficient data yet. (in minutes)

expectedPlatformWaitTime: number (double)

The expected platform wait time, as calculated using WMATA's schedule data plugged into the formula mentioned in the description of averagePlatformWaitTime. (in minutes)

trainFrequencyStatus: string OK, SLOW, DELAYED

The average train frequency (averageTrainFrequency) compared to the expected train frequency (expectedTrainFrequency). If the difference between the average train frequency minus the expected train frequency is less than or equal to one minute, OK is used; if the difference is greater than one minute but less than or equal to two minutes, DELAYED is used; otherwise, OK is used. This may be null if there is not sufficient data yet.

platformWaitTimeTrendStatus: string DECREASING, NEUTRAL, INCREASING

The trend of the average platform wait time (averagePlatformWaitTime) over the last 15 minutes. This may be null if there is not sufficient data yet.

averageHeadwayAdherence: number (double)

Estimated headway adherence of trains, calculated by comparing observed train arrivals at each station to WMATA's schedule data, expressed as a percentage between 0 and 100. We consider a train to be adhering to scheduled headways if the time between the last train\'s arrival and this train\'s arrival is less than or equal to one full expected headway, plus 2 minutes. This may be null if there is not sufficient data yet.

averageScheduleAdherence: number (double)

Estimated schedule adherence of trains, calculated by comparing observed train arrivals at each station to WMATA's schedule data, expressed as a percentage between 0 and 100. We consider a train as adhering to schedule if it arrives within (+/−) 2 minutes of schedule. This may be null if there is not sufficient data yet.

standardDeviationTrainFrequency: number (double)

Train spacing consistency, i.e. the observed variance in the frequency at which trains are arriving at stations. Technically, this is the standard deviation of those frequencies. This may be null if there is not sufficient data yet. (in minutes)

expectedStandardDeviationTrainFrequency: number (double)

Expected train spacing consistency, i.e. the expected variance in the frequency at which trains are arriving at stations. Technically, this is the standard deviation of those expected frequencies calculated using WMATA's schedule data. (in minutes)

date: string (date-time)

The ISO 8601-formatted datetime this data is from.

Example
{
  "lineCode": "OR",
  "directionNumber": 1,
  "direction": "Eastbound",
  "towardsStationName": "New Carrollton",
  "expectedNumTrains": 11,
  "numTrains": 11,
  "numEightCarTrains": 5,
  "numDelayedTrains": 1,
  "numCars": 76,
  "averageTrainDelay": 100,
  "medianTrainDelay": 95,
  "minimumTrainDelay": 0,
  "maximumTrainDelay": 365,
  "averageMinimumHeadways": 6.12,
  "averageTrainFrequency": 6.12,
  "expectedTrainFrequency": 6,
  "averagePlatformWaitTime": 3.12,
  "expectedPlatformWaitTime": 3,
  "trainFrequencyStatus": "OK",
  "platformWaitTimeTrendStatus": "NEUTRAL",
  "averageHeadwayAdherence": 66.6,
  "averageScheduleAdherence": 66.6,
  "standardDeviationTrainFrequency": 1.9,
  "expectedStandardDeviationTrainFrequency": 1.8,
  "date": "2017-06-12T08:24:26.655-04:00"
}

TripInfo: object

fromStationName: string

The name of the origin station (fromStation) of the trip.

fromStationCode: string

The RTU station code of the origin station (fromStation) of the trip.

toStationName: string

The name of the destination station (toStation) of the trip.

toStationCode: string

The RTU station code of the destination station (toStation) of the trip.

tripStationCodes: string[]

An ordered list of RTU station codes of the stations visited on this trip. This list includes the origin station (fromStation) and the destination station (toStation) of the trip in the first and last positions in the list, respectively.

string
lineCodes: string[]

A list of line codes of lines that normally service this trip. This does not take current conditions into account and is basically static data; if different lines are servicing this trip than usual due to track work or something, those temporary service changes are not reflected here.

string RD, OR, SV, BL, YL, GR
expectedRideTime: number (double)

How long this ride usually takes once aboard a train at the origin station (fromStation) of the trip and after that train has departed the station, based on the median trip time of up to 30 days' worth of data about this trip. (in minutes)

predictedRideTime: number (double)

How long this ride is predicted to take once aboard a train at the origin station (fromStation) of the trip and after that train has departed the station, based on current conditions and/or conditions in the recent past. This may be null if there is not sufficient data to make a prediction yet. (in minutes)

timeUntilNextTrain: number (double)

Predicted wait time remaining from the origin station's (fromStation) platform for the next train to service this trip, based on current conditions and/or conditions in the recent past. This does not include scheduled train predictions. 0 means the next train is currently boarding at the origin station of the trip. This can be null if no such train prediction is available. (in minutes)

timeSinceLastTrain: number (double)

How long ago a train designated to service the destination station (toStation) of this trip last departed the origin station (fromStation). This can be null if no such train departure has been observed yet. (in minutes)

fromStationTrainStatuses: TrainPrediction

An ordered list of all train predictions, relative to the origin station (fromStation) of this trip, for trains that are designated to service the destination station (toStation) of this trip, given current conditions. If this trip is currently being serviced by multiple lines, e.g. the Orange, Silver, and Blue lines, any predictions for trains across all those lines will be included in this list. If available, scheduled train predictions will also appear in this list. This list is ordered by estimated time of arrival at the origin station of this trip, in ascending order. This can be null.

TrainPrediction
metroAlerts: MetroAlert

A list of active MetroAlerts that may be relevant to this trip, and stations and lines on this trip. Ordered by date issued or last updated; the most recently issued or updated MetroAlert will appear first in this list. This can be null.

MetroAlert
metroAlertKeywords: Keywords

A set of keywords we've derived from all the MetroAlerts included in metroAlerts that we believe are important. We use heuristics so that MetroAlerts don't need to include the exact text of the keywords we're looking for to have one of our keywords appear in this list. Even so, sometimes this list may be empty. The same keyword will not appear twice. Ordered by last occurrence; the derived keywords from the most recent MetroAlerts will appear first in the list. This can be null.

Keywords
tweets: Tweet

A list of tweets that may be relevant to this trip, and stations and lines on this trip. Ordered by the date they were tweeted; the most recent tweet will appear first in the list. This can be null.

Tweet
tweetKeywords: Keywords

A set of keywords we've derived from all the tweets included in tweets that we believe are important. We use heuristics so that tweets don't need to include the exact text of the keywords we're looking for to have one of our keywords appear in this list. Even so, sometimes this list may be empty. The same keyword will not appear twice. Ordered by last occurrence; the derived keywords from the most recent tweets will appear first in the list. This can be null.

Keywords
fromStationElevatorOutages: ElevatorEscalatorOutage

A list of elevator outages at the origin station (fromStation) of the trip. Ordered by last updated; the most recently updated outage will appear first in the list. This can be null.

ElevatorEscalatorOutage
fromStationEscalatorOutages: ElevatorEscalatorOutage

A list of escalator outages at the origin station (fromStation) of the trip. Ordered by last updated; the most recently updated outage will appear first in the list. This can be null.

ElevatorEscalatorOutage
toStationElevatorOutages: ElevatorEscalatorOutage

A list of elevator outages at the destination station (toStation) of the trip. Ordered by last updated; the most recently updated outage will appear first in the list. This can be null.

ElevatorEscalatorOutage
toStationEscalatorOutages: ElevatorEscalatorOutage

A list of escalator outages at the destination station (toStation) of the trip. Ordered by last updated; the most recently updated outage will appear first in the list. This can be null.

ElevatorEscalatorOutage
date: string (date-time)

The ISO 8601-formatted datetime this data was collectively retrieved or calculated.

Example
{
  "fromStationName": "Vienna",
  "fromStationCode": "K08",
  "toStationName": "Metro Center",
  "toStationCode": "C01",
  "tripStationCodes": [
    "K08",
    "K07",
    "K06",
    "K05",
    "K04",
    "K03",
    "K02",
    "K01",
    "C05",
    "C04",
    "C03",
    "C02",
    "C01"
  ],
  "lineCodes": [
    "OR"
  ],
  "expectedRideTime": 26.12,
  "predictedRideTime": 30.3303,
  "timeUntilNextTrain": 2.02,
  "timeSinceLastTrain": 4.26,
  "fromStationTrainStatuses": [
    {
      "trainId": "155",
      "realTrainId": "901",
      "Car": "8",
      "Destination": "Vienna",
      "DestinationCode": "K08",
      "DestinationName": "Vienna",
      "Group": "1",
      "Line": "OR",
      "LocationCode": "C01",
      "LocationName": "Metro Center",
      "Min": "1",
      "parentMin": "1",
      "minutesAway": 0.89,
      "maxMinutesAway": 1.12,
      "directionNumber": 1,
      "isScheduled": false,
      "numPositiveTags": 1,
      "numNegativeTags": 3,
      "trackNumber": 1,
      "currentStationCode": "C01",
      "currentStationName": "Metro Center",
      "PreviousStationCode": "D01",
      "previousStationName": "Federal Triangle",
      "secondsSinceLastMoved": 65,
      "isCurrentlyHoldingOrSlow": true,
      "secondsOffSchedule": 145,
      "trainSpeed": 23,
      "isNotOnRevenueTrack": false,
      "isKeyedDown": false,
      "wasKeyedDown": false,
      "distanceFromNextStation": 502,
      "lat": 38.89383299999999,
      "lon": -77.02806700000001,
      "direction": 2,
      "observedDate": "Aug 11, 2017 3:51:54 PM"
    }
  ],
  "metroAlerts": [
    {
      "description": "Orange/Blue Line: Trains operate every 24 min w/ single tracking btwn Eastern Market & Stadium-Armory due to scheduled maintenance.",
      "stationCodes": [
        "D07",
        "D06",
        "D08"
      ],
      "lineCodes": [
        "OR",
        "SV"
      ],
      "keywords": [
        "long waits"
      ],
      "date": "2018-04-28T06:49:57-04:00"
    }
  ],
  "metroAlertKeywords": [
    "long waits"
  ],
  "tweets": [
    {
      "twitterId": 990273931222437900,
      "twitterIdString": "990273931222437888",
      "userId": 94625247,
      "text": "@Metrorailinfo does Silver line exist? Been waiting at Ballston, no info about next Wiehle-bound anywhere. Just had a No Passenger come through instead, that was nice",
      "stationCodes": [
        "K04"
      ],
      "lineCodes": [
        "SV"
      ],
      "keywords": [
        "long waits"
      ],
      "url": "https://twitter.com/180912906/status/990301719224573954",
      "date": "2018-04-28T06:49:57-04:00"
    }
  ],
  "tweetKeywords": [
    "long waits"
  ],
  "fromStationElevatorOutages": [],
  "fromStationEscalatorOutages": [],
  "toStationElevatorOutages": [],
  "toStationEscalatorOutages": [
    {
      "stationCode": "C01",
      "stationName": "Metro Center, G and 12th St Entrance",
      "locationDescription": "Escalator between upper and lower platforms",
      "symptomDescription": "Service Call",
      "unitName": "C01N05",
      "unitType": "ESCALATOR",
      "outOfServiceDate": "2018-04-28T09:27:00-04:00",
      "updatedDate": "2018-04-28T09:30:19-04:00",
      "estimatedReturnToServiceDate": "2018-04-29T09:00:00-04:00"
    }
  ],
  "date": "2018-04-28T06:50:34-04:00"
}

MetroAlert: object

description: string

A brief description of the incident being described in this MetroAlert.

stationCodes: string[]

A list of RTU station codes of the stations relevant to the incident described in this MetroAlert.

string
lineCodes: string[]

A list of line codes relevant to the incident described in this MetroAlert.

string RD, OR, SV, BL, YL, GR
keywords: Keywords

A set of keywords we've derived from this MetroAlert that we believe are important. We use heuristics so that MetroAlerts don't need to include the exact text of the keywords we're looking for to have one of our keywords appear in this list. Even so, sometimes this list may be empty. The same keyword will not appear twice.

Keywords
date: string (date-time)

The ISO 8601-formatted datetime this MetroAlert was issued or last updated.

Example
{
  "description": "Orange/Blue Line: Trains operate every 24 min w/ single tracking btwn Eastern Market & Stadium-Armory due to scheduled maintenance.",
  "stationCodes": [
    "D07",
    "D06",
    "D08"
  ],
  "lineCodes": [
    "OR",
    "SV"
  ],
  "keywords": [
    "long waits"
  ],
  "date": "2018-04-28T06:49:57-04:00"
}

Tweet: object

twitterId: number (int64)

The ID from Twitter for this tweet.

twitterIdString: string

The ID from Twitter for this tweet. Same as twitterId but represented as a string. Use this if you notice twitterId overflowing, which can happen if your language or libraries don't support signed 64-bit integers (as with JavaScript, for example).

userId: number (int64)

The ID from Twitter of the Twitter user who posted this tweet.

text: string

The contents of the tweet.

stationCodes: string[]

A list of RTU station codes of the stations referenced in this tweet. If this tweet references a range of stations, e.g. "between Vienna and Ballston", all of the RTU station codes for those stations between and including Vienna and Ballston will be included in this list. We use fuzzy string matching and a bunch of other heuristics so that station names mentioned in tweets don't have to be properly spelled to be included here. Even so, sometimes this list may be empty.

string
lineCodes: string[]

A list of line codes referenced in this tweet. We use heuristics so that line names or codes mentioned in tweets don't have to be properly spelled to be included in this list. We also derive line codes from station codes included in stationCodes. Even so, sometimes this list may be empty.

string RD, OR, SV, BL, YL, GR
keywords: Keywords

A set of keywords we've derived from this tweet that we believe are important. We use heuristics so that tweets don't need to include the exact text of the keywords we're looking for to have one of our keywords appear in this list. Even so, sometimes this list may be empty. The same keyword will not appear twice.

Keywords
url: string

A fully-formed absolute URL to this tweet on Twitter. If the tweet has since been deleted from Twitter by the user or otherwise, this URL won't work.

date: string (date-time)

The ISO 8601-formatted datetime this tweet was posted to Twitter.

Example
{
  "twitterId": 990273931222437900,
  "twitterIdString": "990273931222437888",
  "userId": 94625247,
  "text": "@Metrorailinfo does Silver line exist? Been waiting at Ballston, no info about next Wiehle-bound anywhere. Just had a No Passenger come through instead, that was nice",
  "stationCodes": [
    "K04"
  ],
  "lineCodes": [
    "SV"
  ],
  "keywords": [
    "long waits"
  ],
  "url": "https://twitter.com/180912906/status/990301719224573954",
  "date": "2018-04-28T06:49:57-04:00"
}

ElevatorEscalatorOutage: object

stationCode: string

The RTU station code of the station with this outage.

stationName: string

The name of the station and general location within the station of this outage.

locationDescription: string

A more specific description of the location within the station of this outage.

symptomDescription: string

A brief description of why this outage is taking place.

unitName: string

The name of the unit experiencing this outage.

unitType: string ELEVATOR, ESCALATOR

The type of unit experiencing this outage.

outOfServiceDate: string (date-time)

The ISO 8601-formatted datetime this unit was reported out of service.

updatedDate: string (date-time)

The ISO 8601-formatted datetime the outage details for this unit were last updated.

estimatedReturnToServiceDate: string (date-time)

The ISO 8601-formatted datetime this outage is expected to conclude. May be null if no estimate from WMATA is available.

Example
{
  "stationCode": "C01",
  "stationName": "Metro Center, G and 12th St Entrance",
  "locationDescription": "Escalator between upper and lower platforms",
  "symptomDescription": "Service Call",
  "unitName": "C01N05",
  "unitType": "ESCALATOR",
  "outOfServiceDate": "2018-04-28T09:27:00-04:00",
  "updatedDate": "2018-04-28T09:30:19-04:00",
  "estimatedReturnToServiceDate": "2018-04-29T09:00:00-04:00"
}

TrainPrediction: object

trainId: string

If this prediction is based on real-time train data and not scheduled train data, i.e. if isScheduled is false, then this is the AIMS internal ID of the train, as defined by WMATA's Train Positions API as a three-digit string anywhere from 001 to 512; no two trains can have the same ID at the same time, so this is a unique identifier. Otherwise, this is a unique trip ID, like '58633'.

realTrainId: string

If this prediction is based on real-time train data and not scheduled train data, i.e. if isScheduled is false, then this is the real ID of the train, i.e. the same ID that WMATA uses operationally over the radio and in their train schedules, as a three-digit string anywhere from 000 to 999; in practice, two trains can (unforunately) have the same real ID at the same time, so this is not a unique identifier. Otherwise, this is null.

Car: string

The number of cars that make up this train. Can be 'N/A' indicating that for whatever reason, the number of cars is not known.

Destination: string

A human-readable name of the destination station of this train. Unlike WMATA's Real-Time Rail Predictions API, this is the same as DestinationName, not an abbreviated version of the destination station name.

DestinationCode: string

The RTU station code of the destination station of this train.

DestinationName: string

A human-readable name of the destination station of this train.

Group: string 1, 2

Indicates which side of the tracks ('1' for track 1, '2' for track 2) the train is on.

Line: string RD, OR, SV, BL, YL, GR

The line code of the line this train is servicing.

LocationCode: string

The RTU station code of the station this train prediction is for or, if that's not applicable, the same station code as what's returned for currentStationCode.

LocationName: string

The human-readable station name of the station this train prediction is for or, if that's not applicable, the same station name as what's returned for currentStationName.

Min: string

The predicted arrival time of the train at the station passed into the request to the API that returns this prediction--or, if that's not applicable, the predicted arrival time of the train at the station it will be servicing next--expressed in the nearest whole number of minutes (e.g. '3'), or as 'ARR' for arriving (if the prediction has the train less than or equal to 30 seconds away), or as 'BRD' for boarding. Alternatively, if this prediction is based on scheduled train data and not real-time train data, i.e. if isScheduled is true, a time is used instead--'11:30' for 11:30am or 11:30pm, for example. If an arrival prediction time is not available for this train, '?' will be returned instead.

parentMin: string

The predicted arrival time of the train at the station it will be servicing next, expressed in the nearest whole number of minutes (e.g. '3'), or as 'ARR' for arriving (if the prediction has the train less than or equal to 30 seconds away), or as 'BRD' for boarding. If an arrival prediction time is not available for this train, '?' will be returned instead. This is null if the request to the API that returns this prediction does not specify a station to get a prediction for; in that case, use Min instead. This is also null if this prediction is based on scheduled train data and not real-time train data, i.e. if isScheduled is true.

minutesAway: number (double)

The predicted arrival time of the train at the station it will be servicing next. It can be null if the previous station a train came from (PreviousStationCode) cannot be determined from its current or any previous position. (in minutes)

maxMinutesAway: number (double)

The theoretical maximum predicted arrival time of the train at the station it will be servicing next from the station it serviced previously. This can be used to normalize minutesAway. This is null if this prediction is based on scheduled train data and not real-time train data, i.e. if isScheduled is true. It can also be null if the previous station a train came from (PreviousStationCode) cannot be determined from its current or any previous position. (in minutes)

directionNumber: number (int32) 1, 2

Like Group, this corresponds to either track 1 or 2, however this represents the direction the train is currently headed in, not the track it is currently on. Thus, this and Group can be different if, for example, this train is moving through a single-tracking area.

isScheduled: boolean

True if this prediction is based on scheduled train data and not real-time train data, otherwise false.

numPositiveTags: number (int32)

The number of positive tags, as made by MetroHero users, currently active for this train. See the TrainTags model defintion for more info.

numNegativeTags: number (int32)

The number of negative tags, as made by MetroHero users, currently active for this train. See the TrainTags model defintion for more info.

trackNumber: number (int32) 1, 2

Indicates which side of the tracks (1 for track 1, 2 for track 2) the train is on. The same as Group, but an integer instead of a string.

currentStationCode: string

The RTU station code of the current or next station this train is or will be servicing next.

currentStationName: string

A human-readable name of the current or next station this train is or will be servicing next.

PreviousStationCode: string

The RTU station code of the previous station this train previously serviced last based on its current position. Note that this is not necessarily the actual station the train previously serviced if, for example, the train turned around after visiting its previous station.

previousStationName: string

A human-readable name of the previous station this train previously serviced last based on its current position. Note that this is not necessarily the actual station the train previously serviced if, for example, the train turned around after visiting its previous station.

secondsSinceLastMoved: number (int32)

The number of seconds since Min changed last. (in seconds)

isCurrentlyHoldingOrSlow: boolean

True if secondsSinceLastMoved exceeds that of expected, i.e. Min has not changed for more than 30 seconds if Min is 'ARR', or, if Min is something else, if it has not changed for more than 60 seconds. Otherwise, it's false.

secondsOffSchedule: number (int32)

The running total delay this train has accumulated during its trip so far, not including the current value of secondsSinceLastMoved. This resets once the train completes its trip. (in seconds)

trainSpeed: number (int32)

The estimated speed this train was last observed traveling at. This is very heuristic in nature and is calculated at the track circuit level by observing the train's movement between data updates from WMATA. (in miles per hour)

isNotOnRevenueTrack: boolean

True if the train is on non-revenue track after having last been observed on revenue track, otherwise false. If this is true, the rest of this prediction (e.g. Min, secondsSinceLastMoved, etc) reflect the train's state when it was last observed on revenue track, not its current state on non-revenue track.

isKeyedDown: boolean

True if we believe the train to be powered down, i.e. if it hasn't moved from its current position for 30 minutes or more.

wasKeyedDown: boolean

True if we believe the train to have been powered down recently (not considering isKeyedDown), i.e. if at some point during its current trip from one station to another neighboring station, the train did not move from its position for 30 minutes or more.

distanceFromNextStation: number (int32)

The estimated track distance away this train is from its next station stop, calculated using real track circuit lengths. This is 0 if the train is currently boarding at a station. Can be null if the next station stop (LocationCode) cannot be determined, or if an estimated distance is otherwise not available. (in feet)

lat: number (double)

The estimated latitude of this train, based on the track circuits it is occupying. This can be null if data is temporarily unavailable. (in degrees)

lon: number (double)

The estimated longitude of this train, based on the track circuits it is occupying. This can be null if data is temporarily unavailable. (in degrees)

direction: number (int32)

The estimated heading from cardinal north of this train, from 0 (inclusive) to 360 (exclusive), based on the track circuits the train is occupying and the track circuits it will be occupying next given its direction of travel. This can be null if data is temporarily unavailable. (in degrees)

observedDate: string (date-time)

A poorly-formatted date for when this prediction was made.

Example
{
  "trainId": "155",
  "realTrainId": "901",
  "Car": "8",
  "Destination": "Vienna",
  "DestinationCode": "K08",
  "DestinationName": "Vienna",
  "Group": "1",
  "Line": "OR",
  "LocationCode": "C01",
  "LocationName": "Metro Center",
  "Min": "1",
  "parentMin": "1",
  "minutesAway": 0.89,
  "maxMinutesAway": 1.12,
  "directionNumber": 1,
  "isScheduled": false,
  "numPositiveTags": 1,
  "numNegativeTags": 3,
  "trackNumber": 1,
  "currentStationCode": "C01",
  "currentStationName": "Metro Center",
  "PreviousStationCode": "D01",
  "previousStationName": "Federal Triangle",
  "secondsSinceLastMoved": 65,
  "isCurrentlyHoldingOrSlow": true,
  "secondsOffSchedule": 145,
  "trainSpeed": 23,
  "isNotOnRevenueTrack": false,
  "isKeyedDown": false,
  "wasKeyedDown": false,
  "distanceFromNextStation": 502,
  "lat": 38.89383299999999,
  "lon": -77.02806700000001,
  "direction": 2,
  "observedDate": "Aug 11, 2017 3:51:54 PM"
}

TrainTags: object

numTagsByType: NumTrainTagsByType

Ordered by tag type in descending order by number of tags.

NumTrainTagsByType
numPositiveTags: integer (int32)

The number of tags with positive sentiment currently active for the specified train.

numNegativeTags: integer (int32)

The number of tags with negative sentiment currently active for the specified train.

Example
{
  "numTagsByType": [
    {
      "BAD_OPERATOR": 1,
      "ISOLATED_CARS": 1,
      "NEW_TRAIN": 1,
      "BROKEN_INTERCOM": 0,
      "CROWDED": 0,
      "EMPTY": 0,
      "GOOD_OPERATOR": 0,
      "GOOD_RIDE": 0,
      "NEEDS_WORK": 0,
      "RECENTLY_OFFLOADED": 0,
      "UNCOMFORTABLE_RIDE": 0,
      "UNCOMFORTABLE_TEMPS": 0,
      "WRONG_DESTINATION": 0,
      "WRONG_NUM_CARS": 0
    }
  ],
  "numPositiveTags": 1,
  "numNegativeTags": 2
}

NumTrainTagsByType: object

BAD_OPERATOR: integer (int32)

The number of 'BAD_OPERATOR' tags currently active for the specified train. A 'BAD_OPERATOR' tag is considered to be of negative sentiment, and tags of this type expire after 60 minutes.

ISOLATED_CARS: integer (int32)

The number of 'ISOLATED_CARS' tags currently active for the specified train. A 'ISOLATED_CARS' tag is considered to be of negative sentiment, and tags of this type expire after 30 minutes.

NEW_TRAIN: integer (int32)

The number of 'NEW_TRAIN' tags currently active for the specified train. A 'NEW_TRAIN' tag is considered to be of positive sentiment, and tags of this type expire after 60 minutes.

BROKEN_INTERCOM: integer (int32)

The number of 'BROKEN_INTERCOM' tags currently active for the specified train. A 'BROKEN_INTERCOM' tag is considered to be of negative sentiment, and tags of this type expire after 60 minutes.

CROWDED: integer (int32)

The number of 'CROWDED' tags currently active for the specified train. A 'CROWDED' tag is considered to be of negative sentiment, and tags of this type expire after 30 minutes.

EMPTY: integer (int32)

The number of 'EMPTY' tags currently active for the specified train. A 'EMPTY' tag is considered to be of positive sentiment, and tags of this type expire after 30 minutes.

GOOD_OPERATOR: integer (int32)

The number of 'GOOD_OPERATOR' tags currently active for the specified train. A 'GOOD_OPERATOR' tag is considered to be of positive sentiment, and tags of this type expire after 60 minutes.

GOOD_RIDE: integer (int32)

The number of 'GOOD_RIDE' tags currently active for the specified train. A 'GOOD_RIDE' tag is considered to be of positive sentiment, and tags of this type expire after 30 minutes.

NEEDS_WORK: integer (int32)

The number of 'NEEDS_WORK' tags currently active for the specified train. A 'NEEDS_WORK' tag is considered to be of negative sentiment, and tags of this type expire after 60 minutes.

RECENTLY_OFFLOADED: integer (int32)

The number of 'RECENTLY_OFFLOADED' tags currently active for the specified train. A 'RECENTLY_OFFLOADED' tag is considered to be of negative sentiment, and tags of this type expire after 15 minutes.

UNCOMFORTABLE_RIDE: integer (int32)

The number of 'UNCOMFORTABLE_RIDE' tags currently active for the specified train. A 'UNCOMFORTABLE_RIDE' tag is considered to be of negative sentiment, and tags of this type expire after 30 minutes.

UNCOMFORTABLE_TEMPS: integer (int32)

The number of 'UNCOMFORTABLE_TEMPS' tags currently active for the specified train. A 'UNCOMFORTABLE_TEMPS' tag is considered to be of negative sentiment, and tags of this type expire after 30 minutes.

WRONG_DESTINATION: integer (int32)

The number of 'WRONG_DESTINATION' tags currently active for the specified train. A 'WRONG_DESTINATION' tag is considered to be of negative sentiment, and tags of this type expire after 30 minutes.

WRONG_NUM_CARS: integer (int32)

The number of 'WRONG_NUM_CARS' tags currently active for the specified train. A 'WRONG_NUM_CARS' tag is considered to be of negative sentiment, and tags of this type expire after 60 minutes.

Example
{
  "BAD_OPERATOR": 1,
  "ISOLATED_CARS": 1,
  "NEW_TRAIN": 1,
  "BROKEN_INTERCOM": 0,
  "CROWDED": 0,
  "EMPTY": 0,
  "GOOD_OPERATOR": 0,
  "GOOD_RIDE": 0,
  "NEEDS_WORK": 0,
  "RECENTLY_OFFLOADED": 0,
  "UNCOMFORTABLE_RIDE": 0,
  "UNCOMFORTABLE_TEMPS": 0,
  "WRONG_DESTINATION": 0,
  "WRONG_NUM_CARS": 0
}

StationTags: object

numTagsByType: NumStationTagsByType

Ordered by tag type in descending order by number of tags.

NumStationTagsByType
numPositiveTags: integer (int32)

The number of tags with positive sentiment currently active for the specified station.

numNegativeTags: integer (int32)

The number of tags with negative sentiment currently active for the specified station.

Example
{
  "numTagsByType": [
    {
      "FRIENDLY_OR_HELPFUL_STAFF": 1,
      "UNCOMFORTABLE_TEMPS": 1,
      "AMPLE_SECURITY": 0,
      "BROKEN_ELEVATOR": 0,
      "BROKEN_ESCALATOR": 0,
      "CROWDED": 0,
      "EMPTY": 0,
      "LONG_WAITING_TIME": 0,
      "NEEDS_WORK": 0,
      "POSTED_TIMES_INACCURATE": 0,
      "SMOKE_OR_FIRE": 0,
      "UNFRIENDLY_OR_UNHELPFUL_STAFF": 0
    }
  ],
  "numPositiveTags": 1,
  "numNegativeTags": 1
}

NumStationTagsByType: object

FRIENDLY_OR_HELPFUL_STAFF: integer (int32)

The number of 'FRIENDLY_OR_HELPFUL_STAFF' tags currently active for the specified station. A 'FRIENDLY_OR_HELPFUL_STAFF' tag is considered to be of positive sentiment, and tags of this type expire after 60 minutes.

UNCOMFORTABLE_TEMPS: integer (int32)

The number of 'UNCOMFORTABLE_TEMPS' tags currently active for the specified station. A 'UNCOMFORTABLE_TEMPS' tag is considered to be of negative sentiment, and tags of this type expire after 60 minutes.

AMPLE_SECURITY: integer (int32)

The number of 'AMPLE_SECURITY' tags currently active for the specified station. A 'AMPLE_SECURITY' tag is considered to be of positive sentiment, and tags of this type expire after 30 minutes.

BROKEN_ELEVATOR: integer (int32)

The number of 'BROKEN_ELEVATOR' tags currently active for the specified station. A 'BROKEN_ELEVATOR' tag is considered to be of negative sentiment, and tags of this type expire after 60 minutes.

BROKEN_ESCALATOR: integer (int32)

The number of 'BROKEN_ESCALATOR' tags currently active for the specified station. A 'BROKEN_ESCALATOR' tag is considered to be of negative sentiment, and tags of this type expire after 60 minutes.

CROWDED: integer (int32)

The number of 'CROWDED' tags currently active for the specified station. A 'CROWDED' tag is considered to be of negative sentiment, and tags of this type expire after 30 minutes.

EMPTY: integer (int32)

The number of 'EMPTY' tags currently active for the specified station. A 'EMPTY' tag is considered to be of positive sentiment, and tags of this type expire after 30 minutes.

LONG_WAITING_TIME: integer (int32)

The number of 'LONG_WAITING_TIME' tags currently active for the specified station. A 'LONG_WAITING_TIME' tag is considered to be of negative sentiment, and tags of this type expire after 15 minutes.

NEEDS_WORK: integer (int32)

The number of 'NEEDS_WORK' tags currently active for the specified station. A 'NEEDS_WORK' tag is considered to be of negative sentiment, and tags of this type expire after 180 minutes.

POSTED_TIMES_INACCURATE: integer (int32)

The number of 'POSTED_TIMES_INACCURATE' tags currently active for the specified station. A 'POSTED_TIMES_INACCURATE' tag is considered to be of negative sentiment, and tags of this type expire after 15 minutes.

SMOKE_OR_FIRE: integer (int32)

The number of 'SMOKE_OR_FIRE' tags currently active for the specified station. A 'SMOKE_OR_FIRE' tag is considered to be of negative sentiment, and tags of this type expire after 30 minutes.

UNFRIENDLY_OR_UNHELPFUL_STAFF: integer (int32)

The number of 'UNFRIENDLY_OR_UNHELPFUL_STAFF' tags currently active for the specified station. A 'UNFRIENDLY_OR_UNHELPFUL_STAFF' tag is considered to be of negative sentiment, and tags of this type expire after 60 minutes.

Example
{
  "FRIENDLY_OR_HELPFUL_STAFF": 1,
  "UNCOMFORTABLE_TEMPS": 1,
  "AMPLE_SECURITY": 0,
  "BROKEN_ELEVATOR": 0,
  "BROKEN_ESCALATOR": 0,
  "CROWDED": 0,
  "EMPTY": 0,
  "LONG_WAITING_TIME": 0,
  "NEEDS_WORK": 0,
  "POSTED_TIMES_INACCURATE": 0,
  "SMOKE_OR_FIRE": 0,
  "UNFRIENDLY_OR_UNHELPFUL_STAFF": 0
}

RouteMetrics: object

routeId: string

The bus route these metrics are for.

numObservedBuses: integer (int32)

The number of buses on this bus route for which a GPS position is available.

numExpectedBuses: integer (int32)

The number of buses scheduled to be on this bus route.

headwayAdherence: number (double)

The percentage of bus stops that were serviced no more than 2 minutes later than the scheduled time between visits for that stop.

scheduleAdherence: number (double)

The percentage of bus stops that were serviced no more than 2 minutes earlier or later than their scheduled time.

observedAverageHeadway: number (double)

The observed average time between buses across all bus stops. (in minutes)

expectedAverageHeadway: number (double)

The scheduled average time between buses across all bus stops. (in minutes)

numBusesAheadOfSchedule: integer (int32)

The number of observed buses operating more than 2 minutes early.

numBusesBehindSchedule: integer (int32)

The number of observed buses operating more than 2 minutes late.

standardDeviationFromSchedule: number (double)

The standard deviation of schedule deviations across all observed buses currently on this bus route; lower is better. (in minutes)

date: string (date-time)

The ISO 8601-formatted datetime of when these metrics were calculated.

Example
{
  "routeId": "X2",
  "numObservedBuses": 6,
  "numExpectedBuses": 5,
  "headwayAdherence": 82,
  "scheduleAdherence": 46,
  "observedAverageHeadway": 12.04,
  "expectedAverageHeadway": 13.35,
  "numBusesAheadOfSchedule": 0,
  "numBusesBehindSchedule": 3,
  "standardDeviationFromSchedule": 5.42,
  "date": "2017-06-12T08:24:26.655-04:00"
}

BusPrediction: object

id: string

If this prediction is based on real-time bus data and not scheduled bus data, i.e. if scheduledArrival is null, then this is the unique four-digit vehicle ID of the bus, i.e. the same ID that can be seen inside and outside the physical bus itself. Otherwise, this is a unique scheduled trip ID equal to tripId.

latitude: number (double)
longitude: number (double)
destinationName: string
tripId: string

The unique scheduled trip ID (provided by WMATA) associated with the trip this bus is servicing.

tripDirection: string
deviationFromSchedule: number (int32')
lastPositionUpdateString: string
previousStopId: string
previousStopName: string
nextStopId: string
nextStopName: string
normalizedDistanceToNextStop: number (double)
estimatedTimeToNextStop: number (int32)
estimatedDistanceFromPreviousStop: number (int32)
estimatedDistanceToNextStop: number (int32)
numStopsAway: number (int32)
scheduledArrival: string (date-time)

The scheduled arrival time for this bus at the specified stop passed into the request to the API that returns this prediction. If this prediction is not based on scheduled bus data, or if no stop is passed into the request to the API that returns this prediction, then this is null.

routeId: string
timeToBusInFront: number (int32)
timeFromBusBehind: number (int32)
numPositiveTags: number (int32)

The number of positive tags, as made by MetroHero users, currently active for this train. See the BusTags model defintion for more info.

numNegativeTags: number (int32)

The number of negative tags, as made by MetroHero users, currently active for this train. See the BusTags model defintion for more info.

estimatedSpeed: number (int32)

The estimated speed of the bus, approximated by calculating the distance from the previous GPS position of the bus to its current position, and how much time elapsed between the sampling of those positions. (in miles per hour)

Example
{
  "id": "6236",
  "latitude": 38.901482,
  "longitude": -77.032219,
  "destinationName": "LAFAYETTE SQUARE",
  "tripId": "922289620",
  "tripDirection": "WEST",
  "deviationFromSchedule": 2,
  "lastPositionUpdateString": "2017-08-22T13:36:22",
  "previousStopId": "1001191",
  "previousStopName": "I ST NW + 14TH ST NW",
  "nextStopId": "1001185",
  "nextStopName": "I ST NW + 15TH ST NW",
  "normalizedDistanceToNextStop": 0.952850788114076,
  "estimatedTimeToNextStop": 52,
  "estimatedDistanceFromPreviousStop": 11,
  "estimatedDistanceToNextStop": 213,
  "numStopsAway": 2,
  "scheduledArrival": "2017-08-22T13:45:30",
  "routeId": "X2",
  "timeToBusInFront": 373,
  "timeFromBusBehind": 674,
  "numPositiveTags": 1,
  "numNegativeTags": 0,
  "estimatedSpeed": 16
}

BusTags: object

numTagsByType: NumBusTagsByType

Ordered by tag type in descending order by number of tags.

NumBusTagsByType
numPositiveTags: integer (int32)

The number of tags with positive sentiment currently active for the specified bus.

numNegativeTags: integer (int32)

The number of tags with negative sentiment currently active for the specified bus.

Example
{
  "numTagsByType": [
    {
      "BAD_OPERATOR": 1,
      "DISRUPTIVE_RIDER": 1,
      "GOOD_OPERATOR": 1,
      "COMFORTABLE_TEMPS": 0,
      "CROWDED": 0,
      "EMPTY": 0,
      "COMFORTABLE_RIDE": 0,
      "NEEDS_WORK": 0,
      "RECENTLY_OFFLOADED": 0,
      "UNCOMFORTABLE_RIDE": 0,
      "UNCOMFORTABLE_TEMPS": 0,
      "WRONG_DESTINATION": 0,
      "SKIPPING_STOPS": 0
    }
  ],
  "numPositiveTags": 1,
  "numNegativeTags": 2
}

NumBusTagsByType: object

BAD_OPERATOR: integer (int32)

The number of 'BAD_OPERATOR' tags currently active for the specified bus. A 'BAD_OPERATOR' tag is considered to be of negative sentiment, and tags of this type expire after 60 minutes.

DISRUPTIVE_RIDER: integer (int32)

The number of 'DISRUPTIVE_RIDER' tags currently active for the specified bus. A 'DISRUPTIVE_RIDER' tag is considered to be of negative sentiment, and tags of this type expire after 30 minutes.

GOOD_OPERATOR: integer (int32)

The number of 'GOOD_OPERATOR' tags currently active for the specified bus. A 'GOOD_OPERATOR' tag is considered to be of positive sentiment, and tags of this type expire after 60 minutes.

COMFORTABLE_TEMPS: integer (int32)

The number of 'COMFORTABLE_TEMPS' tags currently active for the specified bus. A 'COMFORTABLE_TEMPS' tag is considered to be of positive sentiment, and tags of this type expire after 30 minutes.

CROWDED: integer (int32)

The number of 'CROWDED' tags currently active for the specified bus. A 'CROWDED' tag is considered to be of negative sentiment, and tags of this type expire after 30 minutes.

EMPTY: integer (int32)

The number of 'EMPTY' tags currently active for the specified bus. A 'EMPTY' tag is considered to be of positive sentiment, and tags of this type expire after 30 minutes.

COMFORTABLE_RIDE: integer (int32)

The number of 'COMFORTABLE_RIDE' tags currently active for the specified bus. A 'COMFORTABLE_RIDE' tag is considered to be of positive sentiment, and tags of this type expire after 30 minutes.

NEEDS_WORK: integer (int32)

The number of 'NEEDS_WORK' tags currently active for the specified bus. A 'NEEDS_WORK' tag is considered to be of negative sentiment, and tags of this type expire after 60 minutes.

RECENTLY_OFFLOADED: integer (int32)

The number of 'RECENTLY_OFFLOADED' tags currently active for the specified bus. A 'RECENTLY_OFFLOADED' tag is considered to be of negative sentiment, and tags of this type expire after 15 minutes.

UNCOMFORTABLE_RIDE: integer (int32)

The number of 'UNCOMFORTABLE_RIDE' tags currently active for the specified bus. A 'UNCOMFORTABLE_RIDE' tag is considered to be of negative sentiment, and tags of this type expire after 30 minutes.

UNCOMFORTABLE_TEMPS: integer (int32)

The number of 'UNCOMFORTABLE_TEMPS' tags currently active for the specified bus. A 'UNCOMFORTABLE_TEMPS' tag is considered to be of negative sentiment, and tags of this type expire after 30 minutes.

WRONG_DESTINATION: integer (int32)

The number of 'WRONG_DESTINATION' tags currently active for the specified bus. A 'WRONG_DESTINATION' tag is considered to be of negative sentiment, and tags of this type expire after 30 minutes.

SKIPPING_STOPS: integer (int32)

The number of 'SKIPPING_STOPS' tags currently active for the specified bus. A 'SKIPPING_STOPS' tag is considered to be of negative sentiment, and tags of this type expire after 15 minutes.

Example
{
  "BAD_OPERATOR": 1,
  "DISRUPTIVE_RIDER": 1,
  "GOOD_OPERATOR": 1,
  "COMFORTABLE_TEMPS": 0,
  "CROWDED": 0,
  "EMPTY": 0,
  "COMFORTABLE_RIDE": 0,
  "NEEDS_WORK": 0,
  "RECENTLY_OFFLOADED": 0,
  "UNCOMFORTABLE_RIDE": 0,
  "UNCOMFORTABLE_TEMPS": 0,
  "WRONG_DESTINATION": 0,
  "SKIPPING_STOPS": 0
}

StopTags: object

numTagsByType: NumStopTagsByType

Ordered by tag type in descending order by number of tags.

NumStopTagsByType
numPositiveTags: integer (int32)

The number of tags with positive sentiment currently active for the specified stop.

numNegativeTags: integer (int32)

The number of tags with negative sentiment currently active for the specified stop.

Example
{
  "numTagsByType": [
    {
      "EMPTY": 2,
      "CLEAN": 0,
      "CROWDED": 0,
      "LONG_WAITING_TIME": 0,
      "POSTED_TIMES_INACCURATE": 0,
      "NEEDS_WORK": 0,
      "RECENTLY_SKIPPED": 0
    }
  ],
  "numPositiveTags": 2,
  "numNegativeTags": 0
}

NumStopTagsByType: object

EMPTY: integer (int32)

The number of 'EMPTY' tags currently active for the specified bus. A 'EMPTY' tag is considered to be of positive sentiment, and tags of this type expire after 30 minutes.

CLEAN: integer (int32)

The number of 'CLEAN' tags currently active for the specified bus. A 'CLEAN' tag is considered to be of positive sentiment, and tags of this type expire after 180 minutes.

CROWDED: integer (int32)

The number of 'CROWDED' tags currently active for the specified bus. A 'CROWDED' tag is considered to be of negative sentiment, and tags of this type expire after 30 minutes.

LONG_WAITING_TIME: integer (int32)

The number of 'LONG_WAITING_TIME' tags currently active for the specified bus. A 'LONG_WAITING_TIME' tag is considered to be of negative sentiment, and tags of this type expire after 15 minutes.

POSTED_TIMES_INACCURATE: integer (int32)

The number of 'POSTED_TIMES_INACCURATE' tags currently active for the specified bus. A 'POSTED_TIMES_INACCURATE' tag is considered to be of negative sentiment, and tags of this type expire after 15 minutes.

NEEDS_WORK: integer (int32)

The number of 'NEEDS_WORK' tags currently active for the specified bus. A 'NEEDS_WORK' tag is considered to be of negative sentiment, and tags of this type expire after 180 minutes.

RECENTLY_SKIPPED: integer (int32)

The number of 'RECENTLY_SKIPPED' tags currently active for the specified bus. A 'RECENTLY_SKIPPED' tag is considered to be of negative sentiment, and tags of this type expire after 15 minutes.

Example
{
  "EMPTY": 2,
  "CLEAN": 0,
  "CROWDED": 0,
  "LONG_WAITING_TIME": 0,
  "POSTED_TIMES_INACCURATE": 0,
  "NEEDS_WORK": 0,
  "RECENTLY_SKIPPED": 0
}

Keywords: string

string delays, single-tracking, trains holding, long waits, problems, jams, trains offloading, being stuck, being stopped, trains moving slowly, train speed problems, crowded conditions, congestion, trains out of service, trains bypassing, malfunctions, disabled trains, track problems, track work, power outages, smoke, fire, fire dept activity, train derailments