This specification contains a data standard for mobility as a service providers to define a RESTful API for municipalities to access on-demand.
The following information applies to all provider
API endpoints. Details on providing authorization to endpoints is specified in the auth document.
provider
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.provider+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 0.2.1
would be specified as application/vnd.mds.provider+json;version=0.2
Note: Normally breaking changes are covered by different major versions in semver notation. However, as this specification is still pre-1.0.0, changes in minor versions may include breaking changes, and therefore are included in the version string.
Clients must specify the version they are targeting through the Accept
header. For example:
Accept: application/vnd.mds.provider+json;version=0.3
Since versioning was not added until the 0.3.0 release, if the
Accept
header isapplication/json
or not set in the request, theprovider
API must respond as if version0.2
was requested.
Responses to client requests must indicate the version the response adheres to through the Content-Type
header. For example:
Content-Type: application/vnd.mds.provider+json;version=0.3
Since versioning was not added until the 0.3.0 release, if the
Content-Type
header isapplication/json
or not set in the response, version0.2
must be assumed.
If an unsupported or invalid version is requested, the API must respond with a status of 406 Not Acceptable
. In which case, the response should include a body specifying a list of supported versions.
The response to a client request must include a valid HTTP status code defined in the IANA HTTP Status Code Registry. It also must set the Content-Type
header, as specified in the Versioning section.
Response bodies must be a UTF-8
encoded JSON object and must minimally include the MDS version
and a data
payload:
{
"version": "x.y.z",
"data": {
"trips": [{
"provider_id": "...",
"trip_id": "...",
}]
}
}
All response fields must use lower_case_with_underscores
.
MDS defines JSON Schema files for trips
and status_changes
.
provider
API responses must validate against their respective schema files. The schema files always take precedence over the language and examples in this and other supporting documentation meant for human consumption.
provider
APIs may decide to paginate the data payload. If so, pagination must comply with the JSON API specification.
The following keys must be used for pagination links:
first
: url to the first page of datalast
: url to the last page of dataprev
: url to the previous page of datanext
: url to the next page of data
At a minimum, paginated payloads must include a next
key, which must be set to null
to indicate the last page of data.
{
"version": "x.y.z",
"data": {
"trips": [{
"provider_id": "...",
"trip_id": "...",
}]
},
"links": {
"first": "https://...",
"last": "https://...",
"prev": "https://...",
"next": "https://..."
}
}
MDS defines the device as the unit that transmits GPS 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.
References to geographic datatypes (Point, MultiPolygon, etc.) imply coordinates encoded in the WGS 84 (EPSG:4326) standard GPS 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
]
}
}
References to timestamp
imply integer milliseconds since Unix epoch. You can find the implementation of unix timestamp in milliseconds for your programming language here.
A trip represents a journey taken by a mobility as a service customer with a geo-tagged start and stop point.
The trips API allows a user to query historical trip data.
Endpoint: /trips
Method: GET
Schema: trips
schema
data
Payload: { "trips": [] }
, an array of objects with the following structure
Field | Type | Required/Optional | Comments |
---|---|---|---|
provider_id |
UUID | Required | A UUID for the Provider, unique within MDS |
provider_name |
String | Required | The public-facing name of the Provider |
device_id |
UUID | Required | A unique device ID in UUID format |
vehicle_id |
String | Required | The Vehicle Identification Number visible on the vehicle itself |
vehicle_type |
Enum | Required | See vehicle types table |
propulsion_type |
Enum[] | Required | Array of propulsion types; allows multiple values |
trip_id |
UUID | Required | A unique ID for each trip |
trip_duration |
Integer | Required | Time, in Seconds |
trip_distance |
Integer | Required | Trip Distance, in Meters |
route |
GeoJSON FeatureCollection |
Required | See Routes detail below |
accuracy |
Integer | Required | The approximate level of accuracy, in meters, of Points within route |
start_time |
timestamp | Required | |
end_time |
timestamp | Required | |
parking_verification_url |
String | Optional | A URL to a photo (or other evidence) of proper vehicle parking |
standard_cost |
Integer | Optional | The cost, in cents, that it would cost to perform that trip in the standard operation of the System |
actual_cost |
Integer | Optional | The actual cost, in cents, paid by the customer of the mobility as a service provider |
The trips API should allow querying trips with a combination of query parameters.
device_id
vehicle_id
min_end_time
: filters for trips whereend_time
occurs at or after the given timemax_end_time
: filters for trips whereend_time
occurs before the given time
vehicle_type |
---|
bicycle |
scooter |
propulsion_type |
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 |
A device may have one or more values from the propulsion_type
, 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_type
represented by the array ['human', 'electric']
. A bicycle with pedal-assist would have the propulsion_type
represented by the array ['human', 'electric_assist']
if it can also be operated as a traditional bicycle.
To represent a route, MDS provider
APIs must create a GeoJSON FeatureCollection
, which includes every observed point in the route.
Routes must include at least 2 points: the start point and end point. Routes must include all possible GPS samples collected by a Provider. Providers may round the latitude and longitude to the level of precision representing the maximum accuracy of the specific measurement. For example, a-GPS is accurate to 5 decimal places, differential GPS is generally accurate to 6 decimal places. Providers may round those readings to the appropriate number for their systems.
"route": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": {
"timestamp": 1529968782421
},
"geometry": {
"type": "Point",
"coordinates": [
-118.46710503101347,
33.9909333514159
]
}
},
{
"type": "Feature",
"properties": {
"timestamp": 1531007628377
},
"geometry": {
"type": "Point",
"coordinates": [
-118.464851975441,
33.990366257735
]
}
}]
}
The status of the inventory of vehicles available for customer use.
This API allows a user to query the historical availability for a system within a time range.
Endpoint: /status_changes
Method: GET
Schema: status_changes
schema
data
Payload: { "status_changes": [] }
, an array of objects with the following structure
Field | Type | Required/Optional | Comments |
---|---|---|---|
provider_id |
UUID | Required | A UUID for the Provider, unique within MDS |
provider_name |
String | Required | The public-facing name of the Provider |
device_id |
UUID | Required | A unique device ID in UUID format |
vehicle_id |
String | Required | The Vehicle Identification Number visible on the vehicle itself |
vehicle_type |
Enum | Required | see vehicle types table |
propulsion_type |
Enum[] | Required | Array of propulsion types; allows multiple values |
event_type |
Enum | Required | See event types table |
event_type_reason |
Enum | Required | Reason for status change, allowable values determined by event type |
event_time |
timestamp | Required | Date/time that event occurred, based on device clock |
event_location |
GeoJSON Point Feature | Required | |
battery_pct |
Float | Required if Applicable | Percent battery charge of device, expressed between 0 and 1 |
associated_trip |
UUID | Required if Applicable | Trip UUID (foreign key to Trips API) required if event_type_reason is user_pick_up or user_drop_off |
The status_changes API should allow querying status changes with a combination of query parameters.
start_time
: filters for status changes whereevent_time
occurs at or after the given timeend_time
: filters for status changes whereevent_time
occurs before the given time
event_type |
Description | event_type_reason |
Description |
---|---|---|---|
available |
A device becomes available for customer use | service_start |
Device introduced into service at the beginning of the day (if program does not operate 24/7) |
user_drop_off |
User ends reservation | ||
rebalance_drop_off |
Device moved for rebalancing | ||
maintenance_drop_off |
Device introduced into service after being removed for maintenance | ||
reserved |
A customer reserves a device (even if trip has not started yet) | user_pick_up |
Customer reserves device |
unavailable |
A device is on the street but becomes unavailable for customer use | maintenance |
A device is no longer available due to equipment issues |
low_battery |
A device is no longer available due to insufficient battery | ||
removed |
A device is removed from the street and unavailable for customer use | service_end |
Device removed from street because service has ended for the day (if program does not operate 24/7) |
rebalance_pick_up |
Device removed from street and will be placed at another location to rebalance service | ||
maintenance_pick_up |
Device removed from street so it can be worked on |
Gets the list of service areas available to the provider.
Endpoint: /service_areas
Method: GET
Query Parameters:
Parameter | Type | Required/Optional | Description |
---|---|---|---|
service_area_id |
UUID | Optional | If provided, retrieve a specific service area (e.g. a retired or old service area). If omitted, will return all active service areas. |
Response:
Field | Types | Required/Optional | Other |
---|---|---|---|
service_area_id |
UUID | Required | |
service_start_date |
Unix Timestamp | Required | Date at which this service area became effective |
service_end_date |
Unix Timestamp | Required | Date at which this service area was replaced. If currently effective, place NaN |
service_area |
MultiPolygon | Required | |
prior_service_area |
UUID | Optional | If exists, the UUID of the prior service area. |
replacement_service_area |
UUID | Optional | If exists, the UUID of the service area that replaced this one |
type |
Enum | Required | See area types table |
type |
Description |
---|---|
unrestricted | Areas where devices may be picked up/dropped off. A provider's unrestricted area shall be contained completely inside the agency's unrestricted area for the provider in question, but it need not cover the entire agency unrestricted area. See the agency version of the service areas endpoint |
agency_restricted | Areas where the agency does not allow device pick-up/drop-off |
agency_preferred_pick_up | Areas where users are encouraged by the agency to pick up devices |
agency_preferred_drop_off | Areas where users are encouraged by the agency to drop off devices |
provider_restricted | Areas where the provider does not allow device pick-up/drop-off |
provider_preferred_pick_up | Areas where users are encouraged by the provider to pick up devices |
provider_preferred_drop_off | Areas where users are encouraged by the provider to drop off devices |
All MDS compatible provider
APIs must expose a public GBFS feed as well. Given that GBFS hasn't fully evolved to support dockless mobility yet, we follow the current guidelines in making bike information avaliable to the public.
gbfs.json
is always required and must contain afeeds
property that lists all published feedssystem_information.json
is always requiredfree_bike_status.json
is required for MDSstation_information.json
andstation_status.json
don't apply for MDS