This document contains specifications that are shared between the various MDS APIs such as agency
, policy
, and provider
.
- Mobility Data Specification: General information
In some cases, features within MDS may be marked as "beta." These are typically recently added endpoints or fields. Because beta features are new, they may not yet be fully mature and proven in real-world operation. The design of beta features may have undiscovered gaps, ambiguities, or inconsistencies. Implementations of those features are typically also quite new and are more likely to contain bugs or other flaws. Beta features are likely to evolve more rapidly than other parts of the specification.
Despite this, MDS users are highly encouraged to use beta features. New features can only become proven and trusted through implementation, use, and the learning that comes with it. Users should be thoughtful about the role of beta features in their operations. Beta features may be suitable for enabling some new tools and analysis, but may not be appropriate for mission-critical applications or regulatory decisions where certainty and reliability are essential.
Users of beta features are strongly encouraged to share their experiences, learnings, and challenges with the broader MDS community via GitHub issues or pull requests. This will inform the refinements that transform beta features into fully proven, stable parts of the specification.
Working Groups and their Steering Committees are expected to review beta designated features with each release cycle and determine whether the feature has reached the level of stability and maturity needed to remove the beta designation. In a case where a beta feature fails to reach substantial adoption after an extended time, Working Group Steering Committees should discuss whether or not the feature should remain in the specification.
Fields specifying a monetary cost use a currency as specified in ISO 4217. All costs should be given as integers in the currency's smallest unit. As an example, to represent $1 USD, specify an amount of 100
(100 cents).
If the currency field is null, USD cents is implied.
Defining terminology and abbreviations used throughout MDS.
- API - Application Programming Interface - A function or set of functions that allow one software application to access or communicate with features of a different software application or service.
- API Endpoint - A point at which an API connects with a software application or service.
- DOT - Department of Transportation, usually a city-run agency.
- PROW - Public Right of Way - the physical infrastructure reserved for transportation purposes, examples include sidewalks, curbs, bike lanes, transit lanes and stations, traffic lanes and signals, and public parking.
MDS defines the device as the unit that transmits GPS or GNSS signals for a particular vehicle. A given device must have a UUID (device_id
below) that is unique within the Provider's fleet.
Additionally, device_id
must remain constant for the device's lifetime of service, regardless of the vehicle components that house the device.
A Modality is an operational model for a form of transportation in MDS. Given the nature of the differing operational flows, and need for regulators to capture this information, each modality may have different state machines, and different data requirements throughout MDS.
modality |
Description |
---|---|
micromobility |
This mode includes e-scooters, and dockless pedal bikes that are available for rent by consumers through a micromobility operator within an agency's jurisdiction |
taxi |
This mode includes franchise taxi service operators who operate and are regulated within an agency's jurisdiction |
References to geographic datatypes (Point, MultiPolygon, etc.) imply coordinates encoded in the WGS 84 (EPSG:4326) standard GPS or GNSS projection expressed as Decimal Degrees.
Whenever an individual location coordinate measurement is presented, it must be
represented as a GeoJSON Feature
object with a corresponding timestamp
property and Point
geometry:
{
"type": "Feature",
"properties": {
"timestamp": 1529968782421
},
"geometry": {
"type": "Point",
"coordinates": [
-118.46710503101347,
33.9909333514159
]
}
}
When an individual location coordinate measurement corresponds to a Stop,
it must be presented with a stop_id
property:
{
"type": "Feature",
"properties": {
"timestamp": 1529968782421,
"stop_id": "b813cde2-a41c-4ae3-b409-72ff221e003d"
},
"geometry": {
"type": "Point",
"coordinates": [
-118.46710503101347,
33.9909333514159
]
}
}
For the purposes of this specification, the intersection of two geographic datatypes is defined according to the ST_Intersects
PostGIS operation
If a geometry or geography shares any portion of space then they intersect. For geography -- tolerance is 0.00001 meters (so any points that are close are considered to intersect).
Overlaps, Touches, Within all imply spatial intersection. If any of the aforementioned returns true, then the geometries also spatially intersect. Disjoint implies false for spatial intersection.
- 200: OK: operation successful.
- 201: Created:
POST
operations, new object created - 400: Bad request.
- 401: Unauthorized: Invalid, expired, or insufficient scope of token.
- 404: Not Found: Object does not exist, returned on
GET
orPOST
operations if the object does not exist. - 409: Conflict:
POST
operations when an object already exists and an update is not possible. - 500: Internal server error: In this case, the answer may contain a
text/plain
body with an error message for troubleshooting.
{
"error": "...",
"error_description": "...",
"error_details": [ "...", "..." ]
}
Field | Type | Field Description |
---|---|---|
error |
String | Error message string |
error_description |
String | Human readable error description (can be localized) |
error_details |
String[] | Array of error details |
All String fields, such as vehicle_id
, are limited to a maximum of 255 characters.
Stops describe vehicle trip start and end locations in a pre-designated physical place. They can vary from docking stations with or without charging, corrals with lock-to railings, or suggested parking areas marked with spray paint. Stops are used in both Provider (including routes and event locations) and Agency (including telemetry data).
Field | Type | Required/Optional | Description |
---|---|---|---|
stop_id | UUID | Required | Unique ID for stop |
name | String | Required | Name of stop |
last_reported | Timestamp | Required | Date/Time that the stop was last updated |
location | GeoJSON Point Feature | Required | Location of the Stop |
status | Stop Status | Required | Object representing the status of the Stop. See Stop Status. |
capacity | {vehicle_type: number} | Required | Number of total spaces per vehicle_type |
num_vehicles_available | {vehicle_type: number} | Required | How many vehicles are available per vehicle_type at this stop? |
num_vehicles_disabled | {vehicle_type: number} | Required | How many vehicles are unavailable/reserved per vehicle_type at this stop? |
provider_id | UUID | Optional | UUID for the Provider managing this stop. Null/undefined if managed by an Agency. |
geography_id | UUID | Optional | Pointer to the Geography that represents the Stop geospatially |
region_id | string | Optional | ID of the region where station is located, see GBFS Station Information |
short_name | String | Optional | Abbreviated stop name |
address | String | Optional | Postal address (useful for directions) |
post_code | String | Optional | Postal code (e.g. 10036 ) |
rental_methods | Enum[] | Optional | List of payment methods accepted at stop, see GBFS Rental Methods |
cross_street | String | Optional | Cross street of where the station is located. |
num_spaces_available | {vehicle_type: number} | Optional | How many spaces are free to be populated with vehicles at this stop? |
num_spaces_disabled | {vehicle_type: number} | Optional | How many spaces are disabled and unable to accept vehicles at this stop? |
parent_stop | UUID | Optional | Describe a basic hierarchy of stops (e.g.a stop inside of a greater stop) |
devices | UUID[] | Optional | List of device_ids for vehicles which are currently at this stop |
Stop Status returns information about the current status of a Stop.
Field | Type | Required/Optional | Description |
---|---|---|---|
is_installed | Boolean | Required | See GBFS station_status.json |
is_renting | Boolean | Required | See GBFS station_status.json |
is_returning | Boolean | Required | See GBFS station_status.json |
Example of the Stop Status object with properties listed:
{
"is_installed": true,
"is_renting": false,
"is_returning": true
}
Some of the fields in the Stops
definition are using notions which are currently not in MDS, such as rental_methods
. These fields are included for compatibility with GBFS.
A timestamp
refers to integer milliseconds since Unix epoch.
Object identifiers are described via Universally Unique Identifiers (UUIDs). For example, the device_id
field used to uniquely identify a vehicle is a UUID.
MDS uses Version 1 UUIDs.
This enum represents the accessibility options available on a given vehicle, or the accessibility options utilized for a given trip. This enum is currently only used by the Taxi mode, and is not used by micromobility.
accessibility_option |
Description |
---|---|
wheelchair_accessible |
This vehicle is wheelchair accessible |
This table describes the list of vehicle conditions that may be used by regulators to assess the disposition of individual vehicles and fleets of vehicles. Some of these states describe vehicles in the Public Right-of-Way (PROW), and others represent vehicles that are not. One state (unknown
) implies that PROW status is unknown.
In a multi-jurisdiction environment, the status of a vehicle is per-jurisdiction. For example, a vehicle may be in the on_trip
status for a county that contains five cities, and also in the on_trip
status for one of those cities, but elsewhere
for the other four cities. In such a condition, generally a Provider would send the device data to the over-arching jurisdiction (the county) and the vehicle state with respect to each city would be determined by the Agency managing the jurisdictions.
vehicle_state |
In PROW? | Description |
---|---|---|
removed |
no | Examples include: at the Provider's warehouse, in a Provider's truck, or destroyed and in a landfill. |
available |
yes | Available for rental via the Provider's app. In PROW. |
non_operational |
yes | Not available for rent. Examples include: vehicle has low battery, or currently outside legal operating hours. |
reserved |
yes | Reserved via Provider's app, waiting to be picked up by a rider. |
on_trip |
yes | In possession of renter. May or may not be in motion. |
elsewhere |
no | Outside of regulator's jurisdiction, and thus not subject to cap-counts or other regulations. Example: a vehicle that started a trip in L.A. has transitioned to Santa Monica. |
unknown |
unknown | Provider has lost contact with the vehicle and its disposition is unknown. Examples include: taken into a private residence, thrown in river. |
state |
In PROW? | Description |
---|---|---|
removed |
no | Vehicle is explicitly removed from the PROW. Examples include: at the shop receiving maintenance, vehicle moved to another fleet |
available |
yes | Available for-hire by a passenger. |
non_operational |
yes | Not available for-hire. Example: driver's shift ends and vehicle goes out of service |
reserved |
yes | Reserved via Provider's app, waiting to be picked up by a rider. |
on_trip |
yes | On a trip with passengers in the vehicle. May or may not be in motion. |
stopped |
yes | Vehicle is stopped to either pick-up, or drop-off a passenger. |
elsewhere |
no | Outside of regulator's jurisdiction, and thus not subject to cap-counts or other regulations. Example: a vehicle that started a trip in L.A. has transitioned to Santa Monica. |
unknown |
unknown | Provider has lost contact with the vehicle and its disposition is unknown. Examples include: driving in a tunnel, hardware malfunction |
This is the list of vehicle_state
and event_type
pairings that constitute the valid transitions of the vehicle state machine.
The state-transition table below describes how the vehicle_state
changes in response to each event_type
. Most events will have a single event_type
. However, if a single event has more than one ordered event_type
entry, the intermediate vehicle_state
value(s) are discarded. For example, in the micromobility state machine, if an event contains [trip_end
, battery_low
] then the vehicle transitions from on_trip
through available
to non_operational
per the state machine, but the vehicle is never "in" the available
state.
Note that to handle out-of-order events, the validity of the prior-state shall not be enforced at the time of ingest via Provider or Agency. Events received out-of-order may result in transient incorrect vehicle states.
Valid prior vehicle_state values |
vehicle_state |
event_type |
Description |
---|---|---|---|
non_operational |
available |
battery_charged |
The vehicle became available because its battery is now charged. |
non_operational |
available |
on_hours |
The vehicle has entered operating hours (per the regulator or per the provider) |
removed , elsewhere , unknown |
available |
provider_drop_off |
The vehicle was placed in the PROW by the provider |
removed , elsewhere , unknown |
available |
agency_drop_off |
The vehicle was placed in the PROW by a city or county |
non_operational |
available |
maintenance |
The vehicle was previously in need of maintenance |
on_trip |
available |
trip_end |
A trip has ended, and the vehicle is again available for rent |
reserved |
available |
reservation_cancel |
A reservation was canceled and the vehicle returned to service |
on_trip |
available |
trip_cancel |
A trip was initiated, then canceled prior to moving any distance |
non_operational |
available |
system_resume |
The vehicle is available because e.g. weather suspension or temporary regulations ended |
unknown |
available |
comms_restored |
The vehicle transmitted status information after a period of being out of communication. |
non_operational , unknown , removed , reserved , elsewhere |
available |
unspecified |
The vehicle became available, but the provider cannot definitively (yet) specify the reason. Generally, regulator Service-Level Agreements will limit the amount of time a vehicle's last event type may be unspecified . |
available |
reserved |
reservation_start |
The vehicle was reserved for use by a customer |
unknown |
reserved |
comms_restored |
The vehicle transmitted status information after a period of being out of communication. |
available , reserved |
on_trip |
trip_start |
A customer initiated a trip with this vehicle |
elsewhere |
on_trip |
trip_enter_jurisdiction |
A vehicle on a trip entered the jurisdiction |
unknown |
on_trip |
comms_restored |
The vehicle transmitted status information after a period of being out of communication. |
on_trip |
elsewhere |
trip_leave_jurisdiction |
A vehicle on a trip left the jurisdiction |
unknown |
elsewhere |
comms_restored |
The vehicle transmitted status information after a period of being out of communication. |
available |
non_operational |
battery_low |
The vehicle's battery is below some rentability threshold |
available |
non_operational |
maintenance |
The vehicle requires some non-charge-related maintenance |
available |
non_operational |
off_hours |
The vehicle has exited operating hours (per the regulator or per the Provider) |
available |
non_operational |
system_suspend |
The vehicle is not available because of e.g. weather or temporary regulations |
available |
non_operational |
unspecified |
The vehicle became unavailable, but he Provider cannot definitively (yet) specify the reason. |
unknown |
non_operational |
comms_restored |
The vehicle transmitted status information after a period of being out of communication |
available , non_operational , elsewhere |
removed |
rebalance_pick_up |
The provider picked up the vehicle for rebalancing purposes |
available , non_operational , elsewhere |
removed |
maintenance_pick_up |
The provider picked up the vehicle to service it |
available , non_operational , elsewhere , unknown |
removed |
agency_pick_up |
An agency picked up the vehicle for some reason, e.g. illegal placement |
available , non_operational , elsewhere |
removed |
compliance_pick_up |
The provider picked up the vehicle because it was placed in a non-compliant location |
available , non_operational , removed , elsewhere , unknown |
removed |
decommissioned |
The provider has removed the vehicle from its fleet |
unknown , non_operational , available , elsewhere |
removed |
unspecified |
The vehicle was removed, but the provider cannot definitively (yet) specify the reason |
available , reserved , on_trip , non_operational , elsewhere |
unknown |
missing |
The vehicle is not at its last reported GPS location, or that location is wildly in error |
available , reserved , on_trip , non_operational , elsewhere |
unknown |
comms_lost |
The vehicle is unable to transmit its GPS location or other status information |
The Micromobility State Machine Diagram shows how the vehicle_state
and event_type
relate to each other and how micromobility vehicles can transition between states. See Google Slides for the source file.
Previous vehicle_state |
vehicle_state |
trip_state |
event_type |
Description |
---|---|---|---|---|
available |
elsewhere |
N/A | leave_jurisdiction |
The vehicle has left jurisdictional boundaries while available for-hire |
available |
non_operational |
N/A | service_end |
The vehicle has went out of service (is unavailable for-hire) |
available |
reserved |
reserved |
reserve |
The vehicle was reserved by a passenger |
available |
unknown |
N/A | comms_lost |
The vehicle has went out of comms while available for-use |
elsewhere |
available |
N/A | enter_jurisdiction |
The vehicle has entered jurisdictional boundaries while available for-hire |
elsewhere |
non_operational |
N/A | enter_jurisdiction |
The vehicle has entered jurisdictional boundaries while not operating commercially |
elsewhere |
on_trip |
on_trip |
enter_jurisdiction |
The vehicle has entered jurisdictional boundaries while on a trip |
elsewhere |
reserved |
N/A | enter_jurisdiction |
The vehicle has entered jurisdictional boundaries while reserved by a customer |
elsewhere |
unknown |
N/A | comms_lost |
The vehicle has went out of comms while outside of jurisdictional boundaries |
non_operational |
available |
N/A | service_start |
The vehicle has went into service (is available for-hire) |
non_operational |
elsewhere |
N/A | leave_jurisdiction |
The vehicle has left jurisdictional boundaries while not operating commercially |
non_operational |
removed |
N/A | decommissioned |
The vehicle has been removed from the Provider's fleet |
non_operational |
removed |
N/A | maintenance_start |
The vehicle has entered the depot for maintenance |
non_operational |
unknown |
N/A | comms_lost |
The vehicle has went out of comms while not operating commercially |
on_trip |
elsewhere |
N/A | leave_jurisdiction |
The vehicle has left jurisdictional boundaries while on a trip |
on_trip |
stopped |
stopped |
trip_stop |
The vehicle has stopped while on a trip |
on_trip |
unknown |
N/A | comms_lost |
The vehicle has went out of comms while on a trip |
removed |
non_operational |
N/A | maintenance_end |
The vehicle has left the depot |
removed |
non_operational |
N/A | recommissioned |
The vehicle has been re-added to the Provider's fleet after being previously decommissioned |
removed |
unknown |
N/A | comms_lost |
The vehicle has went out of comms while removed |
reserved |
available |
N/A | driver_cancellation |
The driver has cancelled the reservation |
reserved |
available |
N/A | passenger_cancellation |
The passenger has cancelled the reservation |
reserved |
elsewhere |
N/A | leave_jurisdiction |
The vehicle has left the jurisdiction while in a reservation |
reserved |
stopped |
stopped |
reserve_stop |
The vehicle has stopped to pick up the passenger |
reserved |
unknown |
N/A | comms_lost |
The vehicle went out of comms while being reserved by a passenger |
stopped |
available |
N/A | driver_cancellation |
The driver has cancelled the trip while either waiting for the passenger, or dropping them off |
stopped |
available |
N/A | passenger_cancellation |
The passenger has cancelled the trip while the vehicle is waiting to pick them up, or they are being dropped off |
stopped |
available |
N/A | trip_end |
The trip has been successfully completed |
stopped |
on_trip |
on_trip |
trip_resume |
Resume a trip that was previously stopped (e.g. picking up a friend to go to the airport with) |
stopped |
on_trip |
on_trip |
trip_start |
Start a trip |
stopped |
unknown |
N/A | comms_lost |
The vehicle has went out of comms while stopped |
unknown |
available |
N/A | comms_restored |
The vehicle has come back into comms while available for-hire |
unknown |
elsewhere |
N/A | comms_restored |
The vehicle has come back into comms while outside of jurisdictional boundaries |
unknown |
non_operational |
N/A | comms_restored |
The vehicle has come back into comms while not operating commercially |
unknown |
on_trip |
on_trip |
comms_restored |
The vehicle has come back into comms while on a trip |
unknown |
removed |
N/A | comms_restored |
The vehicle has come back into comms while removed |
unknown |
reserved |
reserved |
comms_restored |
The vehicle has come back into comms while reserved by a passenger |
unknown |
stopped |
stopped |
comms_restored |
The vehicle has come back into comms while stopped |
The Taxi State Machine Diagram shows how the vehicle_state
and event_type
relate to each other and how taxi vehicles can transition between states.
When there is only one trip ongoing, trip_state == vehicle_state
In cases where there are multiple trips ongoing, please follow the trip state model pseudocode for determining what the vehicle state should be:
t = all on-going trips for vehicle
v = vehicle state
if t.any(state == ‘stopped’):
v = ‘stopped’
else:
if t.any(state == ‘on_trip’):
v = ‘on_trip’
else:
if t.any(state == ‘reserved’):
v = ‘reserved’
trip_state
mappings should be the same as in the table above.
The list of allowed vehicle_type
values in MDS. Aligning with GBFS vehicle types form factors.
vehicle_type |
Description |
---|---|
bicycle | Anything with pedals, including recumbents; can include powered assist |
car | Any automobile |
scooter | Any motorized mobility device intended for one rider |
moped | A motorcycle/bicycle hybrid that can be powered or pedaled |
other | A device that does not fit in the other categories |
A vehicle may have one or more values from the propulsion_types
, depending on the number of modes of operation. For example, a scooter that can be powered by foot or by electric motor would have the propulsion_types
represented by the array ['human', 'electric']
. A bicycle with pedal-assist would have the propulsion_types
represented by the array ['human', 'electric_assist']
if it can also be operated as a traditional bicycle. A hybrid car would have the propulsion_types
represented by the array ['electric', 'combustion']
.
propulsion |
Description |
---|---|
human |
Pedal or foot propulsion |
electric_assist |
Provides power only alongside human propulsion |
electric |
Contains throttle mode with a battery-powered motor |
combustion |
Contains throttle mode with a gas engine-powered motor |
propulsion |
Description |
---|---|
electric |
Contains a battery-powered motor |
combustion |
Contains a gas engine-powered motor |
MDS APIs must handle requests for specific versions of the specification from clients.
Versioning must be implemented through the use of a custom media-type, application/vnd.mds+json
, combined with a required version
parameter.
The version parameter specifies the dot-separated combination of major and minor versions from a published version of the specification. For example, the media-type for version 1.0.1
would be specified as application/vnd.mds+json;version=1.0
Clients must specify the version they are targeting through the Accept
header. For example:
Accept: application/vnd.mds+json;version=0.3
Since versioning was not available from the start, the following APIs provide a fallback version if the
Accept
header is not set as specified above:
- The
provider
API must respond as if version0.2
was requested.- The
agency
API must respond as if version0.3
was requested.- The
policy
API must respond as if version0.4
was requested.
If an unsupported or invalid version is requested, the API must respond with a status of 406 Not Acceptable
.
ral-information.md#stops geo: #geographic-data geojson-feature: https://tools.ietf.org/html/rfc7946#section-3.2 geojson-point: https://tools.ietf.org/html/rfc7946#section-3.1.2 policy: /policy/README.md provider: /provider/README.md st-intersects: https://postgis.net/docs/ST_Intersects.html toc: #table-of-contents ts: /general-information.md#timestamps wgs84: https://en.wikipedia.org/wiki/World_Geodetic_System