diff --git a/.github/ISSUE_TEMPLATE/add-provider-id.md b/.github/ISSUE_TEMPLATE/add-provider-id.md
index 9b5ad30f..091ca3bc 100644
--- a/.github/ISSUE_TEMPLATE/add-provider-id.md
+++ b/.github/ISSUE_TEMPLATE/add-provider-id.md
@@ -9,7 +9,7 @@ assignees: ''
**Note:** See the [Adding an MDS Provider ID](https://github.com/openmobilityfoundation/mobility-data-specification/wiki/Adding-an-MDS-Provider-ID) page for more help.
-Opening this issue will allow you as a mobility service provider get an official provider ID for use across MDS globally.
+Opening this issue will allow you as a mobility service provider or data source provider to get an official provider ID for use across MDS globally.
**Fields needed from you for the [providers.csv file](https://github.com/openmobilityfoundation/mobility-data-specification/blob/main/providers.csv).**
@@ -17,13 +17,16 @@ _All fields are required._
1. **provider_name** - Short name of your company.
- ...
+1. **mode_id** - The mode that you support. Use the mode short identifier from `micromobility`, `passenger-services`, `delivery-robots`, `car-share`. Register a unique ID for each mode you support.
+ - ...
1. **provider_id** - A random UUID version 4. There are lots of way to generate a unique UUID, like using this [website](https://www.uuidgenerator.net/version4).
- ...
1. **url** - URL to the home page of your company.
- ...
-1. **mds_api_url** - Full https:// URL where your root MDS feeds are located.
+1. **mds_api_url** - Full https:// base URL where your root MDS feeds are located.
- ...
-1. **gbfs_api_url** - Full https:// URL where your public GBFS feeds are located.
+1. **gbfs_api_url** - Full https:// base URL where your public GBFS feeds are located.
- ...
Additionally, please provide your name and role within your agency to help with verification.
+ - ...
diff --git a/MDS-state-machine-diagram.svg b/MDS-state-machine-diagram.svg
deleted file mode 100644
index 38d2e2dd..00000000
--- a/MDS-state-machine-diagram.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/README.md b/README.md
index f2218813..08723ed6 100644
--- a/README.md
+++ b/README.md
@@ -6,10 +6,12 @@
- [Endpoints](#endpoints)
- [Modularity](#modularity)
- [GBFS Requirement](#gbfs-requirement)
-- [Get Involved](#get-involved)
- - [Membership](#membership)
+- [Modes](#modes)
- [Versions](#versions)
- [Technical Information](#technical-information)
+ - [Data Validation](#data-validation)
+- [Get Involved](#get-involved)
+ - [Membership](#membership)
- [Cities Using MDS](#cities-using-mds)
- [Providers Using MDS](#providers-using-mds)
- [Software Companies Using MDS](#software-companies-using-mds)
@@ -19,7 +21,7 @@
# About
-The Mobility Data Specification (**MDS**), a project of the [Open Mobility Foundation](http://www.openmobilityfoundation.org) (**OMF**), is a set of Application Programming Interfaces (APIs) focused on shared mobility services such as dockless scooters, bicycles, mopeds, and carshare, and inspired by projects like [GTFS](https://developers.google.com/transit/gtfs/reference/) and [GBFS](https://github.com/NABSA/gbfs). MDS is a digital tool that helps cities better manage transportation in the public right of way, standardizing communication and data-sharing between cities and private mobility providers, allowing cities to share and validate policy digitally, and enabling vehicle management and better outcomes for residents.
+The Mobility Data Specification (**MDS**), a project of the [Open Mobility Foundation](http://www.openmobilityfoundation.org) (**OMF**), is a set of Application Programming Interfaces (APIs) that helps cities better manage transportation in the public right of way, standardizing communication and data-sharing between cities and mobility providers, allowing cities to share and validate policy digitally, and enabling vehicle management and better outcomes for residents. Inspired in part by projects like [GTFS](https://developers.google.com/transit/gtfs/reference/) and [GBFS](https://github.com/NABSA/gbfs), MDS is focused on managing mobility services such as dockless scooters, bicycles, mopeds, car share, delivery robots, and passenger services.
**MDS** is a key piece of digital infrastructure that supports the effective implementation of mobility policies in cities around the world. For a high level overview and visuals, see the [About MDS](https://www.openmobilityfoundation.org/about-mds/) page on the OMF website.
@@ -35,53 +37,100 @@ The Mobility Data Specification (**MDS**), a project of the [Open Mobility Found
-The [`provider`][provider] API endpoints are intended to be implemented by mobility providers and consumed by regulatory agencies. When a municipality queries information from a mobility provider, the Provider API has a historical view of operations in a standard format. It was first released in June 2018.
+The [`provider`][provider] API endpoints are intended to be implemented by mobility providers and consumed by regulatory agencies. Data is **pulled** from providers by agencies. When a municipality queries information from a mobility provider, the Provider API provides historical and recent views of operations. First released in June 2018.
---
-The [`agency`][agency] API endpoints are intended to be implemented by regulatory agencies and consumed by mobility providers. Providers query the Agency API when events (such as a trip start or vehicle status change) occur in their systems. It was first released in April 2019.
+The [`agency`][agency] API endpoints are intended to be implemented by regulatory agencies and consumed by mobility providers. Data is **pushed** to agencies by providers. Providers query the Agency API when events (such as a trip start or vehicle status change) occur in their systems. First released in April 2019.
---
-The [`policy`][policy] API endpoints are intended to be implemented by regulatory agencies and consumed by mobility providers. Providers query the Policy API to get information about local rules that may affect the operation of their mobility service or which may be used to determine compliance. It was first released in October 2019.
+The [`policy`][policy] API endpoints are intended to be implemented by regulatory agencies and consumed by mobility providers. Providers query the Policy API to get information about local rules that may affect the operation of their mobility service or which may be used to determine compliance. First released in October 2019.
---
-The [`geography`][geography] API endpoints are intended to be implemented by regulatory agencies and consumed by mobility providers. Providers query the Policy API to get information about geographical regions for regulatory and other purposes. It was first released in October 2019, originally included as part of the Policy specification.
+The [`geography`][geography] API endpoints are intended to be implemented by regulatory agencies and consumed by mobility providers. Providers query the Geography API to get information about geographical regions for regulatory and other purposes. First released in October 2019, as part of the Policy specification.
---
-The [`jurisdiction`][jurisdiction] API endpoints are intended to be implemented by regulatory agencies that have a need to coordinate with each other. The jurisdiction endpoints allow cities to communicate boundaries between one another and to mobility providers. It was first released in March 2021.
+The [`jurisdiction`][jurisdiction] API endpoints are intended to be implemented by regulatory agencies that have a need to coordinate with each other. The Jurisdiction API endpoints allow cities to communicate boundaries between one another and to mobility providers. First released in March 2021.
---
-The [`metrics`](/metrics) API endpoints are intended to be implemented by regulatory agencies or their appointed third-party representatives to have a standard way to consistently describe available metrics, and create an extensible interface for querying MDS metrics. It was first released in March 2021.
+The [`metrics`](/metrics) API endpoints are intended to be implemented by regulatory agencies or their appointed third-party representatives to have a standard way to consistently describe available metrics, and create an extensible interface for querying MDS metrics. First released in March 2021.
---
## Modularity
-MDS is designed to be a modular kit-of-parts. Regulatory agencies can use the components of the API that are appropriate for their needs. An agency may choose to use only `agency`, `provider`, or `policy`. Other APIs like `geography`, `jurisdiction`, and `metrics` can be used in coordination as described with these APIs or sometimes on their own. Or agencies may select specific elements (endpoints) from each API to help them implement their goals. Development of the APIs takes place under the guidance of the OMF's [MDS Working Group](https://github.com/openmobilityfoundation/mobility-data-specification/wiki/MDS-Working-Group).
+MDS is designed to be a modular kit-of-parts. Regulatory agencies can use the components of the API that are appropriate for their needs. An agency may choose to use only `agency`, `provider`, and/or `policy`. Other APIs like `geography`, `jurisdiction`, and/or `metrics` can be used in coordination as described with these APIs or sometimes on their own. Or agencies may select specific elements (endpoints) from each API to help them implement their goals. Development of the APIs takes place under the guidance of the OMF's [MDS Working Group](https://github.com/openmobilityfoundation/mobility-data-specification/wiki/MDS-Working-Group).
Many parts of the MDS definitions and APIs align across each other. In these cases, consolidated information can be found on the [General Information](/general-information.md) page.
You can read more in our **[Understanding the different MDS APIs](https://github.com/openmobilityfoundation/governance/blob/main/technical/Understanding-MDS-APIs.md)** guide.
-![MDS APIs and Endpoints](https://i.imgur.com/bfUtCif.png)
+![MDS APIs and Endpoints](https://i.imgur.com/i27Mmfw.png)
## GBFS Requirement
-All MDS compatible Provider feeds [must also expose](/provider/README.md#gbfs) a public [GBFS](https://github.com/NABSA/gbfs) feed. Compatibility with [GBFS 2.0](https://github.com/NABSA/gbfs/blob/v2.0/gbfs.md) or greater is advised due to privacy concerns and support for micromobility. See our [MDS Vehicles Guide](https://github.com/openmobilityfoundation/mobility-data-specification/wiki/MDS-Vehicles) for how MDS Provider `/vehicles` can be used by regulators instead of the public GBFS `/free_bike_status`. Additional information on MDS and GBFS can be found in this [guidance document](https://github.com/openmobilityfoundation/governance/blob/main/technical/GBFS_and_MDS.md).
+All MDS compatible Provider and/or Agency feeds must also expose a public [GBFS](https://github.com/NABSA/gbfs) feed for the micromobility and car share [modes](/modes) (passenger services and delivery robots may be optionally supported at the discretion of the agency running the program). Compatibility with [GBFS 2.2](https://github.com/NABSA/gbfs/blob/v2.2/gbfs.md) or greater is advised, or the version recommended per MobilityData's [supported releases](https://github.com/MobilityData/gbfs#past-version-releases) guidance. Read MobilityData's RFP recommendations and required files list in their [GBFS and Shared Mobility Data Policy guide](https://mobilitydata.org/gbfs-and-shared-mobility-data-policy/).
+
+See our [MDS Vehicles Guide](https://github.com/openmobilityfoundation/mobility-data-specification/wiki/MDS-Vehicles) for how MDS Provider/Agency `/vehicles` can be used by regulators instead of the public GBFS `/free_bike_status`. Additional information on MDS and GBFS can be found in this [guidance document](https://github.com/openmobilityfoundation/governance/blob/main/technical/GBFS_and_MDS.md).
+
+[Top][toc]
+
+# Modes
+
+MDS supports multiple "modes", defined as a distinct regulatory framework for a type of mobility service. See the [modes overview](/modes) or get started with a specific mode:
+
+- **[Micromobility](/modes/micromobility.md)** - dockless or docked small devices such as e-scooters and bikes.
+- **[Passenger services](/modes/passenger-services.md)** - transporting individuals with a vehicle driven by another entity, including taxis, TNCs, and microtransit
+- **[Car share](/modes/car-share.md)** - shared point-to-point and station-based multi-passenger vehicles.
+- **[Delivery robots](/modes/delivery-robots.md)** - autonomous and remotely driven goods delivery devices
+
+
+
+
+
+
+
+
+
+[Top][toc]
+
+# Versions
+
+MDS has a **current release** (version 2.0.0), **previous releases** (both recommended and longer recommended for use), and **upcoming releases** in development. For a full list of releases, their status, recommended versions, and timelines, see the [Official MDS Releases](https://github.com/openmobilityfoundation/governance/wiki/Releases) page.
+
+The OMF provides guidance on upgrading for cities, providers, and software companies, and sample permit language for cities. See our [MDS Version Guidance](https://github.com/openmobilityfoundation/governance/blob/main/technical/OMF-MDS-Version-Guidance.md) for best practices on how and when to upgrade MDS as new versions become available. Our complimentary [MDS Policy Language Guidance](https://github.com/openmobilityfoundation/governance/blob/main/technical/OMF-MDS-Policy-Language-Guidance.md) document is for cities writing MDS into their operating policy and includes sample policy language.
+
+## Technical Information
+
+The latest MDS release is in the [`main`](https://github.com/openmobilityfoundation/mobility-data-specification/tree/main) branch, and development for the next release occurs in the [`dev`](https://github.com/openmobilityfoundation/mobility-data-specification/tree/dev) branch.
+
+The MDS specification is versioned using Git tags and [semantic versioning](https://semver.org/). See prior [releases](https://github.com/openmobilityfoundation/mobility-data-specification/releases) and the [Release Guidelines](https://github.com/openmobilityfoundation/governance/blob/main/technical/ReleaseGuidelines.md) for more information and [version support](https://github.com/openmobilityfoundation/governance/blob/main/technical/ReleaseGuidelines.md#ongoing-version-support).
+
+* [Latest Release Branch](https://github.com/openmobilityfoundation/mobility-data-specification/tree/main) (main)
+* [Development Branch](https://github.com/openmobilityfoundation/mobility-data-specification/tree/dev) (dev)
+* [All GitHub Releases](https://github.com/openmobilityfoundation/mobility-data-specification/releases)
+* [MDS Releases](https://github.com/openmobilityfoundation/governance/wiki/Releases) - current/recommended versions, timeline
+* [Release Guidelines](https://github.com/openmobilityfoundation/governance/blob/main/technical/ReleaseGuidelines.md)
+
+## Data Validation
+
+To help with MDS data and feed validation, please see our OpenAPI schema description in the OMF [mds-openapi](https://github.com/openmobilityfoundation/mds-openapi) repository. Browsable interactive documentation is also linked to in that repository.
+
+Starting with MDS 2.0, OpenAPI documents describe MDS endpoints and allow for [schema](/schema) validation, expanding on the JSON Schemas formerly housed in this repository.
[Top][toc]
@@ -112,29 +161,9 @@ Read about [how to become an OMF member](https://www.openmobilityfoundation.org/
[Top][toc]
-# Versions
-
-MDS has a **current release** (version 1.2.0), **previous releases** (both recommended and longer recommended for use), and **upcoming releases** in development. For a full list of releases, their status, recommended versions, and timelines, see the [Official MDS Releases](https://github.com/openmobilityfoundation/governance/wiki/Releases) page.
-
-The OMF provides guidance on upgrading for cities, providers, and software companies, and sample permit language for cities. See our [MDS Version Guidance](https://github.com/openmobilityfoundation/governance/blob/main/technical/OMF-MDS-Version-Guidance.md) for best practices on how and when to upgrade MDS as new versions become available. Our complimentary [MDS Policy Language Guidance](https://github.com/openmobilityfoundation/governance/blob/main/technical/OMF-MDS-Policy-Language-Guidance.md) document is for cities writing MDS into their operating policy and includes sample policy language.
-
-## Technical Information
-
-The latest MDS release is in the [`main`](https://github.com/openmobilityfoundation/mobility-data-specification/tree/main) branch, and development for the next release occurs in the [`dev`](https://github.com/openmobilityfoundation/mobility-data-specification/tree/dev) branch.
-
-The MDS specification is versioned using Git tags and [semantic versioning](https://semver.org/). See prior [releases](https://github.com/openmobilityfoundation/mobility-data-specification/releases) and the [Release Guidelines](https://github.com/openmobilityfoundation/governance/blob/main/technical/ReleaseGuidelines.md) for more information and [version support](https://github.com/openmobilityfoundation/governance/blob/main/technical/ReleaseGuidelines.md#ongoing-version-support).
-
-* [Latest Release Branch](https://github.com/openmobilityfoundation/mobility-data-specification/tree/main) (main)
-* [Development Branch](https://github.com/openmobilityfoundation/mobility-data-specification/tree/dev) (dev)
-* [All GitHub Releases](https://github.com/openmobilityfoundation/mobility-data-specification/releases)
-* [MDS Releases](https://github.com/openmobilityfoundation/governance/wiki/Releases) - current/recommended versions, timeline
-* [Release Guidelines](https://github.com/openmobilityfoundation/governance/blob/main/technical/ReleaseGuidelines.md)
-
-[Top][toc]
-
# Cities Using MDS
-More than 150 cities and public agencies across 6 continents around the world use MDS, and it has been implemented by most major [mobility service providers](#providers-using-mds).
+More than 200 cities and public agencies across 21 countries around the world are known to use MDS, and it has been implemented by most major [mobility service providers](#providers-using-mds).
- See our **[list of cities using MDS](https://www.openmobilityfoundation.org/mds-users/#cities-using-mds)** with links to public mobility websites and policy/permit documents.
Please let us know [via our website](https://www.openmobilityfoundation.org/get-in-touch/) or in the [public discussion area](https://github.com/openmobilityfoundation/mobility-data-specification/discussions) if you are an agency using MDS so we can add you to the city resource list, especially if you have published your policies or documents publicly.
@@ -145,9 +174,10 @@ To add yourself to the [agency list](/agencies.csv) and add your [Policy Require
# Providers Using MDS
-Over two dozen mobility service providers (MSPs) around the world use MDS, allowing them to create tools around a single data standard for multiple cities.
+Over four dozen mobility service providers (MSPs) around the world use MDS, allowing them to create tools around a single data standard for multiple cities.
-- See our **[list of providers using MDS](https://www.openmobilityfoundation.org/mds-users/#mobility-providers-using-mds)**. For a table list with unique IDs, see the MDS [provider list](/providers.csv).
+- See our **[list of providers using MDS](https://www.openmobilityfoundation.org/mds-users/#mobility-providers-using-mds)**. For a table list with unique IDs, see the MDS [provider list](/providers.csv) which includes both service operators and data solution providers.
+- A provider needs a unique ID for each [mode](#modes) they operate under.
To add yourself to the provider list, please let us know [via our website](https://www.openmobilityfoundation.org/get-in-touch/) or open an [Issue](https://github.com/openmobilityfoundation/mobility-data-specification/issues) or [Pull Request](https://github.com/openmobilityfoundation/mobility-data-specification/pulls). Find out how in our [Adding an Provider ID](https://github.com/openmobilityfoundation/mobility-data-specification/wiki/Adding-an-MDS-Provider-ID) help document.
@@ -157,7 +187,10 @@ To add yourself to the provider list, please let us know [via our website](https
An open source approach to data specifications benefits cities and companies by creating a space for collaborative development, reducing costs, and nurturing a healthy, competitive ecosystem for mobility services and software tools. The open model promotes a competitive ecosystem for software tools built by dozens of software companies providing their services to cities, agencies, and providers.
-- See our **[list of third party software companies using MDS](https://www.openmobilityfoundation.org/mds-users/#software-companies-using-mds)** and an article about the [benefits of an open approach](https://www.openmobilityfoundation.org/why-open-behind-omfs-unique-open-source-model/).
+- See our **[list of third party software companies using MDS](https://www.openmobilityfoundation.org/mds-users/#software-companies-using-mds)** and an article about the [benefits of an open approach](https://www.openmobilityfoundation.org/why-open-behind-omfs-unique-open-source-model/).
+- For a table list with unique IDs, see the MDS [provider list](/providers.csv) which includes both service operators and data solution providers.
+
+To add yourself to the provider list (as a data solution providers), please let us know [via our website](https://www.openmobilityfoundation.org/get-in-touch/) or open an [Issue](https://github.com/openmobilityfoundation/mobility-data-specification/issues) or [Pull Request](https://github.com/openmobilityfoundation/mobility-data-specification/pulls). Find out how in our [Adding an Provider ID](https://github.com/openmobilityfoundation/mobility-data-specification/wiki/Adding-an-MDS-Provider-ID) help document.
Please [let us know](https://www.openmobilityfoundation.org/get-in-touch/) if you are using MDS in your company so we can add you to the list.
@@ -173,7 +206,7 @@ MDS includes information about vehicles, their location, and trips taken on thos
* [Understanding the Data in MDS](https://github.com/openmobilityfoundation/mobility-data-specification/wiki/Understanding-the-Data-in-MDS) - technical document outlining what data is (and is not) in MDS
* [Use Case Database](https://www.openmobilityfoundation.org/whats-possible-with-mds/) - a starting point for understanding how MDS can be used, and what parts of MDS is required to meet those use cases
* [Policy Requirements](https://github.com/openmobilityfoundation/mobility-data-specification/tree/main/policy#requirement) - built into MDS, allowing agencies to specify only the endpoints and fields needed for program regulation
-* Using MDS Under GDPR (link coming soon) - how to use MDS in the context of GDPR in Europe
+* [Using MDS Under GDPR](https://www.openmobilityfoundation.org/using-mds-under-gdpr/) - how to use MDS in the context of GDPR in Europe
The OMF’s [Privacy, Security, and Transparency Committee](https://github.com/openmobilityfoundation/privacy-committee#welcome-to-the-privacy-security-and-transparency-committee) creates many of these resources, and advises the OMF on principles and practices that ensure the secure handling of mobility data. The committee – which is composed of both private and public sector OMF members – also holds regular public meetings, which provide additional resources and an opportunity to discuss issues related to privacy and mobility data. Learn more [here](https://github.com/openmobilityfoundation/privacy-committee#welcome-to-the-privacy-security-and-transparency-committee).
@@ -190,7 +223,7 @@ How cities use MDS depends on a variety of factors: their transportation goals,
- **Resident Complaints:** Investigate and validate complaints from residents about operations, parking, riding, speed, etc, usually reported through 311
- **Infrastructure Planning:** Determine where to place new bike/scooter lanes and drop zones based on usage and demand, start and end points, and trips taken
-A list of use cases is useful to show what's possible with MDS, to list what other cities are accomplishing with the data, to see many use cases up front for privacy considerations, and to use for policy discussions and policy language. More details and examples can be seen on the [OMF website](https://www.openmobilityfoundation.org/whats-possible-with-mds/) and our [Wiki Database](https://github.com/openmobilityfoundation/governance/wiki/MDS-Use-Cases).
+A list of use cases is useful to show what's possible with MDS, to list what other cities are accomplishing with the data, to see many use cases up front for privacy considerations, and to use for policy discussions and policy language. More details and examples can be seen on the [OMF website](https://www.openmobilityfoundation.org/whats-possible-with-mds/) and our [Wiki Database](https://github.com/openmobilityfoundation/governance/wiki/MDS-Use-Cases). An agency may align their program to specific use cases by publishing [Policy Requirement use cases](/policy#requirement-apis).
Please [let us know](https://docs.google.com/forms/d/e/1FAIpQLScrMPgeb1TKMYCjjKsJh3y1TPTJO8HR_y1NByrf1rDmTEJS7Q/viewform) if you have recommended updates or use cases to add.
@@ -200,7 +233,7 @@ Please [let us know](https://docs.google.com/forms/d/e/1FAIpQLScrMPgeb1TKMYCjjKs
Community projects are those efforts by individual contributors or informal groups that take place outside Open Mobility Foundation’s formalized process, complementing MDS. These related projects often push new ideas forward through experimental or locally-focused development, and are an important part of a thriving open source community. Some of these projects may eventually be contributed to and managed by the Open Mobility Foundation.
-The OMF's [Communitiy Projects](https://www.openmobilityfoundation.org/community-projects/) page has an every growing list of projects related to MDS, and see our [Privacy Committee's State of Practice](https://github.com/openmobilityfoundation/privacy-committee/blob/main/products/state-of-the-practice.md) for more examples.
+The OMF's [Community Projects](https://www.openmobilityfoundation.org/community-projects/) page has an every growing list of projects related to MDS, and see our [Privacy Committee's State of Practice](https://github.com/openmobilityfoundation/privacy-committee/blob/main/products/state-of-the-practice.md) for more examples.
Please [let us know](https://www.openmobilityfoundation.org/get-in-touch/) if you create open source or private tools for implementing or working with MDS data.
@@ -212,4 +245,5 @@ Please [let us know](https://www.openmobilityfoundation.org/get-in-touch/) if yo
[geography]: /geography/README.md
[jurisdiction]: /jurisdiction/README.md
[metrics]: /metrics/README.md
+[modes]: /modes/README.md
[toc]: #table-of-contents
diff --git a/ReleaseNotes.md b/ReleaseNotes.md
index d93c3d45..629c4a30 100644
--- a/ReleaseNotes.md
+++ b/ReleaseNotes.md
@@ -1,3 +1,112 @@
+## 2.0.0
+
+> Released 2023-05-09
+
+> [Release Plan](https://github.com/openmobilityfoundation/governance/wiki/Release-2.0.0)
+
+The 2.0.0 major release includes support for new mobility modes, clarity around Policy, and the alignment of the data and structure of Agency and Provider.
+
+### CHANGES
+
+See the closed PRs tagged with [Milestone 2.0.0](https://github.com/openmobilityfoundation/mobility-data-specification/pulls?q=is%3Apr+is%3Aclosed+milestone%3A2.0.0) and [Issues](https://github.com/openmobilityfoundation/mobility-data-specification/issues?q=is%3Aissue+milestone%3A2.0.0+is%3Aclosed) for a full list of changes.
+
+#### **_Admin/General Changes_**
+
+- Update [state machine diagrams](https://docs.google.com/presentation/d/1fHdq1efbN5GSFDLF4en-oA_BYPXQKbbIbHff6iROJKA/edit?usp=sharing) and create 4 new diagrams for each mode
+- [Remove Schema and instead link to OpenAPI repo](https://github.com/openmobilityfoundation/mobility-data-specification/issues/281)
+ - OpenAPI support in place of JSON Schema allows easier building of real-time MDS endpoint validation, and interactive documentation on Stoplight.
+- [Remove Geography from Policy](https://github.com/openmobilityfoundation/mobility-data-specification/issues/816)
+- [Authorization consistency across MDS](https://github.com/openmobilityfoundation/mobility-data-specification/issues/584)
+- [Make GBFS optional for some modes](https://github.com/openmobilityfoundation/mobility-data-specification/issues/769)
+- [Align vehicle types to GBFS](https://github.com/openmobilityfoundation/mobility-data-specification/issues/692)
+ - Updated MDS alignment with GBFS to include all of their vehicle types (including seated scooter) and the addition of new ones for modes (bus, truck, delivery robot, motorcycle), all propulsion types, and to require GBFS for only micromobility and car share (delivery robots and passenger services are option, but not well supported in GBFS).
+- [Added maintenance_pick_up event for out of PROW work](https://github.com/openmobilityfoundation/mobility-data-specification/issues/595)
+- Ability to send tip overs, surface type, and parking validation [data if available from sensors](https://github.com/openmobilityfoundation/mobility-data-specification/pull/829)
+ - New optional fields to include sensors now available and in use in the field by many micromobility companies for tip overs, surface type, and parking validation.
+- [Vertical accuracy for GPS telemetry](https://github.com/openmobilityfoundation/mobility-data-specification/issues/661)
+- All vehicle states are now clearly in or out of the right of way, [no unknown state](https://github.com/openmobilityfoundation/mobility-data-specification/issues/770)
+- Many [new provider IDs added](https://github.com/openmobilityfoundation/mobility-data-specification/pulls?q=is%3Apr+is%3Aclosed+label%3A%22identifier+change%22+milestone%3A2.0.0)
+
+#### **_Modes Architecture_**
+
+- [Support for multiple modes/services in MDS](https://github.com/openmobilityfoundation/mobility-data-specification/issues/574)
+ - Updates the base of MDS to have some shared objects and fields, and specific fields as needed for each mode.
+ - Adds specific modes to MDS, with help from Member Networks, and existing real world data exchanges between operators, agencies, and solution providers.
+ - Operators must register a unique UUID for each mode they operate under.
+
+**Passenger Services**
+- [Passenger services/TNC/taxi support ](https://github.com/openmobilityfoundation/mobility-data-specification/issues/95)
+
+**Delivery Robots**
+- [Support for vehicles like delivery robots](https://github.com/openmobilityfoundation/mobility-data-specification/issues/782)
+
+**Car Share**
+- [Carshare Support](https://github.com/openmobilityfoundation/mobility-data-specification/issues/640)
+
+**Work to bring modes together**
+
+- [Add a "Data Provider UUID" to MDS](https://github.com/openmobilityfoundation/mobility-data-specification/issues/805)
+ - New data provider id allows endpoints to include who is producing and serving up the data. Software companies and solution providers are [encouraged to register](https://github.com/openmobilityfoundation/mobility-data-specification/tree/feature-modes-cleanup#software-companies-using-mds) for their own global UUID now to serve up operator or agency data with MDS.
+- [Support for Modes in Policy](https://github.com/openmobilityfoundation/mobility-data-specification/issues/614) - specify which mode your policy applies to
+
+#### **_Policy Reimagining_**
+
+A reimagining of Policy, including top ten most common policies are clearly defined, edge cases (dwell time, trip definition, rule units, updating/ending policies, lookback periods) are clarified, Stops is out of beta, and Policy feeds are public
+
+- [Multimodal support in Policy](https://github.com/openmobilityfoundation/mobility-data-specification/issues/614)
+- [Clarification on possible values of rule_units](https://github.com/openmobilityfoundation/mobility-data-specification/issues/704)
+- [Move Stops out of beta](https://github.com/openmobilityfoundation/mobility-data-specification/issues/674)
+- [Policy is now public](https://github.com/openmobilityfoundation/mobility-data-specification/pull/824/)
+- [Updating and ending policy clarification](https://github.com/openmobilityfoundation/mobility-data-specification/pull/834)
+- [Lookback period clarification ](https://github.com/openmobilityfoundation/mobility-data-specification/issues/749)
+
+**Policy Requirements**
+
+Requirements now supports linking to external use cases, and is moved out of beta because of adoption.
+
+- [Support to reference external use cases](https://github.com/openmobilityfoundation/mobility-data-specification/issues/681)
+- [Move out of beta](https://github.com/openmobilityfoundation/mobility-data-specification/issues/682)
+
+#### **_Agency/Provider Unification_**
+
+The difference between Agency and Provider is that with Agency operators PUSH data to cities, and with Provider cities PULL data from operators. Both share the same data types, referenced in a new file, with the same endpoints and fields available.
+
+- [MDS Agency and Provider Unification](https://github.com/openmobilityfoundation/mobility-data-specification/issues/759)
+ - Endpoints are now identical
+ - Data objects are now identical, referenced in new data-type.md file
+ - Distinction between Agency and Provider is now simply pushing data to agencies, or pulling data from operators
+- [Adding trips endpoint to Agency](https://github.com/openmobilityfoundation/mobility-data-specification/issues/550)
+- [Adding trip data to Agency](https://github.com/openmobilityfoundation/mobility-data-specification/issues/722)
+(https://github.com/openmobilityfoundation/mobility-data-specification/issues/770)
+ - Trip telemetry points are no longer in the trips endpoint directly, instead referenced in their own telemetry endpoint. Start and end location only is available in trips.
+
+#### **_Provider_**
+
+Reports have a new adaptive scooter special group type, and improved formatting.
+
+- [Updates to provider reports](https://github.com/openmobilityfoundation/mobility-data-specification/pulls?q=is%3Apr+is%3Aclosed+label%3AReports) including header, date format, column names, and adaptive scooter special group type
+
+#### **_Geography_**
+
+- [Geography is now public, and removed from Policy](https://github.com/openmobilityfoundation/mobility-data-specification/pull/824/files)
+
+#### **_Jurisdiction_**
+
+- [Jurisdiction is now public](https://github.com/openmobilityfoundation/mobility-data-specification/pull/824/files)
+
+#### **_Technical Updates_**
+
+As part of the OpenAPI schema work, a number of technical updates were made to ensure the spec was internally consistent. A full list can be found for all issues and PRs in [this date range](https://github.com/openmobilityfoundation/mobility-data-specification/issues?q=milestone%3A2.0.0+created%3A%3E2023-04-15+updated%3A%3C2023-05-09).
+
+- [OpenAPI Schema](https://github.com/openmobilityfoundation/mobility-data-specification/issues/281) definitions, created in [`mds-openapi`](https://github.com/openmobilityfoundation/mds-openapi) repo
+- [HTTP error and bulk responses](https://github.com/openmobilityfoundation/mobility-data-specification/issues/856)
+- [Accessibility 'options' renamed to 'attributes'](https://github.com/openmobilityfoundation/mobility-data-specification/issues/847) for consistency
+- [Add missing event types from main list](https://github.com/openmobilityfoundation/mobility-data-specification/issues/845)
+- [Fix car share event types](https://github.com/openmobilityfoundation/mobility-data-specification/issues/843)
+- [Updated fare_attributes.payment_type list](https://github.com/openmobilityfoundation/mobility-data-specification/issues/844)
+- [Use last_updated consistently](https://github.com/openmobilityfoundation/mobility-data-specification/issues/842) across responses
+- [Remove extra 'data' hierarchy](https://github.com/openmobilityfoundation/mobility-data-specification/issues/841) in responses in some endpoints
+
## 1.2.0
> Released: 2021-11-04
diff --git a/agencies.csv b/agencies.csv
index efcd112d..a0403b15 100644
--- a/agencies.csv
+++ b/agencies.csv
@@ -4,7 +4,7 @@ CO,Cundinamarca,Bogotá,Bogotá,85eac875-ab70-469f-8a85-cc5ef22e78d0,https://www
DE,Baden-Württemberg,Ulm,Stadt Ulm,68f28fb8-d177-43f4-b7e8-a286fe0ddca0,https://www.ulm.de/de-de,
US,CA,Long Beach,City of Long Beach,188ed65d-a81e-40b9-b0b2-aeb85436610a,https://www.longbeach.gov/goactivelb/,
US,CA,Los Angeles,Los Angeles,d82d8584-dfa6-4396-93f0-5a36288b9eb1,https://ladot.lacity.org/projects/transportation-services/shared-mobility/micromobility,
-US,CA,San Francisco,San Francisco,8e03693b-0153-446c-8bc0-c31f8a5a7ed8,https://www.sfmta.com/projects/powered-scooter-share-permit-and-pilot-program,
+US,CA,San Francisco,San Francisco Municipal Transportation Agency,8e03693b-0153-446c-8bc0-c31f8a5a7ed8,https://www.sfmta.com/projects/powered-scooter-share-permit-and-pilot-program,https://github.com/openmobilityfoundation/agency-program-requirements/raw/main/requirement/SFMTA-1.2.0.json
US,CA,San Jose,San Jose,801cb4b8-8725-449c-bdb9-7e9ac0e10b5b,https://www.sanjoseca.gov/your-government/departments-offices/transportation/micro-mobility,
US,CA,Santa Monica,Santa Monica,e4e7c0f6-c6aa-4919-a4de-565e4fe9fa57,https://www.smgov.net/Departments/PCD/Transportation/Shared-Mobility-Services/,
US,CO,Denver,Denver,c3d07b63-f602-4837-9525-7285f5ef286b,https://www.denvergov.org/content/denvergov/en/transportation-infrastructure/programs-services/dockless-mobility.html,
@@ -14,7 +14,7 @@ US,IL,Chicago,Chicago,d2ed9de6-2d2d-477c-a843-7d150d2310ed,https://www.chicago.g
US,KY,Louisville,Louisville Metro,44bc31a7-464b-4ed9-b52e-8e74630826bd,https://louisvilleky.gov/government/public-works/dockless-find-and-ride-vehicles,
US,MI,Detroit,Detroit,5814742e-78ba-4ac1-a628-c414ecc45448,https://detroitmi.gov/departments/department-public-works/complete-streets/scooters,
US,MN,Minneapolis,Minneapolis,88303227-48d6-4088-a690-65b4dcf381f7,http://www.minneapolismn.gov/publicworks/trans/WCMSP-212816,
-US,OR,Portland,Portland,7d600eb6-f967-40ea-a212-33917f9b48ae,https://www.portlandoregon.gov/transportation/,
+US,OR,Portland,Portland,7d600eb6-f967-40ea-a212-33917f9b48ae,https://www.portlandoregon.gov/transportation/, https://api.ridereport.com/policy/pdx/requirements
US,PA,Philadelphia,Philadelphia,fa2d0c5a-a716-473c-808b-be3b23e022ee,http://www.phillyotis.com/portfolio-item/dockless-bike-share-pilot/,
US,PA,Pittsburgh,Pittsburgh,f3c50422-7e3e-4efe-88c7-99da3b36c24d,https://pittsburghpa.gov/domi/bikeplan,
US,TX,Austin,City of Austin,296220ae-c90a-4383-9a97-0bc6cf1adf18,https://austintexas.gov/department/shared-mobility-services,
diff --git a/agency/README.md b/agency/README.md
index 4f22cc93..33882304 100644
--- a/agency/README.md
+++ b/agency/README.md
@@ -2,23 +2,32 @@
-The Agency API endpoints are intended to be implemented by regulatory agencies and consumed by mobility providers. Providers query the Agency API when events (such as a trip start or vehicle status change) occur in their systems.
+The Agency API endpoints are intended to be implemented by regulatory agencies and consumed by mobility providers. Data is **pushed** to agencies by providers. Providers query the Agency API when events (such as a trip start or vehicle status change) occur in their systems.
This specification contains a collection of RESTful APIs used to specify the digital relationship between *mobility as a service* providers and the agencies that regulate them.
## Table of Contents
* [General Information](#general-information)
+ * [Authorization](#authorization)
* [Versioning](#versioning)
+ * [Modes](#modes)
* [Responses and Error Messages](#responses-and-error-messages)
- * [Authorization](#authorization)
+ * [GBFS](#gbfs)
* [Vehicles](#vehicles)
-* [Vehicle - Register](#vehicle---register)
-* [Vehicle - Update](#vehicle---update)
-* [Vehicle - Events](#vehicle---event)
-* [Vehicle - Telemetry](#vehicle---telemetry)
-* [Telemetry Data](#telemetry-data)
+ * [Vehicle - Register](#vehicle---register)
+ * [Vehicle - Update](#vehicle---update)
+ * [Vehicle - List](#vehicle---list)
+ * [Vehicle - Status](#vehicle---status)
+* [Trips](#trips)
+* [Telemetry](#telemetry)
+* [Events](#events)
* [Stops](#stops)
+ * [Stops - Register](#stops---register)
+ * [Stops - Update](#stops---update)
+ * [Stops - Readback](#stops---readback)
+* [Reports](#reports)
+ * [Reports - Register](#reports---register)
## General information
@@ -26,45 +35,134 @@ This specification uses data types including timestamps, UUIDs, and vehicle stat
[Top][toc]
+### Authorization
+
+MDS Agency endpoint producers **SHALL** provide authorization for API endpoints via a bearer token based auth system. When making requests, the endpoints expect `provider_id` to be part of the claims in a [JSON Web Token](https://jwt.io/) (JWT) `access_token` in the `Authorization` header, in the form `Authorization: Bearer `. The token issuance, expiration and revocation policies are at the discretion of the agency. [JSON Web Token](/general-information.md#json-web-tokens) is the recommended format.
+
+General authorization details are specified in the [Authorization section](/general-information.md#authorization) in MDS General Information.
+
+[Top][toc]
+
### Versioning
-`agency` APIs must handle requests for specific versions of the specification from clients.
+`Agency` APIs must handle requests for specific versions of the specification from clients.
Versioning must be implemented as specified in the [Versioning section][versioning].
[Top][toc]
+### Modes
+
+MDS is intended to be used for multiple transportation modes, including its original micromobility (e-scooters, bikes, etc.) mode, as well as additional modes such as taxis, car share, and delivery bots. A given `provider_id` shall be associated with a single mobility [mode][modes], so that the mode does not have to be specified in each data structure and API call. A provider implementing more than one mode shall [register](/README.md#providers-using-mds) a unique `provider_id` for each mode.
+
+[Top][toc]
+
### Responses and Error Messages
-See the [Responses][responses] and [Error Messages][error-messages] sections.
+The response to a client request must include a valid HTTP status code defined in the [IANA HTTP Status Code Registry][iana].
+
+The response must set the `Content-Type` header as specified in the [Versioning section][versioning].
+
+Response bodies must be a `UTF-8` encoded JSON object
+
+See the [Responses][responses], [Error Messages][error-messages], and [Bulk Responses][bulk-responses] sections, and the [schema][schema] for more details.
[Top][toc]
-### Authorization
+### GBFS
+
+See the [GBFS Requirement](/README.md#gbfs-requirement) language for more details.
+
+[Top][toc]
-When making requests, the Agency API expects `provider_id` to be part of the claims in a [JWT](https://jwt.io/) `access_token` in the `Authorization` header, in the form `Authorization: Bearer `. The token issuance, expiration and revocation policies are at the discretion of the Agency.
+### Data Schema
+
+See the [Endpoints](#endpoints) below for information on their specific schema, and the [`mds-openapi`](https://github.com/openmobilityfoundation/mds-openapi) repository for full details and interactive documentation.
[Top][toc]
## Vehicles
-The `/vehicles` endpoint returns the specified vehicle (if a device_id is provided) or a list of known vehicles. Providers can only retrieve data for vehicles in their registered fleet.
+The `/vehicles` endpoints allow providers to register and update the properties of their fleet vehicles, and query current vehicle properties and status.
+
+### Vehicle - Register
+
+The `/vehicles` registration endpoint is used to register vehicles for use in the Agency's jurisdiction.
+
+**Endpoint**: `/vehicles`
+**Method:** `POST`
+**Payload:** An array of [Vehicles](/data-types.md#vehicles)
+
+#### Responses
+
+_Possible HTTP Status Codes_:
+201,
+400,
+401,
+406,
+409,
+500
+
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
+
+[Top][toc]
+
+#### Error Codes:
-Endpoint: `/vehicles/{device_id}`
-Method: `GET`
+| `error` | `error_description` | `error_details`[] |
+| -------------------- | ------------------------------------------------- | ------------------------------- |
+| `bad_param` | A validation error occurred | Array of parameters with errors |
+| `missing_param` | A required parameter is missing | Array of missing parameters |
+| `already_registered` | A vehicle with `device_id` is already registered | |
+
+### Vehicle - Update
+
+The `/vehicles` update endpoint is used to change vehicle information, should some aspect of the vehicle change, such as the `vehicle_id`. Each vehicle must already be registered.
+
+**Endpoint**: `/vehicles`
+**Method:** `PUT`
+**Payload:** An array of [Vehicles](/data-types.md#vehicles)
+
+#### Responses
+
+_Possible HTTP Status Codes_:
+200,
+400,
+401,
+406,
+409,
+500
+
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
+
+#### Error Codes:
+
+| `error` | `error_description` | `error_details`[] |
+| -------------------- | ------------------------------------------------- | ------------------------------- |
+| `bad_param` | A validation error occurred | Array of parameters with errors |
+| `unregistered` | This `device_id` is unregistered | |
+
+[Top][toc]
+
+### Vehicle - List
+
+The `/vehicles` endpoint returns the specified vehicle (if a device_id is provided) or a list of known vehicles. Providers can only retrieve data for vehicles in their registered fleet. Contains vehicle properties that do not change often.
+
+**Endpoint**: `/vehicles/{device_id}`
+**Method:** `GET`
+**Payload:** An array of [Vehicles](/data-types.md#vehicles)
-Path Params:
+_Path Parameters:_
-| Param | Type | Required/Optional | Description |
+| Path Parameters | Type | Required/Optional | Description |
| ------------ | ---- | ----------------- | ------------------------------------------- |
| `device_id` | UUID | Optional | If provided, retrieve the specified vehicle |
-200 Success Response:
-
If `device_id` is specified, `GET` will return an array with a single vehicle record, otherwise it will be a list of vehicle records with pagination details per the [JSON API](https://jsonapi.org/format/#fetching-pagination) spec:
```json
{
+ "version": "2.0.0",
"vehicles": [ ... ]
"links": {
"first": "https://...",
@@ -75,270 +173,321 @@ If `device_id` is specified, `GET` will return an array with a single vehicle re
}
```
-A vehicle record is as follows:
+#### Responses
-| Field | Type | Field Description |
-| ------------- | --------- | ----------------------------------------------------------------------------- |
-| `device_id` | UUID | Provided by Operator to uniquely identify a vehicle |
-| `provider_id` | UUID | Issued by Agency and [tracked](../providers.csv) |
-| `vehicle_id` | String | Vehicle Identification Number (vehicle_id) visible on vehicle |
-| `vehicle_type` | Enum | [Vehicle Type][vehicle-types] |
-| `propulsion_types` | Enum[] | Array of [Propulsion Type][propulsion-types]; allows multiple values |
-| `year` | Integer | Year Manufactured |
-| `mfgr` | String | Vehicle Manufacturer |
-| `model` | String | Vehicle Model |
-| `state` | Enum | Current vehicle state. See [Vehicle State][vehicle-states] |
-| `prev_events` | Enum[] | Last [Vehicle Event][vehicle-event] |
-| `updated` | [timestamp][ts] | Date of last event update |
+_Possible HTTP Status Codes_:
+200,
+400 (with parameter),
+401,
+404,
+406,
+500
-404 Failure Response:
-
-_No content returned on vehicle not found._
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
[Top][toc]
-## Vehicle - Register
-
-The `/vehicles` registration endpoint is used to register a vehicle for use in the Agency jurisdiction.
+### Vehicle - Status
-Endpoint: `/vehicles`
-Method: `POST`
+The `/vehicles/status` endpoint returns information about the specified vehicle (if a device_id is provided) or a list of known vehicles current state. Providers can only retrieve data for vehicles in their registered fleet. Contains specific vehicle properties that are updated frequently.
-Body Params:
+**Endpoint**: `/vehicles/status/{device_id}`
+**Method:** `GET`
+**Payload:** An array of [Vehicles](/data-types.md#vehicle-status) objects
-| Field | Type | Required/Optional | Field Description |
-| ------------ | ------- | ----------------- | -------------------------------------------------------------------- |
-| `device_id` | UUID | Required | Provided by Operator to uniquely identify a vehicle |
-| `vehicle_id` | String | Required | Vehicle Identification Number (vehicle_id) visible on vehicle |
-| `vehicle_type` | Enum | Required | [Vehicle Type][vehicle-types] |
-| `propulsion_types` | Enum[] | Required | Array of [Propulsion Type][propulsion-types]; allows multiple values |
-| `year` | Integer | Optional | Year Manufactured |
-| `mfgr` | String | Optional | Vehicle Manufacturer |
-| `model` | String | Optional | Vehicle Model |
+_Path Parameters:_
-201 Success Response:
+| Path Parameters | Type | Required/Optional | Description |
+| ------------ | ---- | ----------------- | ------------------------------------------- |
+| `device_id` | UUID | Optional | If provided, retrieve the specified vehicle |
-_No content returned on success._
+If `device_id` is specified, `GET` will return an array with a vehicle status record, otherwise it will be a list of vehicle records with pagination details per the [JSON API](https://jsonapi.org/format/#fetching-pagination) spec:
-400 Failure Response:
+```json
+{
+ "version": "2.0.0",
+ "vehicles_status": [ ... ]
+ "links": {
+ "first": "https://...",
+ "last": "https://...",
+ "prev": "https://...",
+ "next": "https://..."
+ }
+}
+```
-| `error` | `error_description` | `error_details`[] |
-| -------------------- | ------------------------------------------------- | ------------------------------- |
-| `bad_param` | A validation error occurred. | Array of parameters with errors |
-| `missing_param` | A required parameter is missing. | Array of missing parameters |
+#### Responses
-409 Failure Response:
+_Possible HTTP Status Codes_:
+200,
+400 (with parameter),
+401,
+404,
+406,
+500
-| `error` | `error_description` | `error_details`[] |
-| -------------------- | ------------------------------------------------- | ------------------------------- |
-| `already_registered` | A vehicle with `device_id` is already registered | |
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
[Top][toc]
-## Vehicle - Update
+## Trips
-The `/vehicles` update endpoint is used to update some mutable aspect of a vehicle. For now, only `vehicle_id`.
+The Trips endpoint serves two purposes:
-Endpoint: `/vehicles/{device_id}`
-Method: `PUT`
+* Definitively indicating that a Trip (a sequence of events linked by a trip_id) has been completed. For example, from analyzing only the raw Vehicle Events feed, if a trip crosses an Agency's jurisdictional boundaries but does not end within the jurisdiction (last event_type seen is a `leave_jurisdiction`), this can result in a 'dangling trip'. The Trips endpoint satisfies this concern, by acting as a final indication that a trip has been finished, even if it ends outside of jurisdictional boundaries; if a trip has intersected an Agency's jurisdictional boundaries at all during a trip, it is expected that a Provider will send a Trip payload to the Agency following the trip's completion.
+* Providing information to an Agency regarding an entire trip, without extending any of the Vehicle Event payloads, or changing any requirements on when Vehicle Events should be sent.
-Body Params:
+**Endpoint:** `/trips`
+**Method:** `POST`
+**Payload:** Array of [Trips](/data-types.md#trips)
-| Field | Type | Required/Optional | Field Description |
-| ------------ | ------- | ----------------- | -------------------------------------------------------------------- |
-| `vehicle_id` | String | Required | Vehicle Identification Number (vehicle_id) visible on vehicle |
+### Responses
-200 Success Response:
+_Possible HTTP Status Codes_:
+201,
+400,
+401,
+404,
+406,
+500
-_No content returned on success._
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
-400 Failure Response:
+### Trip Errors:
| `error` | `error_description` | `error_details`[] |
| -------------------- | ------------------------------------------------- | ------------------------------- |
-| `bad_param` | A validation error occurred. | Array of parameters with errors |
-| `missing_param` | A required parameter is missing. | Array of missing parameters |
-
-404 Failure Response:
-
-_No content returned if no vehicle matching `device_id` is found._
+| `bad_param` | A validation error occurred | Array of parameters with errors |
+| `missing_param` | A required parameter is missing | Array of missing parameters |
+| `unregistered` | This `device_id` is unregistered | |
[Top][toc]
-## Vehicle - Event
-
-The vehicle `/event` endpoint allows the Provider to control the state of the vehicle including deregister a vehicle from the fleet.
+## Telemetry
-Endpoint: `/vehicles/{device_id}/event`
-Method: `POST`
-
-Path Params:
-
-| Field | Type | Required/Optional | Field Description |
-| ------------ | ---- | ----------------- | ---------------------------------------- |
-| `device_id` | UUID | Required | ID used in [Register](#vehicle---register) |
+The vehicle `/telemetry` endpoint allows a Provider to send vehicle telemetry data in a batch for any number of vehicles in the fleet.
-Body Params:
+**Endpoint**: `/telemetry`
+**Method**: `POST`
+**Payload**: An array of vehicle [Telemetry][vehicle-telemetry]
-| Field | Type | Required/Optional | Field Description |
-| ----------- | ----------------------------- | -------- | -------------------------------------------------------------------------------- |
-| `vehicle_state` | Enum | Required | see [Vehicle States][vehicle-states] |
-| `event_types` | Enum[] | Required | see [Vehicle Events][vehicle-events] |
-| `timestamp` | [timestamp][ts] | Required | Date of last event update |
-| `telemetry` | [Telemetry](#telemetry-data) | Required | Single point of telemetry. |
-| `event_geographies` | UUID[] | Optional | **[Beta feature](/general-information.md#beta-features):** *Yes (as of 1.1.0)*. Array of Geography UUIDs consisting of every Geography that contains the location of the event. See [Geography Driven Events][geography-driven-events]. Required if `telemetry` is not present. |
-| `trip_id` | UUID | Optional | UUID provided by Operator to uniquely identify the trip. Required if `event_types` contains `trip_start`, `trip_end`, `trip_cancel`, `trip_enter_jurisdiction`, or `trip_leave_jurisdiction` |
+### Responses
-201 Success Response:
+_Possible HTTP Status Codes_:
+201,
+400,
+401,
+404,
+406,
+500
-| Field | Type | Field Description |
-| ------------ | ---- | ----------------------------------------------------------------------------- |
-| `device_id` | UUID | UUID provided by Operator to uniquely identify a vehicle |
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
-400 Failure Response:
+### Telemetry Errors:
-| `error` | `error_description` | `error_details`[] |
-| ------------------- | ------------------------------- | ------------------------------- |
-| `bad_param` | A validation error occurred | Array of parameters with errors |
-| `missing_param` | A required parameter is missing | Array of missing parameters |
-| `unregistered` | Vehicle is not registered | |
+| `error` | `error_description` | `error_details`[] |
+| -------------------- | ------------------------------------------------- | ------------------------------- |
+| `bad_param` | A validation error occurred | Array of parameters with errors |
+| `missing_param` | A required parameter is missing | Array of missing parameters |
+| `unregistered` | This `device_id` is unregistered | |
[Top][toc]
-## Vehicle - Telemetry
-
-The vehicle `/telemetry` endpoint allows a Provider to send vehicle telemetry data in a batch for any number of vehicles in the fleet.
-
-Endpoint: `/vehicles/telemetry`
-Method: `POST`
+## Events
-Body Params:
+The vehicle `/events` endpoint allows the Provider to submit events describing the state changes of multiple vehicles.
-| Field | Type | Required/Optional | Field Description |
-| ------------- | ------------------------------ | ----------------- | -------------------------------------------------------------------------------------- |
-| `data` | [Telemetry](#telemetry-data)[] | Required | Array of telemetry for one or more vehicles. |
-
-200 Success Response:
+**Endpoint:** `/events`
+**Method:** `POST`
+**Payload:** An array of vehicle [Events](/data-types.md#events)
-| Field | Type | Field Description |
-| ---------- | ------------------------------ | ------------------------------------------------------------------------------------------------------- |
-| `success` | Integer | Number of successfully written telemetry data points. |
-| `total` | Integer | Total number of provided points. |
-| `failures` | [Telemetry](#telemetry-data)[] | Array of failed telemetry for zero or more vehicles (empty if all successful). |
+### Responses
-400 Failure Response:
+_Possible HTTP Status Codes_:
+201,
+400,
+401,
+404,
+406,
+500
-| `error` | `error_description` | `error_details`[] |
-| --------------- | ------------------------------------ | --------------------------------- |
-| `bad_param` | A validation error occurred. | Array of parameters with errors |
-| `invalid_data` | None of the provided data was valid. | |
-| `missing_param` | A required parameter is missing. | Array of missing parameters |
-| `unregistered` | Some of the devices are unregistered | Array of unregistered `device_id` |
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
-[Top][toc]
+### Event Errors:
-## Telemetry Data
-
-A standard point of vehicle telemetry. References to latitude and longitude imply coordinates encoded in the [WGS 84 (EPSG:4326)](https://en.wikipedia.org/wiki/World_Geodetic_System) standard GPS or GNSS projection expressed as [Decimal Degrees](https://en.wikipedia.org/wiki/Decimal_degrees).
-
-| Field | Type | Required/Optional | Field Description |
-| -------------- | -------------- | --------------------- | ------------------------------------------------------------ |
-| `device_id` | UUID | Required | ID used in [Register](#vehicle---register) |
-| `timestamp` | [timestamp][ts]| Required | Date/time that event occurred. Based on GPS or GNSS clock |
-| `gps` | Object | Required | Telemetry position data |
-| `gps.lat` | Double | Required | Latitude of the location |
-| `gps.lng` | Double | Required | Longitude of the location |
-| `gps.altitude` | Double | Required if Available | Altitude above mean sea level in meters |
-| `gps.heading` | Double | Required if Available | Degrees - clockwise starting at 0 degrees at true North |
-| `gps.speed` | Float | Required if Available | Estimated speed in meters / sec as reported by the GPS chipset |
-| `gps.accuracy` | Float | Required if Available | Horizontal accuracy, in meters |
-| `gps.hdop` | Float | Required if Available | Horizontal GPS or GNSS accuracy value (see [hdop][hdop]) |
-| `gps.satellites` | Integer | Required if Available | Number of GPS or GNSS satellites
-| `charge` | Float | Required if Applicable | Percent battery charge of vehicle, expressed between 0 and 1 |
-| `stop_id` | UUID | Required if Applicable | Stop that the vehicle is currently located at. Only applicable for _docked_ Micromobility. See [Stops][stops] |
+| `error` | `error_description` | `error_details`[] |
+| ------- | ------------------- | ----------------- |
+| `bad_param` | A validation error occurred | Array of parameters with errors |
+| `missing_param` | A required parameter is missing | Array of missing parameters |
+| `unregistered` | This `device_id` is unregistered | |
[Top][toc]
## Stops
+### Stops - Register
+
The `/stops` endpoint allows an agency to register city-managed Stops, or a provider to register self-managed Stops.
**Endpoint:** `/stops`
**Method:** `POST`
-**[Beta feature][beta]:** Yes (as of 1.0.0). [Leave feedback](https://github.com/openmobilityfoundation/mobility-data-specification/issues/638)
-**Request Body**: An array of [Stops][stops]
+**Payload**: An array of [Stops][stops]
-201 Success Response:
+### Responses
-_No content returned on success._
+_Possible HTTP Status Codes_:
+201,
+400,
+401,
+406,
+409,
+500
-400 Failure Response:
-
-| `error` | `error_description` | `error_details`[] |
-| -------------------- | ------------------------------------------------- | ------------------------------- |
-| `bad_param` | A validation error occurred. | Array of parameters with errors |
-| `missing_param` | A required parameter is missing. | Array of missing parameters |
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
-409 Failure Response:
+#### Stops Register Errors:
| `error` | `error_description` | `error_details`[] |
| -------------------- | ------------------------------------------------- | ------------------------------- |
+| `bad_param` | A validation error occurred | Array of parameters with errors |
+| `missing_param` | A required parameter is missing | Array of missing parameters |
| `already_registered` | A stop with `stop_id` is already registered | |
-**Endpoint:** `/stops`
-**Method:** `PUT`
-**[Beta feature][beta]:** Yes (as of 1.0.0). [Leave feedback](https://github.com/openmobilityfoundation/mobility-data-specification/issues/638)
-**Request Body**: An array of subsets of [Stop][stops] information, where the permitted subset fields are defined as:
+403 Unauthorized Response:
-| Field | Required/Optional | Description |
-|---------------------|-------------------|---------------------------------------------|
-| stop_id | Required |See [Stops][stops] |
-| status | Optional |See [Stops][stops] |
-| num_spots_disabled | Optional |See [Stops][stops] |
+**None**
-200 Success Response:
+[Top][toc]
-_No content returned on success._
+### Stops - Update
-400 Failure Response:
+**Endpoint:** `/stops`
+**Method:** `PUT`
+**Payload**: An array of of [Stop][stops] information, where the permitted changeable fields are defined as:
+
+| Field | Required/Optional | Description |
+|------------------------|-------------------|-------------------|
+| stop_id | Required |See [Stops][stops] |
+| last_updated | Optional |See [Stops][stops] |
+| status | Optional |See [Stops][stops] |
+| rental_methods | Optional |See [Stops][stops] |
+| num_vehicles_available | Optional |See [Stops][stops] |
+| num_vehicles_disabled | Optional |See [Stops][stops] |
+| num_places_available | Optional |See [Stops][stops] |
+| num_places_disabled | Optional |See [Stops][stops] |
+| devices | Optional |See [Stops][stops] |
+
+### Responses
+
+_Possible HTTP Status Codes_:
+200,
+400,
+401,
+404,
+406,
+500
+
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
+
+#### Stops update Errors:
| `error` | `error_description` | `error_details`[] |
| -------------------- | ------------------------------------------------- | ------------------------------- |
-| `bad_param` | A validation error occurred. | Array of parameters with errors |
-| `missing_param` | A required parameter is missing. | Array of missing parameters |
+| `bad_param` | A validation error occurred | Array of parameters with errors |
+| `missing_param` | A required parameter is missing | Array of missing parameters |
+| `unregistered` | No stop with `stop_id` is already registered | |
-404 Failure Response:
+[Top][toc]
-_No content returned if no vehicle matching `stop_id` is found._
+### Stops - Readback
-**Endpoint:** `/stops/:stop_id`
+**Endpoint:** `/stops/{stop_id}`
**Method:** `GET`
-**[Beta feature][beta]:** Yes (as of 1.0.0). [Leave feedback](https://github.com/openmobilityfoundation/mobility-data-specification/issues/638)
-**Payload:** `{ "stops": [] }`, an array of [Stops][stops]
+**Payload:** An array of [Stops][stops]
-Path Params:
+_Path Parameters:_
-| Param | Type | Required/Optional | Description |
+| Path Parameters | Type | Required/Optional | Description |
| ------------ | ---- | ----------------- | ------------------------------------------- |
| `stop_id` | UUID | Optional | If provided, retrieve the specified stop |
-200 Success Response:
-
If `stop_id` is specified, `GET` will return an array with a single stop record, otherwise it will be a list of all stop records.
+### Responses
+
+_Possible HTTP Status Codes_:
+200,
+401,
+404,
+406,
+500
+
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
+
+[Top][toc]
+
+## Reports
+
+Reports are information that providers can send back to agencies containing aggregated data that is not contained within other MDS endpoints, like counts of special groups of riders. These supplemental reports are not a substitute for other MDS Provider endpoints.
+
+The authenticated reports are monthly, historic flat files that may be pre-generated by the provider.
+
+[Top][toc]
+
+## Reports - Register
+
+The `/reports` endpoint allows an agency to register aggregated report counts in CSV structure.
+
+**Endpoint:** `/reports`
+**Method:** `POST`
+**Payload**: A CSV of [Reports][reports]
+
+### Responses
+
+_Possible HTTP Status Codes_:
+201,
+400,
+401,
+406,
+500
+
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
+
+#### Reports Register Errors:
+
+| `error` | `error_description` | `error_details`[] |
+| -------------------- | ------------------------------------------------- | ------------------------------- |
+| `bad_param` | A validation error occurred | Array of parameters with errors |
+
+400 Unauthorized Response:
+
+**None**
+
[Top][toc]
+[accessibility-options]: /general-information.md#accessibility-options
[beta]: /general-information.md#beta-features
+[bulk-responses]: /general-information.md#bulk-responses
[general]: /general-information.md
[geography-driven-events]: /general-information.md#geography-driven-events
[error-messages]: /general-information.md#error-messages
[hdop]: https://en.wikipedia.org/wiki/Dilution_of_precision_(navigation)
-[propulsion-types]: /general-information.md#propulsion-types
+[iana]: https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
+[modes]: /modes/README.md
+[propulsion-types]: /data-types.md#propulsion-types
+[reports]: /data-types.md#reports
[responses]: /general-information.md#responses
-[stops]: /general-information.md#stops
+[schema]: /schema/
+[stops]: /data-types.md#stops
+[telemetry-data]: /data-types.md#telemetry
+[trip-data]: /data-types.md#trips
[toc]: #table-of-contents
[ts]: /general-information.md#timestamps
-[vehicle-types]: /general-information.md#vehicle-types
-[vehicle-states]: /general-information.md#vehicle-states
-[vehicle-events]: /general-information.md#vehicle-state-events
+[vehicle]: /data-types.md#vehicles
+[vehicle-types]: /data-types.md#vehicle-types
+[vehicle-states]: /modes/vehicle_states.md
+[vehicle-event-types]: /modes/event_types.md
+[vehicle-event]: /data-types.md#events
+[vehicle-telemetry]: /data-types.md#telemetry
[versioning]: /general-information.md#versioning
+[error-message]: /general-information.md#error-messages
diff --git a/agency/get_stops.json b/agency/get_stops.json
deleted file mode 100644
index a966091c..00000000
--- a/agency/get_stops.json
+++ /dev/null
@@ -1,308 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/agency/get_stops.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "The MDS Agency Schema, GET stops payload",
- "type": "object",
- "definitions": {
- "stop": {
- "$id": "#/definitions/stop",
- "type": "object",
- "description": "The common schema elements for a Stop in MDS",
- "required": [
- "stop_id",
- "name",
- "last_reported",
- "location",
- "status",
- "capacity",
- "num_vehicles_available",
- "num_vehicles_disabled"
- ],
- "properties": {
- "stop_id": {
- "$id": "#/definitions/stop/properties/stop_id",
- "$ref": "#/definitions/uuid",
- "description": "UUID for the Stop"
- },
- "name": {
- "$id": "#/definitions/stop/properties/name",
- "$ref": "#/definitions/string",
- "description": "Name of the Stop"
- },
- "last_reported": {
- "$id": "#/definitions/stop/properties/last_reported",
- "$ref": "#/definitions/timestamp",
- "description": "Date/Time of the last status update for this Stop"
- },
- "location": {
- "$id": "#/definitions/stop/properties/location",
- "$ref": "#/definitions/MDS_Feature_Point",
- "description": "Location of the stop"
- },
- "status": {
- "$id": "#/definitions/stop/properties/status",
- "$ref": "#/definitions/stop_status",
- "description": "The status of the Stop"
- },
- "capacity": {
- "$id": "#/definitions/stop/properties/capacity",
- "$ref": "#/definitions/vehicle_type_counts",
- "description": "Number of total places per vehicle_type"
- },
- "num_vehicles_available": {
- "$id": "#/definitions/stop/properties/num_vehicles_available",
- "$ref": "#/definitions/vehicle_type_counts",
- "description": "Number of available vehicles per vehicle_type"
- },
- "num_vehicles_disabled": {
- "$id": "#/definitions/stop/properties/num_vehicles_disabled",
- "$ref": "#/definitions/vehicle_type_counts",
- "description": "Number of non_operational/reserved vehicles per vehicle_type"
- },
- "provider_id": {
- "$id": "#/definitions/stop/properties/provider_id",
- "$ref": "#/definitions/uuid",
- "description": "UUID for the Provider managing this Stop. Null/undefined if managed by an Agency."
- },
- "geography_id": {
- "$id": "#/definitions/stop/properties/geography_id",
- "$ref": "#/definitions/uuid",
- "description": "UUID for the Stop"
- },
- "region_id": {
- "$id": "#/definitions/stop/properties/region_id",
- "$ref": "#/definitions/string",
- "description": "ID of the region where the Stop is located. See GBFS Station Information."
- },
- "short_name": {
- "$id": "#/definitions/stop/properties/short_name",
- "$ref": "#/definitions/string",
- "description": "Abbreviated Stop name"
- },
- "address": {
- "$id": "#/definitions/stop/properties/address",
- "$ref": "#/definitions/string",
- "description": "Postal address (useful for directions)"
- },
- "post_code": {
- "$id": "#/definitions/stop/properties/post_code",
- "$ref": "#/definitions/string",
- "description": "Postal code (e.g. 10036)"
- },
- "cross_street": {
- "$id": "#/definitions/stop/properties/cross_street",
- "$ref": "#/definitions/string",
- "description": "Cross street of where Stop is located"
- },
- "num_places_available": {
- "$id": "#/definitions/stop/properties/num_places_available",
- "$ref": "#/definitions/vehicle_type_counts",
- "description": "Number of places free to be populated per vehicle_type"
- },
- "num_places_disabled": {
- "$id": "#/definitions/stop/properties/num_places_disabled",
- "$ref": "#/definitions/vehicle_type_counts",
- "description": "Number of places disabled an unable to accept vehicles per vehicle_type"
- },
- "parent_stop": {
- "$id": "#/definitions/stop/properties/parent_stop",
- "$ref": "#/definitions/uuid",
- "description": "Describe a basic hierarchy of Stops (e.g. a Stop inside a greater Stop)"
- },
- "devices": {
- "$id": "#/definitions/stop/properties/devices",
- "$ref": "#/definitions/uuid_array",
- "description": "List of device_id for vehicles currently at this Stop."
- }
- }
- },
- "stop_status": {
- "$id": "#/definitions/stop_status",
- "type": "object",
- "description": "Status object for a Stop in MDS",
- "required": [
- "is_installed",
- "is_renting",
- "is_returning"
- ],
- "properties": {
- "is_installed": {
- "$id": "#/definitions/stop_status/properties/is_installed",
- "type": "boolean"
- },
- "is_renting": {
- "$id": "#/definitions/stop_status/properties/is_renting",
- "type": "boolean"
- },
- "is_returning": {
- "$id": "#/definitions/stop_status/properties/is_returning",
- "type": "boolean"
- }
- }
- },
- "string": {
- "$id": "#/definitions/string",
- "type": "string",
- "description": "A length-limited string type",
- "maxLength": 255,
- "default": "",
- "examples": [
- "ABC123"
- ],
- "pattern": "^(.*)$"
- },
- "timestamp": {
- "$id": "#/definitions/timestamp",
- "type": "number",
- "description": "Integer milliseconds since Unix epoch",
- "multipleOf": 1.0,
- "minimum": 1514764800000
- },
- "uuid": {
- "$id": "#/definitions/uuid",
- "type": "string",
- "description": "A UUID used to uniquely identifty an object",
- "default": "",
- "examples": [
- "3c9604d6-b5ee-11e8-96f8-529269fb1459"
- ],
- "pattern": "^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$"
- },
- "uuid_array": {
- "$id": "#/definitions/uuid_array",
- "type": "array",
- "description": "Array of UUID",
- "items": {
- "$id": "#/definitions/uuid_array/items",
- "$ref": "#/definitions/uuid"
- }
- },
- "vehicle_type_counts": {
- "$id": "#/definitions/vehicle_type_counts",
- "type": "object",
- "properties": {
- "bicycle": {
- "$id": "#/definitions/vehicle_type_counts/properties/bicycle",
- "type": "integer",
- "minimum": 0
- },
- "cargo_bicycle": {
- "$id": "#/definitions/vehicle_type_counts/properties/cargo_bicycle",
- "type": "integer",
- "minimum": 0
- },
- "car": {
- "$id": "#/definitions/vehicle_type_counts/properties/car",
- "type": "integer",
- "minimum": 0
- },
- "scooter": {
- "$id": "#/definitions/vehicle_type_counts/properties/scooter",
- "type": "integer",
- "minimum": 0
- },
- "moped": {
- "$id": "#/definitions/vehicle_type_counts/properties/moped",
- "type": "integer",
- "minimum": 0
- },
- "other": {
- "$id": "#/definitions/vehicle_type_counts/properties/other",
- "type": "integer",
- "minimum": 0
- }
- },
- "additionalProperties": false
- },
- "MDS_Feature_Point": {
- "$id": "#/definitions/MDS_Feature_Point",
- "title": "MDS GeoJSON Feature Point",
- "type": "object",
- "required": [
- "type",
- "properties",
- "geometry"
- ],
- "properties": {
- "type": {
- "type": "string",
- "enum": [
- "Feature"
- ]
- },
- "id": {
- "oneOf": [
- {
- "type": "number"
- },
- {
- "type": "string"
- }
- ]
- },
- "properties": {
- "type": "object",
- "required": [
- "timestamp"
- ],
- "properties": {
- "timestamp": {
- "$ref": "#/definitions/timestamp"
- },
- "stop_id": {
- "$ref": "#/definitions/uuid"
- },
- "altitude": {
- "type": "number",
- "description": "Altitude above mean sea level in meters"
- },
- "heading": {
- "type": "number",
- "description": "Degrees - clockwise starting at 0 degrees at true North"
- },
- "speed": {
- "type": "number",
- "description": "Estimated speed in meters / sec as reported by the GPS chipset"
- },
- "accuracy": {
- "type": "number",
- "description": "Horizontal accuracy, in meters"
- },
- "hdop": {
- "type": "number",
- "description": "Horizontal GPS or GNSS accuracy value"
- },
- "satellites": {
- "type": "integer",
- "description": "Number of GPS or GNSS satellites"
- }
- }
- },
- "geometry": {
- "$ref": "#/definitions/Point"
- },
- "bbox": {
- "type": "array",
- "minItems": 4,
- "items": {
- "type": "number"
- }
- }
- }
- }
- },
- "required": [
- "stops"
- ],
- "properties": {
- "stops": {
- "$id": "#/properties/stops",
- "type": "array",
- "description": "The array of stops",
- "items": {
- "$ref": "#/definitions/stop"
- }
- }
- },
- "additionalProperties": false
-}
\ No newline at end of file
diff --git a/agency/get_vehicle.json b/agency/get_vehicle.json
deleted file mode 100644
index d03929f6..00000000
--- a/agency/get_vehicle.json
+++ /dev/null
@@ -1,332 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/agency/get_vehicle.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "The MDS Agency Schema, GET vehicle payload",
- "type": "object",
- "definitions": {
- "propulsion_types": {
- "$id": "#/definitions/propulsion_types",
- "type": "array",
- "description": "Array of propulsion types, allowing multiple values",
- "items": {
- "$id": "#/definitions/propulsion_types/items",
- "$ref": "#/definitions/propulsion_type"
- },
- "uniqueItems": true
- },
- "string": {
- "$id": "#/definitions/string",
- "type": "string",
- "description": "A length-limited string type",
- "maxLength": 255,
- "default": "",
- "examples": [
- "ABC123"
- ],
- "pattern": "^(.*)$"
- },
- "timestamp": {
- "$id": "#/definitions/timestamp",
- "type": "number",
- "description": "Integer milliseconds since Unix epoch",
- "multipleOf": 1.0,
- "minimum": 1514764800000
- },
- "vehicle_type": {
- "$id": "#/definitions/vehicle_type",
- "type": "string",
- "description": "The type of vehicle",
- "enum": [
- "bicycle",
- "cargo_bicycle",
- "car",
- "scooter",
- "moped",
- "other"
- ]
- },
- "uuid": {
- "$id": "#/definitions/uuid",
- "type": "string",
- "description": "A UUID used to uniquely identifty an object",
- "default": "",
- "examples": [
- "3c9604d6-b5ee-11e8-96f8-529269fb1459"
- ],
- "pattern": "^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$"
- },
- "vehicle_state": {
- "$id": "#/definitions/vehicle_state",
- "type": "string",
- "description": "The state of a vehicle",
- "enum": [
- "available",
- "elsewhere",
- "non_operational",
- "on_trip",
- "removed",
- "reserved",
- "unknown"
- ]
- },
- "vehicle_event": {
- "$id": "#/definitions/vehicle_event",
- "type": "string",
- "description": "An event that changes a vehicle's state",
- "enum": [
- "agency_drop_off",
- "agency_pick_up",
- "battery_charged",
- "battery_low",
- "comms_lost",
- "comms_restored",
- "compliance_pick_up",
- "decommissioned",
- "located",
- "maintenance",
- "maintenance_pick_up",
- "missing",
- "off_hours",
- "on_hours",
- "provider_drop_off",
- "rebalance_pick_up",
- "reservation_cancel",
- "reservation_start",
- "system_resume",
- "system_suspend",
- "trip_cancel",
- "trip_end",
- "trip_enter_jurisdiction",
- "trip_leave_jurisdiction",
- "trip_start",
- "unspecified"
- ]
- },
- "vehicle_events": {
- "$id": "#/definitions/vehicle_events",
- "type": "array",
- "description": "Array of events indicating a change to a vehicle's state",
- "uniqueItems": true,
- "minItems": 1,
- "items": {
- "$ref": "#/definitions/vehicle_event"
- }
- }
- },
- "required": [
- "provider_id",
- "device_id",
- "vehicle_id",
- "vehicle_type",
- "propulsion_types",
- "year",
- "mfgr",
- "model",
- "state",
- "prev_events",
- "updated"
- ],
- "properties": {
- "provider_id": {
- "$id": "#/definitions/vehicle/properties/provider_id",
- "$ref": "#/definitions/uuid",
- "description": "The UUID for the Provider, unique within MDS"
- },
- "device_id": {
- "$id": "#/definitions/vehicle/properties/device_id",
- "$ref": "#/definitions/uuid",
- "description": "A unique device ID in UUID format"
- },
- "vehicle_id": {
- "$id": "#/definitions/vehicle/properties/vehicle_id",
- "$ref": "#/definitions/string",
- "description": "The Vehicle Identification Number visible on the vehicle itself"
- },
- "vehicle_type": {
- "$id": "#/definitions/vehicle/properties/vehicle_type",
- "$ref": "#/definitions/vehicle_type",
- "description": "The type of vehicle"
- },
- "propulsion_types": {
- "$id": "#/definitions/vehicle/properties/propulsion_types",
- "$ref": "#/definitions/propulsion_types",
- "description": "The type of propulsion; allows multiple values",
- "minItems": 1
- },
- "year": {
- "$id": "#/properties/year",
- "type": "integer",
- "description": "The year the vehicle was manufactured",
- "default": 1970,
- "examples": [
- 2018
- ]
- },
- "mfgr": {
- "$id": "#/properties/mfgr",
- "$ref": "#/definitions/string",
- "description": "The vehicle manufacturer"
- },
- "model": {
- "$id": "#/properties/model",
- "$ref": "#/definitions/string",
- "description": "The vehicle model"
- },
- "state": {
- "$id": "#/properties/state",
- "$ref": "#/definitions/vehicle_state",
- "description": "Current vehicle state"
- },
- "prev_events": {
- "$id": "#/properties/prev_events",
- "$ref": "#/definitions/vehicle_events",
- "description": "Last vehicle event"
- },
- "updated": {
- "$id": "#/properties/updated",
- "$ref": "#/definitions/timestamp"
- }
- },
- "additionalProperties": false,
- "allOf": [
- {
- "description": "valid vehicle_state and vehicle_events combinations",
- "oneOf": [
- {
- "properties": {
- "state": {
- "const": "available"
- },
- "prev_events": {
- "contains": {
- "enum": [
- "agency_drop_off",
- "battery_charged",
- "comms_restored",
- "located",
- "maintenance",
- "on_hours",
- "provider_drop_off",
- "reservation_cancel",
- "system_resume",
- "trip_cancel",
- "trip_end",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "state": {
- "const": "elsewhere"
- },
- "prev_events": {
- "contains": {
- "enum": [
- "comms_restored",
- "located",
- "trip_leave_jurisdiction",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "state": {
- "const": "non_operational"
- },
- "prev_events": {
- "contains": {
- "enum": [
- "battery_low",
- "comms_restored",
- "located",
- "maintenance",
- "off_hours",
- "system_suspend",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "state": {
- "const": "on_trip"
- },
- "prev_events": {
- "contains": {
- "enum": [
- "comms_restored",
- "located",
- "trip_enter_jurisdiction",
- "trip_start",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "state": {
- "const": "removed"
- },
- "prev_events": {
- "contains": {
- "enum": [
- "agency_pick_up",
- "comms_restored",
- "compliance_pick_up",
- "decommissioned",
- "located",
- "maintenance_pick_up",
- "rebalance_pick_up",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "state": {
- "const": "reserved"
- },
- "prev_events": {
- "contains": {
- "enum": [
- "comms_restored",
- "located",
- "reservation_start",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "state": {
- "const": "unknown"
- },
- "prev_events": {
- "contains": {
- "enum": [
- "comms_lost",
- "missing",
- "unspecified"
- ]
- }
- }
- }
- }
- ]
- }
- ]
-}
\ No newline at end of file
diff --git a/agency/post_stops.json b/agency/post_stops.json
deleted file mode 100644
index 570973b9..00000000
--- a/agency/post_stops.json
+++ /dev/null
@@ -1,308 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/agency/post_stops.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "The MDS Agency Schema, register Stops",
- "type": "object",
- "definitions": {
- "stop": {
- "$id": "#/definitions/stop",
- "type": "object",
- "description": "The common schema elements for a Stop in MDS",
- "required": [
- "stop_id",
- "name",
- "last_reported",
- "location",
- "status",
- "capacity",
- "num_vehicles_available",
- "num_vehicles_disabled"
- ],
- "properties": {
- "stop_id": {
- "$id": "#/definitions/stop/properties/stop_id",
- "$ref": "#/definitions/uuid",
- "description": "UUID for the Stop"
- },
- "name": {
- "$id": "#/definitions/stop/properties/name",
- "$ref": "#/definitions/string",
- "description": "Name of the Stop"
- },
- "last_reported": {
- "$id": "#/definitions/stop/properties/last_reported",
- "$ref": "#/definitions/timestamp",
- "description": "Date/Time of the last status update for this Stop"
- },
- "location": {
- "$id": "#/definitions/stop/properties/location",
- "$ref": "#/definitions/MDS_Feature_Point",
- "description": "Location of the stop"
- },
- "status": {
- "$id": "#/definitions/stop/properties/status",
- "$ref": "#/definitions/stop_status",
- "description": "The status of the Stop"
- },
- "capacity": {
- "$id": "#/definitions/stop/properties/capacity",
- "$ref": "#/definitions/vehicle_type_counts",
- "description": "Number of total places per vehicle_type"
- },
- "num_vehicles_available": {
- "$id": "#/definitions/stop/properties/num_vehicles_available",
- "$ref": "#/definitions/vehicle_type_counts",
- "description": "Number of available vehicles per vehicle_type"
- },
- "num_vehicles_disabled": {
- "$id": "#/definitions/stop/properties/num_vehicles_disabled",
- "$ref": "#/definitions/vehicle_type_counts",
- "description": "Number of non_operational/reserved vehicles per vehicle_type"
- },
- "provider_id": {
- "$id": "#/definitions/stop/properties/provider_id",
- "$ref": "#/definitions/uuid",
- "description": "UUID for the Provider managing this Stop. Null/undefined if managed by an Agency."
- },
- "geography_id": {
- "$id": "#/definitions/stop/properties/geography_id",
- "$ref": "#/definitions/uuid",
- "description": "UUID for the Stop"
- },
- "region_id": {
- "$id": "#/definitions/stop/properties/region_id",
- "$ref": "#/definitions/string",
- "description": "ID of the region where the Stop is located. See GBFS Station Information."
- },
- "short_name": {
- "$id": "#/definitions/stop/properties/short_name",
- "$ref": "#/definitions/string",
- "description": "Abbreviated Stop name"
- },
- "address": {
- "$id": "#/definitions/stop/properties/address",
- "$ref": "#/definitions/string",
- "description": "Postal address (useful for directions)"
- },
- "post_code": {
- "$id": "#/definitions/stop/properties/post_code",
- "$ref": "#/definitions/string",
- "description": "Postal code (e.g. 10036)"
- },
- "cross_street": {
- "$id": "#/definitions/stop/properties/cross_street",
- "$ref": "#/definitions/string",
- "description": "Cross street of where Stop is located"
- },
- "num_places_available": {
- "$id": "#/definitions/stop/properties/num_places_available",
- "$ref": "#/definitions/vehicle_type_counts",
- "description": "Number of places free to be populated per vehicle_type"
- },
- "num_places_disabled": {
- "$id": "#/definitions/stop/properties/num_places_disabled",
- "$ref": "#/definitions/vehicle_type_counts",
- "description": "Number of places disabled an unable to accept vehicles per vehicle_type"
- },
- "parent_stop": {
- "$id": "#/definitions/stop/properties/parent_stop",
- "$ref": "#/definitions/uuid",
- "description": "Describe a basic hierarchy of Stops (e.g. a Stop inside a greater Stop)"
- },
- "devices": {
- "$id": "#/definitions/stop/properties/devices",
- "$ref": "#/definitions/uuid_array",
- "description": "List of device_id for vehicles currently at this Stop."
- }
- }
- },
- "stop_status": {
- "$id": "#/definitions/stop_status",
- "type": "object",
- "description": "Status object for a Stop in MDS",
- "required": [
- "is_installed",
- "is_renting",
- "is_returning"
- ],
- "properties": {
- "is_installed": {
- "$id": "#/definitions/stop_status/properties/is_installed",
- "type": "boolean"
- },
- "is_renting": {
- "$id": "#/definitions/stop_status/properties/is_renting",
- "type": "boolean"
- },
- "is_returning": {
- "$id": "#/definitions/stop_status/properties/is_returning",
- "type": "boolean"
- }
- }
- },
- "string": {
- "$id": "#/definitions/string",
- "type": "string",
- "description": "A length-limited string type",
- "maxLength": 255,
- "default": "",
- "examples": [
- "ABC123"
- ],
- "pattern": "^(.*)$"
- },
- "timestamp": {
- "$id": "#/definitions/timestamp",
- "type": "number",
- "description": "Integer milliseconds since Unix epoch",
- "multipleOf": 1.0,
- "minimum": 1514764800000
- },
- "uuid": {
- "$id": "#/definitions/uuid",
- "type": "string",
- "description": "A UUID used to uniquely identifty an object",
- "default": "",
- "examples": [
- "3c9604d6-b5ee-11e8-96f8-529269fb1459"
- ],
- "pattern": "^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$"
- },
- "uuid_array": {
- "$id": "#/definitions/uuid_array",
- "type": "array",
- "description": "Array of UUID",
- "items": {
- "$id": "#/definitions/uuid_array/items",
- "$ref": "#/definitions/uuid"
- }
- },
- "vehicle_type_counts": {
- "$id": "#/definitions/vehicle_type_counts",
- "type": "object",
- "properties": {
- "bicycle": {
- "$id": "#/definitions/vehicle_type_counts/properties/bicycle",
- "type": "integer",
- "minimum": 0
- },
- "cargo_bicycle": {
- "$id": "#/definitions/vehicle_type_counts/properties/cargo_bicycle",
- "type": "integer",
- "minimum": 0
- },
- "car": {
- "$id": "#/definitions/vehicle_type_counts/properties/car",
- "type": "integer",
- "minimum": 0
- },
- "scooter": {
- "$id": "#/definitions/vehicle_type_counts/properties/scooter",
- "type": "integer",
- "minimum": 0
- },
- "moped": {
- "$id": "#/definitions/vehicle_type_counts/properties/moped",
- "type": "integer",
- "minimum": 0
- },
- "other": {
- "$id": "#/definitions/vehicle_type_counts/properties/other",
- "type": "integer",
- "minimum": 0
- }
- },
- "additionalProperties": false
- },
- "MDS_Feature_Point": {
- "$id": "#/definitions/MDS_Feature_Point",
- "title": "MDS GeoJSON Feature Point",
- "type": "object",
- "required": [
- "type",
- "properties",
- "geometry"
- ],
- "properties": {
- "type": {
- "type": "string",
- "enum": [
- "Feature"
- ]
- },
- "id": {
- "oneOf": [
- {
- "type": "number"
- },
- {
- "type": "string"
- }
- ]
- },
- "properties": {
- "type": "object",
- "required": [
- "timestamp"
- ],
- "properties": {
- "timestamp": {
- "$ref": "#/definitions/timestamp"
- },
- "stop_id": {
- "$ref": "#/definitions/uuid"
- },
- "altitude": {
- "type": "number",
- "description": "Altitude above mean sea level in meters"
- },
- "heading": {
- "type": "number",
- "description": "Degrees - clockwise starting at 0 degrees at true North"
- },
- "speed": {
- "type": "number",
- "description": "Estimated speed in meters / sec as reported by the GPS chipset"
- },
- "accuracy": {
- "type": "number",
- "description": "Horizontal accuracy, in meters"
- },
- "hdop": {
- "type": "number",
- "description": "Horizontal GPS or GNSS accuracy value"
- },
- "satellites": {
- "type": "integer",
- "description": "Number of GPS or GNSS satellites"
- }
- }
- },
- "geometry": {
- "$ref": "#/definitions/Point"
- },
- "bbox": {
- "type": "array",
- "minItems": 4,
- "items": {
- "type": "number"
- }
- }
- }
- }
- },
- "required": [
- "stops"
- ],
- "properties": {
- "stops": {
- "$id": "#/properties/stops",
- "type": "array",
- "description": "The array of stops",
- "items": {
- "$ref": "#/definitions/stop"
- }
- }
- },
- "additionalProperties": false
-}
\ No newline at end of file
diff --git a/agency/post_vehicle.json b/agency/post_vehicle.json
deleted file mode 100644
index 21d14ec2..00000000
--- a/agency/post_vehicle.json
+++ /dev/null
@@ -1,101 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/agency/post_vehicle.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "The MDS Agency Schema, register vehicle body",
- "type": "object",
- "definitions": {
- "propulsion_types": {
- "$id": "#/definitions/propulsion_types",
- "type": "array",
- "description": "Array of propulsion types, allowing multiple values",
- "items": {
- "$id": "#/definitions/propulsion_types/items",
- "$ref": "#/definitions/propulsion_type"
- },
- "uniqueItems": true
- },
- "string": {
- "$id": "#/definitions/string",
- "type": "string",
- "description": "A length-limited string type",
- "maxLength": 255,
- "default": "",
- "examples": [
- "ABC123"
- ],
- "pattern": "^(.*)$"
- },
- "vehicle_type": {
- "$id": "#/definitions/vehicle_type",
- "type": "string",
- "description": "The type of vehicle",
- "enum": [
- "bicycle",
- "cargo_bicycle",
- "car",
- "scooter",
- "moped",
- "other"
- ]
- },
- "uuid": {
- "$id": "#/definitions/uuid",
- "type": "string",
- "description": "A UUID used to uniquely identifty an object",
- "default": "",
- "examples": [
- "3c9604d6-b5ee-11e8-96f8-529269fb1459"
- ],
- "pattern": "^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$"
- }
- },
- "required": [
- "device_id",
- "vehicle_id",
- "vehicle_type",
- "propulsion_types"
- ],
- "properties": {
- "device_id": {
- "$id": "#/definitions/vehicle/properties/device_id",
- "$ref": "#/definitions/uuid",
- "description": "A unique device ID in UUID format"
- },
- "vehicle_id": {
- "$id": "#/definitions/vehicle/properties/vehicle_id",
- "$ref": "#/definitions/string",
- "description": "The Vehicle Identification Number visible on the vehicle itself"
- },
- "vehicle_type": {
- "$id": "#/definitions/vehicle/properties/vehicle_type",
- "$ref": "#/definitions/vehicle_type",
- "description": "The type of vehicle"
- },
- "propulsion_types": {
- "$id": "#/definitions/vehicle/properties/propulsion_types",
- "$ref": "#/definitions/propulsion_types",
- "description": "The type of propulsion; allows multiple values",
- "minItems": 1
- },
- "year": {
- "$id": "#/properties/year",
- "type": "integer",
- "description": "The year the vehicle was manufactured",
- "default": 1970,
- "examples": [
- 2018
- ]
- },
- "mfgr": {
- "$id": "#/properties/mfgr",
- "$ref": "#/definitions/string",
- "description": "The vehicle manufacturer"
- },
- "model": {
- "$id": "#/properties/model",
- "$ref": "#/definitions/string",
- "description": "The vehicle model"
- }
- },
- "additionalProperties": false
-}
\ No newline at end of file
diff --git a/agency/post_vehicle_event.json b/agency/post_vehicle_event.json
deleted file mode 100644
index 284bc222..00000000
--- a/agency/post_vehicle_event.json
+++ /dev/null
@@ -1,345 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/agency/post_vehicle_event.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "The MDS Agency Schema, POST vehicle status body",
- "type": "object",
- "definitions": {
- "timestamp": {
- "$id": "#/definitions/timestamp",
- "type": "number",
- "description": "Integer milliseconds since Unix epoch",
- "multipleOf": 1.0,
- "minimum": 1514764800000
- },
- "uuid": {
- "$id": "#/definitions/uuid",
- "type": "string",
- "description": "A UUID used to uniquely identifty an object",
- "default": "",
- "examples": [
- "3c9604d6-b5ee-11e8-96f8-529269fb1459"
- ],
- "pattern": "^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$"
- },
- "vehicle_telemetry": {
- "$id": "#/definitions/vehicle_telemetry",
- "type": "object",
- "description": "A telemetry datum for a specific vehicle at a specific time",
- "required": [
- "device_id",
- "timestamp",
- "gps"
- ],
- "additionalProperties": false,
- "properties": {
- "device_id": {
- "$ref": "#/definitions/uuid"
- },
- "timestamp": {
- "$ref": "#/definitions/timestamp"
- },
- "gps": {
- "type": "object",
- "required": [
- "lat",
- "lng"
- ],
- "additionalProperties": false,
- "properties": {
- "lat": {
- "type": "number",
- "description": "Latitude of the location",
- "minimum": -90,
- "maximum": 90
- },
- "lng": {
- "type": "number",
- "description": "Longitude of the location",
- "minimum": -180,
- "maximum": 180
- },
- "altitude": {
- "type": "number",
- "description": "Altitude above mean sea level in meters"
- },
- "heading": {
- "type": "number",
- "description": "Degrees - clockwise starting at 0 degrees at true North"
- },
- "speed": {
- "type": "number",
- "description": "Estimated speed in meters / sec as reported by the GPS chipset"
- },
- "accuracy": {
- "type": "number",
- "description": "Horizontal accuracy, in meters"
- },
- "hdop": {
- "type": "number",
- "description": "Horizontal GPS or GNSS accuracy value"
- },
- "satellites": {
- "type": "integer",
- "description": "Number of GPS or GNSS satellites"
- }
- }
- },
- "charge": {
- "type": "number",
- "description": "Fraction of charge of the vehicle (required if applicable)",
- "minimum": 0,
- "maximum": 1
- }
- }
- },
- "vehicle_state": {
- "$id": "#/definitions/vehicle_state",
- "type": "string",
- "description": "The state of a vehicle",
- "enum": [
- "available",
- "elsewhere",
- "non_operational",
- "on_trip",
- "removed",
- "reserved",
- "unknown"
- ]
- },
- "vehicle_event": {
- "$id": "#/definitions/vehicle_event",
- "type": "string",
- "description": "An event that changes a vehicle's state",
- "enum": [
- "agency_drop_off",
- "agency_pick_up",
- "battery_charged",
- "battery_low",
- "comms_lost",
- "comms_restored",
- "compliance_pick_up",
- "decommissioned",
- "located",
- "maintenance",
- "maintenance_pick_up",
- "missing",
- "off_hours",
- "on_hours",
- "provider_drop_off",
- "rebalance_pick_up",
- "reservation_cancel",
- "reservation_start",
- "system_resume",
- "system_suspend",
- "trip_cancel",
- "trip_end",
- "trip_enter_jurisdiction",
- "trip_leave_jurisdiction",
- "trip_start",
- "unspecified"
- ]
- },
- "vehicle_events": {
- "$id": "#/definitions/vehicle_events",
- "type": "array",
- "description": "Array of events indicating a change to a vehicle's state",
- "uniqueItems": true,
- "minItems": 1,
- "items": {
- "$ref": "#/definitions/vehicle_event"
- }
- }
- },
- "required": [
- "vehicle_state",
- "event_types",
- "timestamp",
- "telemetry"
- ],
- "properties": {
- "vehicle_state": {
- "$ref": "#/definitions/vehicle_state"
- },
- "event_types": {
- "$ref": "#/definitions/vehicle_events"
- },
- "timestamp": {
- "$ref": "#/definitions/timestamp"
- },
- "telemetry": {
- "$ref": "#/definitions/vehicle_telemetry"
- },
- "trip_id": {
- "$ref": "#/definitions/uuid"
- }
- },
- "additionalProperties": false,
- "allOf": [
- {
- "description": "valid vehicle_state and vehicle_events combinations",
- "oneOf": [
- {
- "properties": {
- "vehicle_state": {
- "const": "available"
- },
- "event_types": {
- "contains": {
- "enum": [
- "agency_drop_off",
- "battery_charged",
- "comms_restored",
- "located",
- "maintenance",
- "on_hours",
- "provider_drop_off",
- "reservation_cancel",
- "system_resume",
- "trip_cancel",
- "trip_end",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "vehicle_state": {
- "const": "elsewhere"
- },
- "event_types": {
- "contains": {
- "enum": [
- "comms_restored",
- "located",
- "trip_leave_jurisdiction",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "vehicle_state": {
- "const": "non_operational"
- },
- "event_types": {
- "contains": {
- "enum": [
- "battery_low",
- "comms_restored",
- "located",
- "maintenance",
- "off_hours",
- "system_suspend",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "vehicle_state": {
- "const": "on_trip"
- },
- "event_types": {
- "contains": {
- "enum": [
- "comms_restored",
- "located",
- "trip_enter_jurisdiction",
- "trip_start",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "vehicle_state": {
- "const": "removed"
- },
- "event_types": {
- "contains": {
- "enum": [
- "agency_pick_up",
- "comms_restored",
- "compliance_pick_up",
- "decommissioned",
- "located",
- "maintenance_pick_up",
- "rebalance_pick_up",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "vehicle_state": {
- "const": "reserved"
- },
- "event_types": {
- "contains": {
- "enum": [
- "comms_restored",
- "located",
- "reservation_start",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "vehicle_state": {
- "const": "unknown"
- },
- "event_types": {
- "contains": {
- "enum": [
- "comms_lost",
- "missing",
- "unspecified"
- ]
- }
- }
- }
- }
- ]
- },
- {
- "description": "Conditionally require a trip_id reference",
- "anyOf": [
- {
- "not": {
- "properties": {
- "event_types": {
- "contains": {
- "enum": [
- "trip_cancel",
- "trip_end",
- "trip_enter_jurisdiction",
- "trip_leave_jurisdiction",
- "trip_start"
- ]
- }
- }
- }
- }
- },
- {
- "required": [
- "trip_id"
- ]
- }
- ]
- }
- ]
-}
\ No newline at end of file
diff --git a/agency/post_vehicle_telemetry.json b/agency/post_vehicle_telemetry.json
deleted file mode 100644
index 021c9d8e..00000000
--- a/agency/post_vehicle_telemetry.json
+++ /dev/null
@@ -1,108 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/agency/post_vehicle_telemetry.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "The MDS Agency Schema, POST vehicle telemetry body",
- "type": "object",
- "definitions": {
- "timestamp": {
- "$id": "#/definitions/timestamp",
- "type": "number",
- "description": "Integer milliseconds since Unix epoch",
- "multipleOf": 1.0,
- "minimum": 1514764800000
- },
- "uuid": {
- "$id": "#/definitions/uuid",
- "type": "string",
- "description": "A UUID used to uniquely identifty an object",
- "default": "",
- "examples": [
- "3c9604d6-b5ee-11e8-96f8-529269fb1459"
- ],
- "pattern": "^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$"
- },
- "vehicle_telemetry": {
- "$id": "#/definitions/vehicle_telemetry",
- "type": "object",
- "description": "A telemetry datum for a specific vehicle at a specific time",
- "required": [
- "device_id",
- "timestamp",
- "gps"
- ],
- "additionalProperties": false,
- "properties": {
- "device_id": {
- "$ref": "#/definitions/uuid"
- },
- "timestamp": {
- "$ref": "#/definitions/timestamp"
- },
- "gps": {
- "type": "object",
- "required": [
- "lat",
- "lng"
- ],
- "additionalProperties": false,
- "properties": {
- "lat": {
- "type": "number",
- "description": "Latitude of the location",
- "minimum": -90,
- "maximum": 90
- },
- "lng": {
- "type": "number",
- "description": "Longitude of the location",
- "minimum": -180,
- "maximum": 180
- },
- "altitude": {
- "type": "number",
- "description": "Altitude above mean sea level in meters"
- },
- "heading": {
- "type": "number",
- "description": "Degrees - clockwise starting at 0 degrees at true North"
- },
- "speed": {
- "type": "number",
- "description": "Estimated speed in meters / sec as reported by the GPS chipset"
- },
- "accuracy": {
- "type": "number",
- "description": "Horizontal accuracy, in meters"
- },
- "hdop": {
- "type": "number",
- "description": "Horizontal GPS or GNSS accuracy value"
- },
- "satellites": {
- "type": "integer",
- "description": "Number of GPS or GNSS satellites"
- }
- }
- },
- "charge": {
- "type": "number",
- "description": "Fraction of charge of the vehicle (required if applicable)",
- "minimum": 0,
- "maximum": 1
- }
- }
- }
- },
- "required": [
- "data"
- ],
- "properties": {
- "data": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/vehicle_telemetry"
- }
- }
- },
- "additionalProperties": false
-}
\ No newline at end of file
diff --git a/agency/put_stops.json b/agency/put_stops.json
deleted file mode 100644
index 5f510cdb..00000000
--- a/agency/put_stops.json
+++ /dev/null
@@ -1,107 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/agency/put_stops.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "The MDS Agency Schema, update Stops",
- "type": "object",
- "definitions": {
- "stop_status": {
- "$id": "#/definitions/stop_status",
- "type": "object",
- "description": "Status object for a Stop in MDS",
- "required": [
- "is_installed",
- "is_renting",
- "is_returning"
- ],
- "properties": {
- "is_installed": {
- "$id": "#/definitions/stop_status/properties/is_installed",
- "type": "boolean"
- },
- "is_renting": {
- "$id": "#/definitions/stop_status/properties/is_renting",
- "type": "boolean"
- },
- "is_returning": {
- "$id": "#/definitions/stop_status/properties/is_returning",
- "type": "boolean"
- }
- }
- },
- "uuid": {
- "$id": "#/definitions/uuid",
- "type": "string",
- "description": "A UUID used to uniquely identifty an object",
- "default": "",
- "examples": [
- "3c9604d6-b5ee-11e8-96f8-529269fb1459"
- ],
- "pattern": "^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$"
- },
- "vehicle_type_counts": {
- "$id": "#/definitions/vehicle_type_counts",
- "type": "object",
- "properties": {
- "bicycle": {
- "$id": "#/definitions/vehicle_type_counts/properties/bicycle",
- "type": "integer",
- "minimum": 0
- },
- "cargo_bicycle": {
- "$id": "#/definitions/vehicle_type_counts/properties/cargo_bicycle",
- "type": "integer",
- "minimum": 0
- },
- "car": {
- "$id": "#/definitions/vehicle_type_counts/properties/car",
- "type": "integer",
- "minimum": 0
- },
- "scooter": {
- "$id": "#/definitions/vehicle_type_counts/properties/scooter",
- "type": "integer",
- "minimum": 0
- },
- "moped": {
- "$id": "#/definitions/vehicle_type_counts/properties/moped",
- "type": "integer",
- "minimum": 0
- },
- "other": {
- "$id": "#/definitions/vehicle_type_counts/properties/other",
- "type": "integer",
- "minimum": 0
- }
- },
- "additionalProperties": false
- }
- },
- "required": [
- "stops"
- ],
- "properties": {
- "stops": {
- "$id": "#/properties/stops",
- "type": "array",
- "description": "The array of stops",
- "items": {
- "type": "object",
- "required": [
- "stop_id"
- ],
- "properties": {
- "stop_id": {
- "$ref": "#/definitions/uuid"
- },
- "status": {
- "$ref": "#/definitions/stop_status"
- },
- "num_spots_disabled": {
- "$ref": "#/definitions/vehicle_type_counts"
- }
- }
- }
- }
- },
- "additionalProperties": false
-}
\ No newline at end of file
diff --git a/data-types.md b/data-types.md
new file mode 100644
index 00000000..304a43cf
--- /dev/null
+++ b/data-types.md
@@ -0,0 +1,311 @@
+# Mobility Data Specification: **Data Types**
+
+This MDS data types page catalogs the objects (fields, types, requirements, descriptions) used across MDS, particularly with the unified Provider and Agency endpoints.
+
+## Table of Contents
+
+- [Vehicles](#vehicles)
+ - [Vehicle Types](#vehicle-types)
+ - [Propulsion Types](#propulsion-types)
+ - [Vehicle Status](#vehicle-status)
+- [Events](#events)
+ - [Event Types](#event-times)
+- [Telemetry](#telemetry)
+ - [GPS Data][gps]
+- [Stops](#stops)
+ - [Stop Status](#stop-status)
+- [Trips](#trips)
+- [Reports](#reports)
+
+## Vehicles
+
+A vehicle record is as follows:
+
+| Field | Type | Required/Optional | Comments |
+| -------------------- | -------- | --------------------- | -------- |
+| `device_id` | UUID | Required | A unique device ID in UUID format, should match this device in Provider |
+| `provider_id` | UUID | Required | A UUID for the Provider, unique within MDS. See MDS [provider list](/providers.csv). |
+| `data_provider_id` | UUID | Optional | If different than `provider_id`, a UUID for the data solution provider managing the data feed in this endpoint. See MDS [provider list](/providers.csv) which includes both service operators and data solution providers. |
+| `vehicle_id` | String | Required | A unique vehicle identifier (visible code, license plate, etc), visible on the vehicle itself |
+| `vehicle_type` | Enum | Required | The [vehicle type][vehicle-types] |
+| `vehicle_attributes` | Map | Optional | **[Mode](/modes#list-of-supported-modes) Specific**. [Vehicle attributes](/modes#vehicle-attributes) given as mode-specific unordered key-value pairs |
+| `propulsion_types` | Enum[] | Required | Array of [propulsion types][propulsion-types]; allows multiple values |
+| `accessibility_attributes` | Enum[] | Required if Available | **[Mode](/modes#list-of-supported-modes) Specific**. [Accessibility attributes](/modes#accessibility-attributes) given as an array of enumerated values. List of any accessibility attributes **available on the vehicle**. |
+| `battery_capacity` | Integer | Required if Available | Capacity of battery expressed as milliamp hours (mAh) |
+| `fuel_capacity` | Integer | Required if Available | Capacity of fuel tank (liquid, solid, gaseous) expressed in liters |
+| `maximum_speed` | Integer | Required if Available | Maximum speed (kph) possible with vehicle under normal, flat incline, smooth surface conditions. Applicable if the device has a built-in or intelligent speed limiter/governor. |
+
+[Top][toc]
+
+### Vehicle Types
+
+The list of allowed `vehicle_type` values in MDS.
+
+| `vehicle_type` | Description |
+|--------------------| ----------- |
+| `bicycle` | A two-wheeled mobility device intended for personal transportation that can be operated via pedals, with or without a motorized assist (includes e-bikes, recumbents, and tandems) |
+| `bus` | A vehicle larger than a car or small truck capable of transporting multiple passengers at once |
+| `cargo_bicycle` | A two- or three-wheeled bicycle intended for transporting larger, heavier cargo than a standard bicycle (such as goods or passengers), with or without motorized assist (includes bakfiets/front-loaders, cargo trikes, and long-tails) |
+| `car` | A passenger car or similar light-duty vehicle |
+| `delivery_robot` | A robot or remote-operated device intended for transporting goods |
+| `moped` | A seated fully-motorized mobility device capable of travel at moderate or high speeds and suited for operation in general urban traffic |
+| `motorcycle` | A seated fully-motorized mobility device capable of travel at high speeds and suited for operation in general urban traffic and highways |
+| `scooter_standing` | A standing fully-motorized mobility device without a seat intended for one rider, capable of travel at low or moderate speeds, and suited for operation in infrastructure shared with motorized bicycles |
+| `scooter_seated` | A fully-motorized mobility device with a seat intended for one rider, capable of travel at low or moderate speeds, and suited for operation in infrastructure shared with motorized bicycles |
+| `truck` | A truck or vehicle larger than a car or similar heavy-duty vehicle |
+| `other` | A device that does not fit in the other categories |
+
+Values based off of `form_factor` in [GBFS vehicle_types](https://github.com/MobilityData/gbfs/blob/master/gbfs.md#vehicle_typesjson), with some additional to support MDS modes.
+
+[Top][toc]
+
+### Propulsion Types
+
+The list of allowed `propulsion_type` values in MDS.
+
+| `propulsion` | Description |
+| -------------------- | ------------------------------------------------------ |
+| `human` | Pedal or foot propulsion |
+| `electric_assist` | Provides electric motor assist only in combination with human propulsion - no throttle mode |
+| `electric` | Powered by battery-powered electric motor with throttle mode |
+| `combustion` | Powered by gasoline combustion engine |
+| `combustion_diesel` | Powered by diesel combustion engine |
+| `hybrid` | Powered by combined combustion engine and battery-powered motor |
+| `hydrogen_fuel_cell` | Powered by hydrogen fuel cell powered electric motor |
+| `plug_in_hybrid` | Powered by combined combustion engine and battery-powered motor with plug-in charging |
+
+A vehicle may have one or more values from the `propulsion`, 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` represented by the array `['human', 'electric']`. A bicycle with pedal-assist would have the `propulsion` represented by the array `['human', 'electric_assist']` if it can also be operated as a traditional bicycle.
+
+Values based off of `propulsion_type` in [GBFS vehicle_types](https://github.com/MobilityData/gbfs/blob/master/gbfs.md#vehicle_typesjson).
+
+[Top][toc]
+
+### Vehicle Status
+
+A vehicle status record represents the current or last-known event and telemetry from a vehicle, defined as follows:
+
+| Field | Type | Required/Optional | Comments |
+| ----- | ---- | ----------------- | -------- |
+| `device_id` | UUID | Required | A unique device ID in UUID format, should match this device in Provider |
+| `provider_id` | UUID | Required | A UUID for the Provider, unique within MDS. See MDS [provider list](/providers.csv). |
+| `data_provider_id` | UUID | Optional | If different than `provider_id`, a UUID for the data solution provider managing the data feed in this endpoint. See MDS [provider list](/providers.csv) which includes both service operators and data solution providers. |
+| `last_event` | Event | Required | Most recent [Event](#events) for this device based on `timestamp` |
+| `last_telemetry` | Telemetry | Required | Most recent [Telemetry](#telemetry) for this device based on `timestamp` |
+
+[Top][toc]
+
+## Events
+
+Events represent changes in vehicle status.
+
+| Field | Type | Required/Optional | Comments |
+| ----- | ---- | ----------------- | -------- |
+| `device_id` | UUID | Required | A unique device ID in UUID format |
+| `provider_id` | UUID | Required | A UUID for the Provider, unique within MDS. See MDS [provider list](/providers.csv). |
+| `data_provider_id` | UUID | Optional | If different than `provider_id`, a UUID for the data solution provider managing the data feed in this endpoint. See MDS [provider list](/providers.csv) which includes both service operators and data solution providers. |
+| `event_id` | UUID | Required | A unique event ID |
+| `vehicle_state` | Enum | Required | See [vehicle state][vehicle-states] table |
+| `event_types` | Enum[] | Required | Vehicle [event types][vehicle-events] for state change, with allowable values determined by `vehicle_state` |
+| `timestamp` | [Timestamp][ts] | Required | Date/time that event occurred at. See [Event Times][event-times] |
+| `publication_time` | [Timestamp][ts] | Optional | Date/time that event became available through the status changes endpoint |
+| `location` | [GPS][gps] | Required | See also [Stop-based Geographic Data][stop-based-geo]. |
+| `event_geographies` | UUID[] | Optional | **[Beta feature](/general-information.md#beta-features):** *Yes (as of 2.0.0)*. Array of Geography UUIDs consisting of every Geography that contains the location of the status change. See [Geography Driven Events][geography-driven-events]. Required if `location` is not present. |
+| `battery_percent` | Integer | Required if Applicable | Percent battery charge of vehicle, expressed between 0 and 100 |
+| `fuel_percent` | Integer | Required if Applicable | Percent fuel in vehicle, expressed between 0 and 100 |
+| `trip_ids` | UUID[] | Required if Applicable | Trip UUIDs (foreign key to /trips endpoint), required if `event_types` contains `trip_start`, `trip_end`, `trip_cancel`, `trip_enter_jurisdiction`, or `trip_leave_jurisdiction` |
+| `associated_ticket` | String | Optional | Identifier for an associated ticket inside an Agency-maintained 311 or CRM system |
+
+### Event Times
+
+Because of the unreliability of device clocks, the provider is unlikely to know with total confidence what time an event occurred at. However, providers are responsible for constructing as accurate a timeline as possible. Most importantly, the order of the timestamps for a particular device's events must reflect the provider's best understanding of the order in which those events occurred.
+
+[Top][toc]
+
+## Telemetry
+
+A standard point of vehicle telemetry. References to latitude and longitude imply coordinates encoded in the [WGS 84 (EPSG:4326)](https://en.wikipedia.org/wiki/World_Geodetic_System) standard GPS or GNSS projection expressed as [Decimal Degrees](https://en.wikipedia.org/wiki/Decimal_degrees).
+
+| Field | Type | Required/Optional | Field Description |
+| ----- | ---- | ----------------- | ----------------- |
+| `device_id` | UUID | Required | A unique device ID in UUID format |
+| `provider_id` | UUID | Required | A UUID for the Provider, unique within MDS. See MDS [provider list](/providers.csv). |
+| `data_provider_id`| UUID | Optional | If different than `provider_id`, a UUID for the data solution provider managing the data feed in this endpoint. See MDS [provider list](/providers.csv) which includes both service operators and data solution providers. |
+| `telemetry_id` | UUID | Required | ID used for uniquely-identifying a Telemetry entry |
+| `timestamp` | [Timestamp][ts] | Required | Date/time that event occurred. Based on GPS or GNSS clock |
+| `trip_ids` | UUID[] | Required | If telemetry occurred during a trip, the ID of the trip(s). If not in a trip, `null`.
+| `journey_id` | UUID | Required | If telemetry occurred during a trip and journeys are used for the mode, the ID of the journey. If not in a trip, `null`.
+| `stop_id` | UUID | Required if Applicable | Stop that the vehicle is currently located at. See [Stops][stops] |
+| `location` | [GPS][gps] | Required | Telemetry position data |
+| `location_type` | Enum | Required if Known | If detectable and known, what type of location the device is on or in. One of `street`, `sidewalk`, `crosswalk`, `garage`, `bike_lane`. |
+| `battery_percent` | Integer | Required if Applicable | Percent battery charge of vehicle, expressed between 0 and 100 |
+| `fuel_percent` | Integer | Required if Applicable | Percent fuel in vehicle, expressed between 0 and 100 |
+| `tipped_over` | Boolean | Required if Known | If detectable and known, is the device tipped over or not? Default is 'false'. |
+
+### GPS Data
+
+| Field | Type | Required/Optional | Field Description |
+| ---------- | -------------- | --------------------- | ------------------------------------------------------------ |
+| `lat` | Double | Required | Latitude of the location |
+| `lng` | Double | Required | Longitude of the location |
+| `altitude` | Double | Required if Available | Altitude above mean sea level in meters |
+| `heading` | Double | Required if Available | Degrees - clockwise starting at 0 degrees at true North |
+| `speed` | Float | Required if Available | Estimated speed in meters / sec as reported by the GPS chipset |
+| `horizontal_accuracy` | Float | Required if Available | Horizontal accuracy, in meters |
+| `vertical_accuracy` | Float | Required if Available | Vertical accuracy, in meters |
+| `satellites` | Integer | Required if Available | Number of GPS or GNSS satellites |
+
+[Top][toc]
+
+## Stops
+
+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](/provider#stops) and [Agency](/agency#stops) telemetry data.
+
+| Field | Type | Required/Optional | Description |
+| ----- | ---- |-------------------|-------------|
+| `stop_id` | UUID | Required | Unique ID for stop |
+| `name` | String | Required | Name of stop |
+| `last_updated` | Timestamp | Required | Date/Time that the stop was last updated |
+| `location` | [GPS][gps] | Required | Simple centerpoint location of the Stop. The use of the optional `geography_id` is recommended to provide more detail. |
+| `status` | [Stop Status](#stop-status) | Required | Object representing the status of the Stop. See [Stop Status](#stop-status). |
+| `capacity` | {vehicle_type: number} | Required | Number of total places 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. See MDS [provider list](/providers.csv). |
+| `data_provider_id` | UUID | Optional | UUID for the data provider managing the data coming from this stop. Null/undefined if managed by an agency or a provider. See MDS [provider list](/providers.csv). |
+| `geography_id` | UUID | Optional | Pointer to the [Geography](/geography) that represents the Stop geospatially via Polygon or MultiPolygon. |
+| `region_id` | string | Optional | ID of the region where station is located, see [GBFS Station Information][gbfs-station-info] |
+| `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[]][gbfs-station-info] | Optional | List of payment methods accepted at stop, see [GBFS Rental Methods][gbfs-station-info] |
+| `cross_street` | String | Optional | Cross street of where the station is located. |
+| `num_places_available` | {vehicle_type: number} | Optional | How many places are free to be populated with vehicles at this stop? |
+| `num_places_disabled` | {vehicle_type: number} | Optional | How many places 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 |
+| `image_url` | URL | Optional | Link to an image, photo, or diagram of the stop. Could be used by providers to help riders find or use the stop. |
+
+[Top][toc]
+
+### Stop Status
+
+**Stop Status** returns information about the current status of a **[Stop](#stops)**.
+
+| Field | Type | Required/Optional | Description |
+|----------------|---------|-------------------|-----------------------------------------------------|
+| `is_installed` | Boolean | Required | See GBFS [station_status.json][gbfs-station-status] |
+| `is_renting` | Boolean | Required | See GBFS [station_status.json][gbfs-station-status] |
+| `is_returning` | Boolean | Required | See GBFS [station_status.json][gbfs-station-status] |
+
+Example of the **Stop Status** object with properties listed:
+
+```json
+{
+ "is_installed": true,
+ "is_renting": false,
+ "is_returning": true
+}
+```
+
+[Top][toc]
+
+## Trips
+
+A Trip is defined by the following structure:
+
+| Field | Type | Required/Optional | Comments |
+| ----- | ---- | ----------------- | -------- |
+| `provider_id` | UUID | Required | A UUID for the Provider, unique within MDS. See MDS [provider list](/providers.csv). |
+| `data_provider_id` | UUID | Optional | If different than `provider_id`, a UUID for the data solution provider managing this data endpoint. See MDS [provider list](/providers.csv) which includes both service operators and data solution providers. |
+| `device_id` | UUID | Required | A unique device ID in UUID format. Cross reference with `/vehicles` for more device details. |
+| `journey_id` | UUID | Optional | A unique [journey ID](/modes#journey-id) for associating collections of trips for its [mode][modes] |
+| `journey_attributes` | Map | Optional | **[Mode](/modes#list-of-supported-modes) Specific**. [Journey attributes](/modes#journey-attributes) given as unordered key-value pairs |
+| `trip_id` | UUID | Required | A unique ID for each trip |
+| `trip_type` | Enum | Optional | **[Mode](/modes#list-of-supported-modes) Specific**. The [trip type](/modes#trip-type) describing the purpose of a trip segment |
+| `trip_attributes` | Map | Optional | **[Mode](/modes#list-of-supported-modes) Specific**. [Trip attributes](/modes#trip-attributes) given as unordered key-value pairs |
+| `fare_attributes` | Map | Optional | **[Mode](/modes#list-of-supported-modes) Specific**. [Fare attributes](/modes#fare-attributes) given as unordered key-value pairs |
+| `start_time` | [Timestamp][ts] | Required | Start of the passenger/driver trip |
+| `end_time` | [Timestamp][ts] | Required | End of the passenger/driver trip |
+| `start_location` | [GPS][gps] | Required | Location of the start of the trip. |
+| `end_location` | [GPS][gps] | Required | Location of the end of the trip. |
+| `duration` | Integer | Required | Time, in Seconds |
+| `distance` | Integer | Required | Trip Distance, in Meters |
+| `publication_time` | [Timestamp][ts] | Optional | Date/time that trip became available through the trips endpoint |
+| `accessibility_attributes` | Enum[] | Required if Available | **[Mode](/modes#list-of-supported-modes) Specific**. [Accessibility attributes](/modes#accessibility-attributes) given as an array of enumerated values. List of any accessibility attributes **used during the trip**. |
+| `parking_verification_url` | URL | Optional | A URL to a photo (or other evidence) of proper vehicle parking at the end of a trip, provided by customer or operator. |
+| `parking_category` | Enum | Optional | The type of parking location detected or provided and the end of a trip. One of `corral`, `curb`, `rack`, `other_valid`, `invalid`. Note that `other_valid` covers any other allowed parking location beyond what is enumerated, and `invalid` is any improper parking based on agency parking rules.
+| `standard_cost` | Integer | Optional | The cost, in the currency defined in `currency`, to perform that trip in the standard operation of the System (see [Costs & Currencies][costs-and-currencies]) |
+| `actual_cost` | Integer | Optional | The actual cost, in the currency defined in `currency`, paid by the customer of the *mobility as a service* provider (see [Costs & Currencies][costs-and-currencies]) |
+| `currency` | String | Optional, USD cents is implied if null.| An [ISO 4217 Alphabetic Currency Code][iso4217] representing the currency of the payee (see [Costs & Currencies][costs-and-currencies]) |
+
+[Top][toc]
+
+## Reports
+
+A Report is defined by the following structure:
+
+| Column Name | Type | Comments |
+|----------------------| ----------------------------------------- | ------------------------------------------------ |
+| `provider_id` | UUID | A UUID for the Provider, unique within MDS. See MDS provider_id in [provider list](/providers.csv). |
+| `start_date` | date | Start date of trip the data row, ISO 8601 date format, i.e. YYYY-MM-DD |
+| `duration` | string | Value is always `P1M` for monthly. Based on [ISO 8601 duration](https://en.wikipedia.org/wiki/ISO_8601#Durations) |
+| `special_group_type` | [Special Group Type](#special-group-type) | Type that applies to this row |
+| `geography_id` | [Geography](/geography) | ID that applies to this row. Includes all IDs in /geography. When there is no /geography then return `null` for this value and return counts based on the entire operating area. |
+| `vehicle_type` | [Vehicle Type](/general-information.md#vehicle-types) | Type that applies to this row |
+| `trip_count` | integer | Count of trips taken for this row |
+| `rider_count` | integer | Count of unique riders for this row |
+
+[Top][toc]
+
+### Data Notes
+
+Report contents include every combination of special group types, geography IDs, and vehicle types in operation for each month since the provider began operations in the jurisdiction. New files are added monthly in addition to the previous monthly historic files.
+
+Counts are calculated based the agency's local time zone. Trips are counted based on their start time, i.e. if a trip starts in month A but ends in month B, it will be counted only as part of the report for month A. Similarly, trips are counted based on their start geography, i.e. if a trip starts in geography A and ends in geography B, it will appear in the counts for geography A and not for geography B.
+
+All geography IDs included in the city published [Geography](/geography) API endpoint are included in the report results. In lieu of serving an API, this can alternately be a [flat file](/geography#file-format) created by the city and sent to the provider via link. If there is no `/geography` available, then counts are for the entire agency operating area, and `null` is returned for each Geography ID.
+
+[Top][toc]
+
+### Data Redaction
+
+Some combinations of parameters may return a small count of trips, which could increase a privacy risk of re-identification. To correct for that, Reports does not return data below a certain count of results. This data redaction is called k-anonymity, and the threshold is set at a k-value of 10. For more explanation of this methodology, see our [Data Redaction Guidance document](https://github.com/openmobilityfoundation/mobility-data-specification/wiki/MDS-Data-Redaction).
+
+**If the query returns fewer than `10` trips in a count, then that row's count value is returned as "-1".** Note "0" values are also returned as "-1" since the goal is to group both low and no count values for privacy.
+
+This value may be adjusted in future releases and/or may become dynamic to account for specific categories of use cases and users. To improve the specification and to inform future guidance, users are encouraged to share their feedback and questions about k-values on this [discussion thread](https://github.com/openmobilityfoundation/mobility-data-specification/discussions/622).
+
+Using k-anonymity will reduce, but not necessarily eliminate the risk that an individual could be re-identified in a dataset, and this data should still be treated as sensitive. This is just one part of good privacy protection practices, which you can read more about in our [MDS Privacy Guide for Cities](https://github.com/openmobilityfoundation/governance/blob/main/documents/OMF-MDS-Privacy-Guide-for-Cities.pdf).
+
+[Top][toc]
+
+### Special Group Type
+
+Here are the possible values for the `special_group_type` dimension field:
+
+| Name | Description |
+| ---------------- | --------------------------------------------------------------------------------------------------------------------- |
+| low_income | Trips where a low income discount is applied by the provider, e.g., a discount from a qualified provider equity plan. |
+| adaptive_scooter | Trips taken on a scooter with features to improve accessibility for people with disabilities, e.g., scooter with a seat or wider base |
+| all_riders | All riders from any group |
+
+Other special group types may be added in future MDS releases as relevant agency and provider use cases are identified. When additional special group types or metrics are proposed, a thorough review of utility and relevance in program oversight, evaluation, and policy development should be done by OMF Working Groups, as well as any privacy implications by the OMF Privacy Committee.
+
+[Top][toc]
+
+[costs-and-currencies]: /general-information.md#costs-and-currencies
+[event-times]: /general-information.md#event-times
+[gbfs-station-info]: https://github.com/NABSA/gbfs/blob/master/gbfs.md#station_informationjson
+[gbfs-station-status]: https://github.com/NABSA/gbfs/blob/master/gbfs.md#station_statusjson
+[geography-driven-events]: /general-information.md#geography-driven-events
+[gps]: #gps-data
+[iso4217]: https://en.wikipedia.org/wiki/ISO_4217#Active_codes
+[modes]: /modes/README.md
+[propulsion-types]: /general-information.md#propulsion-types
+[stop-based-geo]: #stop-based-geographic-data
+[stops]: #stops
+[toc]: #table-of-contents
+[ts]: /general-information.md#timestamps
+[vehicle-states]: /modes#vehicle-states
+[vehicle-events]: /modes#event-types
+[vehicle-types]: /general-information.md#vehicle-types
diff --git a/general-information.md b/general-information.md
index 20fd7589..7b433028 100644
--- a/general-information.md
+++ b/general-information.md
@@ -1,35 +1,75 @@
# Mobility Data Specification: **General information**
-This document contains specifications that are shared between the various MDS APIs such as [`agency`][agency], [`policy`][policy], [`provider`][provider], etc.
+This document contains specifications that are shared between the various MDS [APIs and endpoints](/README.md#endpoints).
## Table of Contents
-* [Beta Features](#beta-features)
-* [Costs and Currencies](#costs-and-currencies)
-* [Definitions](#definitions)
-* [Devices](#devices)
-* [Geographic Data][geo]
- * [Geographic Telemetry Data](#geographic-telemetry-data)
- * [Stop-based Geographic Data](#stop-based-geographic-data)
- * [Intersection Operation](#intersection-operation)
-* [Geography-Driven Events](#geography-driven-events)
-* [Optional Authentication](#optional-authentication)
-* [Propulsion Types](#propulsion-types)
-* [Responses](#responses)
- * [Error Messages](#error-messages)
-* [Strings](#strings)
-* [Stops](#stops)
- * [Stop Status](#stop-status)
- * [GBFS Compatibility](#gbfs-compatibility)
-* [Timestamps](#timestamps)
-* [UUIDs](#uuids)
-* [Vehicle States](#vehicle-states)
- * [Event Types](#event-types)
- * [Limitations on the Use of Certain Values](#limitations-on-the-use-of-certain-values)
- * [Vehicle State Events](#vehicle-state-events)
- * [State Machine Diagram](#state-machine-diagram)
-* [Vehicle Types](#vehicle-types)
-* [Versioning](#versioning)
+- [Authorization](#authorization)
+- [Beta Features](#beta-features)
+- [Costs and Currencies](#costs-and-currencies)
+- [Data Types](#data-types)
+- [Definitions](#definitions)
+- [Devices](#devices)
+- [GBFS Compatibility](#gbfs-compatibility)
+- [Geographic Data](#geographic-data)
+ - [Intersection Operation](#intersection-operation)
+- [Geography-Driven Events](#geography-driven-events)
+- [Responses](#responses)
+ - [Error Messages](#error-messages)
+ - [Bulk Responses](#bulk-responses)
+ - [Failure Details](#failure-details)
+- [Strings](#strings)
+- [Timestamps](#timestamps)
+- [Trips](#trips)
+- [UUIDs](#uuids)
+- [Vehicle States](#vehicle-states)
+- [Versioning](#versioning)
+
+## Authorization
+
+Outlines shared authorization details and methods across all MDS APIs.
+
+### Endpoint Requirements
+
+All MDS Provider, Agency, and Metrics APIs require authentication, as outlined.
+
+If implementing MDS Policy, Geography, and/or Jurisdiction APIs and endpoints, an agency must make them unauthenticated and public. This allows transparency for the public to see how the city is regulating, holds the city accountable for their policy decisions, and reduces the technical burden on providers to use these endpoints. A side benefit is that this allows third parties to ingest this information into their applications and services for public benefit.
+
+As of MDS 0.3.0, `gbfs.json` is required. The required GBFS endpoints should be made available publicly. See Provider [#realtime-data](https://github.com/openmobilityfoundation/mobility-data-specification/tree/main/provider#realtime-data) for more information about how to implement GBFS for dockless systems.
+
+### Header
+
+The `Authorization` header is sent as part of an HTTP request. Example:
+
+```
+GET /trips HTTP/1.1
+Host: api.provider.co
+Authorization: Bearer
+```
+
+More info on how to document [Bearer Auth in swagger](https://swagger.io/docs/specification/authentication/bearer-authentication/).
+
+### JSON Web Tokens
+
+JSON Web Token ([JWT](https://jwt.io/introduction/)) is **RECOMMENDED** as the token format.
+
+JWTs provide a safe, secure way to verify the identity of an agency and provide access to MDS resources without providing access to other, potentially sensitive data.
+
+> JSON Web Token (JWT) is an open standard ([RFC 7519](https://tools.ietf.org/html/rfc7519)) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.
+
+MDS API producers **MAY** include any metadata in the JWT they wish that helps to route, log, permission, or debug agency requests, leaving their internal implementation flexible.
+
+JWT provides a helpful [debugger](https://jwt.io/#debugger) for testing your token and verifying security.
+
+### OAuth 2.0
+
+OAuth 2.0's `client_credentials` grant type (outlined in [RFC6749](https://tools.ietf.org/html/rfc6749#section-4.4)) is **RECOMMENDED** as the authentication and authorization scheme.
+
+OAuth 2.0 is an industry standard authorization framework with a variety of existing tooling. The `client_credentials` grant type facilitates generation of tokens that can be used for access by agencies and distributed to data partners.
+
+If an MDS endpoint producer implements this auth scheme, it **MAY** choose to specify token scopes that define access parameters like allowable time ranges. These guidelines **SHOULD** be encoded into the returned token in a parsable way.
+
+[Top][toc]
## Beta Features
@@ -43,7 +83,7 @@ Working Groups and their Steering Committees are expected to review beta designa
[Top][toc]
-## Costs and currencies
+## Costs and Currencies
Fields specifying a monetary cost use a currency as specified in [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217#Active_codes). 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).
@@ -51,85 +91,43 @@ If the currency field is null, USD cents is implied.
[Top][toc]
-## Definitions
+## Data Types
-Defining terminology and abbreviations used throughout MDS.
+Shared data structures including [vehicles](/data-types.md#vehicles), [vehicle events](/data-types.md#vehicle-state-events), [vehicle telemetry](/data-types.md#telemetry-data), and [trips](/data-types.md#trips) can be found in the [Data Types](/data-types.md) page.
-* **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.
-* **Jurisdiction** - An agency’s area of legal authority to manage and regulate a mobility program in the real world. Note there is also an MDS API called [Jurisdiction](/jurisdiction), which is a way to digitally represent this.
-* **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.
+Standard [JSON data type definitions](https://en.wikipedia.org/wiki/JSON#Data_types) apply when feeds are in JSON format. The spec may also have more specific formatting requests, like enumeration (an enumerated set of approved values), object (an unordered key-value mapping of integer, strings, and symbols), map (an ordered mapping of any data types), integer (whole number), float (number with up to 8 decimal places), double (number with up 16 decimal places), etc.
[Top][toc]
-## Devices
+## Definitions
-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.
+Defining terminology and abbreviations used throughout MDS.
-Additionally, `device_id` must remain constant for the device's lifetime of service, regardless of the vehicle components that house the device.
+- **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.
+- **Jurisdiction** - An agency’s area of legal authority to manage and regulate a mobility program in the real world. Note there is also an MDS API called [Jurisdiction](/jurisdiction), which is a way to digitally represent this.
+- **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.
[Top][toc]
-## Geographic Data
-
-References to geographic datatypes (Point, MultiPolygon, etc.) imply coordinates encoded in the [WGS 84 (EPSG:4326)][wgs84] standard GPS or GNSS projection expressed as [Decimal Degrees][decimal-degrees]. When points are used, you may assume a 20 meter buffer around the point when needed.
-
-### Geographic Telemetry Data
+## Devices
-Whenever a vehicle location coordinate measurement is presented, it must be represented as a GeoJSON [`Feature`][geojson-feature] object with a corresponding `properties` object with the following properties:
+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.
-| Field | Type | Required/Optional | Field Description |
-| -------------- | --------------- | --------------------- | ------------------------------------------------------------ |
-| `timestamp` | [timestamp][ts] | Required | Date/time that event occurred. Based on GPS or GNSS clock |
-| `altitude` | Double | Required if Available | Altitude above mean sea level in meters |
-| `heading` | Double | Required if Available | Degrees - clockwise starting at 0 degrees at true North |
-| `speed` | Float | Required if Available | Estimated speed in meters / sec as reported by the GPS chipset |
-| `accuracy` | Float | Required if Available | Horizontal accuracy, in meters |
-| `hdop` | Float | Required if Available | Horizontal GPS or GNSS accuracy value (see [hdop][hdop]) |
-| `satellites` | Integer | Required if Available | Number of GPS or GNSS satellites |
+[Top][toc]
-Example of a vehicle location GeoJSON [`Feature`][geojson-feature] object:
+## GBFS Compatibility
-```json
-{
- "type": "Feature",
- "properties": {
- "timestamp": 1529968782421,
- "accuracy": 10,
- "speed": 1.21
- },
- "geometry": {
- "type": "Point",
- "coordinates": [
- -118.46710503101347,
- 33.9909333514159
- ]
- }
-}
-```
+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.
-### Stop-based Geographic Data
+[Top][toc]
-When an individual location coordinate measurement (Point) corresponds to a [Stop][general-stops], it must be presented with a `stop_id` property:
+## Geographic Data
-```json
-{
- "type": "Feature",
- "properties": {
- "timestamp": 1529968782421,
- "stop_id": "b813cde2-a41c-4ae3-b409-72ff221e003d"
- },
- "geometry": {
- "type": "Point",
- "coordinates": [
- -118.46710503101347,
- 33.9909333514159
- ]
- }
-}
-```
+References to geographic datatypes (Point, MultiPolygon, etc.) imply coordinates encoded in the [WGS 84 (EPSG:4326)][wgs84] standard GPS or GNSS projection expressed as [Decimal Degrees][decimal-degrees]. When points are used, you may assume a 20 meter buffer around the point when needed.
### Intersection Operation
@@ -143,9 +141,9 @@ For the purposes of this specification, the intersection of two geographic datat
## Geography-Driven Events
-**[Beta feature](/general-information.md#beta-features):** *Yes (as of 1.1.0)*. [Leave feedback](https://github.com/openmobilityfoundation/mobility-data-specification/issues/670)
+**[Beta feature](/general-information.md#beta-features):** _Yes (as of 1.1.0)_. [Leave feedback](https://github.com/openmobilityfoundation/mobility-data-specification/issues/670)
-Geography-Driven Events (GDE) is a new MDS feature for Agencies to perform complete Policy compliance monitoring without precise location data. Geography-Driven Events describe individual vehicles in realtime – not just aggregate data. However, rather than receiving the exact location of a vehicle, Agencies receive information about the vehicle's current geographic region. The regions used for Geography-Driven Events correspond to the Geographies in an Agency's current Policy. In this way, the data-shared using Geography-Driven Events is matched to an Agency's particular regulatory needs.
+Geography-Driven Events (GDE) is an MDS feature for Agencies to perform complete Policy compliance monitoring without precise location data. Geography-Driven Events describe individual vehicles in realtime – not just aggregate data. However, rather than receiving the exact location of a vehicle, Agencies receive information about the vehicle's current geographic region. The regions used for Geography-Driven Events correspond to the Geographies in an Agency's current Policy. In this way, the data-shared using Geography-Driven Events is matched to an Agency's particular regulatory needs.
See [this example](/policy/examples/requirements.md#geography-driven-events) for how to implement GDE using [Policy Requirements](/policy#requirement).
@@ -153,68 +151,82 @@ Here's how it works in practice:
1. The Agency creates a geographic Policy Area for a local regulatory need
- *Scooters traveling within downtown during peak hours incur a $0.20 fee.*
+ _Scooters traveling within downtown during peak hours incur a $0.20 fee._
2. Providers notify the Agency in real-time about events in the Policy Area.
- *At 5:21pm scooter X7123 entered downtown.*
+ _At 5:21pm scooter X7123 entered downtown._
3. The Agency can refine their data needs over time by revising their published Policy Areas.
- *Agency adds rule disallowing parking on waterfront path, begins receiving data on events within area.*
+ _Agency adds rule disallowing parking on waterfront path, begins receiving data on events within area._
-Agencies that wish to use Geography-Driven Events do so by requiring a new `event_geographies` field in status events. When an Agency is using Geography-Driven Events, Providers must emit a new `changed_geographies` status event whenever a vehicle in a trip enters or leaves a Geography managed by a Policy.
+Agencies that wish to use Geography-Driven Events do so by requiring a new `event_geographies` field in status events. When an Agency is using Geography-Driven Events, Providers must emit a new `changed_geographies` status event whenever a vehicle in a trip enters or leaves a Geography managed by a Policy.
During the Beta period for this feature, location and telemetry data remain required fields. This allows Agencies to test Geography-Driven Events, measuring its accuracy and efficacy against regulatory systems based on precise location data. After the beta period, if Geography-Driven Events is deemed by the OMF to be accurate and effective, the specification will evolve to allow cities to use Geography-Driven Events in lieu of location or telemetry data.
[Top][toc]
-## Optional Authentication
-
-Authorization of the Policy and Geography APIs is no longer required and will be deprecated in next major release with these endpoints (plus Jursidictions) becoming 'optionally private' instead of 'optionally public'. An agency may optionally decide to make the Policy and Geography endpoints, as well as Jursidictions, unauthenticated and public. This allows transparency for the public to see how the city is regulating, holds the city accountable for their policy decisions, and reduces the technical burden on providers to use these endpoints. A side benefit is that this allows third parties to ingest this information into their applications and services for public benefit.
-
-Note if implementing the beta feature [Geography Driven Events](/general-information.md#geography-driven-events), both Policy and Geography must be public.
-
-[Top][toc]
-
-## Propulsion Types
+## Responses
-| `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 |
+- **200:** OK: operation successful.
+- **201:** Created: `POST` operations, new object(s) created
+- **400:** Bad request.
+- **401:** Unauthorized: Invalid, expired, or insufficient scope of token.
+- **404:** Not Found: Object does not exist, returned on `GET` or `POST` operations if the object does not exist.
+- **406:** MDS version in Accept header is unsupported or invalid.
+- **409:** Conflict: `POST` operations when an object already exists and an update is not possible.
+- **500:** Internal server error: In this case, the answer should contain an `application/json` body with an [error message](#error-messages) for troubleshooting.
-A vehicle may have one or more values from the `propulsion`, 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` represented by the array `['human', 'electric']`. A bicycle with pedal-assist would have the `propulsion` represented by the array `['human', 'electric_assist']` if it can also be operated as a traditional bicycle.
+### Error Messages
-[Top][toc]
+```jsonc
+{
+ "error": "...",
+ "error_description": "...",
+ "error_details": ["...", "..."]
+}
+```
-## Responses
+| 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 |
-* **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` or `POST` 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.
+### Bulk Responses
-### Error Messages
+For multi-record POST and PUT calls, e.g. sending Events using the Agency API, the bulk-response structure describes a list of failures is as follows:
-```json
+```jsonc
{
- "error": "...",
- "error_description": "...",
- "error_details": [ "...", "..." ]
+ "success": "...",
+ "total": "...",
+ "failures": [ { // list of failure details
+ "item": { ... }, // copy of the item with the problem
+ "error": "...",
+ "error_description": "...",
+ "error_details": [ "...", "..." ]
+ }, {
+ // additional failure records
+ } ]
}
```
-| 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 |
+| Field | Type | Field Description |
+| ---------- | ------------------------------------- | --------------------------------------------------------------- |
+| `success` | Integer | Number of successfully written records |
+| `total` | Integer | Total number of provided records |
+| `failures` | [Failure Details](#failure-details)[] | Array of details about failed records (empty if all successful) |
+
+### Failure Details
+
+| Field | Type | Field Description |
+| ------------------- | -------------------- | --------------------------------------------------- |
+| `item` | Vehicle, Event, etc. | Invalid submitted item |
+| `error` | Enum | Error code |
+| `error_description` | String | Human readable error description (can be localized) |
+| `error_details` | String[] | Array of fields with errors, if applicable |
[Top][toc]
@@ -224,64 +236,26 @@ All String fields, such as `vehicle_id`, are limited to a maximum of 255 charact
[Top][toc]
-## Stops
-
-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](/provider#stops) (including routes and event locations) and [Agency](/agency#stops) (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](#stop-based-geographic-data) | Required | Simple centerpoint location of the Stop. The use of the optional `geography_id` is recommended to provide more detail. |
-| status | [Stop Status](#stop-status) | Required | Object representing the status of the Stop. See [Stop Status](#stop-status). |
-| capacity | {vehicle_type: number} | Required | Number of total places 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. See MDS [provider list](/providers.csv). |
-| geography_id | UUID | Optional | Pointer to the [Geography](/geography) that represents the Stop geospatially via Polygon or MultiPolygon. |
-| region_id | string | Optional | ID of the region where station is located, see [GBFS Station Information][gbfs-station-info] |
-| 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[]][gbfs-station-info] | Optional | List of payment methods accepted at stop, see [GBFS Rental Methods][gbfs-station-info] |
-| cross_street | String | Optional | Cross street of where the station is located. |
-| num_places_available | {vehicle_type: number} | Optional | How many places are free to be populated with vehicles at this stop? |
-| num_places_disabled | {vehicle_type: number} | Optional | How many places 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 |
-| image_url | URL | Optional | Link to an image, photo, or diagram of the stop. Could be used by providers to help riders find or use the stop. |
-
-
-### Stop Status
-
-**Stop Status** returns information about the current status of a **[Stop](#stops)**.
-
-| Field | Type | Required/Optional | Description |
-|--------------|---------|-------------------|-----------------------------------------------------|
-| is_installed | Boolean | Required | See GBFS [station_status.json][gbfs-station-status] |
-| is_renting | Boolean | Required | See GBFS [station_status.json][gbfs-station-status] |
-| is_returning | Boolean | Required | See GBFS [station_status.json][gbfs-station-status] |
-
-Example of the **Stop Status** object with properties listed:
-
-```json
-{
- "is_installed": true,
- "is_renting": false,
- "is_returning": true
-}
-```
-
-### GBFS Compatibility
+## Timestamps
-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.
[Top][toc]
-## Timestamps
+## Trips
-A `timestamp` refers to integer milliseconds since Unix epoch.
+Counting trips is a common analysis with MDS data, but in some instances when
+a user rents a vehicle the rental may end up being very short because the
+vehicle is unusable or because the customer changes their mind.
+To facilitate a common definition of trips for analysis, MDS defines a trip
+as a user taking control of a vehicle for 60 seconds or more.
+If a user reserves a vehicle and cancels before taking control of the vehicle
+that reservation does not count as a trip, nor does a user taking control of
+the vehicle and canceling or ending the trip in under 60 seconds.
+
+Providers are still expected to report all trips and trip related events in
+all MDS endpoints, but parties may use this definition as a shared reference
+at the recommendation of the MDS community when analyzing trips.
[Top][toc]
@@ -295,147 +269,25 @@ MDS uses Version 1 UUIDs by default. Version 4 UUIDs may be used where noted.
## Vehicle States
-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. |
+See new location within [vehicle states](/modes/vehicle_states.md) in [modes](/modes#vehicle-states).
[Top][toc]
### Event Types
-Event types are the possible transitions between some vehicle states.
-
-| `event_type` | Description |
-|--------------|-------------|
-| `agency_drop_off` | Drop off by the agency |
-| `agency_pick_up` | Pick up by the agency |
-| `battery_charged` | Battery charged |
-| `battery_low` | Battery low |
-| `comms_lost` | Communications lost |
-| `comms_restored` | Communications restored |
-| `compliance_pick_up` | Pick up for compliance |
-| `decommissioned` | Decommissioned |
-| `located` | Located |
-| `maintenance` | General maintenance |
-| `maintenance_pick_up` | Pick up for maintenance |
-| `missing` | Missing |
-| `off_hours` | Off hours - end of service |
-| `on_hours` | On hours - start of service |
-| `provider_drop_off` | Drop off by the provider |
-| `rebalance_pick_up` | Pick up for rebalancing |
-| `reservation_cancel` | Reservation cancelled |
-| `reservation_start` | Reservation started |
-| `system_resume` | Resume system operations |
-| `system_suspend` | Suspend system operations |
-| `trip_cancel` | Cancel trip |
-| `trip_end` | End trip |
-| `trip_enter_jurisdiction` | Trip enters a jurisdiction |
-| `trip_leave_jurisdiction` | Trip leaves a jurisdiction |
-| `trip_start` | Start trip |
-| `unspecified` | Unspecified |
-
-[Top][toc]
-
-### Limitations on the Use of Certain Values
-
-MDS is intended to communicate the provider's best available information to regulators. However there may be legitimate circumstances where providers do not have definitive or current information about devices on the ground. MDS incorporates some values to convey these situations. These vehicle state and event type values are to be used sparingly and temporarily, and are not meant for repeated or prolonged use. These values exist to create logical coherence within MDS about vehicles that are operating abnormally or are out of communication. When a more accurate value is known, the MDS API should be updated with the latest information. Cities may add language to their Service Level Agreements (SLAs) that minimize the use of these values by providers.
-
-**Vehicle State: Unknown**
-
-The `unknown` vehicle state means that the vehicle cannot be reliably placed into any of the other available states by the provider. This could be due to connectivity loss, GPS issues, missing vehicles, or other operational variances. It is expected that `unknown` will not be used frequently, and only for short periods of time. Cities may put in place specific limitations via an SLA. As vehicles regain connectivity or are located by providers they should return to their prior state, and then send additional events to reflect any subsequent changes to that state.
-
-**Event Type: Unspecified**
-
-The `unspecified` event type state transition means that the vehicle has moved from one state to another for an unspecified or unknown reason. It is used when there are multiple possible event types between states, but the reason for the transition is not clear. It is expected that `unspecified` will not be used frequently, and only for short periods of time. Cities may put in place specific limitations via an SLA. When more accurate information becomes available to the provider, it should be updated in the MDS data by sending a new event type state transition with the current timestamp.
+See new location within [event types](/modes/event_types.md) in [modes](/modes#event-types).
[Top][toc]
### Vehicle State Events
-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, 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.
-
-Vehicles can enter the `unknown` state to and from any other state with the following event types: any state can go to `unknown` with event type `comms_lost`, `missing`, or `unspecified`, and `unknown` can go to any state with event type `comms_restored` of `unspecified`.
-
-| 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`, `unknown` | `available` | `provider_drop_off` | The vehicle was placed in the PROW by the provider |
-| `removed`, `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. |
-| `unknown` | `available` | `located` | The vehicle has been located by the provider |
-| `non_operational`, `unknown`| `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. |
-| `unknown` | `reserved` | `located` | The vehicle has been located by the provider |
-| `unknown` | `reserved` | `unspecified` | The provider cannot definitively state how a vehicle became reserved. |
-| `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. |
-| `unknown` | `on_trip` | `located` | The vehicle has been located by the provider |
-| `unknown` | `on_trip` | `unspecified` | The provider cannot definitively state how a vehicle started a trip. |
-| `on_trip` | `elsewhere` | `trip_leave_jurisdiction` | A vehicle on a trip left the jurisdiction |
-| `on_trip` | `on_trip ` | `changed_geographies` | **[Beta feature](/general-information.md#beta-features):** *Yes (as of 1.1.0)*. The vehicle has entered or left one or more Geographies managed by a Policy. See [Geography Driven Events](#geography-driven-events).|
-| `unknown` | `elsewhere` | `comms_restored` | The vehicle transmitted status information after a period of being out of communication. |
-| `unknown` | `elsewhere` | `located` | The vehicle has been located by the provider |
-| `unknown` | `elsewhere` | `unspecified` | The provider cannot definitively state how a vehicle went `elsewhere`. |
-| `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`, `unknown` | `non_operational` | `unspecified` | The vehicle became unavailable, but the 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 |
-| `unknown` | `non_operational` | `located` | The vehicle has been located by the provider |
-| `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`, `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 |
-| `unknown` | `removed` | `comms_restored` | The vehicle transmitted status information after a period of being in an unknown state |
-| `unknown` | `removed` | `located` | The vehicle has been located by the provider |
-| `available`, `elsewhere`, `non_operational`, `on_trip`, `removed`, `reserved` | `unknown` | `missing` | The vehicle is not at its last reported GPS location, or that location is wildly in error |
-| `available`, `elsewhere`, `non_operational`, `on_trip`, `removed`, `reserved` | `unknown` | `comms_lost` | The vehicle is unable to transmit its GPS location or other status information |
-| `available`, `elsewhere`, `non_operational`, `on_trip`, `removed`, `reserved` | `unknown` | `unspecified` | The provider cannot definitively (yet) specify the reason for the unknown state |
-
-### State Machine Diagram
-
-The *State Machine Diagram* shows how `vehicle_state` and `event_type` relate to each other and how vehicles can transition between states. See [Google Slides](https://docs.google.com/presentation/d/1Ar2-ju8YlddSsTATvQw4YjsSa5108XtidtnJNk-UAfA/edit) for the source file.
-![MDS State Machine Diagram](/MDS-state-machine-diagram.svg)
+See new location within [individual modes](/modes#list-of-supported-modes) in [modes](/modes#state-transitions).
[Top][toc]
-## Vehicle Types
-
-The list of allowed `vehicle_type` values in MDS. Aligning with [GBFS vehicle types form factors](https://github.com/NABSA/gbfs/blob/master/gbfs.md#vehicle_typesjson-added-in-v21-rc).
+### State Machine Diagram
-| `vehicle_type` | Description |
-|----------------| ----------- |
-| bicycle | A two-wheeled mobility device intended for personal transportation that can be operated via pedals, with or without a motorized assist (includes e-bikes, recumbents, and tandems) |
-| cargo_bicycle | A two- or three-wheeled bicycle intended for transporting larger, heavier cargo than a standard bicycle (such as goods or passengers), with or without motorized assist (includes bakfiets/front-loaders, cargo trikes, and long-tails) |
-| car | A passenger car or similar light-duty vehicle |
-| scooter | A standing or seated fully-motorized mobility device intended for one rider, capable of travel at low or moderate speeds, and suited for operation in infrastructure shared with motorized bicycles |
-| moped | A seated fully-motorized mobility device capable of travel at moderate or high speeds and suited for operation in general urban traffic |
-| other | A device that does not fit in the other categories |
+See new location within [individual modes](/modes#list-of-supported-modes) in [modes](/modes#state-machine-diagram).
[Top][toc]
@@ -443,38 +295,27 @@ The list of allowed `vehicle_type` values in MDS. Aligning with [GBFS vehicle ty
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.
+Versioning must be implemented through the use of a custom media-type, `application/vnd.mds+json`, combined with a required `version` parameter. The one exception is the `/reports` endpoint, which returns CSV files instead of JSON, and so uses `text/vnd.mds+csv` as its media-type.
-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`
+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`. Only major and minor versions are allowed and required in the media-type version string (not [patch](https://github.com/openmobilityfoundation/governance/blob/main/technical/ReleaseGuidelines.md#versioning) releases).
Clients must specify the version they are targeting through the `Accept` header. For example:
```http
-Accept: application/vnd.mds+json;version=1.2.0
+Accept: application/vnd.mds+json;version=2.0
```
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 version `0.2` was requested.
-* The `agency` API must respond as if version `0.3` was requested.
-* The `policy` API must respond as if version `0.4` was requested.
+- The `provider` API must respond as if version `0.2` was requested.
+- The `agency` API must respond as if version `0.3` was requested.
+- The `policy` API must respond as if version `0.4` was requested.
If an unsupported or invalid version is requested, the API must respond with a status of `406 Not Acceptable`.
[Top][toc]
-[agency]: /agency/README.md
[decimal-degrees]: https://en.wikipedia.org/wiki/Decimal_degrees
-[hdop]: https://en.wikipedia.org/wiki/Dilution_of_precision_(navigation)
-[gbfs-station-info]: https://github.com/NABSA/gbfs/blob/master/gbfs.md#station_informationjson
-[gbfs-station-status]: https://github.com/NABSA/gbfs/blob/master/gbfs.md#station_statusjson
-[general-stops]: /general-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
diff --git a/geography/README.md b/geography/README.md
index 2699de0d..cab295b6 100644
--- a/geography/README.md
+++ b/geography/README.md
@@ -4,28 +4,27 @@
This specification contains a collection of RESTful APIs used to read Geographies (descriptions of geographical information, e.g. multi-polygons, currently represented via GeoJSON).
-Geographical data has many applications in the context of mobility, such as the description of municipal boundaries, locations for pick-up and drop-off zones, and areas of temporary closure for special events or emergencies. This API is intended to support a variety of other APIs, including the Policy API.
+Geographical data has many applications in the context of mobility, such as the description of municipal boundaries, locations for pick-up and drop-off zones, and areas of temporary closure for special events or emergencies. This API is intended to support a variety of other APIs, including the Policy API.
-Geographical data will be stored as GeoJSON and read from either `geographies.json` or the `/geographies` endpoint, referenced by UUID. Geography data once published through this API shall be treated as immutable, to ensure that any rules or regulations referring to the boundaries cannot be retroactively changed. A Geography may be deprecated and replaced by updated version with a new UUID.
+Geographical data will be stored as GeoJSON and read from either `geographies.json` or the `/geographies` endpoint, referenced by UUID. Geography data once published through this API shall be treated as immutable, to ensure that any rules or regulations referring to the boundaries cannot be retroactively changed. A Geography may be deprecated and replaced by updated version with a new UUID.
## Table of Contents
-* [General Information](#general-information)
- * [Versioning](#versioning)
- * [Transition from Policy](#transition-from-policy)
-* [Distribution](#distribution)
- * [Flat Files](#flat-files)
- * [Response Format](#response-format)
- * [Authorization](#authorization)
-* [Schema](#schema)
- * [Geography Fields](#geography-fields)
- * [Previous Geographies](#previous-geographies)
- * [Geography Type](#geography-type)
-* [File Format](#file-format)
-* [Endpoints](#endpoints)
- * [Geography](#geography)
- * [Geographies](#geographies)
-* [Examples](#examples)
+- [General Information](#general-information)
+ - [Authorization](#authorization)
+ - [Versioning](#versioning)
+- [Distribution](#distribution)
+ - [Flat Files](#flat-files)
+ - [Response Format](#response-format)
+- [Schema](#schema)
+ - [Geography Fields](#geography-fields)
+ - [Previous Geographies](#previous-geographies)
+ - [Geography Type](#geography-type)
+- [File Format](#file-format)
+- [Endpoints](#endpoints)
+ - [Geography](#geography)
+ - [Geographies](#geographies)
+- [Examples](#examples)
## General Information
@@ -33,29 +32,27 @@ The following information applies to all `geography` API endpoints.
[Top][toc]
-### Versioning
-
-MDS APIs must handle requests for specific versions of the specification from clients.
+### Authorization
-Versioning must be implemented as specified in the [Versioning section][versioning].
+This endpoint should be made public. Authorization is not required.
[Top][toc]
-### Transition from Policy
+### Versioning
-To ensure this Geography API is not creating a breaking change for the 1.1.0 release, it's expected that the data contained in the [`/geographies`](/policy#geography) endpoint in the Policy API is identical to this Geography API. This will ensure that when a Geography ID is used anywhere in this release, the data could be retrieved from either location.
+MDS APIs must handle requests for specific versions of the specification from clients.
-This temporary requirement is to ensure backwards compatibility, but the overall intent is to remove the /policy/geographies endpoint at the next major MDS release.
+Versioning must be implemented as specified in the [Versioning section][versioning].
[Top][toc]
## Distribution
-Geographies shall be published by regulatory agencies or their authorized delegates as JSON objects. These JSON objects shall be served by either [flat files](#flat-files) or via [REST API endpoints](#rest-endpoints). In either case, geography data shall follow the [schema](#schema) outlined below.
+Geographies shall be published by regulatory agencies or their authorized delegates as JSON objects. These JSON objects shall be served by either [flat files](#flat-files) or via [REST API endpoints](#endpoints). In either case, geography data shall follow the [schema](#schema) outlined below.
Published geographies, should be treated as immutable data. Obsoleting or otherwise changing a geography is accomplished by publishing a new geography with a field named `prev_geographies`, a list of UUID references to the geography or policies geographies by the new geography.
-Geographical data shall be represented as GeoJSON `Feature` objects. Typically no part of the geographical data should be outside the [municipality boundary][muni-boundary] unless an agency has the authority to regulate there.
+Geographical data shall be represented as GeoJSON `FeatureCollection` objects. Typically no part of the geographical data should be outside the [municipality boundary][muni-boundary] unless an agency has the authority to regulate there.
Geographies should be re-fetched at an agreed upon interval between providers and agencies, or when either entity requests it.
@@ -65,13 +62,13 @@ Geographies should be re-fetched at an agreed upon interval between providers an
To use a flat file, geographies shall be represented in one (1) file equivalent to the /geographies endpoint:
-* `geographies.json`
+- `geographies.json` in Geography API
-The files shall be structured like the output of the [REST endpoints](#rest-endpoints) above.
+The files shall be structured like the output of the [REST endpoints](#endpoints) above.
The publishing Agency should establish and communicate to providers how frequently these files should be polled.
-The `updated` field in the payload wrapper should be set to the time of publishing a revision, so that it is simple to identify a changed file.
+The `last_updated` field in the payload wrapper should be set to the time of publishing a revision, so that it is simple to identify a changed file.
[Top][toc]
@@ -81,15 +78,9 @@ See the [Responses][responses] and [Error Messages][error-messages] sections.
[Top][toc]
-### Authorization
-
-Authorization is not required. An agency may decide to make this endpoint unauthenticated and public. See [Optional Authentication](/general-information.md#optional-authentication) for details.
-
-[Top][toc]
-
## Schema
-See the [Endpoints](#endpoints) below for links to their specific JSON Schema documents.
+See the [Endpoints](#endpoints) below for links to specific data objects, and the [`mds-openapi`](https://github.com/openmobilityfoundation/mds-openapi) repository for full details and interactive documentation.
[Top][toc]
@@ -99,27 +90,27 @@ See the [Endpoints](#endpoints) below for links to their specific JSON Schema do
| ---------------- | --------- | --- | --------------------------------------------------------------------------------------------- |
| `name` | String | Required | Name of geography |
| `description` | String | Optional | Detailed description of geography |
-| `geography_type` | String | Optional | Type of geography, e.g. `municipal_boundary` or `council_district` or custom text. See [Geography Types](#geography-types). |
+| `geography_type` | String | Optional | Type of geography, e.g. `municipal_boundary` or `council_district` or custom text. See [Geography Type](#geography-type). |
| `geography_id` | UUID | Required | Unique ID of geography |
| `geography_json` | JSON | Required | The GeoJSON that defines the geographical coordinates. |
| `effective_date` | [timestamp][ts] | Optional | The date at which a Geography is considered "live". Must be at or after `published_date`. |
| `published_date` | [timestamp][ts] | Required | Time that the geography was published, i.e. made immutable |
-| `retire_date` | [timestamp][ts] | Optional | Time that the geography is slated to retire. Once the retire date is passed, new policies can no longer reference it and old policies referencing it should be updated. Retired geographies should continue to be returned in the geographies list. Must be after `effective_date`. |
+| `retire_date` | [timestamp][ts] | Optional | Time that the geography is slated to retire. Once the retire date is passed, new policies can no longer reference it and old policies referencing it should be updated. Retired geographies should continue to be returned in the geographies list. Must be after `effective_date`. Geographies referencing others with `prev_geographies` immediately replace the previous ones. |
| `prev_geographies` | UUID[] | Optional | Unique IDs of prior geographies replaced by this one |
[Top][toc]
### Previous Geographies
-Obsoleting or otherwise changing a geography is accomplished by publishing a new geography with the `prev_geographies` field, which is a list of UUID references to the geography or geographies superseded by the new geography. The previous geographies are also published in the `/geographies` endpoint. Using it allows agencies to look back historically at previously published geographies, for analysis, historic reference, or an auditable change trail.
+Obsoleting or otherwise changing a geography is accomplished by publishing a new geography with the `prev_geographies` field, which is a list of UUID references to the geography or geographies superseded by the new geography. The previous geographies are also published in the `/geographies` endpoint. Using it allows agencies to look back historically at previously published geographies, for analysis, historic reference, or an auditable change trail.
-This field is optional can be omitted by the publishing Agency.
+This field is optional can be omitted by the publishing Agency.
[Top][toc]
### Geography Type
-Type of geography. These specific types are recommendations based on ones commonly defined by agencies. Others may be created by the Agency as needed, or the optional `geography_type` field may be omitted.
+Type of geography. These specific types are recommendations based on ones commonly defined by agencies. Others may be created by the Agency as needed, or the optional `geography_type` field may be omitted.
`geography_type` does not imply policy or required actions by providers, but instead is for organizational and discovery purposes within the standalone Geography API. Geographies need to be referenced from other areas of MDS to be meaningfully applied.
@@ -128,13 +119,13 @@ Type of geography. These specific types are recommendations based on ones common
| `municipal_boundary` | Edge of a city |
| `policy_zone` | Zone where [Policy](/policy) rules could be in effect, like operating area, distribution/equity zones, no/slow ride zone, no parking, etc |
| `county_boundary` | Edge of a county |
-| `stop` | See [Stops](/general-information.ms#stops) |
+| `stop` | See [Stops](/general-information.md#stops) |
| `council_district` | City council district |
| `political_district` | Politically defined voting area |
| `neighborhood` | Neighborhood area |
| `market_area` | Economic area |
| `opportunity_zone` | Defined Opportunity Zone |
-| `overlay_district` | Agengy overlay district |
+| `overlay_district` | Agency overlay district |
| `post_code` | Zip or postal code |
| `traffic_zone` | Transportation planning area |
| `property_line` | One or more property lines |
@@ -147,44 +138,54 @@ Type of geography. These specific types are recommendations based on ones common
## File format
-Note: to use flat files rather than REST endpoints, Geography objects should be stored in `geographies.json`. The `geographies.json` file will look like the output of `GET /geographies`.
+Note: to use flat files rather than REST endpoints, Geography objects should be stored in `geographies.json`. The `geographies.json` file will look like the output of `GET /geographies`.
Example `geographies.json`
```jsonc
{
- "version": "1.2.0",
- "updated": "1570035222868",
- "geographies": [
- {
- // Geography 1
- },
- {
- // Geography 2
- }
- ]
+ "version": "2.0.0",
+ "last_updated": "1682984274000",
+ "geographies": [
+ {
+ // Geography 1
+ },
+ {
+ // Geography 2
+ }
+ ]
}
```
+#### Responses
+
+_Possible HTTP Status Codes_:
+200,
+404,
+406,
+500
+
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
+
[Top][toc]
## Endpoints
Responses must set the `Content-Type` header, as specified in the [Provider versioning](../provider/README.md#versioning) section. They must also specify the API version in the JSON-formatted response body, under the `version` key.
-The Geography Author API consists of the following endpoints:
+The Geography API consists of the following endpoints:
### Geography
-**Endpoint**: `/geographies/{geography_id}`
+**Endpoint**: `/geographies/{geography_id}`
**Method**: `GET`
-**Schema:** [`geography` schema](./geography.json)
+**Schema:** See [`mds-openapi`](https://github.com/openmobilityfoundation/mds-openapi) repository for schema.
-#### Query Parameters
+#### Path Parameters
-| Name | Type | Required/Optional | Description |
-| ------------- | ---- | --- | --------------------------------------------------- |
-| `geography_id` | UUID | Required | Unique identifier for a single specific Geography |
+| Path Parameter | Type | Required/Optional | Description |
+| -------------- | ---- | ----------------- | ------------------------------------------------- |
+| `geography_id` | UUID | Required | Unique identifier for a single specific Geography |
Returns: Details of a single Geography based on a UUID.
@@ -192,7 +193,7 @@ Response body:
```js
{
- "version": '1.2.0',
+ "version": "2.0.0",
"geography": {
"geography_id": UUID,
"geography_type": string,
@@ -202,24 +203,28 @@ Response body:
"effective_date": timestamp,
"prev_geographies": UUID[],
"geography_json": GeoJSON FeatureCollection
- }
+ }
}
```
-Response codes:
+#### Responses
-* 200 - success
-* 401 - unauthorized
-* 404 - no geography found
-* 403 - user is attempting to read an unpublished geography, but only has the `geographies:read:published` scope.
+_Possible HTTP Status Codes_:
+200,
+400 (with parameter),
+404,
+406,
+500
+
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
[Top][toc]
### Geographies
-**Endpoint**: `/geographies`
+**Endpoint**: `/geographies`
**Method**: `GET`
-**Schema:** [`geographies` schema](./geographies.json)
+**Schema:** See [`mds-openapi`](https://github.com/openmobilityfoundation/mds-openapi) repository for schema.
Returns: All geography objects
@@ -227,23 +232,28 @@ Response body:
```jsonc
{
- "version": "1.2.0",
- "updated": "1570035222868",
- "geographies": [
- {
- // Geography 1
- },
- {
- // Geography 2
- }
- ]
+ "version": "2.0.0",
+ "last_updated": "1682984274000",
+ "geographies": [
+ {
+ // Geography 1
+ },
+ {
+ // Geography 2
+ }
+ ]
}
```
-Response codes:
+#### Responses
+
+_Possible HTTP Status Codes_:
+200,
+404,
+406,
+500
-* 200 - success
-* 401 - unauthorized
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
[Top][toc]
@@ -253,8 +263,10 @@ See the [Geography Examples](examples/README.md) for ways these can be implement
[Top][toc]
+[bulk-responses]: /general-information.md#bulk-responses
[error-messages]: /general-information.md#error-messages
[responses]: /general-information.md#responses
+[schema]: /schema/
[ts]: /general-information.md#timestamps
[versioning]: /general-information.md#versioning
[muni-boundary]: ../provider/README.md#municipality-boundary
diff --git a/geography/geographies.json b/geography/geographies.json
deleted file mode 100644
index d1ebbc76..00000000
--- a/geography/geographies.json
+++ /dev/null
@@ -1,163 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/geography/geographies.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "The MDS Geographies Schema",
- "type": "object",
- "definitions": {
- "geography": {
- "$id": "#/definitions/geography",
- "type": "object",
- "title": "The geography object schema",
- "additionalProperties": false,
- "required": [
- "name",
- "geography_id",
- "geography_json",
- "published_date"
- ],
- "properties": {
- "name": {
- "$id": "#/definitions/geography/properties/name",
- "$ref": "#/definitions/string",
- "description": "Name of geography"
- },
- "description": {
- "$id": "#/definitions/geography/properties/description",
- "$ref": "#/definitions/string",
- "description": "Description of geography"
- },
- "geography_type": {
- "$id": "#/definitions/geography/properties/geography_type",
- "type": "string",
- "description": "The type of geography"
- },
- "geography_id": {
- "$id": "#/definitions/geography/properties/geography_id",
- "$ref": "#/definitions/uuid",
- "description": "Unique ID of geography"
- },
- "geography_json": {
- "$id": "#/definitions/geography/properties/geography_json",
- "$ref": "https://geojson.org/schema/FeatureCollection.json",
- "description": "The GeoJSON FeatureCollection that defines the geographical coordinates"
- },
- "effective_date": {
- "$id": "#/definitions/geography/properties/effective_date",
- "$ref": "#/definitions/null_timestamp",
- "description": "The date at which a Geography is considered 'live'. Must be at or after published_date."
- },
- "published_date": {
- "$id": "#/definitions/geography/properties/published_date",
- "$ref": "#/definitions/timestamp",
- "description": "Timestamp at which the geography was published i.e. made immutable"
- },
- "retire_date": {
- "$id": "#/definitions/geography/properties/end_date",
- "$ref": "#/definitions/null_timestamp",
- "description": "Time that the geography is slated to retire. Once the retire date is passed, new policies can no longer reference it and old policies referencing it should be updated. Retired geographies should continue to be returned in the geographies list. Must be after effective_date."
- },
- "prev_geographies": {
- "$id": "#/definitions/geography/properties/prev_geographies",
- "$ref": "#/definitions/null_uuid_array",
- "description": "Unique IDs of prior geographies replaced by this one",
- "uniqueItems": true
- }
- }
- },
- "string": {
- "$id": "#/definitions/string",
- "type": "string",
- "description": "A length-limited string type",
- "maxLength": 255,
- "default": "",
- "examples": [
- "ABC123"
- ],
- "pattern": "^(.*)$"
- },
- "timestamp": {
- "$id": "#/definitions/timestamp",
- "type": "number",
- "description": "Integer milliseconds since Unix epoch",
- "multipleOf": 1.0,
- "minimum": 1514764800000
- },
- "uuid": {
- "$id": "#/definitions/uuid",
- "type": "string",
- "description": "A UUID used to uniquely identifty an object",
- "default": "",
- "examples": [
- "3c9604d6-b5ee-11e8-96f8-529269fb1459"
- ],
- "pattern": "^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$"
- },
- "version": {
- "$id": "#/definitions/version",
- "type": "string",
- "description": "The version of MDS this data represents",
- "examples": [
- "1.2.0"
- ],
- "pattern": "^1\\.2\\.[0-9]+$"
- },
- "uuid_array": {
- "$id": "#/definitions/uuid_array",
- "type": "array",
- "description": "Array of UUID",
- "items": {
- "$id": "#/definitions/uuid_array/items",
- "$ref": "#/definitions/uuid"
- }
- },
- "null_timestamp": {
- "$id": "#/definitions/null_timestamp",
- "type": [
- "number",
- "null"
- ],
- "description": "Integer milliseconds since Unix epoch",
- "multipleOf": 1.0,
- "minimum": 1514764800000
- },
- "null_uuid_array": {
- "$id": "#/definitions/null_uuid_array",
- "type": [
- "array",
- "null"
- ],
- "description": "Array of UUID",
- "items": {
- "$id": "#/definitions/uuid_array/items",
- "$ref": "#/definitions/uuid"
- }
- }
- },
- "required": [
- "geographies",
- "updated",
- "version"
- ],
- "properties": {
- "geographies": {
- "$id": "#/properties/geographies",
- "type": "array",
- "title": "The array of policy objects in this payload",
- "items": {
- "$id": "#/properties/geographies/items",
- "$ref": "#/definitions/geography"
- }
- },
- "updated": {
- "$id": "#/properties/updated",
- "$ref": "#/definitions/timestamp",
- "description": "The timestamp when geographies was last updated"
- },
- "version": {
- "$id": "#/properties/version",
- "$ref": "#/definitions/version",
- "description": "The version of MDS that the geographies represents"
- }
- },
- "additionalProperties": false
-}
\ No newline at end of file
diff --git a/geography/geography.json b/geography/geography.json
deleted file mode 100644
index 661263f8..00000000
--- a/geography/geography.json
+++ /dev/null
@@ -1,154 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/geography/geography.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "The MDS Geography Schema",
- "type": "object",
- "definitions": {
- "geography": {
- "$id": "#/definitions/geography",
- "type": "object",
- "title": "The geography object schema",
- "additionalProperties": false,
- "required": [
- "name",
- "geography_id",
- "geography_json",
- "published_date"
- ],
- "properties": {
- "name": {
- "$id": "#/definitions/geography/properties/name",
- "$ref": "#/definitions/string",
- "description": "Name of geography"
- },
- "description": {
- "$id": "#/definitions/geography/properties/description",
- "$ref": "#/definitions/string",
- "description": "Description of geography"
- },
- "geography_type": {
- "$id": "#/definitions/geography/properties/geography_type",
- "type": "string",
- "description": "The type of geography"
- },
- "geography_id": {
- "$id": "#/definitions/geography/properties/geography_id",
- "$ref": "#/definitions/uuid",
- "description": "Unique ID of geography"
- },
- "geography_json": {
- "$id": "#/definitions/geography/properties/geography_json",
- "$ref": "https://geojson.org/schema/FeatureCollection.json",
- "description": "The GeoJSON FeatureCollection that defines the geographical coordinates"
- },
- "effective_date": {
- "$id": "#/definitions/geography/properties/effective_date",
- "$ref": "#/definitions/null_timestamp",
- "description": "The date at which a Geography is considered 'live'. Must be at or after published_date."
- },
- "published_date": {
- "$id": "#/definitions/geography/properties/published_date",
- "$ref": "#/definitions/timestamp",
- "description": "Timestamp at which the geography was published i.e. made immutable"
- },
- "retire_date": {
- "$id": "#/definitions/geography/properties/end_date",
- "$ref": "#/definitions/null_timestamp",
- "description": "Time that the geography is slated to retire. Once the retire date is passed, new policies can no longer reference it and old policies referencing it should be updated. Retired geographies should continue to be returned in the geographies list. Must be after effective_date."
- },
- "prev_geographies": {
- "$id": "#/definitions/geography/properties/prev_geographies",
- "$ref": "#/definitions/null_uuid_array",
- "description": "Unique IDs of prior geographies replaced by this one",
- "uniqueItems": true
- }
- }
- },
- "string": {
- "$id": "#/definitions/string",
- "type": "string",
- "description": "A length-limited string type",
- "maxLength": 255,
- "default": "",
- "examples": [
- "ABC123"
- ],
- "pattern": "^(.*)$"
- },
- "timestamp": {
- "$id": "#/definitions/timestamp",
- "type": "number",
- "description": "Integer milliseconds since Unix epoch",
- "multipleOf": 1.0,
- "minimum": 1514764800000
- },
- "uuid": {
- "$id": "#/definitions/uuid",
- "type": "string",
- "description": "A UUID used to uniquely identifty an object",
- "default": "",
- "examples": [
- "3c9604d6-b5ee-11e8-96f8-529269fb1459"
- ],
- "pattern": "^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$"
- },
- "version": {
- "$id": "#/definitions/version",
- "type": "string",
- "description": "The version of MDS this data represents",
- "examples": [
- "1.2.0"
- ],
- "pattern": "^1\\.2\\.[0-9]+$"
- },
- "uuid_array": {
- "$id": "#/definitions/uuid_array",
- "type": "array",
- "description": "Array of UUID",
- "items": {
- "$id": "#/definitions/uuid_array/items",
- "$ref": "#/definitions/uuid"
- }
- },
- "null_timestamp": {
- "$id": "#/definitions/null_timestamp",
- "type": [
- "number",
- "null"
- ],
- "description": "Integer milliseconds since Unix epoch",
- "multipleOf": 1.0,
- "minimum": 1514764800000
- },
- "null_uuid_array": {
- "$id": "#/definitions/null_uuid_array",
- "type": [
- "array",
- "null"
- ],
- "description": "Array of UUID",
- "items": {
- "$id": "#/definitions/uuid_array/items",
- "$ref": "#/definitions/uuid"
- }
- }
- },
- "required": [
- "geography",
- "version"
- ],
- "properties": {
- "geography": {
- "$id": "#/properties/geography",
- "$ref": "#/definitions/geography",
- "description": "The geography in this payload",
- "additionalProperties": false
- },
- "version": {
- "$id": "#/properties/version",
- "$ref": "#/definitions/version",
- "description": "The version of MDS that the geography represents"
- }
- },
- "additionalProperties": false
-}
\ No newline at end of file
diff --git a/jurisdiction/README.md b/jurisdiction/README.md
index ea9ab373..1f32b8a5 100644
--- a/jurisdiction/README.md
+++ b/jurisdiction/README.md
@@ -2,17 +2,19 @@
-This specification details the purpose, use cases, and schema for Jurisdictions. Jurisdictions are an optional service that are served by a coordinated group of agencies. Jurisdictions can be '[optionally authenticated](/general-information.md#optional-authentication)', making the endpoints unauthenticated and public. In the future this will shift to 'optionally private', where Jursidictions will be public by default. Note that it serves a different purpose from the [Geography](/geography) API, though it does reference areas within Geography by ID.
+This specification details the purpose, use cases, and schema for Jurisdictions. Jurisdictions are an optional service that are served by a coordinated group of agencies. Jurisdictions should be unauthenticated and public. Note that Jurisdictions serves a different purpose from the [Geography](/geography) API, though it does reference areas within Geography by ID.
## Table of Contents
- [Background](#background)
- [Beta Feature](#beta-feature)
+- [Authorization](#authorization)
- [Use Cases](#use-cases)
- [Distribution](#distribution)
- - [REST](#rest)
- [Schema](#schema)
- [REST Endpoints](#rest-endpoints)
+ - [Get Jurisdictions](#get-jurisdictions)
+ - [Get Jurisdiction](#get-jurisdiction)
- [Flat Files](#flat-files)
- [Examples](#examples)
@@ -33,12 +35,22 @@ A jurisdiction is:
- Purview to make rules over physical boundaries and modal boundaries (e.g. a jurisdiction could be for taxis only)
- A way of tracking revisions in an agency's authority
+[Top][toc]
+
## Beta Feature
The Jurisdictions API and all of its endpoints are marked as a [beta feature](https://github.com/openmobilityfoundation/mobility-data-specification/blob/feature-metrics/general-information.md#beta-features) starting in the 1.1.0 release. It has not been tested in real world scenarios, and may be adjusted in future releases.
**[Beta feature](https://github.com/openmobilityfoundation/mobility-data-specification/blob/feature-metrics/general-information.md#beta-features)**: _Yes (as of 1.1.0)_. [Leave feedback](https://github.com/openmobilityfoundation/mobility-data-specification/issues/673)
+[Top][toc]
+
+### Authorization
+
+This endpoint should be made public. Authorization is not required.
+
+[Top][toc]
+
## Use Cases
### 1. Defining boundaries and what the vehicle state `elsewhere` means
@@ -64,29 +76,19 @@ Example: A SaaS company contracts with Miami-Dade County to provide MDS. There a
Example: The City of Miami has different data visualization tools from the city of Coral Gables
Those tools can be granted data access from the SaaS tool based on the jurisdiction's stable identifier.
-[Top](#table-of-contents)
+[Top][toc]
## Distribution
-Jurisdictions can be served by agencies through the following REST API, or via [flat-files](#flat-files). Agencies may choose to make the endpoints public and non-authenticated.
-
-### REST
+Jurisdictions can be served by agencies through the following REST API, or via [flat-files](#flat-files). See [Authorization](#authorization).
-All response fields must use `lower_case_with_underscores`.
-
-Responses must set the `Content-Type` header, as specified in the [Provider versioning](../provider/README.md#versioning) section. They must also specify the current API version being served in the JSON-formatted response body, under the `version` key.
-
-Response bodies must be a `UTF-8` encoded JSON object.
-
-#### HTTP Response Codes
-
-The response to a client request must include a valid HTTP status code defined in the [IANA HTTP Status Code Registry](https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml)
-
-[Top](#table-of-contents)
+[Top][toc]
## Schema
-A Jurisdiction optionally contains a reference to a Geography object. This reference may change over time, e.g. if two
+See the [Endpoints](#endpoints) below for information on their specific schema, and the [`mds-openapi`](https://github.com/openmobilityfoundation/mds-openapi) repository for full details and interactive documentation.
+
+A Jurisdiction optionally contains a reference to a Geography object.
When a Jurisdiction is updated, the old version should remain in the back-end for archival purposes.
@@ -99,55 +101,106 @@ An individual `Jurisdiction` object is defined by the following fields:
| `agency_name` | String | Optional | Human-readable agency name for display purposes. |
| `description` | String | Required | Description of Jurisdiction. |
| `geography_id` | UUID | Optional | The unique ID of the geography covered by this Jurisdiction. |
-| `mobility_modes` | String[] | Optional | Set this field to specify what mobility modes a jurisdiction applies to. Valid values are left up to the agency to determine, but a couple examples that we think might be useful are 'taxi' and 'micromobility'. An empty array or undefined field indicates all mobility modes are covered under this jurisdiction. |
+| `mode_ids` | String[] | Required | Use this field to specify an array of what mobility [modes][modes] a jurisdiction applies to. |
| `timestamp` | timestamp | Required | Creation or update time of a Jurisdiction. |
Formatted in JSON, a Jurisdiction object should look like this:
```
{
- jurisdiction_id: UUID
- agency_key: string
- agency_name: string
- geography_id: UUID
- timestamp: Timestamp
+ "jurisdiction_id": UUID,
+ "agency_key": string,
+ "agency_name": string,
+ "geography_id": UUID,
+ "mode_ids": [
+ string
+ ],
+ "timestamp": Timestamp
}
```
+[Top][toc]
## REST Endpoints
-### GET /Jurisdictions
+### Format
+
+All response fields must use `lower_case_with_underscores`.
+
+Responses must set the `Content-Type` header, as specified in the [Provider versioning](../provider/README.md#versioning) section. They must also specify the current API version being served in the JSON-formatted response body, under the `version` key.
+
+Response bodies must be a `UTF-8` encoded JSON object.
+
+[Top][toc]
+
+### HTTP Response Codes
+
+The response to a client request must include a valid HTTP status code defined in the [IANA HTTP Status Code Registry](https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml)
+
+[Top][toc]
+
+### Get Jurisdictions
Gets all of an agency's Jurisdictions. Served by agencies.
-Parameters:
-| Name | Type | R/O | Description |
+**Endpoint:** `/jurisdictions/`
+**Method:** `GET`
+**[Beta feature][beta]:** _Yes (as of 1.1.0)_. [Leave feedback](https://github.com/openmobilityfoundation/mobility-data-specification/issues/673)
+**Schema:** [`jurisdiction` schema](#schema)
+**`data` Payload:** `{ "jurisdiction": [] }`, an array of [jurisdiction](#schema) objects
+
+_Query Parameters:_
+
+| Query Parameters | Type | R/O | Description |
| ------------ | --------- | --- | ---------------------------------------------- |
| `effective` | Timestamp | O | See the state of all the Jurisdictions (i.e. which ones are effective) at that point in time. If not supplied, the default is to show only Jurisdictions that are currently in effect. |
-Response codes:
+#### Responses
+
+_Possible HTTP Status Codes_:
+200,
+400 (with parameter),
+404,
+406,
+500
+
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
-- 200 - success
-- 403 - unauthorized
-- 500 - server error
+[Top][toc]
-### GET /Jurisdictions/:jurisdiction_id
+### GET Jurisdiction
-Gets a single Jurisdictions. Served by agencies
+Gets a single Jurisdictions. Served by agencies.
-Parameters:
-| Name | Type | R/O | Description |
+**Endpoint:** `/jurisdictions/{jurisdiction_id}`
+**Method:** `GET`
+**[Beta feature][beta]:** _Yes (as of 1.1.0)_. [Leave feedback](https://github.com/openmobilityfoundation/mobility-data-specification/issues/673)
+**Schema:** [`jurisdiction` schema](#schema)
+**`data` Payload:** `{ "jurisdiction": [] }`, an array of [jurisdiction](#schema) objects
+
+_Path Parameters:_
+
+| Path Parameters | Type | R/O | Description |
+| ------------ | --------- | --- | ---------------------------------------------- |
+| `jurisdiction_id` | UUID | R | Single jurisdiction to return |
+
+_Query Parameters:_
+
+| Query Parameters | Type | R/O | Description |
| ------------ | --------- | --- | ---------------------------------------------- |
| `effective` | Timestamp | O | See the version of the Jurisdiction that was in effect at that point in time. |
-Response codes:
+#### Responses
-- 200 - Success
-- 403 - Unauthorized
-- 404 - not found
-- 500 - Server error
+_Possible HTTP Status Codes_:
+200,
+400 (with parameter),
+404,
+406,
+500
-[Top](#table-of-contents)
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
+
+[Top][toc]
## Flat Files
@@ -160,9 +213,19 @@ The format and content of `jurisdictions.json` should resemble the responses fro
The publishing Agency should establish and communicate to interested parties how frequently these files should be polled.
-The `updated` field in the payload wrapper should be set to the time of publishing a revision, so that it is simple to identify a changed file.
+The `last_updated` field in the payload wrapper should be set to the time of publishing a revision, so that it is simple to identify a changed file.
+
+### Responses
+
+_Possible HTTP Status Codes_:
+200,
+404,
+406,
+500
-[Top](#table-of-contents)
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
+
+[Top][toc]
## Examples
@@ -170,4 +233,10 @@ See the [Jurisdiction Examples](examples/README.md) for a sample `jurisdictions.
See the [Geography Examples](/geography/examples/README.md) for an example `geographies.json`.
-[Top](#table-of-contents)
+[Top][toc]
+
+[bulk-responses]: /general-information.md#bulk-responses
+[modes]: /modes#list-of-supported-modes
+[responses]: /general-information.md#responses
+[schema]: /schema/
+[toc]: #table-of-contents
diff --git a/metrics/README.md b/metrics/README.md
index 22e5d0cf..1ae39775 100644
--- a/metrics/README.md
+++ b/metrics/README.md
@@ -10,10 +10,11 @@ The Metrics API endpoints are intended to be implemented by regulatory agencies,
- [General Information](#general-information)
- [Implementation](#implementation)
+- [Authorization](#authorization)
- [Data Requirements](#data-requirements)
- [Beta Feature](#beta-feature)
- [Date and Time Format](#date-and-time-format)
-- [Authorization](#authorization)
+- [Data Schema](#data-schema)
- [Data Redaction](#data-redaction)
- [Metrics Discovery API](#metrics-discovery-api)
- [Metrics Query API](#metrics-query-api)
@@ -58,6 +59,22 @@ Here are initial design use cases and scenarios for Metrics.
[Top][toc]
+## Authorization
+
+### For Agencies hosting the Metrics API
+
+MDS Metrics endpoint producers **SHALL** provide authorization for API endpoints via a bearer token based auth system. When making requests, the endpoints expect one of two scopes `metrics:read` or `metrics:read:provider` to be present as part of the `scope` claims in a [JSON Web Token](https://jwt.io/) (JWT) `access_token` in the `Authorization` header, in the form `Authorization: Bearer `. The token issuance, expiration and revocation policies are at the discretion of the agency. [JSON Web Token](/general-information.md#json-web-tokens) is the recommended format.
+
+If a client has a `metrics:read` scope, they are permitted to read _all_ metrics available via the Metrics API.
+
+If a client has a `metrics:read:provider` scope, they are only permitted to read metrics which pertain to a particular `provider_id` claim in the aforementioned [JWT](https://jwt.io/) `access_token`.
+
+Further scopes and requirements may be added at the discretion of the agency, depending on their particular access control needs.
+
+General authorization details are specified in the [Authorization section](/general-information.md#authorization) in MDS General Information.
+
+[Top][toc]
+
## Data Requirements
The Metrics API does not replace required MDS Provider and Agency endpoints (e.g., [trips](/provider#trips), [events](/provider#events), [vehicles](/provider#vehicles), etc.) in any way. City regulators use disaggregated data access for policy, data validation, auditing, and operational needs, and the Metrics API is not designed to serve these purposes.
@@ -82,17 +99,9 @@ All interval durations (duration) are [ISO 8601](https://en.wikipedia.org/wiki/I
[Top][toc]
-## Authorization
-
-### For Agencies hosting the Metrics API
-
-When making requests, the Metrics API expects one of two scopes `metrics:read` or `metrics:read:provider` to be present as part of the `scope` claims in a [JWT](https://jwt.io/) `access_token` in the `Authorization` header, in the form `Authorization: Bearer `. The token issuance, expiration and revocation policies are at the discretion of the Agency.
-
-If a client has a `metrics:read` scope, they are permitted to read _all_ metrics available via the Metrics API.
-
-If a client has a `metrics:read:provider` scope, they are only permitted to read metrics which pertain to a particular `provider_id` claim in the aforementioned [JWT](https://jwt.io/) `access_token`.
+## Data Schema
-Further scopes and requirements may be added at the discretion of the Agency, depending on their particular access control needs.
+See the [Endpoints](#endpoints) below for information on their specific schema, and the [`mds-openapi`](https://github.com/openmobilityfoundation/mds-openapi) repository for full details and interactive documentation.
[Top][toc]
@@ -151,9 +160,14 @@ None.
}
```
-See the [Metrics Examples](examples) for ways these can be implemented.
+### Responses
-[Top][toc]
+_Possible HTTP Status Codes_:
+200,
+404,
+500
+
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
## Metrics Query API
@@ -165,7 +179,7 @@ Supports querying one or more metrics with the following parameters.
### Parameters
-| Name | Type | Required | Comments |
+| Query Parameters | Type | Required | Comments |
| --------------- | -------- | -------- | ------------------------------------------------------------------------------- |
| `measures` | string[] | Yes | list of measures to return. [See metric names](core_metrics.md) |
| `interval` | duration | Yes | [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601#Durations) duration for metrics intervals. |
@@ -239,6 +253,16 @@ All named fields are required to be returned in response. Non-relevant values ca
}
```
+### Responses
+
+_Possible HTTP Status Codes_:
+200,
+400 (with parameter),
+404,
+500
+
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
+
[Top][toc]
## Examples
@@ -247,4 +271,7 @@ See the [Metrics Examples](examples) for ways these can be implemented.
[Top][toc]
+[bulk-responses]: /general-information.md#bulk-responses
+[responses]: /general-information.md#responses
[toc]: #table-of-contents
+[schema]: /schema/
diff --git a/modes/README.md b/modes/README.md
new file mode 100644
index 00000000..26187fc7
--- /dev/null
+++ b/modes/README.md
@@ -0,0 +1,126 @@
+# Mobility Data Specification: **Modes**
+
+This directory contains descriptions of the different mobility modes that can be described by the Mobility Data Specification. It contains a list of all defined vehicle states and event types, as well as mode-specific state-machines, unique mode properties and attributes.
+
+All MDS APIs should be mode-agnostic.
+
+## Table of Contents
+
+- [Modes](#modes)
+ - [Provider ID](#provider-id)
+- [List of Supported Modes](#list-of-supported-modes)
+- [Mode Attributes](#mode-attributes)
+- [Mode Properties](#mode-properties)
+
+## Modes
+
+The `mode` value is used to specify the applicable mobility category in MDS Policy, Provider/Agency, and many other parts of MDS.
+
+A `mode` is defined as: A distinct regulatory framework for a type of mobility service or program, as distinguished by a combination of:
+
+1. the data needed by regulators,
+1. the operating rules under which the service functions,
+1. the legal authority under which it is regulated, and
+1. the design and operating model of the service itself.
+
+There will be some gray areas and some differences from one jurisdiction to another (e.g. taxis and ridehail may be regulated under the same rules on one place, but different rules in another). MDS will not pre-define a complete taxonomy of modes, or identify every modal boundary upfront, but will instead add modes on an as-needed basis, maintaining as much consistency of naming as possible.
+
+We err on the side of treating highly similar services as one mode, but consult with our members and community to inform each decision about how to integrate a new service and whether it needs to be designated as its own mode. This is a policy implementation question as much as it is a technical one.
+
+Each mode defined in MDS shall include key descriptive information, such as journey type (e.g. point-to-point, multi-segment, multi-segment overlapping), primary purpose (goods, single passenger, multi-passenger, etc.), and a description of the service being offered that aligns with terminology commonly understood by the public (e.g. “e-scooter” or “ridehailing”).
+
+[Top][toc]
+
+### Provider ID
+
+MDS is intended to be used for multiple transportation modes, including its original micromobility (e-scooters, bikes, etc.) mode, as well as additional modes such as taxis, car share, and delivery bots. A given `provider_id` shall be associated with a single mobility mode, so that the mode does not have to be specified in each data structure and API call. A provider implementing more than one mode shall [register](/README.md#providers-using-mds) a unique `provider_id` for each mode.
+
+[Top][toc]
+
+## List of Supported Modes
+
+- **[Micromobility](/modes/micromobility.md)** (`micromobility`) - dockless or docked small devices such as e-scooters and bikes.
+- **[Passenger services](/modes/passenger-services.md)** (`passenger-services`) - transporting individuals with a vehicle driven by another entity, including taxis, TNCs, and microtransit
+- **[Car share](/modes/car-share.md)** (`car-share`) - shared point-to-point and station-based multi-passenger vehicles.
+- **[Delivery robots](/modes/delivery-robots.md)** (`delivery-robots`) - autonomous and remotely driven goods delivery devices
+
+
+
+
+
+
+
+
+
+[Top][toc]
+
+## Mode Attributes
+
+Some fields used across MDS APIs are defined in more detail within each mode.
+
+### Journey ID
+
+The `journey_id` field allows multiple trip segments to be referentially linked together. See each [mode definition](#list-of-supported-modes) for details.
+
+### Journey Attributes
+
+The `journey_attributes` object allows additional mode-specific information about the nature of a journey to be described. See each [mode definition](#list-of-supported-modes) for details.
+
+### Trip Type
+
+The `trip_type` field allows the purpose of each trip segment to be described. See each [mode definition](#list-of-supported-modes) for details.
+
+### Trip Attributes
+
+The `trip_attributes` object allows additional mode-specific information about the nature of a trip to be described. It can return a list of JSON-formatted key/value pairs which correspond to the allowed attributes and values for the operative mode. See each [mode definition](#list-of-supported-modes) for details.
+
+_See more available trip attributes for any mode in the [trips object](/data-types.md#trips)._
+
+### Fare Attributes
+
+The `fare_attributes` object allows additional mode-specific information about fare information associated with the trip. It can return a list of JSON-formatted key/value pairs which correspond to the allowed attributes and values for the operative mode. See each [mode definition](#list-of-supported-modes) for details.
+
+_See more available fare attributes for any mode in the [trips object](/data-types.md#trips)._
+
+### Vehicle Attributes
+
+The `vehicle_attributes` object returns a list of JSON-formatted key/value pairs which correspond to the allowed attributes and values for the operative mode. For each mode, the allowed attributes and corresponding values are defined in the [mode definition](#list-of-supported-modes).
+
+_See more available vehicle attributes for any mode in the [vehicles object](/data-types.md#vehicles)._
+
+### Accessibility Attributes
+
+The `accessibility_attributes` object returns a list of JSON-formatted key/value pairs which correspond to the allowed accessibility attributes and values for the operative mode. For each mode, the allowed attributes and corresponding values are defined in the [mode definition](#list-of-supported-modes).
+
+[Top][toc]
+
+## Mode Properties
+
+While each mode is unique in its operational and business models, there are several areas where there are significant differences from one mode to the next. Each of these areas is defined in more detail within the mode, and each pull from a base of options defined in a central location.
+
+### Vehicle States
+
+Vehicle states are used to define the disposition of individual vehicles and fleets of vehicles. See [vehicle states](/modes/vehicle_states.md) for a list of possible values, and each [mode definition](#list-of-supported-modes) for details about which are used per mode.
+
+### Event Types
+
+Event types are the possible transitions between vehicle states. See [event types](/modes/event_types.md) for a list of possible values, and each [mode definition](#list-of-supported-modes) for details about which are used per mode.
+
+### State Transitions
+
+Possible combinations of how the `vehicle_state` changes in response to each `event_type`. See each [mode definition](#list-of-supported-modes) for a table of possible transition combinations.
+
+### State Machine Diagram
+
+The State Machine Diagram visually shows the state transitions. See each [mode definition](#list-of-supported-modes) for a diagram.
+
+[Top][toc]
+
+---
+
+[MDS Home][home]
+
+[home]: /README.md
+[modes]: /modes/README.md
+[micromobility]: /modes/micromobility.md
+[toc]: #table-of-contents
diff --git a/modes/car-share-state-machine-diagram.svg b/modes/car-share-state-machine-diagram.svg
new file mode 100644
index 00000000..365977f5
--- /dev/null
+++ b/modes/car-share-state-machine-diagram.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/modes/car-share.md b/modes/car-share.md
new file mode 100644
index 00000000..fb9e4b5a
--- /dev/null
+++ b/modes/car-share.md
@@ -0,0 +1,281 @@
+# Mobility Data Specification: **Car Share**
+
+
+
+**Car Share** refers to shared point-to-point and station-based mutli-passenger vehicles. Car Share typically has a driver who is the customer, and possibly one or more passengers or cargo.
+
+See the [modes overview](/modes) for how the mode specific information below applies across MDS.
+
+## Table of Contents
+
+- [Mode Attributes](#mode-attributes)
+ - [Mode ID](#mode-id)
+- [Trip Properties](#trip-properties)
+ - [Journey ID](#journey-id)
+ - [Journey Attributes](#journey-attributes)
+ - [Trip ID Requirements](#trip-id-requirements)
+ - [Trip Type](#trip-type)
+ - [Trip Attributes](#trip-attributes)
+ - [Fare Attributes](#fare-attributes)
+- [Vehicle Properties](#vehicle-properties)
+ - [Vehicle Attributes](#vehicle-attributes)
+ - [Accessibility Attributes](#accessibility-attributes)
+- [State Machine](#state-machine)
+ - [Vehicle States](#vehicle-states)
+ - [Event Types](#event-types)
+ - [Vehicle State Events](#vehicle-states-events)
+ - [State Machine Diagram](#state-machine-diagram)
+
+## Mode Attributes
+
+### Mode ID
+
+The short name identifier for Car Share used across MDS is `car-share`.
+
+[Top][toc]
+
+## Trip Properties
+
+_See more available trip and fare attributes for any mode used in the [trips object](/data-types.md#trips)._
+
+### Journey ID
+
+The `journey_id` field shall have a consistent value in overlapping trips for a single reservation period, e.g. trips taken by a customer between ignition states over the duration of their reservation. A reservation is the duration the customer has continuous exclusive access to the vehicle whether parked or in motion. Journeys may be point-to-point or multi-segment.
+
+- **Example 1**: customer makes a reservation and company delivers vehicle to customer, then one trip point-to-point by customer, ending reservation at destination
+- **Example 2**: customer reservation for multiple days with trips for errands, gas, entertainment, etc
+- **Example 3**: one trip point-to-point with an employee moving the vehicle to a new location for maintenance
+
+![Journey Diagram](https://i.imgur.com/FHxQLps.png)
+
+[Top][toc]
+
+### Journey Attributes
+
+The `journey_attributes` object **may** have the following key value pairs:
+
+- `reservation_id` (UUID, optional): unique identifier for an entire car share reservation, tied across multiple journeys and therefore trips.
+
+[Top][toc]
+
+### Trip ID Requirements
+
+Events require a valid `trip_id` in events where `event_types` contains `reservation_start`, `reservation_stop`, `trip_start`, `trip_resume`, `trip_end`,`trip_cancel`, `customer_cancellation`, `provider_cancellation`, or `driver_cancellation`.
+
+Additionally, `trip_id` is required if `event_types` contains a `trip_enter_jurisdiction` or `trip_leave_jurisdiction` event pertaining to a trip.
+
+[Top][toc]
+
+### Trip Type
+
+The `trip_type` field **must** have one of the following enumerated values:
+
+- `private`: a private trip made by one paying customer with one or more guests
+- `reservation`: en route to pickup a customer who has made a reservation, with no passengers in the vehicle
+- `empty`: vehicle movement with no customer (outside of other `trip_type` values) that may need to be reported, e.g. for maintenance
+
+[Top][toc]
+
+### Trip Attributes
+
+The `trip_attributes` object **may** have the following key value pairs:
+
+- `reservation_type` (enumerated, required): how was the vehicle reserved, one of `phone_dispatch`, `phone`, `text`, `app`
+- `app_name` (text, optional): name of the app used to reserve the vehicle which could be provider's app or 3rd party app
+- `permit_license_number` (string, optional) - The permit license number of the organization that dispatched the vehicle
+- `driver_id` (string, optional): Universal identifier of a specific driver, static across operators, like a driver's license number, for company employees in `reservation` or `empty` trip types, not `private` trips. Could also be used as a lookup in an agency's internal driver system.
+
+[Top][toc]
+
+### Fare Attributes
+
+The `fare_attributes` object **may** have the following key value pairs:
+
+- `payment_type` (enumerated, required): `account_number`, `cash`, `credit_card`, `mobile_app`, `no payment`, `phone`, `voucher`, `test`
+- `fare_type` (enumerated, required): `meter_fare`, `upfront_pricing`, `flat_rate`. Indicator of which rate was charged.
+- `tolls` (currency, optional) - Sum of any and all tolls charged for the trip, such as bridge tolls
+- `base_rate` (currency, optional) - Minimum fare to be charged as soon as the trip starts.
+- `exit_fee` (currency, optional) - Fee to exit location, like an airport
+- `other_fees` (currency, optional) - amount of any fees charged to the customer. Includes baggage fees, cleaning fee. Excludes other fees returned.
+- `tip` (currency, optional) - amount of tip paid by customer
+- `extra_amount` (currency, optional) - miscellaneous extra amounts charged to customer not covered by other fields.
+- `taxes` (currency, optional) - amount of taxes paid for the ride
+- `surcharge` (currency, optional) - any surcharge pricing
+
+[Top][toc]
+
+## Vehicle Properties
+
+_See more available vehicle attributes and accessibility options for any mode used in the [vehicles object](/data-types.md#vehicles)._
+
+### Vehicle Attributes
+
+The `vehicle_attributes` object **may** have the following key value pairs:
+
+- `year` (integer, required)
+- `make` (string, required)
+- `model` (string, required)
+- `color` (string, required)
+- `vin` (string, required) - the Vehicle Identification Number of the vehicle
+- `license_plate` (string, required) - the registered external license plate number of the vehicle
+- `inspection_date` (date YYYY-MM-DD, optional) - the date of the last inspection of the vehicle
+- `snow_shovel` (boolean, optional) - shovel for removing snow or ice from around vehicle or vehicle path
+- `snow_brush` (boolean, optional) - brushes for removing snow or ice from vehicle
+- `bike_rack` (boolean, optional) - car roof or trunk mounted bike rack
+- `park_access` (boolean, optional) - access pass to a national/regional/municipal park system
+- `toll_transponder` (boolean, optional) - toll transponder for national/regional toll system
+- `phone_charger` (boolean, optional) - a place to charge your phone
+- `sunshade` (boolean, optional) - sunshade available (i.e. for windshield)
+- `cargo_volume_capacity` (integer, optional) - Cargo volume available in the vehicle, expressed in liters. For cars, it corresponds to the space between the boot floor, including the storage under the hatch, to the rear shelf in the trunk.
+- `cargo_load_capacity` (integer, optional) - The capacity of the vehicle cargo space (excluding passengers), expressed in kilograms.
+- `door_count` (integer, optional) - number of doors this vehicle type has
+- `wheel_count` (integer, optional) - number of wheels this vehicle type has
+- `air_conditioning` (boolean, optional) - vehicle has air conditioning
+- `gear_switch` (enum, optional) - one of `automatic`, `manual`
+- `convertible` (boolean, optional) - vehicle has a retractable roof
+- `cruise_control` (boolean, optional) - vehicle has a cruise control system
+- `navigation` (boolean, optional) - vehicle has a built-in navigation system
+
+Note many of these attributes come from fields in [GBFS vehicle_types](https://github.com/MobilityData/gbfs/blob/v2.3/gbfs.md#vehicle_typesjson).
+
+[Top][toc]
+
+### Accessibility Attributes
+
+This `accessibility_attributes` enum represents the accessibility attributes available on a given vehicle, or the accessibility attributes utilized for a given trip.
+
+| `accessibility_attributes` | Description |
+|----------------------------|---------------------------------------|
+| `wheelchair_accessible` | This vehicle is wheelchair accessible |
+
+[Top][toc]
+
+## State Machine
+
+### Vehicle States
+
+Valid car share vehicle states are
+
+- `removed`
+- `available`
+- `non_operational`
+- `reserved`
+- `on_trip`
+- `stopped`
+- `non_contactable`
+- `elsewhere`
+
+See [Vehicle States][vehicle-states] for descriptions.
+
+[Top][toc]
+
+### Event Types
+
+Valid car share vehicle event types are
+
+- `charging_start`
+- `charging_end`
+- `comms_lost`
+- `comms_restored`
+- `customer_cancellation`
+- `driver_cancellation`
+- `fueling_start`
+- `fueling_end`
+- `maintenance`
+- `maintenance_pick_up`
+- `maintenance_end`
+- `provider_cancellation`
+- `remote_start`
+- `remote_end`
+- `reservation_stop`
+- `reservation_start`
+- `service_end`
+- `service_start`
+- `trip_end`
+- `trip_enter_jurisdiction`
+- `trip_leave_jurisdiction`
+- `trip_resume`
+- `trip_start`
+- `trip_stop`
+
+See vehicle [Event Types][vehicle-events] for descriptions.
+
+[Top][toc]
+
+### Vehicle States Events
+
+This is the list of `vehicle_state` and `event_type` pairings that constitute the valid transitions of the vehicle state machine.
+
+| **From** `vehicle_state` | **To** `vehicle_state` | `trip_state` | `event_type` | Description |
+| ------------------------ | ---------------------- | ------------ | ------------------------ | --------------------------------------------------------------------------------------------------------------- |
+| `available` | `elsewhere` | N/A | `trip_leave_jurisdiction` | The vehicle has left jurisdictional boundaries while available for-hire |
+| `available` | `non_contactable` | N/A | `comms_lost` | The vehicle has went out of comms while available for-use |
+| `available` | `non_operational` | N/A | `service_end` | The vehicle has went out of service (is unavailable for-hire) |
+| `available` | `reserved` | `reserved` | `reservation_start` | The vehicle was reserved by a passenger |
+| `elsewhere` | `available` | N/A | `trip_enter_jurisdiction` | The vehicle has entered jurisdictional boundaries while available for-hire |
+| `elsewhere` | `non_contactable` | N/A | `comms_lost` | The vehicle has went out of comms while outside of jurisdictional boundaries |
+| `elsewhere` | `non_operational` | N/A | `trip_enter_jurisdiction` | The vehicle has entered jurisdictional boundaries while not operating commercially |
+| `elsewhere` | `on_trip` | `on_trip` | `trip_enter_jurisdiction` | The vehicle has entered jurisdictional boundaries while on a trip |
+| `elsewhere` | `reserved` | N/A | `trip_enter_jurisdiction` | The vehicle has entered jurisdictional boundaries while reserved by a customer |
+| `non_contactable` | `available` | N/A | `comms_restored` | The vehicle has come back into comms while available for-hire |
+| `non_contactable` | `elsewhere` | N/A | `comms_restored` | The vehicle has come back into comms while outside of jurisdictional boundaries |
+| `non_contactable` | `non_operational` | N/A | `comms_restored` | The vehicle has come back into comms while not operating commercially |
+| `non_contactable` | `on_trip` | `on_trip` | `comms_restored` | The vehicle has come back into comms while on a trip |
+| `non_contactable` | `removed` | N/A | `comms_restored` | The vehicle has come back into comms while removed |
+| `non_contactable` | `reserved` | `reserved` | `comms_restored` | The vehicle has come back into comms while reserved by a passenger |
+| `non_contactable` | `stopped` | `stopped` | `comms_restored` | The vehicle has come back into comms while stopped |
+| `non_operational` | `available` | N/A | `service_start` | The vehicle has went into service (is available for-hire) |
+| `non_operational` | `elsewhere` | N/A | `trip_leave_jurisdiction` | The vehicle has left jurisdictional boundaries while not operating commercially |
+| `non_operational` | `non_contactable` | N/A | `comms_lost` | The vehicle has went out of comms 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_pick_up` | The vehicle has entered the depot for maintenance |
+| `non_operational` | `removed` | N/A | `maintenance` | The vehicle is undergoing maintenance on site |
+| `on_trip` | `elsewhere` | N/A | `trip_leave_jurisdiction` | The vehicle has left jurisdictional boundaries while on a trip |
+| `on_trip` | `non_contactable` | N/A | `comms_lost` | The vehicle has gone out of comms while on a trip |
+| `on_trip` | `stopped` | `stopped` | `trip_stop` | The vehicle has stopped while on a trip |
+| `removed` | `non_contactable` | N/A | `comms_lost` | The vehicle has gone out of comms while removed |
+| `removed` | `non_operational` | N/A | `maintenance_end` | The vehicle maintenance work has ended |
+| `removed` | `non_operational` | N/A | `recommissioned` | The vehicle has been re-added to the Provider's fleet after being previously `decommissioned` |
+| `reserved` | `available` | N/A | `driver_cancellation` | The driver has canceled the reservation |
+| `reserved` | `available` | N/A | `customer_cancellation` | The customer has canceled the reservation |
+| `reserved` | `available` | N/A | `provider_cancellation` | The provider has canceled the reservation |
+| `reserved` | `elsewhere` | N/A | `trip_leave_jurisdiction` | The vehicle has left the jurisdiction while in a reservation |
+| `reserved` | `non_contactable` | N/A | `comms_lost` | The vehicle went out of comms while being reserved by a passenger |
+| `reserved` | `stopped` | `stopped` | `reservation_stop` | The vehicle has stopped to pick up the passenger |
+| `stopped` | `available` | N/A | `driver_cancellation` | The driver has canceled the trip while either waiting for the passenger, or dropping them off |
+| `stopped` | `available` | N/A | `customer_cancellation` | The customer has canceled the trip while the vehicle is waiting to pick them up, or they are being dropped off |
+| `stopped` | `available` | N/A | `provider_cancellation` | The provider has canceled the trip while the vehicle is waiting for a passenger, or dropping them off |
+| `stopped` | `available` | N/A | `trip_end` | The trip has been successfully completed |
+| `stopped` | `non_contactable` | N/A | `comms_lost` | The vehicle has went out of comms while stopped |
+| `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` | `stopped` | `stopped` | `charging_end` | End charging the device battery |
+| `stopped` | `stopped` | `stopped` | `charging_start` | Start charging the device battery |
+| `stopped` | `stopped` | `stopped` | `fueling_end` | End fueling the device with physical fuel |
+| `stopped` | `stopped` | `stopped` | `fueling_start` | Start fueling the device with physical fuel |
+| `stopped` | `stopped` | `stopped` | `remote_end` | Remotely stop the engine while vehicle is already stopped |
+| `stopped` | `stopped` | `stopped` | `remote_start` | Remotely start the engine while vehicle is stopped, usually to charge battery or warm up |
+
+[Top][toc]
+
+### State Machine Diagram
+
+This *State Machine Diagram* shows how `vehicle_state` and `event_type` relate to each other and how vehicles can transition between states. See [Google Slides](https://docs.google.com/presentation/d/1fHdq1efbN5GSFDLF4en-oA_BYPXQKbbIbHff6iROJKA/edit#slide=id.g2072486e468_1_300) for the source file.
+
+![Car Share State Machine Diagram](car-share-state-machine-diagram.svg)
+
+[Top][toc]
+
+---
+
+[Modes Overview][modes]
+
+---
+
+[MDS Home][home]
+
+[home]: /README.md
+[modes]: /modes/README.md
+[toc]: #table-of-contents
+[vehicle-states]: /modes/vehicle_states.md
+[vehicle-events]: /modes/event_types.md
diff --git a/modes/delivery-robots-state-machine-diagram.svg b/modes/delivery-robots-state-machine-diagram.svg
new file mode 100644
index 00000000..9e2dfa7c
--- /dev/null
+++ b/modes/delivery-robots-state-machine-diagram.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/modes/delivery-robots.md b/modes/delivery-robots.md
new file mode 100644
index 00000000..b7908445
--- /dev/null
+++ b/modes/delivery-robots.md
@@ -0,0 +1,302 @@
+# Mobility Data Specification: **Delivery Robots**
+
+
+
+**Delivery Robots** refers to autonomous and remotely driven goods delivery devices. There can be one or multiple orders on different trips at the same time. The state machine tracks the trip states of the orders separately from the vehicle state.
+
+See the [modes overview](/modes) for how the mode specific information below applies across MDS.
+
+## Robots Vs Other Delivery Types
+
+Autonomous and remotely piloted delivery robots do not require a driver, whereas other forms of deliveries may, e.g. in a commercial or private car, truck, bike, etc. For this MDS release, this mode is limited to deliveries where a human driver is not on board the vehicle doing the delivery, and human passengers are not being transported.
+
+## Table of Contents
+
+- [Mode Attributes](#mode-attributes)
+ - [Mode ID](#mode-id)
+- [Trip Properties](#trip-properties)
+ - [Journey ID](#journey-id)
+ - [Journey Attributes](#journey-attributes)
+ - [Trip ID Requirements](#trip-id-requirements)
+ - [Trip Type](#trip-type)
+ - [Trip Attributes](#trip-attributes)
+ - [Fare Attributes](#fare-attributes)
+- [Vehicle Properties](#vehicle-properties)
+ - [Vehicle Attributes](#vehicle-attributes)
+ - [Accessibility Attributes](#accessibility-attributes)
+- [State Machine](#state-machine)
+ - [Vehicle States](#vehicle-states)
+ - [Event Types](#event-types)
+ - [Vehicle State Events](#vehicle-states-events)
+ - [State Machine Diagram](#state-machine-diagram)
+
+## Mode Attributes
+
+### Mode ID
+
+The short name identifier for deliveries used across MDS is `delivery-robots`.
+
+[Top][toc]
+
+## Trip Properties
+
+_See more available trip and fare attributes for any mode used in the [trips object](/data-types.md#trips)._
+
+### Journey ID
+
+The `journey_id` field shall have a consistent value in overlapping trips. Journeys may be point-to-point, multi-segment, or multi-segment overlapping.
+
+- **Example 1**: delivery to a single location, then return
+- **Example 2**: three overlapping delivery trips in the same journey
+
+![Journey Diagram](https://i.imgur.com/Mx8jVQq.png)
+
+[Top][toc]
+
+### Journey Attributes
+
+The `journey_attributes` object is not used in this mode.
+
+
+[Top][toc]
+
+### Trip ID Requirements
+
+Events require a valid `trip_id` in events where `event_types` contains `reservation_start`, `reservation_stop`, `trip_start`, `trip_pause`, `trip_resume`, `trip_end`,`trip_cancel`, `customer_cancellation`, `provider_cancellation`, or `driver_cancellation`.
+
+For the robots, the notion of driver does not exist, even when remotely operated.
+
+Additionally, `trip_id` is required if `event_types` contains a `trip_enter_jurisdiction` or `trip_leave_jurisdiction` event pertaining to a trip.
+
+### Trip Type
+
+The `trip_type` field is used to describe the trip itself.
+
+The `trip_type` field **must** have one of the following enumerated values:
+
+- `delivery`: making a delivery
+- `return`: returning to home location or next trip start
+- `advertising`: displaying advertising and not making a delivery
+- `mapping`: mapping the environment and not making a delivery
+- `roaming`: moving in right of way but not in another trip_type
+
+[Top][toc]
+
+### Trip Attributes
+
+The `trip_attributes` object **may** have the following key value pairs:
+
+- `driver_type` (enum, required): type of driver operating the device: `human`, `semi_autonomous`, `autonomous`
+- `driver_id` (UUID, optional): consistent unique identifier of the primary driver. Could be based on software version or an internal human driver id.
+- `app_name` (text, optional): name of the app used to reserve the trip which could be provider's app or 3rd party app
+- `requested_time` ([Timestamp][ts], optional): when the customer requested the trip
+- `has_payload` (boolean, optional): is there any payload for any delivery included in the device at trip start. 1 = loaded, 0 = empty
+- `range` (integer, optional): estimated range in meters based on energy levels in device at trip start
+- `identification_required` (boolean, optional): does the cargo require providing customer identification before trip start or upon delivery?
+
+[Top][toc]
+
+### Fare Attributes
+
+The `fare_attributes` object **may** have the following key value pairs:
+
+- `payment_type` (enumerated, optional): `account_number`, `cash`, `credit_card`, `mobile_app`, `no payment`, `phone`, `voucher`, `test`
+- `price` (currency, optional): Total price of the order
+
+[Top][toc]
+
+## Vehicle Properties
+
+_See more available vehicle attributes and accessibility attributes for any mode used in the [vehicles object](/data-types.md#vehicles)._
+
+### Vehicle Attributes
+
+The `vehicle_attributes` object **may** have the following key value pairs:
+
+- `year` (integer, optional)
+- `make` (string, optional)
+- `model` (string, optional)
+- `color` (string, optional)
+- `inspection_date` (date YYYY-MM-DD, optional): the date of the last inspection of the vehicle
+- `equipped_cameras` (integer, optional): number of cameras equipped on device
+- `equipped_lighting` (integer, optional): number of lights used to illuminate the environment on the the device
+- `wheel_count` (integer, optional): number of wheels on the device
+- `width` (integer, optional): width in meters of the device
+- `length` (integer, optional): length in meters of the device
+- `height` (integer, optional): height in meters of the device (minus flexible elements like flags)
+- `weight` (integer, optional): weight in kilograms rounded up of the device not including cargo
+- `top_speed` (integer, optional): theoretical top speed in meters per second of the device
+- `storage_capacity` (integer, optional): cubic centimeters of cargo space available not including any cargo
+
+[Top][toc]
+
+### Accessibility Attributes
+
+The `accessibility_attributes` object **may** have the following key value pairs:
+
+- `audio_cue` (boolean, optional): is the device equipped with audio cues upon delivery
+- `visual_cue` (boolean, optional): is the device equipped with visual cues upon delivery
+- `remote_open` (boolean, optional): can the device door be remotely opened to retrieve cargo upon delivery
+
+[Top][toc]
+
+## State Machine
+
+### Vehicle States
+
+Valid delivery vehicle states are
+
+- `removed`
+- `available`
+- `non_operational`
+- `reserved`
+- `on_trip`
+- `stopped`
+- `non_contactable`
+- `missing`
+- `elsewhere`
+
+See [Vehicle States][vehicle-states] for descriptions.
+
+[Top][toc]
+
+### Event Types
+
+Valid delivery vehicle event types are
+
+- `comms_lost`
+- `comms_restored`
+- `compliance_pick_up`
+- `decommissioned`
+- `not_located`
+- `located`
+- `maintenance`
+- `maintenance_pick_up`
+- `maintenance_end`
+- `driver_cancellation`
+- `order_drop_off`
+- `order_pick_up`
+- `customer_cancellation`
+- `provider_cancellation`
+- `recommission`
+- `reservation_start`
+- `reservation_stop`
+- `service_end`
+- `service_start`
+- `trip_end`
+- `trip_enter_jurisdiction`
+- `trip_leave_jurisdiction`
+- `trip_resume`
+- `trip_start`
+- `trip_pause`
+
+See vehicle [Event Types][vehicle-events] for descriptions.
+
+[Top][toc]
+
+### Vehicle States Events
+
+This is the list of `vehicle_state` and `event_type` pairings that constitute the valid transitions of the vehicle state machine.
+
+| **From** `vehicle_state` | **To** `vehicle_state` | `trip_state` | `event_type` | Description |
+| ------------------------ | ---------------------- | ------------ | ----------------------- | --------------------------------------------------------------------------------------------- |
+| `available` | `elsewhere` | N/A | `trip_leave_jurisdiction` | The vehicle has left jurisdictional boundaries while available for-hire |
+| `available` | `non_contactable` | N/A | `comms_lost` | The vehicle has gone out of comms while available for-use |
+| `available` | `non_operational` | N/A | `service_end` | The vehicle has gone out of service (is unavailable for-hire) |
+| `available` | `reserved` | `reserved` | `reservation_start` | The vehicle was reserved by a customer |
+| `elsewhere` | `available` | N/A | `trip_enter_jurisdiction` | The vehicle has entered jurisdictional boundaries while available for-hire |
+| `elsewhere` | `non_contactable` | N/A | `comms_lost` | The vehicle has gone out of comms while outside of jurisdictional boundaries |
+| `elsewhere` | `non_operational` | N/A | `trip_enter_jurisdiction` | The vehicle has entered jurisdictional boundaries while not operating commercially |
+| `elsewhere` | `on_trip` | `on_trip` | `trip_enter_jurisdiction` | The vehicle has entered jurisdictional boundaries while on a trip |
+| `elsewhere` | `reserved` | N/A | `trip_enter_jurisdiction` | The vehicle has entered jurisdictional boundaries while reserved by a customer |
+| `missing` | `available` | N/A | `located` | The vehicle has been located while available for-hire |
+| `missing` | `elsewhere` | N/A | `located` | The vehicle has been located while outside of jurisdictional boundaries |
+| `missing` | `non_operational` | N/A | `located` | The vehicle has been located while not operating commercially |
+| `missing` | `on_trip` | `on_trip` | `located` | The vehicle has been located while on a trip |
+| `missing` | `removed` | N/A | `located` | The vehicle has been located while removed |
+| `missing` | `reserved` | `reserved` | `located` | The vehicle has been located while reserved by a customer |
+| `missing` | `stopped` | `stopped` | `located` | The vehicle has been located while stopped |
+| `non_contactable` | `available` | N/A | `comms_restored` | The vehicle has come back into comms while available for-hire |
+| `non_contactable` | `elsewhere` | N/A | `comms_restored` | The vehicle has come back into comms while outside of jurisdictional boundaries |
+| `non_contactable` | `missing` | N/A | `not_located` | The vehicle has gone missing after a period of lost comms |
+| `non_contactable` | `non_operational` | N/A | `comms_restored` | The vehicle has come back into comms while not operating commercially |
+| `non_contactable` | `on_trip` | `on_trip` | `comms_restored` | The vehicle has come back into comms while on a trip |
+| `non_contactable` | `removed` | N/A | `comms_restored` | The vehicle has come back into comms while removed |
+| `non_contactable` | `reserved` | `reserved` | `comms_restored` | The vehicle has come back into comms while reserved by a customer |
+| `non_contactable` | `stopped` | `stopped` | `comms_restored` | The vehicle has come back into comms while stopped |
+| `non_operational` | `available` | N/A | `service_start` | The vehicle has gone into service (is available for-hire) |
+| `non_operational` | `elsewhere` | N/A | `trip_leave_jurisdiction` | The vehicle has left jurisdictional boundaries while not operating commercially |
+| `non_operational` | `non_contactable` | N/A | `comms_lost` | The vehicle has gone out of comms while not operating commercially |
+| `non_operational` | `non_operational` | N/A | `maintenance` | The vehicle has maintenance performed on site |
+| `non_operational` | `non_operational` | N/A | `maintenance_end` | Maintenance is complete |
+| `non_operational` | `removed` | N/A | `maintenance_pick_up` | The vehicle has entered the depot for maintenance |
+| `non_operational` | `removed` | N/A | `decommissioned` | The vehicle has been removed from the Provider's fleet |
+| `on_trip` | `elsewhere` | N/A | `trip_leave_jurisdiction` | The vehicle has left jurisdictional boundaries while on a trip |
+| `on_trip` | `non_contactable` | N/A | `comms_lost` | The vehicle has gone out of comms while on a trip to pick up the order |
+| `on_trip` | `stopped` | N/A | `order_drop_off` | The vehicle is at the customer's place and is waiting for them |
+| `on_trip` | `stopped` | `stopped` | `order_pick_up` | The vehicle has come to pick up the order at the restaurant |
+| `on_trip` | `stopped` | `stopped` | `trip_pause` | The vehicle has paused while on a trip |
+| `removed` | `non_contactable` | N/A | `comms_lost` | The vehicle has gone out of comms while removed |
+| `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` |
+| `reserved` | `available` | N/A | `customer_cancellation` | The customer has canceled the reservation |
+| `reserved` | `available` | N/A | `driver_cancellation` | The driver has canceled the reservation |
+| `reserved` | `available` | N/A | `provider_cancellation` | The provider has canceled the reservation |
+| `reserved` | `elsewhere` | N/A | `trip_leave_jurisdiction` | The vehicle has left the jurisdiction while in a reservation |
+| `reserved` | `non_contactable` | N/A | `comms_lost` | The vehicle has gone of comms while being reserved by a customer |
+| `reserved` | `stopped` | `stopped` | `reservation_stop` | The vehicle has stopped to pickup reservation |
+| `stopped` | `available` | N/A | `customer_cancellation` | The customer has canceled the trip while the vehicle is waiting |
+| `stopped` | `available` | N/A | `driver_cancellation` | The driver has canceled the trip while waiting |
+| `stopped` | `available` | N/A | `provider_cancellation` | The provider has canceled the trip while the vehicle is waiting |
+| `stopped` | `available` | N/A | `trip_end` | The trip has been successfully completed |
+| `stopped` | `non_contactable` | N/A | `comms_lost` | The vehicle has gone out of comms while stopped |
+| `stopped` | `on_trip` | `on_trip` | `trip_resume` | Resume a trip that was previously paused (e.g. picking up an order) |
+| `stopped` | `on_trip` | `on_trip` | `trip_start` | Start a trip |
+
+[Top][toc]
+
+### State Machine Diagram
+
+This *State Machine Diagram* shows how `vehicle_state` and `event_type` relate to each other and how vehicles can transition between states. See [Google Slides](https://docs.google.com/presentation/d/1fHdq1efbN5GSFDLF4en-oA_BYPXQKbbIbHff6iROJKA/edit#slide=id.g207ec9d0152_0_0) for the source file.
+
+![Delivery Robots State Machine Diagram](delivery-robots-state-machine-diagram.svg)
+
+#### Delivery Robots State Notes
+
+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 = for the one vehicle, all on-going trips which are 'delivery' or undefined trips (we do not take into account 'roaming', 'return' or 'advertising' trips)
+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’
+else:
+if t=[]:
+ v = ‘available’
+
+```
+`trip_state` mappings should be the same as in the table above.
+
+[Top][toc]
+
+---
+
+[Modes Overview][modes]
+
+---
+
+[MDS Home][home]
+
+[home]: /README.md
+[modes]: /modes/README.md
+[toc]: #table-of-contents
+[ts]: /general-information.md#timestamps
+[vehicle-states]: /modes/vehicle_states.md
+[vehicle-events]: /modes/event_types.md
diff --git a/modes/event_types.md b/modes/event_types.md
new file mode 100644
index 00000000..54eb29df
--- /dev/null
+++ b/modes/event_types.md
@@ -0,0 +1,74 @@
+# Mobility Data Specification: **Event Types**
+
+This file defines all possible `event_type`s that can be used in state machines across all MDS modes. Each mode will use some subset of these events. See individual [mode definitions](/modes#list-of-supported-modes) for additional details specific to that mode.
+
+As with all MDS definitions, they should be described in a way that maximizes their relevance to multiple modes whenever possible.
+
+| `event_type` | Description |
+| ------------------------- | ----------------------------------------------------------------------------------------------- |
+| `agency_drop_off` | Drop off by the agency |
+| `agency_pick_up` | Pick up by the agency, e.g. impound |
+| `battery_charged` | Battery charged (entering service) |
+| `battery_low` | Battery low (exiting service) |
+| `changed_geographies` | Geography change per [Geography Driven Events](/general-information.md#geography-driven-events) |
+| `charging_start` | Battery start charging |
+| `charging_end` | Battery end charging |
+| `comms_lost` | Communications lost |
+| `comms_restored` | Communications restored |
+| `compliance_pick_up` | Pick up for compliance (rule violation) |
+| `customer_cancellation` | Customer cancelled a trip |
+| `decommissioned` | Decommissioned |
+| `driver_cancellation` | Driver cancelled a trip |
+| `fueling_start` | Fueling starts |
+| `fueling_end` | Fueling ends |
+| `located` | Location found (opposite of Missing) |
+| `maintenance` | Start general maintenance in right of way |
+| `maintenance_pick_up` | Start pick up for maintenance outside of right of way |
+| `maintenance_end` | End of maintenance |
+| `not_located` | Location unknown |
+| `off_hours` | Off hours - end of service |
+| `on_hours` | On hours - start of service |
+| `order_drop_off` | Pick up of the order at business |
+| `order_pick_up` | Delivery of the order at the customer location |
+| `passenger_cancellation` | Passenger cancelled a trip |
+| `provider_cancellation` | Provider cancelled a trip |
+| `provider_drop_off` | Drop off by the provider |
+| `rebalance_pick_up` | Pick up for rebalancing |
+| `recommission` | Recommissioned |
+| `remote_start` | Remotely start the engine |
+| `remote_end` | Remotely stop the engine |
+| `reservation_cancel` | Reservation cancelled before trip |
+| `reservation_start` | Reservation started |
+| `reservation_stop` | Reservation stopped temporarily |
+| `service_end` | End of service |
+| `system_start` | Start of service |
+| `system_resume` | Resume system operations, e.g. start of day |
+| `system_suspend` | Suspend system operations, e.g. end of day |
+| `trip_cancel` | Cancel trip |
+| `trip_end` | End trip |
+| `trip_enter_jurisdiction` | Trip enters a jurisdiction |
+| `trip_leave_jurisdiction` | Trip leaves a jurisdiction |
+| `trip_pause` | Pause trip temporarily but do not end trip |
+| `trip_resume` | Resume trip |
+| `trip_start` | Start trip |
+| `trip_stop` | Stop trip |
+| `unspecified` | Unspecified |
+
+### Limitations on the Use of Certain Values
+
+MDS is intended to communicate the provider's best available information to regulators. However there may be legitimate circumstances where providers do not have definitive or current information about devices on the ground. MDS incorporates some values to convey these situations. These vehicle state and event type values are to be used sparingly and temporarily, and are not meant for repeated or prolonged use. These values exist to create logical coherence within MDS about vehicles that are operating abnormally or are out of communication. When a more accurate value is known, the MDS API should be updated with the latest information. Cities may add language to their Service Level Agreements (SLAs) that minimize the use of these values by providers.
+
+#### Event Type: Unspecified
+
+The `unspecified` event type state transition means that the vehicle has moved from one state to another for an unspecified or unknown reason. It is used when there are multiple possible event types between states, but the reason for the transition is not clear. It is expected that `unspecified` will not be used frequently, and only for short periods of time. Cities may put in place specific limitations via an SLA. When more accurate information becomes available to the provider, it should be updated in the MDS data by sending a new event type state transition with the current timestamp.
+
+---
+
+[Modes Overview][modes]
+
+---
+
+[MDS Home][home]
+
+[home]: /README.md
+[modes]: /modes/README.md
diff --git a/modes/micromobility-state-machine-diagram.svg b/modes/micromobility-state-machine-diagram.svg
new file mode 100644
index 00000000..e870daab
--- /dev/null
+++ b/modes/micromobility-state-machine-diagram.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/modes/micromobility.md b/modes/micromobility.md
new file mode 100644
index 00000000..4f3d1ae9
--- /dev/null
+++ b/modes/micromobility.md
@@ -0,0 +1,244 @@
+# Mobility Data Specification: **Micromobility**
+
+
+
+"**Micromobility**" refers to single-occupancy modes of docked or dockless transportation such as e-scooters, e-bikes, and human-powered bikes.
+
+See the [modes overview](/modes) for how the mode specific information below applies across MDS.
+
+## Table of Contents
+
+- [Mode Attributes](#mode-attributes)
+ - [Mode ID](#mode-id)
+- [Trip Properties](#trip-properties)
+ - [Journey ID](#journey-id)
+ - [Journey Attributes](#journey-attributes)
+ - [Trip ID Requirements](#trip-id-requirements)
+ - [Trip Type](#trip-type)
+ - [Trip Attributes](#trip-attributes)
+ - [Fare Attributes](#fare-attributes)
+- [Vehicle Properties](#vehicle-properties)
+ - [Vehicle Attributes](#vehicle-attributes)
+ - [Accessibility Attributes](#accessibility-attributes)
+- [State Machine](#state-machine)
+ - [Vehicle States](#vehicle-states)
+ - [Event Types](#event-types)
+ - [Vehicle State Events](#vehicle-states-events)
+ - [State Machine Diagram](#state-machine-diagram)
+
+## Mode Attributes
+
+### Mode ID
+
+The short name identifier for Micromobility used across MDS is `micromobility`.
+
+[Top][toc]
+
+## Trip Properties
+
+_See more available trip and fare attributes for any mode used in the [trips object](/data-types.md#trips)._
+
+### Journey ID
+
+The `journey_id` field is not used in this mode. Trips are point-to-point.
+
+[Top][toc]
+
+### Journey Attributes
+
+The `journey_attributes` object is not used in this mode.
+
+[Top][toc]
+
+### Trip ID Requirements
+
+Required in events if `event_types` contains `trip_start`, `trip_end`, `trip_cancel`, `trip_enter_jurisdiction`, or `trip_leave_jurisdiction`.
+
+[Top][toc]
+
+### Trip Type
+
+The `trip_type` field **may** have one of the following values:
+
+- `rider`: a single rider is taking a trip
+- `rebalance`: vehicle ridden by operator to rebalance
+- `maintenance`: vehicles ridden by operator to perform maintenance or check operation
+
+[Top][toc]
+
+### Trip Attributes
+
+The `trip_attributes` object is not used in this mode.
+
+[Top][toc]
+
+### Fare Attributes
+
+The `fare_attributes` object is not used in this mode.
+
+[Top][toc]
+
+## Vehicle Properties
+
+_See more available vehicle attributes and accessibility attributes for any mode used in the [vehicles object](/data-types.md#vehicles)._
+
+### Vehicle Attributes
+
+The `vehicle_attributes` object **may** have the following key value pairs:
+
+- `year` (integer, optional)
+- `make` (string, optional)
+- `model` (string, optional)
+
+[Top][toc]
+
+### Accessibility Attributes
+
+This `accessibility_attributes` enum represents the accessibility attributes available on a given vehicle, or the accessibility attributes utilized for a given trip.
+
+| `accessibility_attributes` | Description |
+|----------------------------|---------------------------------------|
+| `adaptive` | This vehicle is accessible to people with various physical disabilities, and may include three wheels or be self balancing, a seat, or a basket or storage area |
+
+[Top][toc]
+
+## State Machine
+
+### Vehicle States
+
+Valid micromobility vehicle states are
+
+- `removed`
+- `available`
+- `non_operational`
+- `reserved`
+- `on_trip`
+- `non_contactable`
+- `missing`
+- `elsewhere`
+
+See [Vehicle States][vehicle-states] for descriptions.
+
+[Top][toc]
+
+### Event Types
+
+Valid micromobility vehicle event types are
+
+- `agency_drop_off`
+- `agency_pick_up`
+- `battery_charged`
+- `battery_low`
+- `changed_geographies`
+- `comms_lost`
+- `comms_restored`
+- `compliance_pick_up`
+- `decommissioned`
+- `not_located`
+- `located`
+- `maintenance`
+- `maintenance_pick_up`
+- `off_hours`
+- `on_hours`
+- `provider_drop_off`
+- `rebalance_pick_up`
+- `reservation_cancel`
+- `reservation_start`
+- `system_resume`
+- `system_suspend`
+- `trip_cancel`
+- `trip_end`
+- `trip_enter_jurisdiction`
+- `trip_leave_jurisdiction`
+- `trip_start`
+- `unspecified`
+
+Note that providers should make best-effort to map their business logic onto these states, which are meant to provide a view of the fleet to an agency. But if an agency does not perform `agency_drop_off` or `agency_pick_up`, for example, they need not be included in the provider's implementation.
+
+See vehicle [Event Types][vehicle-events] for descriptions.
+
+[Top][toc]
+
+### Vehicle State Events
+
+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, 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.
+
+Vehicles can enter the `non_contactable` state to and from any other state with the following event types: any state can go to `non_contactable` with event type `comms_lost` or `unspecified`, and `non_contactable` can go to any state with event type `comms_restored` of `unspecified`.
+
+Vehicles can exit the `missing` state to any other state with the following event types: `missing` can go to any state with event type `located` or `unspecified`.
+| **From** `vehicle_state` | **To** `vehicle_state` | `event_type` | Description |
+|-------------------------------------------------------------------------------|--------------------|---------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `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` | `reserved` | `reservation_start` | The vehicle was reserved for use by a customer |
+| `available` | `non_operational` | `system_suspend` | The vehicle is not available because of e.g. weather or temporary regulations |
+| `available`, `elsewhere`, `non_operational`, `on_trip`, `removed`, `reserved` | `non_contactable` | `comms_lost` | The vehicle is unable to transmit its GPS location or other status information |
+| `available`, `elsewhere`, `non_operational`, `on_trip`, `removed`, `reserved` | `non_contactable` | `unspecified` | The provider cannot definitively (yet) specify the reason for the non_contactable state |
+| `available`, `non_contactable`, `missing` | `non_operational` | `unspecified` | The vehicle became unavailable, but the Provider cannot definitively (yet) specify the reason. |
+| `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`, `elsewhere` | `removed` | `maintenance_pick_up` | The provider picked up the vehicle to service it |
+| `available`, `non_operational`, `elsewhere` | `removed` | `rebalance_pick_up` | The provider picked up the vehicle for rebalancing purposes |
+| `available`, `non_operational`, `elsewhere`, `non_contactable`, `missing` | `removed` | `agency_pick_up` | An agency picked up the vehicle for some reason, e.g. illegal placement |
+| `available`, `non_operational`, `elsewhere`, `non_contactable`, `missing` | `removed` | `decommissioned` | The provider has removed the vehicle from its fleet |
+| `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 |
+| `missing` | `available` | `located` | The vehicle has been located by the provider |
+| `missing` | `elsewhere` | `located` | The vehicle has been located by the provider |
+| `missing` | `non_operational` | `located` | The vehicle has been located by the provider |
+| `missing` | `on_trip` | `located` | The vehicle has been located by the provider |
+| `missing` | `removed` | `located` | The vehicle has been located by the provider |
+| `missing` | `reserved` | `located` | The vehicle has been located by the provider |
+| `non_contactable` | `available` | `comms_restored` | The vehicle transmitted status information after a period of being out of communication. |
+| `non_contactable` | `elsewhere` | `comms_restored` | The vehicle transmitted status information after a period of being out of communication. |
+| `non_contactable` | `non_operational` | `comms_restored` | The vehicle transmitted status information after a period of being out of communication |
+| `non_contactable` | `on_trip` | `comms_restored` | The vehicle transmitted status information after a period of being out of communication. |
+| `non_contactable` | `removed` | `comms_restored` | The vehicle transmitted status information after a period of being in an non_contactable state |
+| `non_contactable` | `reserved` | `comms_restored` | The vehicle transmitted status information after a period of being out of communication. |
+| `non_contactable` | `missing` | `not_located` | The vehicle is not at its last reported GPS location, or that location is wildly in error |
+| `non_contactable` | `missing` | `unspecified` | The provider cannot definitively (yet) specify the reason for the missing state |
+| `non_contactable`, `missing` | `elsewhere` | `unspecified` | The provider cannot definitively state how a vehicle went `elsewhere`. |
+| `non_contactable`, `missing` | `on_trip` | `unspecified` | The provider cannot definitively state how a vehicle started a trip. |
+| `non_contactable`, `missing` | `reserved` | `unspecified` | The provider cannot definitively state how a vehicle became reserved. |
+| `non_contactable`, `missing`, `non_operational`, `available`, `elsewhere` | `removed` | `unspecified` | The vehicle was removed, but the provider cannot definitively (yet) specify the reason |
+| `non_operational` | `available` | `battery_charged` | The vehicle became available because its battery is now charged. |
+| `non_operational` | `available` | `maintenance` | The vehicle was previously in need of maintenance |
+| `non_operational` | `available` | `on_hours` | The vehicle has entered operating hours (per the regulator or per the provider) |
+| `non_operational` | `available` | `system_resume` | The vehicle is available because e.g. weather suspension or temporary regulations ended |
+| `non_operational`, `non_contactable`, `missing` | `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`. |
+| `on_trip` | `on_trip ` | `changed_geographies` | **[Beta feature](/general-information.md#beta-features):** *Yes (as of 1.1.0)*. The vehicle has entered or left one or more Geographies managed by a Policy. See [Geography Driven Events](#geography-driven-events). |
+| `on_trip` | `available` | `trip_cancel` | A trip was initiated, then canceled prior to moving any distance |
+| `on_trip` | `available` | `trip_end` | A trip has ended, and the vehicle is again available for rent |
+| `on_trip` | `elsewhere` | `trip_leave_jurisdiction` | A vehicle on a trip left the jurisdiction |
+| `removed`, `non_contactable`, `missing` | `available` | `agency_drop_off` | The vehicle was placed in the PROW by a city or county |
+| `removed`, `non_contactable`, `missing` | `available` | `provider_drop_off` | The vehicle was placed in the PROW by the provider |
+| `reserved` | `available` | `reservation_cancel` | A reservation was canceled and the vehicle returned to service |
+
+
+[Top][toc]
+
+### State Machine Diagram
+
+This *State Machine Diagram* shows how `vehicle_state` and `event_type` relate to each other and how vehicles can transition between states. See [Google Slides](https://docs.google.com/presentation/d/1fHdq1efbN5GSFDLF4en-oA_BYPXQKbbIbHff6iROJKA/edit#slide=id.g206f7c6e12e_0_0) for the source file.
+
+![micromobility-state-machine-diagram](/modes/micromobility-state-machine-diagram.svg)
+
+[Top][toc]
+
+---
+
+[Modes Overview][modes]
+
+---
+
+[MDS Home][home]
+
+[home]: /README.md
+[modes]: /modes/README.md
+[toc]: #table-of-contents
+[vehicle-states]: /modes/vehicle_states.md
+[vehicle-events]: /modes/event_types.md
diff --git a/modes/passenger-services-state-machine-diagram.svg b/modes/passenger-services-state-machine-diagram.svg
new file mode 100644
index 00000000..b5c27f1e
--- /dev/null
+++ b/modes/passenger-services-state-machine-diagram.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/modes/passenger-services.md b/modes/passenger-services.md
new file mode 100644
index 00000000..a10aa394
--- /dev/null
+++ b/modes/passenger-services.md
@@ -0,0 +1,298 @@
+# Mobility Data Specification: **Passenger Services**
+
+
+
+**Passenger Services** refers to taxis, transportation network companies (TNCs), commercial transport apps (CTAs), and private hire vehicles (PHVs). Passenger Services typically have a driver, one or more passengers, and multiple passengers may be on different trips. The state machine tracks the trip states of the passengers separately from the vehicle state.
+
+See the [modes overview](/modes) for how the mode specific information below applies across MDS.
+
+## Taxi vs. TNC implementation differences
+
+Taxis typically require explicit tracking of maintenance while TNCs typically do not. Public agency regulations, legal authority, differ based on local, state, and federal laws and jurisdictions between taxis, TNCs, CTAs, PHV, etc.
+
+## Table of Contents
+
+- [Mode Attributes](#mode-attributes)
+ - [Mode ID](#mode-id)
+- [Trip Properties](#trip-properties)
+ - [Journey ID](#journey-id)
+ - [Journey Attributes](#journey-attributes)
+ - [Trip ID Requirements](#trip-id-requirements)
+ - [Trip Type](#trip-type)
+ - [Trip Attributes](#trip-attributes)
+ - [Fare Attributes](#fare-attributes)
+- [Vehicle Properties](#vehicle-properties)
+ - [Vehicle Attributes](#vehicle-attributes)
+ - [Accessibility Attributes](#accessibility-attributes)
+- [State Machine](#state-machine)
+ - [Vehicle States](#vehicle-states)
+ - [Event Types](#event-types)
+ - [Vehicle State Events](#vehicle-states-events)
+ - [State Machine Diagram](#state-machine-diagram)
+
+## Mode Attributes
+
+### Mode ID
+
+The short name identifier for Passenger Services used across MDS is `passenger-services`.
+
+[Top][toc]
+
+## Trip Properties
+
+_See more available trip and fare attributes for any mode used in the [trips object](/data-types.md#trips)._
+
+### Journey ID
+
+The `journey_id` field shall have a consistent value in overlapping trips, e.g. "pooled" or "shared" rides with different start and/or end locations. Journeys may be point-to-point, multi-segment, or multi-segment overlapping.
+
+- **Example 1**: one private trip with reservation, then return to depot
+- **Example 2**: three shared trips, some overlapping
+
+![Journey Diagram](https://i.imgur.com/ciNnDKC.png)
+
+[Top][toc]
+
+### Journey Attributes
+
+The `journey_attributes` object **may** have the following key value pairs:
+
+- `shift_id` (UUID, optional): unique identifier for an entire driver's work shift, tied across multiple journeys and therefore trips.
+
+[Top][toc]
+
+### Trip ID Requirements
+
+Events require a valid `trip_id` in events where `event_types` contains `reservation_start`, `reservation_stop`, `trip_start`, `trip_pause`, `trip_resume`, `trip_end`,`trip_cancel`, `customer_cancellation`, `provider_cancellation`, or `driver_cancellation`.
+
+Additionally, `trip_id` is required if `event_types` contains a `trip_enter_jurisdiction` or `trip_leave_jurisdiction` event pertaining to a trip.
+
+[Top][toc]
+
+### Trip Type
+
+The `trip_type` field **must** have one of the following enumerated values:
+
+- `private`: a private trip made by one paying customer with one or more guests
+- `shared`: a shared or pooled trip with more than one paying customer
+- `reservation`: en route to pickup a customer who has made a reservation, with no passengers in the vehicle
+- `empty`: vehicle movement with no passengers (outside of other `trip_type` values) that may need to be reported, e.g. for deadheading
+
+[Top][toc]
+
+### Trip Attributes
+
+The `trip_attributes` object **may** have the following key value pairs:
+
+- `hail_type` (enumerated, required): `street_hail`, `phone_dispatch`, `phone`, `text`, `app`
+- `app_name` (text, optional): name of the app used to reserve the trip which could be provider's app or 3rd party app
+- `passenger_count` (integer, required): unique count of passengers transported during trip duration
+- `requested_time` ([Timestamp][ts], required): when the passenger requested the trip
+- `requested_trip_start_location` ([GPS](gps), Conditionally Required): Location where the customer requested the trip to start (required if this is within jurisdictional boundaries)
+- `quoted_trip_start_time` ([Timestamp][ts], Required): Time the trip was estimated or scheduled to start, that was provided to the passenger
+- `dispatch_time` ([Timestamp][ts], Conditionally Required): Time the vehicle was dispatched to the customer (required if trip was dispatched)
+- `trip_wait_time` (milliseconds, optional): part of the passenger trip where the vehicle was moving slow or stopped (e.g. <12mph), which is a different fare rate in some jurisdictions
+- `trip_fare_time` (milliseconds, optional): part of the passenger trip where the vehicle was moving more quickly (e.g. >12mph), which is a different fare rate in some jurisdictions
+- `pickup_address` (text, optional): street address where the trip originated from
+- `dropoff_address` (text, optional): street address where the trip ended
+- `permit_license_number` (string, optional) - The permit license number of the organization that dispatched the vehicle
+- `driver_id` (string, optional): Universal identifier of a specific driver, static across operators, like a driver's license number. Could also be used as a lookup in an agency's internal driver system.
+- `wheelchair_transported` (boolean, optional) - was a wheelchair transported as part of this trip?
+- `cancellation_reason` (String, Conditionally Required): The reason why a *driver* cancelled a reservation. (required if a driver cancelled a trip, and a `driver_cancellation` event_type was part of the trip)
+
+[Top][toc]
+
+### Fare Attributes
+
+The `fare_attributes` object **may** have the following key value pairs:
+
+- `payment_type` (enumerated, required): `account_number`, `cash`, `credit_card`, `mobile_app`, `no_payment`, `paratransit`, `phone`, `voucher`, `test`
+- `fare_type` (enumerated, required): `meter_fare`, `upfront_pricing`, `flat_rate`. Indicator of which rate was charged.
+- `meter_fare_amount` (currency, conditionally required): if `upfront_pricing` is used as a `fare_type` include what the metered fare would have been if `meter_fare` would have been used. Allows cost comparison in evaluation of programs and pilots.
+- `tolls` (currency, optional) - Sum of any and all tolls charged for the trip, such as bridge tolls
+- `base_rate` (currency, optional) - Minimum fare to be charged as soon as the trip starts.
+- `exit_fee` (currency, optional) - Fee to exit location, like an airport
+- `other_fees` (currency, optional) - amount of any fees charged to the customer. Includes baggage fees, cleaning fee. Excludes other fees returned.
+- `tip` (currency, optional) - amount of tip paid by customer
+- `extra_amount` (currency, optional) - miscellaneous extra amounts charged to customer not covered by other fields.
+- `taxes` (currency, optional) - amount of taxes paid for the ride
+- `surcharge` (currency, optional) - any surcharge pricing
+- `commission` (currency, optional) - any extra commission for the ride
+- `driver_trip_pay` (currency, optional) - The payment the driver received for the trip
+- `rate_code_id` (enumerated, optional) - one of `meter_fare`, `shared`, `out_of_town`, `disabled`, `upfront_pricing`, `promo_rate`
+
+[Top][toc]
+
+## Vehicle Properties
+
+_See more available vehicle attributes and accessibility attributes for any mode used in the [vehicles object](/data-types.md#vehicles)._
+
+### Vehicle Attributes
+
+The `vehicle_attributes` object **may** have the following key value pairs:
+
+- `year` (integer, optional)
+- `make` (string, optional)
+- `model` (string, optional)
+- `color` (string, optional)
+- `vin` (string, optional) - the Vehicle Identification Number of the vehicle
+- `placard_number` (string, optional) - the registered placard number of the vehicle
+- `license_plate` (string, optional) - the registered vehicle license/number/registration plate identifier on the vehicle
+- `inspection_date` (date YYYY-MM-DD, optional) - the date of the last inspection of the vehicle
+
+[Top][toc]
+
+### Accessibility Attributes
+
+This `accessibility_attributes` enum represents the accessibility attributes available on a given vehicle, or the accessibility attributes utilized for a given trip.
+
+| `accessibility_attributes` | Description |
+|----------------------------|---------------------------------------|
+| `wheelchair_accessible` | This vehicle is wheelchair accessible |
+
+[Top][toc]
+
+## State Machine
+
+### Vehicle States
+
+Valid passenger services vehicle states are
+
+- `removed`
+- `available`
+- `non_operational`
+- `reserved`
+- `on_trip`
+- `stopped`
+- `non_contactable`
+- `elsewhere`
+
+See [Vehicle States][vehicle-states] for descriptions.
+
+[Top][toc]
+
+### Event Types
+
+Valid passenger services vehicle event types are
+
+- `comms_lost`
+- `comms_restored`
+- `driver_cancellation`
+- `maintenance`
+- `maintenance_pick_up`
+- `maintenance_end`
+- `passenger_cancellation`
+- `provider_cancellation`
+- `reservation_stop`
+- `reservation_start`
+- `service_end`
+- `service_start`
+- `trip_end`
+- `trip_enter_jurisdiction`
+- `trip_leave_jurisdiction`
+- `trip_resume`
+- `trip_start`
+- `trip_stop`
+
+This list is somewhat shorter than the micromobility event list, as passenger service vehicles are controlled by a driver or potentially an AI. They are not picked up or dropped off for rebalancing or compliance, for example, and they do not go out of service because of a low battery.
+
+See vehicle [Event Types][vehicle-events] for descriptions.
+
+[Top][toc]
+
+### Vehicle States Events
+
+This is the list of `vehicle_state` and `event_type` pairings that constitute the valid transitions of the vehicle state machine.
+
+| **From** `vehicle_state` | **To** `vehicle_state` | `trip_state` | `event_type` | Description |
+| ------------------------ | ---------------------- | ------------ | ------------------------ | --------------------------------------------------------------------------------------------------------------- |
+| `available` | `elsewhere` | N/A | `trip_leave_jurisdiction` | The vehicle has left jurisdictional boundaries while available for-hire |
+| `available` | `non_contactable` | N/A | `comms_lost` | The vehicle has went out of comms while available for-use |
+| `available` | `non_operational` | N/A | `service_end` | The vehicle has went out of service (is unavailable for-hire) |
+| `available` | `reserved` | `reserved` | `reservation_start` | The vehicle was reserved by a passenger |
+| `elsewhere` | `available` | N/A | `trip_enter_jurisdiction` | The vehicle has entered jurisdictional boundaries while available for-hire |
+| `elsewhere` | `non_contactable` | N/A | `comms_lost` | The vehicle has went out of comms while outside of jurisdictional boundaries |
+| `elsewhere` | `non_operational` | N/A | `trip_enter_jurisdiction` | The vehicle has entered jurisdictional boundaries while not operating commercially |
+| `elsewhere` | `on_trip` | `on_trip` | `trip_enter_jurisdiction` | The vehicle has entered jurisdictional boundaries while on a trip |
+| `elsewhere` | `reserved` | N/A | `trip_enter_jurisdiction` | The vehicle has entered jurisdictional boundaries while reserved by a customer |
+| `non_contactable` | `available` | N/A | `comms_restored` | The vehicle has come back into comms while available for-hire |
+| `non_contactable` | `elsewhere` | N/A | `comms_restored` | The vehicle has come back into comms while outside of jurisdictional boundaries |
+| `non_contactable` | `non_operational` | N/A | `comms_restored` | The vehicle has come back into comms while not operating commercially |
+| `non_contactable` | `on_trip` | `on_trip` | `comms_restored` | The vehicle has come back into comms while on a trip |
+| `non_contactable` | `removed` | N/A | `comms_restored` | The vehicle has come back into comms while removed |
+| `non_contactable` | `reserved` | `reserved` | `comms_restored` | The vehicle has come back into comms while reserved by a passenger |
+| `non_contactable` | `stopped` | `stopped` | `comms_restored` | The vehicle has come back into comms while stopped |
+| `non_operational` | `available` | N/A | `service_start` | The vehicle has went into service (is available for-hire) |
+| `non_operational` | `elsewhere` | N/A | `trip_leave_jurisdiction` | The vehicle has left jurisdictional boundaries while not operating commercially |
+| `non_operational` | `non_contactable` | N/A | `comms_lost` | The vehicle has went out of comms while not operating commercially |
+| `non_operational` | `non_operational` | N/A | `maintenance` | The vehicle has maintenance performed on site |
+| `non_operational` | `non_operational` | N/A | `maintenance_end` | Maintenance is complete |
+| `non_operational` | `removed` | N/A | `maintenance_pick_up` | The vehicle has entered the depot for maintenance |
+| `non_operational` | `removed` | N/A | `decommissioned` | The vehicle has been removed from the Provider's fleet |
+| `on_trip` | `elsewhere` | N/A | `trip_leave_jurisdiction` | The vehicle has left jurisdictional boundaries while on a trip |
+| `on_trip` | `non_contactable` | N/A | `comms_lost` | The vehicle has gone out of comms while on a trip |
+| `on_trip` | `stopped` | `stopped` | `trip_stop` | The vehicle has stopped while on a trip |
+| `removed` | `non_contactable` | N/A | `comms_lost` | The vehicle has gone out of comms while removed |
+| `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` |
+| `reserved` | `available` | N/A | `driver_cancellation` | The driver has canceled the reservation |
+| `reserved` | `available` | N/A | `passenger_cancellation` | The passenger has canceled the reservation |
+| `reserved` | `available` | N/A | `provider_cancellation` | The provider has canceled the reservation |
+| `reserved` | `elsewhere` | N/A | `trip_leave_jurisdiction` | The vehicle has left the jurisdiction while in a reservation |
+| `reserved` | `non_contactable` | N/A | `comms_lost` | The vehicle went out of comms while being reserved by a passenger |
+| `reserved` | `stopped` | `stopped` | `reservation_stop` | The vehicle has stopped to pick up the passenger |
+| `stopped` | `available` | N/A | `driver_cancellation` | The driver has canceled the trip while either waiting for the passenger, or dropping them off |
+| `stopped` | `available` | N/A | `passenger_cancellation` | The passenger has canceled the trip while the vehicle is waiting to pick them up, or they are being dropped off |
+| `stopped` | `available` | N/A | `provider_cancellation` | The provider has canceled the trip while the vehicle is waiting for a passenger, or dropping them off |
+| `stopped` | `available` | N/A | `trip_end` | The trip has been successfully completed |
+| `stopped` | `non_contactable` | N/A | `comms_lost` | The vehicle has went out of comms while stopped |
+| `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 |
+
+[Top][toc]
+
+### State Machine Diagram
+
+This *State Machine Diagram* shows how `vehicle_state` and `event_type` relate to each other and how vehicles can transition between states. See [Google Slides](https://docs.google.com/presentation/d/1fHdq1efbN5GSFDLF4en-oA_BYPXQKbbIbHff6iROJKA/edit#slide=id.g2072486e468_1_19) for the source file.
+
+![Passenger Services State Machine Diagram](passenger-services-state-machine-diagram.svg)
+
+[Top][toc]
+
+#### Passenger Services State Notes
+
+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.
+
+[Top][toc]
+
+---
+
+[Modes Overview][modes]
+
+---
+
+[MDS Home][home]
+
+[gps]: /data-types.md#gps-data
+[home]: /README.md
+[modes]: /modes/README.md
+[toc]: #table-of-contents
+[ts]: /general-information.md#timestamps
+[vehicle-states]: /modes/vehicle_states.md
+[vehicle-events]: /modes/event_types.md
diff --git a/modes/vehicle_states.md b/modes/vehicle_states.md
new file mode 100644
index 00000000..0969852c
--- /dev/null
+++ b/modes/vehicle_states.md
@@ -0,0 +1,34 @@
+# Mobility Data Specification: **Vehicle States**
+
+This file defines all possible `vehicle_state`s that can be used in state machines across all MDS modes. Each mode will use some subset of these states. It does not assign states to modes, but simply lists all possible values. As with all global definitions, they are described in a way that maximizes their relevance to multiple modes. See individual [mode definitions](/modes#list-of-supported-modes) for additional details specific to that mode.
+
+| `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. |
+| `non_operational` | yes | Not available for hire. Examples include: vehicle has low battery, or currently outside legal operating hours. |
+| `reserved` | yes | Reserved via Provider's app. A scooter waiting to be picked up by a rider, a taxi en route to a pickup. |
+| `on_trip` | yes | In a trip. For micromobility, in possession of renter. May or may not be in motion. |
+| `stopped` | yes | In a trip, but stopped temporarily for some purpose, e.g. to pick up or drop off passengers or packages, or if a driver is on break. |
+| `non_contactable` | yes | Provider has temporarily lost contact with the vehicle and its disposition is unknown. Examples include: connectivity loss, GPS issues. |
+| `missing` | no | Provider has lost contact with the vehicle and its disposition is unknown with no immediate resolution. Examples include: scooter taken into a private residence, bike thrown in river. |
+| `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. |
+
+### Limitations on the Use of Certain Values
+
+MDS is intended to communicate the provider's best available information to regulators. However there may be legitimate circumstances where providers do not have definitive or current information about devices on the ground. MDS incorporates some values to convey these situations. These vehicle state and event type values are to be used sparingly and temporarily, and are not meant for repeated or prolonged use. These values exist to create logical coherence within MDS about vehicles that are operating abnormally or are out of communication. When a more accurate value is known, the MDS API should be updated with the latest information. Cities may add language to their Service Level Agreements (SLAs) that minimize the use of these values by providers.
+
+#### Vehicle State: Non-Contactible and Missing
+
+It is expected that `non-contactable` will be used only for short periods of time and cities may put in place specific limitations via an SLA. As vehicles regain connectivity they should return to their prior state, and then send additional events to reflect any subsequent changes to that state. If vehicles remain `non-contactable` for over a specific limit as stated in the City SLA, then vehicles should be moved to `missing`.
+
+---
+
+[Modes Overview][modes]
+
+---
+
+[MDS Home][home]
+
+[home]: /README.md
+[modes]: /modes/README.md
diff --git a/policy/README.md b/policy/README.md
index 65476f09..1c449030 100644
--- a/policy/README.md
+++ b/policy/README.md
@@ -8,29 +8,39 @@ This specification describes the digital relationship between _mobility as a ser
## Table of Contents
-- [General Information](#general-information)
- - [Versioning](#versioning)
+- [General information](#general-information)
+ - [Background](#background)
+ - [Policy Examples](#policy-examples)
+ - [Authorization](#authorization)
- [Update Frequency](#update-frequency)
-- [Background](#background)
-- [Distribution](#distribution)
+ - [Updating or Ending Policies](#updating-or-ending-policies)
+ - [Versioning](#versioning)
+ - [Distribution](#distribution)
- [REST Endpoints](#rest-endpoints)
+ - [Responses and Error Messages](#responses-and-error-messages)
- [Policies](#policies)
- [Geographies](#geographies)
- [Requirements](#requirements)
- [Flat Files](#flat-files)
+ - [Example `policies.json`](#example-policiesjson)
+ - [Example `geographies.json`](#example-geographiesjson)
- [Schema](#schema)
+ - [Data Schema](#data-schema)
- [Policy](#policy)
- [Rules](#rules)
- [Rule Types](#rule-types)
- [Rule Units](#rule-units)
- - [Geography](#geography)
- - [Rate Recurrences](#rate-recurrences)
+ - [Rates](#rates)
+ - [Rate Amounts](#rate-amounts)
+ - [Rate Recurrences](#rate-recurrences)
+ - [Rate Applies When](#rate-applies-when)
- [Messages](#messages)
- [Value URL](#value-url)
- [Order of Operations](#order-of-operations)
- [Requirement](#requirement)
- - [Update Frequency](#requirement-update-frequency)
+ - [Examples](#examples)
- [Public Hosting](#public-hosting)
+ - [Update Frequency](#requirement-update-frequency)
- [Version Tracking](#version-tracking)
- [Beta Limitations](#beta-limitations)
- [Format](#requirement-format)
@@ -45,21 +55,7 @@ The following information applies to all `policy` API endpoints.
[Top][toc]
-### Update Frequency
-
-The publishing agency should establish beforehand and communicate to providers how frequently the Policy endpoints are expected to change, how often they should be polled to get the latest information, and expectations around emergency updates.
-
-[Top][toc]
-
-### Versioning
-
-`policy` APIs must handle requests for specific versions of the specification from clients.
-
-Versioning must be implemented as specified in the [Versioning section][versioning].
-
-[Top][toc]
-
-## Background
+### Background
The goal of the Policy API specification is to enable agencies to create, revise, and publish machine-readable policies, as sets of rules for individual and collective device behavior exhibited by both _mobility as a service_ providers and riders / users. [Examples](./examples/README.md) of policies include:
@@ -72,24 +68,54 @@ The goal of the Policy API specification is to enable agencies to create, revise
The machine-readable format allows Providers to obtain policies and compute compliance where it can be determined entirely by data obtained internally, and know what data is required from them and provided to them.
-**See the [Policy Examples](./examples/README.md) for ways these can be implemented.**
+[Top][toc]
+
+### Policy Examples
+
+See the [Policy Examples](./examples/README.md) for ways Policy can be implemented.
[Top][toc]
-## Distribution
+### Authorization
-Policies shall be published by regulatory bodies or their authorized delegates as JSON objects. These JSON objects shall be served by either [flat files](#flat-files) or via [REST API endpoints](#rest-endpoints). In either case, policy data shall follow the [schema](#schema) outlined below.
+The Policy endpoints should be made public. Authorization is not required.
+
+[Top][toc]
+
+### Update Frequency
+
+The publishing agency should establish beforehand and communicate to providers how frequently the Policy endpoints are expected to change, how often they should be polled to get the latest information, and expectations around emergency updates.
-Policies typically refer to one or more associated geographies. Geographic information is obtained from the MDS [Geography](/geography#general-information) API. Each policy and geography shall have a unique ID (UUID).
+[Top][toc]
+
+### Updating or Ending Policies
Published policies, like geographies, should be treated as immutable data. Obsoleting or otherwise changing a policy is accomplished by publishing a new policy with a field named `prev_policies`, a list of UUID references to the policy or policies superseded by the new policy.
+To update a policy, create a new policy with the new rules rules, and list the now updated policy id in `prev_policies`.
+
+To revoke or end a policy, create a new policy with empty rules, and list the ended policy id in `prev_policies`.
+
+[Top][toc]
+
+### Versioning
+
+`Policy` APIs must handle requests for specific versions of the specification from clients.
+
+[Top][toc]
+
+### Distribution
+
+Policies shall be published by regulatory bodies or their authorized delegates as JSON objects. These JSON objects shall be served by either [flat files](#flat-files) or via [REST API endpoints](#rest-endpoints). In either case, policy data shall follow the [schema](#schema) outlined below.
+
+Policies typically refer to one or more associated geographies. Geographic information is obtained from the MDS [Geography](/geography) API. Each policy and geography shall have a unique ID (UUID).
+
Geographical data shall be represented as GeoJSON `Feature` objects. No part of the geographical data should be outside the [municipality boundary][muni-boundary].
Policies should be re-fetched whenever:
-1) a policy expires (via its `end_date`), or
-2) at an interval specified by the regulatory body, e.g. "daily at midnight".
+1. a policy expires (via its `end_date`), or
+2. at an interval specified by the regulatory body, e.g. "daily at midnight".
Flat files have an optional `end_date` field that will apply to the file as a whole.
@@ -99,10 +125,10 @@ Flat files have an optional `end_date` field that will apply to the file as a wh
Among other use-cases, configuring a REST API allows an Agency to:
-1) Dynamically adjust caps
-2) Set Provider specific policies
-3) Adjust other attributes in closer to real time
-4) Enumerate when policies are set to change
+1. Dynamically adjust caps
+2. Set Provider specific policies
+3. Adjust other attributes in closer to real time
+4. Enumerate when policies are set to change
Responses must set the `Content-Type` header, as specified in the [versioning][versioning] section.
@@ -112,45 +138,50 @@ The response to a client request must include a valid HTTP status code defined i
See the [Responses section][responses] for information on valid MDS response codes and the [Error Messages section][error-messages] for information on formatting error messages.
-### Authorization
-
-Authorization is not required and agencies are encouraged to make these endpoints unauthenticated and public. See [Optional Authentication](/general-information.md#optional-authentication) for details.
-
### Policies
-**Endpoint**: `/policies/{id}`
+**Endpoint**: `/policies/{policy_id}`
**Method**: `GET`
-**Schema:** [`policy` schema][json-schema]
+**Schema:** See [`mds-openapi`](https://github.com/openmobilityfoundation/mds-openapi) repository for schema.
+**Authorization**: public
**`data` Payload**: `{ "policies": [] }`, an array of objects with the structure [outlined below](#policy).
-#### Query Parameters
+_Path Parameters:_
+
+| Path Parameter | Type | Required / Optional | Description |
+| ------------ | --------- | --- | ---------------------------------------------- |
+| `policy_id` | UUID | Optional | If provided, returns one policy object with the matching UUID; default is to return all policy objects. |
+
+_Query Parameters:_
-| Name | Type | Required / Optional | Description |
+| Query Parameter | Type | Required / Optional | Description |
| ------------ | --------- | --- | ---------------------------------------------- |
-| `id` | UUID | Optional | If provided, returns one policy object with the matching UUID; default is to return all policy objects. |
-| `start_date` | [timestamp][ts] | Optional | Earliest effective date; default is policies effective as of the request time |
-| `end_date` | [timestamp][ts] | Optional | Latest effective date; default is all policies effective in the future |
+| `policy_id` | UUID | Optional | If provided, returns one policy object with the matching UUID; default is to return all policy objects. |
+| `start_date` | [timestamp][ts] | Optional | Beginning date of the queried time range; the default value is the request time |
+| `end_date` | [timestamp][ts] | Optional | Ending date of the queried time range; the default value is null, which captures all policies that are effective in the future|
-`start_date` and `end_date` are only considered when no `id` parameter is provided.
+`start_date` and `end_date` are only considered when no `id` parameter is provided. They should return any policy whose effectiveness overlaps with or is contained with this range. Suppose there's a policy with a `start_date` of 1/1/21 and `end_date` of 1/31/21. Assuming an `end_date` that is null, 12/1/20 and 1/5/21 `start_dates` will return the policy, but 2/10/21 wouldn't. Assuming a `start_date` parameter of say, 11/1/20, then an `end_date` of 12/1/20 wouldn't return the policy, but 1/5/21 and 2/10/21 would. Lastly, a `start_date` of 1/5/21 and `end_date` of 1/6/21 would also return the policy. Please note also that while dates in the format MM:DD:YY are being used here, `start_date` and `end_date` must be numbers representing milliseconds since the Unix epoch time.
Policies will be returned in order of effective date (see schema below), with pagination as in the `agency` and `provider` specs.
`provider_id` is an implicit parameter and will be encoded in the authentication mechanism, or a complete list of policies should be produced. If the Agency decides that Provider-specific policy documents should not be shared with other Providers (e.g. punitive policy in response to violations), an Agency should filter policy objects before serving them via this endpoint.
-### Geographies
+### Responses
-**Deprecated:** see the new [Geography API](/geography#transition-from-policy) to understand the transistion away from this endpoint, and how to support both in MDS 1.x.0 releases.
+_Possible HTTP Status Codes_:
+200,
+400 (with parameter),
+404,
+406,
+500
-**Endpoint**: `/geographies/{id}`
-**Method**: `GET`
-**Schema:** [`policy` schema][json-schema]
-**`data` Payload**: `{ geographies: [] }`, an array of GeoJSON `Feature` objects that follow the schema [outlined here](#geography) or in [Geography](/geography#general-information).
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
+
+[Top][toc]
-#### Query Parameters
+### Geographies
-| Name | Type | Required / Optional | Description |
-| ------------ | --------- | --- | ---------------------------------------------- |
-| `id` | UUID | Optional | If provided, returns one [Geography](/geography#general-information) object with the matching UUID; default is to return all geography objects. |
+**Deprecated:** see the [Geography API](/geography#transition-from-policy) for the current home of this endpoint.
[Top][toc]
@@ -158,44 +189,65 @@ Policies will be returned in order of effective date (see schema below), with pa
**Endpoint**: `/requirements/`
**Method**: `GET`
-**[Beta feature](/general-information.md#beta-features)**: *Yes (as of 1.2.0)*. [Leave feedback](https://github.com/openmobilityfoundation/mobility-data-specification/issues/682)
-**Schema:** TBD when out of beta
+**[Beta feature](/general-information.md#beta-features)**: *No (as of 2.0.0)*.
+**Authorization**: public
+**Schema:** See [`mds-openapi`](https://github.com/openmobilityfoundation/mds-openapi) repository for schema.
**`data` Payload**: `{ requirements: [] }`, JSON objects that follow the schema [outlined here](#requirement).
See [Policy Requirements Examples](/policy/examples/requirements.md) for how this can be implemented.
+#### Responses
+
+_Possible HTTP Status Codes_:
+200,
+404,
+406,
+500
+
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
+
[Top][toc]
## Flat Files
To use flat files, policies shall be represented in two (2) files:
-- `policies.json`
-- `geographies.json`
+- `policies.json` in Policy API
+- `geographies.json` in Geography API
The files shall be structured like the output of the [REST endpoints](#rest-endpoints) above.
-The publishing Agency should establish and communicate to providers how frequently these files should be polled.
+The publishing agency should establish and communicate to providers how frequently these files should be polled.
+
+The `last_updated` field in the payload wrapper should be set to the time of publishing a revision, so that it is simple to identify a changed file.
+
+### Responses
+
+_Possible HTTP Status Codes_:
+200,
+404,
+406,
+500
+
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
-The `updated` field in the payload wrapper should be set to the time of publishing a revision, so that it is simple to identify a changed file.
+[Top][toc]
### Example `policies.json`
```jsonc
{
- "version": "0.4.0",
- "updated": 1570035222868,
- "end_date": 1570035222868,
- "data": {
- "policies": [
- {
- // policy JSON 1
- },
- {
- // policy JSON 2
- }
- ]
+ "version": "2.0.0",
+ "last_updated": 1570035222868,
+ "end_date": 1570035222868,
+ "policies": [
+ {
+ // policy JSON 1
+ },
+ {
+ // policy JSON 2
}
+ ]
}
```
@@ -205,18 +257,16 @@ The optional `end_date` field applies to all policies represented in the file.
```jsonc
{
- "version": "0.4.0",
- "updated": 1570035222868,
- "data": {
- "geographies": [
- {
- // GeoJSON Feature 1
- },
- {
- // GeoJSON Feature 2
- }
- ]
+ "version": "2.0.0",
+ "last_updated": 1570035222868,
+ "geographies": [
+ {
+ // GeoJSON Feature 1
+ },
+ {
+ // GeoJSON Feature 2
}
+ ]
}
```
@@ -226,21 +276,19 @@ The optional `end_date` field applies to all policies represented in the file.
All response fields must use `lower_case_with_underscores`.
-Response bodies must be a `UTF-8` encoded JSON object and must minimally include the MDS `version`, a timestamp indicating the last time the data was `updated`, and a `data` payload:
+Response bodies must be a `UTF-8` encoded JSON object and must minimally include the MDS `version`, a timestamp indicating the last time the data was `last_updated`, and a `data` payload:
```jsonc
{
- "version": "x.y.z",
- "updated": 1570035222868,
- "data": {
- // endpoint/file specific payload
- }
+ "version": "x.y.z",
+ "last_updated": 1570035222868,
+ // endpoint/file specific payload
}
```
-### JSON Schema
+### Data Schema
-The JSON Schema file is available in this repository: [`policy.json`](./policy.json).
+See the [Endpoints](#endpoints) below for information on their specific schema, and the [`mds-openapi`](https://github.com/openmobilityfoundation/mds-openapi) repository for full details and interactive documentation.
Before publishing a new Policy document, the document should be validated against the schema to ensure it has the correct format and fields.
@@ -253,10 +301,11 @@ An individual `Policy` object is defined by the following fields:
| Name | Type | Required / Optional | Description |
| ---------------- | --------------- | ---------- | ----------------------------------------------------------------------------------- |
| `name` | String | Required | Name of policy |
+| `mode_id` | [Mode][modes] | Required | Mode this rule should apply, see MDS [mode list][modes] for options. Default `micromobility` for backwards compatibility (this default will likely be removed in a subsequent MDS release) |
| `policy_id` | UUID | Required | Unique ID of policy |
-| `provider_ids` | UUID[] | Optional | Providers for whom this policy is applicable; empty arrays and `null`/absent implies all Providers. See MDS [provider list](/providers.csv). |
+| `provider_ids` | UUID[] | Optional | Providers for whom this policy is applicable; empty arrays and `null`/absent implies all Providers. See MDS [provider list](/providers.csv). |
| `description` | String | Required | Description of policy |
-| `currency` | String | Optional | An ISO 4217 Alphabetic Currency Code representing the [currency](../general-information.md#costs-and-currencies) of all Rules of [type](#rule-types) `rate`.|
+| `currency` | String | Optional | An ISO 4217 Alphabetic Currency Code representing the [currency](../general-information.md#costs-and-currencies) of all Rules with a `rate_amount`.|
| `start_date` | [timestamp][ts] | Required | Beginning date/time of policy enforcement. In order to give providers sufficient time to poll, `start_date` must be at least 20 minutes after `published_date`. |
| `end_date` | [timestamp][ts] | Optional | End date/time of policy enforcement |
| `published_date` | [timestamp][ts] | Required | Timestamp that the policy was published |
@@ -275,8 +324,9 @@ An individual `Rule` object is defined by the following fields:
| `rule_id` | UUID | Required | Unique ID of the rule |
| `rule_type` | enum | Required | Type of policy (see [Rule Types](#rule-types)) |
| `geographies` | UUID[] | Required | List of [Geography](/geography#general-information) UUIDs (non-overlapping) specifying the covered geography |
-| `states` | `{ state: event[] }` | Required | [Vehicle state][vehicle-states] to which this rule applies. Optionally provide a list of specific [vehicle events][#vehicle-events] as a subset of a given status for the rule to apply to. An empty list or `null`/absent defaults to "all". |
+| `states` | `{ state: event[] }` | Required | [Vehicle state][vehicle-states] to which this rule applies. Optionally provide a list of specific [vehicle events][vehicle-events] as a subset of a given status for the rule to apply to. An empty list or `null`/absent defaults to "all". |
| `rule_units` | enum | Conditionally Required | Measured units of policy (see [Rule Units](#rule-units)) |
+| `accessibility_options` | [AccessibilityOption][accessibility-options][] | Applicable vehicle [accessibility options][accessibility-options], default any (or none) |
| `vehicle_types` | `vehicle_type[]` | Optional | Applicable vehicle types, default "all". |
| `propulsion_types` | `propulsion_type[]` | Optional | Applicable vehicle [propulsion types][propulsion-types], default "all". |
| `minimum` | integer | Optional | Minimum value, if applicable (default 0) |
@@ -299,54 +349,40 @@ An individual `Rule` object is defined by the following fields:
| Name | Description |
| ------- | ------------------------------------------------------------------------------------------------------------- |
| `count` | Fleet counts based on regions. Rule `minimum`/`maximum` refers to number of devices in [Rule Units](#rule-units). |
-| `time` | Individual limitations or fees based upon time spent in one or more vehicle-states. Rule `minimum`/`maximum` refers to increments of time in [Rule Units](#rule-units). |
+| `time` | Individual limitations or fees based upon time spent in one or more vehicle states. Rule `minimum`/`maximum` refers to increments of time in [Rule Units](#rule-units). |
| `speed` | Global or local speed limits. Rule `minimum`/`maximum` refers to speed in [Rule Units](#rule-units). |
-| `rate` | **[Beta feature](/general-information.md#beta-features):** *Yes (as of 1.0.0)*. Fees or subsidies based on regions and time spent in one or more vehicle-states. Rule `rate_amount` refers to the rate charged according to the [Rate Recurrences](#rate_recurrences) and the [currency requirements](/general-information.md#costs-and-currencies) in [Rule Units](#rule-units). *Prior to implementation agencies should consult with providers to discuss how the `rate` rule will be used. Most agencies do this as a matter of course, but it is particularly important to communicate in advance how frequently and in what ways rates might change over time.* |
| `user` | Information for users, e.g. about helmet laws. Generally can't be enforced via events and telemetry. |
[Top][toc]
### Rule Units
-| Name | Rule Types | Description |
-| --------- | ---------------------- | ------------------- |
-| `seconds` | `rate`, `time` | Seconds |
-| `minutes` | `rate`, `time` | Minutes |
-| `hours` | `rate`, `time` | Hours |
-| `days` | `rate`, `time` | Days |
-| `amount` | `rate` | Cost (in [local currency](/general-information.md#costs-and-currencies)) |
-| `mph` | `speed` | Miles per hour |
-| `kph` | `speed` | Kilometers per hour |
-| `devices` | `count` | Devices |
+| Name | Rule Types | Description |
+| --------- | -------------- | ------------------- |
+| `seconds` | `time` | Seconds |
+| `minutes` | `time` | Minutes |
+| `hours` | `time` | Hours |
+| `days` | `time` | Days |
+| `mph` | `speed` | Miles per hour |
+| `kph` | `speed` | Kilometers per hour |
+| `devices` | `count` | Devices |
[Rule type](#rule-types) `user` has no associated Rule units; `rule_units` is not required when the Rule type is `user`.
[Top][toc]
-### Geography
-
-**Deprecated:** see the new [Geography API](/geography#transition-from-policy) to understand the transistion away from this endpoint, and how to support both in a MDS 1.x.0 release.
-
-| Name | Type | Required / Optional | Description |
-| ---------------- | --------- | --- | ----------------------------------------------------------------------------------- |
-| `name` | String | Required | Name of geography |
-| `description` | String | Optional | Detailed description of geography |
-| `geography_id` | UUID | Required | Unique ID of [Geography](/geography#general-information) |
-| `geography_json` | JSON | Required | The GeoJSON that defines the geographical coordinates.
-| `effective_date` | [timestamp][ts] | Optional | `start_date` for first published policy that uses this geo. Server should set this when policies are published. This may be used on the client to distinguish between “logical” geographies that have the same name. E.g. if a policy publishes a geography on 5/1/2020, and then another policy is published which references that same geography is published on 4/1/2020, the effective_date will be set to 4/1/2020.
-| `publish_date` | [timestamp][ts] | Required | Timestamp that the policy was published, i.e. made immutable |
-| `prev_geographies` | UUID[] | Optional | Unique IDs of prior [geographies](/geography#general-information) replaced by this one |
-
-[Top][toc]
-
### Rates
-Rate-related properties can currently be specified on `rate` and `time` Rules. Note: A future MDS version will likely support rates for `count` and `speed` rules, but their behavior is currently undefined.
-**[Beta feature](/general-information.md#beta-features)**: *Yes (as of 1.0.0)*. [Leave feedback](https://github.com/openmobilityfoundation/mobility-data-specification/issues/674)
+Rate-related properties can currently be specified on all rule types except `user`, i.e. any rule that can be measured.
+
+**[Beta feature](/general-information.md#beta-features)**: *No (as of 2.0.0)*.
#### Rate Amounts
+
The amount of a rate applied when this rule applies, if applicable (default zero). A positive integer rate amount represents a fee, while a negative integer represents a subsidy. Rate amounts are given in the `currency` defined in the [Policy](#policy).
+[Top][toc]
+
#### Rate Recurrences
Rate recurrences specify how a rate is applied – either once, or periodically according to a `time_unit` specified using [Rule Units](#rule-units). A `time_unit` refers to a unit of time as measured in local time for the jurisdiction – a day begins at midnight local time, an hour begins at the top of the hour, etc.
@@ -373,6 +409,8 @@ The `rate_applies_when` field may take the following values:
| `in_bounds` | Rate applies when an event or count is within the rule `minimum` and `maximum` |
| `out_of_bounds` | Rate applies when an event or count is outside of the rule `minimum` and `maximum` |
+[Top][toc]
+
### Messages
Some Policies as established by the Agency may benefit from rider communication. This optional field contains a map of languages to messages, to be shown to the user.
@@ -422,29 +460,37 @@ The internal mechanics of ordering are up to the Policy editing and hosting soft
### Requirement
-A public agency's Policy program Requirements endpoint enumerates all of the parts of MDS, GBFS, and other specifications that an agency requires from providers for certain programs, including APIs, endpoints, and optional fields, as well as information for providers about the APIs the agency is hosting. The program requirements are specific to the needs and use cases of each agency, and ensure there is clarity on what data is being asked for in operating policy documents from providers, reducing the burden on both. This also allows additional public transparency and accountability around data requirements from agencies, and encourages privacy by allowing agencies to ask for only the data they need.
+A public agency's Policy program Requirements endpoint enumerates all of the parts of MDS, [CDS](https://github.com/openmobilityfoundation/curb-data-specification), GBFS, and other specifications that an agency requires from providers for certain programs, including APIs, endpoints, and optional fields, as well as information for providers about the APIs the agency is hosting. The program requirements are specific to the needs and use cases of each agency, and ensure there is clarity on what data is being asked for in operating policy documents from providers, reducing the burden on both. This also allows additional public transparency and accountability around data requirements from agencies, and encourages privacy by allowing agencies to ask for only the data they need.
Requirements can also be used to define a scaled-down MDS implementation in situations where an agency has more limited regulatory goals, has legal limitations on the types of data they can collect, or wants to use a lightweight version of MDS for a pilot project or other experiment where aspects of a full MDS implementation would be irrelevant or unnecessary.
+[Top][toc]
+
+#### Examples
+
See [Policy Requirements Examples](/policy/examples/requirements.md) for ideas on how this can be implemented.
+[Top][toc]
+
#### Public Hosting
This endpoint is not authenticated (ie. public), and allows the discovery of other public endpoints within Geography, Policy, and Jurisdiction. The agency can host this as a file or dynamic endpoint on their servers, on a third party server, or the OMF can host on behalf of an agency in the [agency program requirements repo](https://github.com/openmobilityfoundation/agency-program-requirements). See this [hosting guidance document](https://github.com/openmobilityfoundation/mobility-data-specification/wiki/Policy-Requirements-OMF-Hosting-Guidance) for more information. This requirements file can be [referenced directly](https://github.com/openmobilityfoundation/governance/blob/main/technical/OMF-MDS-Policy-Language-Guidance.md) in an agency's operating permit/policy document when discussing program data requirements, and [updated digitally as needed](#requirement-update-frequency). To be compliant with MDS you must obtain an `agency_id` and list your public URL in [agencies.csv](/agencies.csv), per our [guidance document](https://github.com/openmobilityfoundation/mobility-data-specification/wiki/Adding-an-MDS-Agency-ID).
+[Top][toc]
+
#### Requirement Update Frequency
The OMF recommends updating the Requirements feed no more than monthly, and you may specify your expected timeframe with the `max_update_interval` in the [metadata](#requirement-metadata) section so providers have some idea of how often to check the feed. More specifically the OMF recommends giving the following notice to providers: 1 month for optional field additions, 3 months for endpoint/API changes/additions, 3 months for new minor releases, and 4 months for major releases. You should also communicate these future changes ahead of time with the `start_date` field. Finally, the OMF recommends any changes need to be part of a discussion between agencies and affected providers.
+[Top][toc]
+
#### Version Tracking
If you are upgrading to a new MDS version, it is recommended to create a new requirements file at a new URL, since field names and available options may have changed. To make this more obvious, the MDS version number could be part of your URL, e.g. "https://mds.cityname.gov/requirements/1.2.0".
When requirements are updated within the same MDS version, in the [metadata](#requirement-metadata) section, increment the `file_version` value by one and update the `last_updated` timestamp. Though not required, you may choose to use the `start_date` and `end_date` fields in the [programs](#requirement-programs) section to keep retired requirements accessible. We also recommend hosting your requirements file in a location that has a publicly-accessible version history, like GitHub or Bitbucket, or keeping previous versions accessible with a versioned URL, e.g. "https://mds.cityname.gov/requirements/1.2.0/v3".
-#### Beta Limitations
-
-Note that while Requirements is in [beta](#Requirements) in this **minor**, non-breaking MDS 1.2.0 release, items listed as "required" or "disallowed" will be treated as a _request_ only by default (precluding intentional formal agency communications with providers) to prevent an _unintentional_ burden on providers. For the next **major**, breaking MDS 2.0.0 release, these items will be required or disallowed as documented.
+[Top][toc]
#### Requirement Format
@@ -481,17 +527,15 @@ An agency's program [Requirements](#requirements) endpoint contains a number of
// other data specs per the "Requirement Data Specs" section
]
},
- // other MDS versions per the "Requriement MDS Version" section
+ // other MDS versions per the "Requirement MDS Version" section
}
}
```
| Name | Type | Required / Optional | Description |
| ---------------------------- | --------------- | -------- | ----------------------------------- |
-| `metadata` | Array | Required | Array of [Requirement Metadata](#requirement-metadata) fields. |
+| `metadata` | JSON | Required | [Requirement Metadata](#requirement-metadata) object. |
| `programs` | Array | Required | Array of [Requirement Programs](#requirement-programs) data. |
-| `required_data_specs` | Array | Required | Array of [Requirement Data Specs](#requirement-data-specs) data. |
-| `required_apis` | Array | Required | Array of [Requirement APIs](#requirement-apis) data. |
[Top][toc]
@@ -576,7 +620,7 @@ Unique combinations for data specs, specific providers, vehicle types, policies,
| `program_website_url` | URL | Required | URL of the agency's transportation policy page. E.g. "https://www.cityname.gov/transportation/shared-devices.htm" |
| `program_document_url` | URL | Optional | URL of the agency's operating permit rules that mention data requirements. E.g. "https://www.cityname.gov/mds_data_policy.pdf" |
| `provider_ids` | UUID[] | Required | Array of provider UUIDs that apply to this group the requirements |
-| `vehicle_type` | Enum | Optional | Array of [Vehicle Types](../general-information.md#vehicle-types) that apply to this requirement. If absent it applies to all vehicle types. |
+| `vehicle_type` | Enum | Optional | Array of [Vehicle Types](/general-information.md#vehicle-types) that apply to this requirement. If absent it applies to all vehicle types. |
| `start_date` | [timestamp][ts] | Required | Beginning date/time of requirements |
| `end_date` | [timestamp][ts] | Required | End date/time of requirements. Can be null. Keep data at least one year past `end_date` before removing. |
| `required_data_specs` | Array | Required | Array of required [Data Specs](#requirement-data-specs) |
@@ -593,6 +637,7 @@ For each combination of items in a program, you can specify the data specs, APIs
{
"data_spec_name": "[DATA SPEC NAME]",
"version": "[VERSION NUMBER]",
+ "mode_id": "[MODE SHORTNAME]",
"required_apis": [
{
// Required APIs array
@@ -611,8 +656,9 @@ For each combination of items in a program, you can specify the data specs, APIs
| Name | Type | Required / Optional | Description |
| -------------------- | ------ | -------- | ----------------------------------- |
-| `data_spec_name` | Enum | Required | Name of the data spec required. Supported values are: '[MDS](https://github.com/openmobilityfoundation/mobility-data-specification/tree/ms-requirements)', '[GBFS](https://github.com/NABSA/gbfs/tree/v2.2)'. Others like GOFS, GTFS, TOMP-API, etc can be tested by agencies and officially standardized here in the future -- leave your feedback on [this issue](https://github.com/openmobilityfoundation/mobility-data-specification/issues/682). |
+| `data_spec_name` | Enum | Required | Name of the data spec required. Supported values are: '[MDS](https://github.com/openmobilityfoundation/mobility-data-specification/tree/ms-requirements)', '[CDS](https://github.com/openmobilityfoundation/curb-data-specification)' '[GBFS](https://github.com/NABSA/gbfs/tree/v2.2)'. Others like GOFS, GTFS, TOMP-API, etc may also be referenced now by agencies and officially standardized here in the future -- leave your feedback on [this issue](https://github.com/openmobilityfoundation/mobility-data-specification/issues/682). |
| `version` | Text | Required | Version number of the data spec required. E.g. '1.2.0' |
+| `mode_id` | Text | Optional | The [mode list][modes] shortname for MDS. E.g. 'passenger-services' |
| `required_apis` | Array | Conditionally Required | Name of the [Requirement APIs](#requirement-apis) that need to be served by providers. At least one API is required. APIs not listed will not be available to the agency. |
| `available_apis` | Array | Conditionally Required | Name of the [Requirement APIs](#requirement-apis) that are being served by agencies. Not applicable to GBFS. APIs not listed will not be available to the provider. |
@@ -620,7 +666,7 @@ For each combination of items in a program, you can specify the data specs, APIs
#### Requirement APIs
-For each data specification, you can specify which APIs, endpoints, and fields are required from providers, and which are available from your agency.
+For each data specification, you can specify which APIs, endpoints, and fields are required from providers, and which are available from your agency, and the use cases you need the data for.
An agency may require providers to serve optional APIs, endpoints, and fields that are needed for your agency's program. This is a `required_apis` array within the [Requirement Data Specs](#requirement-data-specs) section in the [Requirement](#requirement) data feed.
@@ -647,8 +693,7 @@ You may also show which APIs, endpoints, and fields your agency is serving to pr
},
// other endpoints
]
- },
- // other APIs in same data spec
+ }
],
"available_apis": [
{
@@ -665,6 +710,14 @@ You may also show which APIs, endpoints, and fields your agency is serving to pr
// other endpoints
]
}
+ ],
+ // other APIs in same data spec
+ "use_cases": [
+ {
+ "external_url": "[REFERENCE URL]",
+ "ids": ["1","2","3"]
+ },
+ // next external use case source
]
// ...
```
@@ -673,6 +726,9 @@ You may also show which APIs, endpoints, and fields your agency is serving to pr
| -------------------- | ----- | -------- | ----------------------------------- |
| `api_name` | Text | Required | Name of the applicable API required. At least one API is required. APIs not listed will not be available to the agency. E.g. for MDS: 'provider', or 'agency'. For GBFS, this field is omitted since GBFS starts at the `endpoint` level. |
| `endpoint_name` | Text | Required | Name of the required endpoint under the API. At least one endpoint is required. E.g. for MDS 'provider': 'trips' |
+| `use_cases` | Object with Array | Optional | The list of policy uses cases that this data standard's information covers for your program. Includes an `external_url` to a HTTP reference list or database (e.g. to the [OMF Use Case Database](https://airtable.com/shrPf4QvORkjZmHIs/tblzFfU6fxQm5Sdhm)), **and** an array of `ids` of each applicable use case (e.g. "OMF-MDS-31"). You may enumerate multiple external use case sources and ids. |
+
+[Top][toc]
**Provider Endpoints** - Specific to the `required_apis` array
@@ -695,22 +751,26 @@ You may also show which APIs, endpoints, and fields your agency is serving to pr
- All fields marked 'Required' in MDS are still included by default and should not be enumerated in `required_fields`. They are not affected by the Requirements endpoint, unless explicitly listed in `disallowed_fields`.
- Fields in MDS marked 'Required if available' are still returned if available, and are not affected by the Requirements endpoint, unless explicitly listed in `disallowed_fields`.
- If a 'Required' or 'Required if available' or 'Optional' field in MDS is listed in `disallowed_fields`, those fields should not be returned by the provider in the endpoint. The field (and therefore its value) must be completely removed from the response. If used, [schema](/schema) validation may fail on missing required fields.
-- To reference fields that are lower in a heirarchy, use [dot separated notation](https://docs.oracle.com/en/database/oracle/oracle-database/18/adjsn/simple-dot-notation-access-to-json-data.html#GUID-7249417B-A337-4854-8040-192D5CEFD576), where a dot between field names represents one nested level deeper into the data structure. E.g. 'gps.heading' or 'features.properties.rules.vehicle_type_id'.
-- To require [Greography Driven Events](/general-information.md#geography-driven-events), simply include the `event_geographies` field for either the Agency or Provider API `api_name`. Per how GDEs work, `event_location` will then not be returned, and the `changed_geographies` vehicle state `event_type` will be used.
-- [While in beta](#beta-limitations), items marked as required or disallowed will only be considered a 'request' by providers, unless agencies have communicated with providers outside of MDS.
+- To reference fields that are lower in a hierarchy, use [dot separated notation](https://docs.oracle.com/en/database/oracle/oracle-database/18/adjsn/simple-dot-notation-access-to-json-data.html#GUID-7249417B-A337-4854-8040-192D5CEFD576), where a dot between field names represents one nested level deeper into the data structure. E.g. 'gps.heading' or 'features.properties.rules.vehicle_type_id'.
+- To require [Geography Driven Events](/general-information.md#geography-driven-events), simply include the `event_geographies` field for either the Agency or Provider API `api_name`. Per how GDEs work, `event_location` will then not be returned, and the `changed_geographies` vehicle state `event_type` will be used.
[Top][toc]
+[accessibility-options]: /general-information.md#accessibility-options
[beta]: /general-information.md#beta
+[bulk-responses]: /general-information.md#bulk-responses
[error-messages]: /general-information.md#error-messages
[iana]: https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
[json-schema]: #json-schema
-[muni-boundary]: ../provider/README.md#municipality-boundary
+[modes]: /modes/README.md
+[muni-boundary]: /provider/README.md#municipality-boundary
[propulsion-types]: /general-information.md#propulsion-types
[responses]: /general-information.md#responses
+[schema]: /schema/
[ts]: /general-information.md#timestamps
[toc]: #table-of-contents
-[vehicle-events]: /general-information.md#vehicle-state-events
-[vehicle-states]: /general-information.md#vehicle-states
+[vehicle-events]: /modes#event-types
+[vehicle-states]: /modes#vehicle-states
[vehicle-types]: /general-information.md#vehicle-types
[versioning]: /general-information.md#versioning
+[modes]: /general-information.md#modes
diff --git a/policy/examples/README.md b/policy/examples/README.md
index 99e38bc4..64de23d6 100644
--- a/policy/examples/README.md
+++ b/policy/examples/README.md
@@ -4,249 +4,544 @@ This file presents a series of example [Policy documents](../README.md#policy) f
## Table of Contents
-- [Policy Examples](#policy-examples)
- - [Table of Contents](#table-of-contents)
- - [Prohibited Zone](#prohibited-zone)
- - [Provider Cap](#provider-cap)
- - [Idle Time](#idle-time)
- - [Speed Limits](#speed-limits)
- - [Per Trip Fees](#per-trip-fees)
- - [Vehicle Right of Way Fees](#vehicle-right-of-way-fees)
- - [Metered Parking Fees](#metered-parking-fees)
- - [Required Parking](#required-parking)
- - [Tiered Parking Fees Per Hour](#tiered-parking-fees-per-hour)
- - [Tiered Parking Fees Total](#tiered-parking-fees-total)
+- [Operating Area](#operating-area)
+- [No Riding](#no-riding)
+- [No Parking](#no-parking)
+- [Parking](#parking)
+- [Parking Time Limit](#parking-time-limit)
+- [Speed Limit](#speed-limit)
+- [Distribution Policies](#distribution-policies)
+- [Provider Caps or Minimums](#provider-caps-or-minimums)
+- [Per Trip Fees](#per-trip-fees)
+- [Vehicle Right of Way Fees](#vehicle-right-of-way-fees)
+- [Metered Parking Fees](#metered-parking-fees)
+- [Tiered Parking Fees Per Hour](#tiered-parking-fees-per-hour)
+- [Tiered Parking Fees Total](#tiered-parking-fees-total)
+
+## Operating Area
+
+The vehicle should stay within the areas of operation defined (riding area).
-## Prohibited Zone
+```json
+{
+ "name": "Operating Area ",
+ "policy_id": "dcc49f37-aafb-4306-b16c-49518d5a8038",
+ "mode_id": "micromobility",
+ "provider_ids": null,
+ "description": "E-scooter operation area of the city",
+ "start_date": 1635750000000,
+ "end_date": null,
+ "published_date": 1635795374668,
+ "prev_policies": [],
+ "rules": [
+ {
+ "name": "Operating ",
+ "rule_id": "c30684c5-173b-45dc-a6fc-95776bf63dbc",
+ "rule_type": "time",
+ "geographies": [
+ "34aad1d6-fc32-4580-8881-dfd2a5b64891"
+ ],
+ "states": {
+ "available": [
+ "battery_charged",
+ "on_hours",
+ "provider_drop_off",
+ "agency_drop_off",
+ "maintenance",
+ "trip_end",
+ "reservation_cancel",
+ "trip_cancel",
+ "system_resume",
+ "comms_restored",
+ "located",
+ "unspecified"
+ ],
+ "non_operational": [
+ "battery_low",
+ "maintenance",
+ "off_hours",
+ "system_suspend",
+ "unspecified",
+ "comms_restored",
+ "located"
+ ],
+ "on_trip": [
+ "trip_start",
+ "trip_enter_jurisdiction",
+ "comms_restored",
+ "located",
+ "unspecified"
+ ],
+ "reserved": [
+ "reservation_start",
+ "comms_restored",
+ "located",
+ "unspecified"
+ ],
+ "elsewhere": [
+ "trip_leave_jurisdiction",
+ "comms_restored",
+ "located",
+ "unspecified"
+ ]
+ },
+ "rule_units": "seconds",
+ "vehicle_types": [
+ "scooter"
+ ],
+ "maximum": 0,
+ "minimum": 0,
+ "inclusive_minimum": true,
+ "inclusive_maximum": true,
+ "days": [],
+ "messages": {}
+ }
+ ]
+}
+```
-This Policy shows how to prohibit dockless vehicles from operating in a specific area. This is otherwise known as a "geofence". This geofence prohibits both:
+[Top](#table-of-contents)
-- Operators from deploying devices
-- Users from renting / dropping devices off
+## No Riding
-File: [`prohibited-zone.json`](prohibited-zone.json)
+The vehicle should not be in one of these defined areas regardless of status.
-```json
+```json
{
- "policy_id": "39a653be-7180-4188-b1a6-cae33c280341",
- "name": "Prohibited Dockless Zones",
- "description": "Prohibited areas for dockless vehicles within the City of Los Angeles for the LADOT Dockless On-Demand Personal Mobility Program",
- "provider_ids": null,
- "start_date": 1552678594428,
- "end_date": null,
- "published_date": 1552678594428,
- "prev_policies": null,
- "rules": [
- {
- "name": "Prohibited Dockless Zones",
- "rule_id": "8ad39dc3-005b-4348-9d61-c830c54c161b",
- "rule_type": "count",
- "rule_units": "devices",
- "geographies": [
- "c0591267-bb6a-4f28-a612-ff7f4a8f8b2a"
- ],
- "states": {
- "available": [],
- "non_operational": [],
- "reserved": [],
- "on_trip": []
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ],
- "maximum": 0
- }
- ]
+ "name": "No Ride Zones",
+ "policy_id": "d78625e9-5a7f-45ae-afab-18ee946acf8f",
+ "provider_ids": [],
+ "description": "The vehicle should not be in one of these defined areas regardless of status.",
+ "start_date": 1617260400000,
+ "end_date": null,
+ "published_date": 1630099948146,
+ "rules": [
+ {
+ "name": " No Ride Zone",
+ "rule_id": "a2393d69-18a2-44f6-8467-744313a956ed",
+ "rule_type": "count",
+ "rate_recurrence": null,
+ "rate_amount": null,
+ "geographies": [
+ "f0313182-1ce6-4b3f-a7ce-87ff90051462"
+ ],
+ "states": {
+ "available": [],
+ "non_operational": [],
+ "reserved": [],
+ "on_trip": []
+ },
+ "rule_units": "devices",
+ "days": null,
+ "minimum": null,
+ "maximum": 0,
+ "start_time": null,
+ "end_time": null,
+ "messages": null,
+ "value_url": null
+ }
+ ]
}
```
[Top](#table-of-contents)
-## Provider Cap
+## No Parking
+
+The vehicle should not be parked in one of these defined areas in the statuses Available, Reserved and Non-operational.
+
+```json
+{
+ "name": "No Parking Zone - SJSU" ,
+ "policy_id": "ff290586-0066-4ab9-a67c-52173785b0fa",
+ "provider_ids": [
+ "63f13c48-34ff-49d2-aca7-cf6a5b6171c3"
+ ],
+ "description": "The vehicle should not be parked in one of these defined areas in the statuses Available, Reserved and Non-operational.",
+ "start_date": 1625122800000,
+ "end_date": 1635749940000,
+ "published_date": 1631206072291,
+ "prev_policies": [],
+ "rules": [
+ {
+ "name": "No Parking Zone - SJSU",
+ "rule_id": "f092ae62-3a0d-470a-a773-6f3943df904c",
+ "rule_type": "time",
+ "geographies": [
+ "571980df-ed71-4713-afa6-a3e02962d1f0"
+ ],
+ "states": {
+ "available": [
+ "battery_charged",
+ "on_hours",
+ "provider_drop_off",
+ "agency_drop_off",
+ "maintenance",
+ "trip_end",
+ "reservation_cancel",
+ "trip_cancel",
+ "system_resume",
+ "comms_restored",
+ "located",
+ "unspecified"
+ ],
+ "non_operational": [
+ "battery_low",
+ "maintenance",
+ "off_hours",
+ "system_suspend",
+ "unspecified",
+ "comms_restored",
+ "located"
+ ],
+ "reserved": [
+ "reservation_start",
+ "comms_restored",
+ "located",
+ "unspecified"
+ ]
+ },
+ "rule_units": "seconds",
+ "vehicle_types": [
+ "scooter"
+ ],
+ "maximum": 0,
+ "minimum": 0,
+ "inclusive_minimum": true,
+ "inclusive_maximum": true,
+ "days": [],
+ "messages": {}
+ }
+ ]
+}
+```
+
+[Top](#table-of-contents)
-This Policy defines a Provider cap to incentivize deployment inside disadvantaged communities.
+## Parking
-File: [`provider-cap.json`](provider-cap.json)
+The vehicle should be parked in one of these defined areas.
```json
{
- "name": "Test City Mobility Caps: Company X",
- "description": "Mobility caps as described in the One-Year Permit",
- "policy_id": "99f7a469-6e3a-4981-9313-c2f6c0bbd5ce",
- "provider_ids": [
- "2411d395-04f2-47c9-ab66-d09e9e3c3251"
- ],
- "start_date": 1558389669540,
- "end_date": null,
- "published_date": 1558389669540,
- "prev_policies": null,
- "rules": [
- {
- "name": "Disadvantaged Community",
- "rule_id": "8a61de66-d9fa-4cba-a38d-5d948e2373fe",
- "rule_type": "count",
- "rule_units": "devices",
- "geographies": [
- "e3ed0a0e-61d3-4887-8b6a-4af4f3769c14"
- ],
- "states": {
- "available": [],
- "non_operational": [],
- "reserved": [],
- "on_trip": []
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ],
- "maximum": 10000
- },
- {
- "name": "Not Disadvantaged Communities",
- "rule_id": "57d47e74-6aef-4f41-b0c5-79bb35aa5b9d",
- "rule_type": "count",
- "rule_units": "devices",
- "geographies": [
- "1f943d59-ccc9-4d91-b6e2-0c5e771cbc49"
- ],
- "states": {
- "available": [],
- "non_operational": [],
- "reserved": [],
- "on_trip": []
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ],
- "maximum": 3000
- }
- ]
+ "name": "Parking Zone",
+ "policy_id": "ff290586-0066-4ab9-a67c-52173785b0fa",
+ "provider_ids": [
+ "63f13c48-34ff-49d2-aca7-cf6a5b6171c3"
+ ],
+ "description": "A device is allowed to park in these designated parking areas",
+ "start_date": 1625122800000,
+ "end_date": 1635749940000,
+ "published_date": 1631206072291,
+ "prev_policies": [],
+ "rules": [
+ {
+ "name": "Parking Zone",
+ "rule_id": "f092ae62-3a0d-470a-a773-6f3943df904c",
+ "rule_type": "time",
+ "geographies": [
+ "571980df-ed71-4713-afa6-a3e02962d1f0" [parking areas]
+ ],
+ "states": {
+ "available": [
+ "battery_charged",
+ "on_hours",
+ "provider_drop_off",
+ "agency_drop_off",
+ "maintenance",
+ "trip_end",
+ "reservation_cancel",
+ "trip_cancel",
+ "system_resume",
+ "comms_restored",
+ "located",
+ "unspecified"
+ ],
+ "non_operational": [
+ "battery_low",
+ "maintenance",
+ "off_hours",
+ "system_suspend",
+ "unspecified",
+ "comms_restored",
+ "located"
+ ],
+ "reserved": [
+ "reservation_start",
+ "comms_restored",
+ "located",
+ "unspecified"
+ ]
+ },
+ "rule_units": "seconds",
+ "vehicle_types": [
+ "scooter"
+ ],
+ "maximum": 0,
+ "minimum": 0,
+ "inclusive_minimum": true,
+ "inclusive_maximum": true,
+ "days": [],
+ "messages": {}
+ }
+ ]
}
```
[Top](#table-of-contents)
-## Idle Time
+## Parking Time Limit
-This Policy allows scooters and bikes can be in the public right-of-way for up to three days if rentable, and only one day if not.
+The vehicle should only be parked in one of these defined areas for a limited amount of time.
-File: [`idle-time.json`](idle-time.json)
+```json
+{
+ "name": " Parking time limit" ,
+ "policy_id": "ff290586-0066-4ab9-a67c-52173785b0fa",
+ "provider_ids": [
+ "63f13c48-34ff-49d2-aca7-cf6a5b6171c3"
+ ],
+ "description": "The vehicle should only be parked in these geographies for a limited amount of time.",
+ "start_date": 1625122800000,
+ "end_date": 1635749940000,
+ "published_date": 1631206072291,
+ "prev_policies": [],
+ "rules": [
+ {
+ "name": "Parking Time Limit",
+ "rule_id": "f092ae62-3a0d-470a-a773-6f3943df904c",
+ "rule_type": "time",
+ "geographies": [
+ "571980df-ed71-4713-afa6-a3e02962d1f0"
+ ],
+ "states": {
+ "available": [
+ "battery_charged",
+ "on_hours",
+ "provider_drop_off",
+ "agency_drop_off",
+ "maintenance",
+ "trip_end",
+ "reservation_cancel",
+ "trip_cancel",
+ "system_resume",
+ "comms_restored",
+ "located",
+ "unspecified"
+ ],
+ "non_operational": [
+ "battery_low",
+ "maintenance",
+ "off_hours",
+ "system_suspend",
+ "unspecified",
+ "comms_restored",
+ "located"
+ ],
+ "reserved": [
+ "reservation_start",
+ "comms_restored",
+ "located",
+ "unspecified"
+ ]
+ },
+ "rule_units": "seconds",
+ "vehicle_types": [
+ "scooter"
+ ],
+ "maximum": 7200,
+ "minimum": 0,
+ "inclusive_minimum": true,
+ "inclusive_maximum": true,
+ "days": [],
+ "messages": {}
+ }
+ ]
+}
+```
+
+[Top](#table-of-contents)
+
+## Speed Limit
+
+The vehicle should operate at a specific maximum speed in these defined areas.
```json
{
- "policy_id": "a2c9a65f-fd85-463e-9564-fc95ea473f7d",
- "name": "Idle Times",
- "description": "LADOT Idle Time Limitations",
- "start_date": 1552678594428,
- "end_date": null,
- "published_date": 1558389669540,
- "prev_policies": null,
- "rules": [
- {
- "name": "Greater LA (rentable)",
- "rule_id": "e1942f2d-e5c7-46c4-94c7-293d4e481ed0",
- "rule_type": "time",
- "rule_units": "hours",
- "geographies": [
- "b4bcc213-4888-48ce-a33d-4dd6c3384bda"
- ],
- "states": {
- "available": [],
- "reserved": []
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ],
- "maximum": 72
- },
- {
- "name": "Greater LA (non-rentable)",
- "rule_id": "a7eb28b9-969e-4c52-b18c-4243a96f7143",
- "rule_type": "time",
- "rule_units": "hours",
- "geographies": [
- "12b3fcf5-22af-4b0d-a169-ac7ac903d3b9"
- ],
- "states": {
- "non_operational": [],
- "on_trip": []
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ],
- "maximum": 24
- }
- ]
+ "name": "Improper Riding - Speed Limit | 7 Speed limits",
+ "policy_id": "a7cda310-e146-452f-9657-8fdb3f7b2a5d",
+ "provider_ids": [
+ "63f13c48-34ff-49d2-aca7-cf6a5b6171c3"
+ ],
+ "description": "Set Speed Limit Cap of 12 mph (> 13 mph enforced) for electric scooters within these geographies.",
+ "start_date": 1625209140000,
+ "end_date": 1635749940000,
+ "published_date": 1631202164491,
+ "prev_policies": [],
+ "rules": [
+ {
+ "name": "Speed Limit Policy",
+ "rule_id": "bd383ba9-0941-4ff2-9665-f950f5b3ffe9",
+ "rule_type": "speed",
+ "geographies": [
+ "794d7361-afdb-490e-94ba-2e0e9c387e17"
+ ],
+ "states": {},
+ "rule_units": "kmh",
+ "vehicle_types": [
+ "scooter"
+ ],
+ "maximum": 13,
+ "minimum": 0,
+ "inclusive_minimum": true,
+ "inclusive_maximum": true,
+ "days": [],
+ "messages": {}
+ }
+ ]
}
```
[Top](#table-of-contents)
-## Speed Limits
+## Distribution Policies
-This Policy sets a 15 MPH speed limit in greater LA, and a 10 MPH speed limit in Venice Beach on Saturday/Sunday from noon until midnight.
+The amount of vehicles spread amongst these defined areas are controlled.
-File: [`speed-limits.json`](speed-limits.json)
+```json
+{
+ "policy_id":"9beb897c-a3ff-4367-bd80-eae30c8eae5c",
+ "prev_policies":[],
+ "published_date":"2021-08-26T16:52:13.689923+00:00",
+ "start_date":null,
+ "name":"Deployment Equity Zones",
+ "description":"A minimum of 3 vehicles must be available in each equity zone every day.",
+ "rules":[
+ {
+ "days":[],
+ "name":"Distribution",
+ "maximum":null,
+ "minimum":3,
+ "rule_id":"02a5dfa1-3edb-2492-3a65-248d265bb95e",
+ "end_time":"09:00:00",
+ "messages":{},
+ "rule_type":"count",
+ "rule_units":"devices",
+ "start_time":"05:00:00",
+ "geographies":["b105868b-f4cb-40af-a3f2-5c5b699b8718"]
+ },
+ {
+ "days":[],
+ "name":"Distribution",
+ "maximum":null,
+ "minimum":3,
+ "rule_id":"d9ad4a83-6dff-1787-5cfe-59a7b7c47bb4",
+ "end_time":"09:00:00",
+ "messages":{},
+ "rule_type":"count",
+ "rule_units":"devices",
+ "start_time":"05:00:00",
+ "geographies":["4a339c20-8e6f-4b3a-a336-0cadac93c570"]
+ },
+ {
+ "days":[],
+ "name":"Distribution",
+ "maximum":null,
+ "minimum":3,"rule_id":
+ "a29140e0-140e-ccdd-9521-a45527f2171d",
+ "end_time":"09:00:00",
+ "messages":{},
+ "rule_type":"count",
+ "rule_units":"devices",
+ "start_time":"05:00:00",
+ "geographies":["6c0bf328-8af5-4140-8a66-bf6673fc3e1c"]
+ },
+ {"days":[],
+ "name":"Distribution",
+ "maximum":null,
+ "minimum":3,
+ "rule_id":"0f4ccc90-95b4-39bd-0d89-1d48817fb73f",
+ "end_time":"09:00:00",
+ "messages":{},
+ "rule_type":"count",
+ "rule_units":"devices",
+ "start_time":"05:00:00",
+ "geographies":["070c3590-4dea-4920-99d3-45bc4a8fc064"]
+ }
+ ]
+}
+```
+
+[Top](#table-of-contents)
+
+## Provider Caps or Minimums
+
+The maximum or minimum amount of vehicles deployed by a provider are controlled.
```json
{
- "policy_id": "95645117-fd85-463e-a2c9-fc95ea47463e",
- "name": "Speed Limits",
- "description": "LADOT Pilot Speed Limit Limitations",
- "start_date": 1552678594428,
- "end_date": null,
- "published_date": 1552678594428,
- "prev_policies": null,
- "rules": [
- {
- "name": "Venice Beach on weekend afternoons",
- "rule_id": "d4c0f42f-3f79-4eb4-850a-430b9701d5cf",
- "rule_type": "speed",
- "rule_units": "mph",
- "geographies": [
- "ec551174-f324-4251-bfed-28d9f3f473fc"
- ],
- "states": {
- "on_trip": []
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ],
- "days": [
- "sat",
- "sun"
- ],
- "start_time": "12:00:00",
- "end_time": "23:59:59",
- "maximum": 10,
- "messages": {
- "en-US": "Remember to stay under 10 MPH on Venice Beach on weekends!",
- "es-US": "¡Recuerda permanecer menos de 10 millas por hora en Venice Beach los fines de semana!"
- }
- },
- {
- "name": "Greater LA",
- "rule_id": "529b6cd7-0e0d-4439-babf-c5908a664ecf",
- "rule_type": "speed",
- "rule_units": "mph",
- "geographies": [
- "b4bcc213-4888-48ce-a33d-4dd6c3384bda"
- ],
- "states": {
- "on_trip": []
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ],
- "maximum": 15
- }
- ]
+
+ "name": "Device Limit - Lime",
+ "policy_id": "56b3b3b4-a8ee-4b19-9295-3c2d7cbd76ca",
+ "provider_ids": [
+ "63f13c48-34ff-49d2-aca7-cf6a5b6171c3"
+ ],
+ "description": "Lime is permitted for up to 750 devices. All operators must maintain a minimum of 50 devices.",
+ "start_date": 1625122800000,
+ "end_date": 1656658740000,
+ "published_date": 1631201721121,
+ "prev_policies": [],
+ "rules": [
+ {
+ "name": "Device Limit - Lime",
+ "rule_id": "563780fb-5be5-41d0-89f6-db4f238d1737",
+ "rule_type": "count",
+ "geographies": [
+ "794d7361-afdb-490e-94ba-2e0e9c387e17"
+ ],
+ "states": {
+ "available": [
+ "battery_charged",
+ "on_hours",
+ "provider_drop_off",
+ "agency_drop_off",
+ "maintenance",
+ "trip_end",
+ "reservation_cancel",
+ "trip_cancel",
+ "system_resume",
+ "comms_restored",
+ "located",
+ "unspecified"
+ ],
+ "non_operational": [
+ "battery_low",
+ "maintenance",
+ "off_hours",
+ "system_suspend",
+ "unspecified",
+ "comms_restored",
+ "located"
+ ],
+ "reserved": [
+ "reservation_start",
+ "comms_restored",
+ "located",
+ "unspecified"
+ ]
+ },
+ "rule_units": "seconds",
+ "vehicle_types": [
+ "scooter"
+ ],
+ "maximum": 750,
+ "minimum": 50,
+ "inclusive_minimum": true,
+ "inclusive_maximum": true,
+ "days": [],
+ "messages": {}
+ }
+ ]
}
```
@@ -256,8 +551,6 @@ File: [`speed-limits.json`](speed-limits.json)
This policy sets a 25 cent per-trip fee that is applied for trips that start in the municipal boundary.
-File: [`per-trip-fees.json`](per-trip-fees.json)
-
```json
{
"policy_id": "d2567b3c-3071-48a6-bbeb-3424721dbd12",
@@ -271,10 +564,11 @@ File: [`per-trip-fees.json`](per-trip-fees.json)
{
"name": "City Wide Trip Fee",
"rule_id": "4137a47c-836a-11ea-bc55-0242ac130003",
- "rule_type": "rate",
- "rule_units": "amount",
+ "rule_type": "count",
+ "rule_units": "devices",
"rate_amount": 25,
"rate_recurrence": "once_on_match",
+ "rate_applies_when": "in_bounds",
"geographies": [
"b4bcc213-4888-48ce-a33d-4dd6c3384bda"
],
@@ -294,8 +588,6 @@ File: [`per-trip-fees.json`](per-trip-fees.json)
This policy sets a Right-of-Way fee that is charged once a day for vehicles deployed in a given area. It charges a 25 cents per day for vehicles deployed downtown, and 5 cents per day for vehicles deployed in a historically underserved neighborhood. In the case where a vehicle is deployed twice in both areas in the same day, the higher fee would apply (because it appears first in the rules).
-File: [`vehicle-row-fees.json`](vehicle-row-fees.json)
-
```json
{
"policy_id": "4137a47c-836a-11ea-bc55-0242ac130003",
@@ -309,10 +601,11 @@ File: [`vehicle-row-fees.json`](vehicle-row-fees.json)
{
"rule_id": "96033eb2-eff7-4ed3-bb93-0101aff3bb6a",
"name": "Downtown Right of Way Fee",
- "rule_type": "rate",
+ "rule_type": "time",
+ "rule_units": "days",
"rate_amount": 25,
"rate_recurrence": "each_time_unit",
- "rule_units": "days",
+ "rate_applies_when": "in_bounds",
"geographies": [
"1f943d59-ccc9-4d91-b6e2-0c5e771cbc49"
],
@@ -325,10 +618,11 @@ File: [`vehicle-row-fees.json`](vehicle-row-fees.json)
{
"rule_id": "62778174-97f6-4a2b-a949-070709b4190a",
"name": "Decreased Right of Way Fee",
- "rule_type": "rate",
+ "rule_type": "time",
+ "rule_units": "days",
"rate_amount": 5,
"rate_recurrence": "each_time_unit",
- "rule_units": "days",
+ "rate_applies_when": "in_bounds",
"geographies": [
"e3ed0a0e-61d3-4887-8b6a-4af4f3769c14"
],
@@ -348,8 +642,6 @@ File: [`vehicle-row-fees.json`](vehicle-row-fees.json)
This policy sets a 10 cent per hour metered parking charge that is applied while a vehicle is parked in a congested area during rush hour.
-File: [`metered-parking-fees.json`](metered-parking-fees.json)
-
```json
{
"policy_id": "6a3dd008-836a-11ea-bc55-0242ac130003",
@@ -363,10 +655,11 @@ File: [`metered-parking-fees.json`](metered-parking-fees.json)
{
"rule_id": "0da40491-73eb-418f-9b3c-cf5f150775e8",
"name": "Downtown Peak-Hour Parking Fee",
- "rule_type": "rate",
+ "rule_type": "time",
+ "rule_units": "hours",
"rate_amount": 10,
"rate_recurrence": "per_complete_time_unit",
- "rule_units": "hours",
+ "rate_applies_when": "in_bounds",
"geographies": [
"5473e836-b38a-4940-8b5e-0d506ca4e4a8"
],
@@ -390,65 +683,6 @@ File: [`metered-parking-fees.json`](metered-parking-fees.json)
[Top](#table-of-contents)
-## Required Parking
-
-This policy states that within the downtown region, parking of scooters and bicycles must take place within specific geographies.
-
-File: [`required-parking.json`](required-parking.json)
-
-```json
-{
- "policy_id": "99f7a469-6e3a-4981-9313-c2f6c0bbd5ce",
- "name": "Test City Mobility Hubs",
- "description": "Enforced parking in specific mobility hubs for downtown area",
- "start_date": 1558389669540,
- "end_date": null,
- "published_date": 1558389669540,
- "prev_policies": null,
- "rules": [
- {
- "name": "Allow parking in specific locations",
- "rule_id": "8a61de66-d9fa-4cba-a38d-5d948e2373fe",
- "minimum": 0,
- "rule_type": "count",
- "rule_units": "devices",
- "geographies": [
- "e3ed0a0e-61d3-4887-8b6a-4af4f3769c14",
- "1512a3f4-313c-45fc-9fae-0dca6d7ab355"
- ],
- "states": {
- "available": [
- "trip_end"
- ]
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ]
- },
- {
- "name": "Disallow parking elsewhere in downtown area",
- "rule_id": "0240899e-a8ad-4263-953a-6e278ff859ab",
- "rule_type": "count",
- "maximum": 0,
- "rule_units": "devices",
- "geographies": [
- "075a5303-2571-4ca5-b429-841bcc4025d1"
- ],
- "states": {
- "available": [
- "trip_end"
- ]
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ]
- }
- ]
-}
-```
-
## Tiered Parking Fees Per Hour
This policy states parking fees as such:
- Parking for the first hour costs $2
@@ -466,8 +700,6 @@ By default the `rate_applies_when` field has the value `out_of_bounds`,
meaning the rate should take effect when an event is outside the bounds
of a rule's `minimum` and `maximum` values.
-File: [`tiered-parking-fees-per-hour.json`](tiered-parking-fees-per-hour.json)
-
```json
{
"name": "Tiered Dwell Time Example",
@@ -527,8 +759,6 @@ the rate takes effect when an event is within a rule's `minimum` and
`maximum` values. Note that this also uses the `inclusive_minimum` and
`inclusive_maximum` fields to create non-overlapping ranges for the rules.
-File: [`tiered-parking-fees-per-hour-in-bounds.json`](tiered-parking-fees-per-hour-in-bounds.json)
-
```json
{
"name": "Tiered Dwell Time Example",
@@ -589,6 +819,8 @@ File: [`tiered-parking-fees-per-hour-in-bounds.json`](tiered-parking-fees-per-ho
}
```
+[Top](#table-of-contents)
+
## Tiered Parking Fees Total
This policy states parking fees as such:
- If parked for less than an hour, $2 on exit
@@ -596,7 +828,6 @@ This policy states parking fees as such:
- If parked for any duration longer than 2 hours, $10 on exit
For example, if a vehicle is parked for 6.5 hours, it will be charged $10 on exit.
-File: [`tiered-parking-fees-total.json`](tiered-parking-fees-total.json)
```json
{
diff --git a/policy/examples/idle-time.json b/policy/examples/idle-time.json
deleted file mode 100644
index bbaf0b74..00000000
--- a/policy/examples/idle-time.json
+++ /dev/null
@@ -1,55 +0,0 @@
-{
- "updated": 0,
- "version": "1.2.0",
- "data": {
- "policies": [
- {
- "policy_id": "a2c9a65f-fd85-463e-9564-fc95ea473f7d",
- "name": "Idle Times",
- "description": "LADOT Idle Time Limitations",
- "start_date": 1552678594428,
- "end_date": null,
- "published_date": 1558389669540,
- "prev_policies": null,
- "rules": [
- {
- "name": "Greater LA (rentable)",
- "rule_id": "e1942f2d-e5c7-46c4-94c7-293d4e481ed0",
- "rule_type": "time",
- "rule_units": "hours",
- "geographies": [
- "b4bcc213-4888-48ce-a33d-4dd6c3384bda"
- ],
- "states": {
- "available": [],
- "reserved": []
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ],
- "maximum": 72
- },
- {
- "name": "Greater LA (non-rentable)",
- "rule_id": "a7eb28b9-969e-4c52-b18c-4243a96f7143",
- "rule_type": "time",
- "rule_units": "hours",
- "geographies": [
- "12b3fcf5-22af-4b0d-a169-ac7ac903d3b9"
- ],
- "states": {
- "non_operational": [],
- "on_trip": []
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ],
- "maximum": 24
- }
- ]
- }
- ]
- }
-}
\ No newline at end of file
diff --git a/policy/examples/metered-parking-fees.json b/policy/examples/metered-parking-fees.json
deleted file mode 100644
index a12a07a0..00000000
--- a/policy/examples/metered-parking-fees.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "updated": 0,
- "version": "1.2.0",
- "data": {
- "policies": [
- {
- "policy_id": "6a3dd008-836a-11ea-bc55-0242ac130003",
- "published_date": 1586736000000,
- "name": "Parking Fees",
- "description": "This policy sets a 10 cent per hour metered parking charge that is applied while a vehicle is parked in a congested area during rush hour.",
- "start_date": 1586822400000,
- "end_date": 1587427200000,
- "prev_policies": null,
- "rules": [
- {
- "rule_id": "0da40491-73eb-418f-9b3c-cf5f150775e8",
- "name": "Downtown Peak-Hour Parking Fee",
- "rule_type": "rate",
- "rate_amount": 10,
- "rate_recurrence": "per_complete_time_unit",
- "rule_units": "hours",
- "geographies": [
- "5473e836-b38a-4940-8b5e-0d506ca4e4a8"
- ],
- "days": [
- "mon",
- "tue",
- "wed",
- "thu",
- "fri"
- ],
- "start_time": "07:00:00",
- "end_time": "08:30:00",
- "states": {
- "available": [],
- "non_operational": []
- }
- }
- ]
- }
- ]
- }
-}
\ No newline at end of file
diff --git a/policy/examples/per-trip-fees.json b/policy/examples/per-trip-fees.json
deleted file mode 100644
index d48de4cc..00000000
--- a/policy/examples/per-trip-fees.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "updated": 0,
- "version": "1.2.0",
- "data": {
- "policies": [
- {
- "policy_id": "d2567b3c-3071-48a6-bbeb-3424721dbd12",
- "published_date": 1586736000000,
- "name": "Trip Fees",
- "description": "This policy sets a 25 cent per-trip fee that is applied for trips that start in the municipal boundary.",
- "start_date": 1586822400000,
- "end_date": 1587427200000,
- "prev_policies": null,
- "rules": [
- {
- "name": "City Wide Trip Fee",
- "rule_id": "4137a47c-836a-11ea-bc55-0242ac130003",
- "rule_type": "rate",
- "rule_units": "amount",
- "rate_amount": 25,
- "rate_recurrence": "once",
- "geographies": [
- "b4bcc213-4888-48ce-a33d-4dd6c3384bda"
- ],
- "states": {
- "on_trip": [
- "trip_start"
- ]
- }
- }
- ]
- }
- ]
- }
-}
\ No newline at end of file
diff --git a/policy/examples/prohibited-zone.json b/policy/examples/prohibited-zone.json
deleted file mode 100644
index 27dc080c..00000000
--- a/policy/examples/prohibited-zone.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "updated": 0,
- "version": "1.2.0",
- "data": {
- "policies": [
- {
- "policy_id": "39a653be-7180-4188-b1a6-cae33c280341",
- "name": "Prohibited Dockless Zones",
- "description": "Prohibited areas for dockless vehicles within the City of Los Angeles for the LADOT Dockless On-Demand Personal Mobility Program",
- "provider_ids": null,
- "start_date": 1552678594428,
- "end_date": null,
- "published_date": 1552678594428,
- "prev_policies": null,
- "rules": [
- {
- "name": "Prohibited Dockless Zones",
- "rule_id": "8ad39dc3-005b-4348-9d61-c830c54c161b",
- "rule_type": "count",
- "rule_units": "devices",
- "geographies": [
- "c0591267-bb6a-4f28-a612-ff7f4a8f8b2a"
- ],
- "states": {
- "available": [],
- "non_operational": [],
- "reserved": [],
- "on_trip": []
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ],
- "maximum": 0
- }
- ]
- }
- ]
- }
-}
\ No newline at end of file
diff --git a/policy/examples/provider-cap.json b/policy/examples/provider-cap.json
deleted file mode 100644
index d1006049..00000000
--- a/policy/examples/provider-cap.json
+++ /dev/null
@@ -1,62 +0,0 @@
-{
- "updated": 0,
- "version": "1.2.0",
- "data": {
- "policies": [
- {
- "name": "Test City Mobility Caps: Company X",
- "description": "Mobility caps as described in the One-Year Permit",
- "policy_id": "99f7a469-6e3a-4981-9313-c2f6c0bbd5ce",
- "provider_ids": [
- "2411d395-04f2-47c9-ab66-d09e9e3c3251"
- ],
- "start_date": 1558389669540,
- "end_date": null,
- "published_date": 1558389669540,
- "prev_policies": null,
- "rules": [
- {
- "name": "Disadvantaged Community",
- "rule_id": "8a61de66-d9fa-4cba-a38d-5d948e2373fe",
- "rule_type": "count",
- "rule_units": "devices",
- "geographies": [
- "e3ed0a0e-61d3-4887-8b6a-4af4f3769c14"
- ],
- "states": {
- "available": [],
- "non_operational": [],
- "reserved": [],
- "on_trip": []
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ],
- "maximum": 10000
- },
- {
- "name": "Not Disadvantaged Communities",
- "rule_id": "57d47e74-6aef-4f41-b0c5-79bb35aa5b9d",
- "rule_type": "count",
- "rule_units": "devices",
- "geographies": [
- "1f943d59-ccc9-4d91-b6e2-0c5e771cbc49"
- ],
- "states": {
- "available": [],
- "non_operational": [],
- "reserved": [],
- "on_trip": []
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ],
- "maximum": 3000
- }
- ]
- }
- ]
- }
-}
\ No newline at end of file
diff --git a/policy/examples/required-parking.json b/policy/examples/required-parking.json
deleted file mode 100644
index 76f13468..00000000
--- a/policy/examples/required-parking.json
+++ /dev/null
@@ -1,58 +0,0 @@
-{
- "updated": 0,
- "version": "1.2.0",
- "data": {
- "policies": [
- {
- "policy_id": "99f7a469-6e3a-4981-9313-c2f6c0bbd5ce",
- "name": "Test City Mobility Hubs",
- "description": "Enforced parking in specific mobility hubs for downtown area",
- "start_date": 1558389669540,
- "end_date": null,
- "published_date": 1558389669540,
- "prev_policies": null,
- "rules": [
- {
- "name": "Allow parking in specific locations",
- "rule_id": "8a61de66-d9fa-4cba-a38d-5d948e2373fe",
- "minimum": 0,
- "rule_type": "count",
- "rule_units": "devices",
- "geographies": [
- "e3ed0a0e-61d3-4887-8b6a-4af4f3769c14",
- "1512a3f4-313c-45fc-9fae-0dca6d7ab355"
- ],
- "states": {
- "available": [
- "trip_end"
- ]
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ]
- },
- {
- "name": "Disallow parking elsewhere in downtown area",
- "rule_id": "0240899e-a8ad-4263-953a-6e278ff859ab",
- "rule_type": "count",
- "maximum": 0,
- "rule_units": "devices",
- "geographies": [
- "075a5303-2571-4ca5-b429-841bcc4025d1"
- ],
- "states": {
- "available": [
- "trip_end"
- ]
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ]
- }
- ]
- }
- ]
- }
-}
\ No newline at end of file
diff --git a/policy/examples/requirements.md b/policy/examples/requirements.md
index 4df23334..23bf17b1 100644
--- a/policy/examples/requirements.md
+++ b/policy/examples/requirements.md
@@ -10,6 +10,7 @@ This file presents a series of example [Requirements](../README.md#requirement)
- [Trips with No Routes, Vehicles IDs, or Dates](#trips-with-no-routes-vehicle-ids-or-dates)
- [Provider and Other APIs](#provider-and-other-apis)
- [Agency](#agency)
+- [Use Cases](#use-cases)
- [Geography Driven Events](#geography-driven-events)
- [GBFS Only](#gbfs-only)
@@ -135,6 +136,7 @@ Version 1.1.0 for one provider with scooters, and 1.0.0 for another provider for
{
"data_spec_name": "MDS",
"version": "1.2.0",
+ "mode_id": "micromobility",
"required_apis": [
{
"api_name": "provider",
@@ -193,7 +195,7 @@ Version 1.1.0 for one provider with scooters, and 1.0.0 for another provider for
## Trips Only
-Version 1.1.0 for 2 providers requiring only historic Provider `/trips` with the optional `parking_verificaiton_url` field, linked to a specific MDS Policy.
+Version 1.1.0 for 2 providers requiring only historic Provider `/trips` with the optional `parking_verification_url` field, linked to a specific MDS Policy.
```json
{
@@ -318,7 +320,7 @@ Version 1.1.0 for 2 providers asking for only historic [Provider `/trips`](/prov
## Provider and Other APIs
-Version 1.1.0 or 0.4.1 for 3 providers with many APIs and endpoints.
+Version 1.1.0 or 0.4.1 for 3 providers with many APIs and endpoints, for two programs: shared dockless and city docked bikes. With use cases added.
Note: by specifying geography, policy, and jurisdiction here with a URL, the agency is in effect saying that they have created and are hosting these, and they are available for use if public.
@@ -431,6 +433,14 @@ Note: by specifying geography, policy, and jurisdiction here with a URL, the age
{
"api_name": "metrics"
}
+ ],
+ "use_cases": [
+ {
+ "external_url": "https://airtable.com/shrPf4QvORkjZmHIs/tblzFfU6fxQm5Sdhm",
+ "ids": ["OMF-MDS-2","OMF-MDS-8","OMF-MDS-12","OMF-MDS-13","OMF-MDS-14","OMF-MDS-20","OMF-MDS-29","OMF-MDS-31","OMF-MDS-44"]
+ },
+ "external_url": "https://github.com/CDSM-WG/CDS-M/tree/main/use-cases",
+ "ids": ["open-data","most-used-routes","vehicle-cap","impact-on-transit","origins","vehicle-rotation","distribution-requirements-availability","distribution-requirements-availability","publish-speed-regulations"]
]
},
{
@@ -587,6 +597,73 @@ Version 1.1.0 for 3 providers and serving Agency only linking to a defined MDS P
[Top](#table-of-contents)
+## Use Cases
+
+Version 2.0.0 for 2 providers requiring Provider `/vehicles` with external use cases for the program enumerated.
+
+```json
+{
+ "metadata": {
+ "mds_release": "2.0.0",
+ "file_version": "2",
+ "last_updated": "1611953923",
+ "max_update_interval": "P1M",
+ "agency_id": "46c9882d-1297-48fc-83e5-3067d4e9337f",
+ "agency_name": "Gemeente Amsterdam",
+ "agency_timezone": "Europe/Amsterdam",
+ "agency_language": "nl_NL",
+ "agency_currency": "EUR",
+ "agency_website_url": "https://www.cityname.gov/transportation/",
+ "url": "https://mds.cityname.gov/policy/requirements/2.0.0"
+ },
+ "programs": [
+ {
+ "description": "SMART MOBILITY Actieprogramma",
+ "program_website_url": "https://www.cityname.gov/transportation/shared-devices.html",
+ "program_document_url": "https://www.cityname.gov/mds_data_policy.pdf",
+ "provider_ids": [
+ "70aa475d-1fcd-4504-b69c-2eeb2107f7be",
+ "2411d395-04f2-47c9-ab66-d09e9e3c3251"
+ ],
+ "start_date": 1611958740,
+ "end_date": 1611970539,
+ "required_data_specs": [
+ {
+ "data_spec_name": "MDS",
+ "version": "2.0.0",
+ "required_apis": [
+ {
+ "api_name": "provider",
+ "required_endpoints": [
+ {
+ "endpoint_name": "vehicles"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "data_spec_name": "GBFS",
+ "version": "2.2"
+ }
+ ],
+ "use_cases": [
+ {
+ "external_url": "https://airtable.com/shr2cnPQvKjzONJpG",
+ "ids": ["OMF-MDS-4","OMF-MDS-12","OMF-MDS-34"]
+ },
+ {
+ "external_url": "https://github.com/CDSM-WG/CDS-M/tree/main/use-cases",
+ "ids": ["reduced-speed-area","start-trips","end-trips","realtime-events"]
+ }
+ ]
+ }
+ ]
+}
+```
+
+[Top](#table-of-contents)
+
## Geography Driven Events
Version 1.1.0 for 2 providers requiring Provider `/status_changes` with the minimum required for beta feature [Geography Driven Events](/general-information.md#geography-driven-events).
@@ -699,7 +776,6 @@ Since Requirements allows the GBFS versions and optional endpoints and fields to
{
"endpoint_name": "system_pricing_plans.json",
"required_fields": [
- "per_km_pricing",
"per_km_pricing",
"surge_pricing"
]
diff --git a/policy/examples/speed-limits.json b/policy/examples/speed-limits.json
deleted file mode 100644
index d14dd2ef..00000000
--- a/policy/examples/speed-limits.json
+++ /dev/null
@@ -1,63 +0,0 @@
-{
- "updated": 0,
- "version": "1.2.0",
- "data": {
- "policies": [
- {
- "policy_id": "95645117-fd85-463e-a2c9-fc95ea47463e",
- "name": "Speed Limits",
- "description": "LADOT Pilot Speed Limit Limitations",
- "start_date": 1552678594428,
- "end_date": null,
- "published_date": 1552678594428,
- "prev_policies": null,
- "rules": [
- {
- "name": "Venice Beach on weekend afternoons",
- "rule_id": "d4c0f42f-3f79-4eb4-850a-430b9701d5cf",
- "rule_type": "speed",
- "rule_units": "mph",
- "geographies": [
- "ec551174-f324-4251-bfed-28d9f3f473fc"
- ],
- "states": {
- "on_trip": []
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ],
- "days": [
- "sat",
- "sun"
- ],
- "start_time": "12:00:00",
- "end_time": "23:59:59",
- "maximum": 10,
- "messages": {
- "en-US": "Remember to stay under 10 MPH on Venice Beach on weekends!",
- "es-US": "¡Recuerda permanecer menos de 10 millas por hora en Venice Beach los fines de semana!"
- }
- },
- {
- "name": "Greater LA",
- "rule_id": "529b6cd7-0e0d-4439-babf-c5908a664ecf",
- "rule_type": "speed",
- "rule_units": "mph",
- "geographies": [
- "b4bcc213-4888-48ce-a33d-4dd6c3384bda"
- ],
- "states": {
- "on_trip": []
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ],
- "maximum": 15
- }
- ]
- }
- ]
- }
-}
\ No newline at end of file
diff --git a/policy/examples/tiered-parking-fees-per-hour-in-bounds.json b/policy/examples/tiered-parking-fees-per-hour-in-bounds.json
deleted file mode 100644
index 3a2489c8..00000000
--- a/policy/examples/tiered-parking-fees-per-hour-in-bounds.json
+++ /dev/null
@@ -1,89 +0,0 @@
-{
- "updated": 0,
- "version": "1.2.0",
- "data": {
- "policies": [
- {
- "name": "Tiered Dwell Time Example",
- "description": "First hour $2, second hour $4, every hour onwards $10",
- "policy_id": "2800cd0a-7827-4110-9713-b9e5bf29e9a1",
- "start_date": 1558389669540,
- "publish_date": 1558389669540,
- "end_date": null,
- "prev_policies": null,
- "provider_ids": [],
- "currency": "USD",
- "rules": [
- {
- "name": "0-1 Hour",
- "rule_id": "6b6fe61b-dbe5-4367-8e35-84fb14d23c54",
- "rule_type": "time",
- "rule_units": "hours",
- "geographies": [
- "0c77c813-bece-4e8a-84fd-f99af777d198"
- ],
- "statuses": {
- "available": [],
- "non_operational": []
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ],
- "maximum": 1,
- "inclusive_maximum": false,
- "rate_applies_when": "in_bounds",
- "rate_amount": 200,
- "rate_recurrence": "each_time_unit"
- },
- {
- "name": "1-2 Hours",
- "rule_id": "edd6a195-bb30-4eb5-a2cc-44e5a18798a2",
- "rule_type": "time",
- "rule_units": "hours",
- "geographies": [
- "0c77c813-bece-4e8a-84fd-f99af777d198"
- ],
- "statuses": {
- "available": [],
- "non_operational": []
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ],
- "minimum": 1,
- "maximum": 2,
- "inclusive_minimum": true,
- "inclusive_maximum": false,
- "rate_applies_when": "in_bounds",
- "rate_amount": 400,
- "rate_recurrence": "each_time_unit"
- },
- {
- "name": "> 2 hours",
- "rule_id": "9cd1768c-ab9e-484c-93f8-72a7078aa7b9",
- "rule_type": "time",
- "rule_units": "hours",
- "geographies": [
- "0c77c813-bece-4e8a-84fd-f99af777d198"
- ],
- "statuses": {
- "available": [],
- "non_operational": []
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ],
- "minimum": 2,
- "inclusive_minimum": true,
- "rate_applies_when": "in_bounds",
- "rate_amount": 1000,
- "rate_recurrence": "each_time_unit"
- }
- ]
- }
- ]
- }
-}
diff --git a/policy/examples/tiered-parking-fees-per-hour.json b/policy/examples/tiered-parking-fees-per-hour.json
deleted file mode 100644
index aa973921..00000000
--- a/policy/examples/tiered-parking-fees-per-hour.json
+++ /dev/null
@@ -1,81 +0,0 @@
-{
- "updated": 0,
- "version": "1.2.0",
- "data": {
- "policies": [
- {
- "name": "Tiered Dwell Time Example",
- "description": "First hour $2, second hour $4, every hour onwards $10",
- "policy_id": "2800cd0a-7827-4110-9713-b9e5bf29e9a1",
- "start_date": 1558389669540,
- "publish_date": 1558389669540,
- "end_date": null,
- "prev_policies": null,
- "provider_ids": [],
- "currency": "USD",
- "rules": [
- {
- "name": "> 2 hours",
- "rule_id": "9cd1768c-ab9e-484c-93f8-72a7078aa7b9",
- "rule_type": "time",
- "rule_units": "hours",
- "geographies": [
- "0c77c813-bece-4e8a-84fd-f99af777d198"
- ],
- "statuses": {
- "available": [],
- "non_operational": []
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ],
- "maximum": 2,
- "rate_amount": 1000,
- "rate_recurrence": "each_time_unit"
- },
- {
- "name": "1-2 Hours",
- "rule_id": "edd6a195-bb30-4eb5-a2cc-44e5a18798a2",
- "rule_type": "time",
- "rule_units": "hours",
- "geographies": [
- "0c77c813-bece-4e8a-84fd-f99af777d198"
- ],
- "statuses": {
- "available": [],
- "non_operational": []
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ],
- "maximum": 1,
- "rate_amount": 400,
- "rate_recurrence": "each_time_unit"
- },
- {
- "name": "0-1 Hour",
- "rule_id": "6b6fe61b-dbe5-4367-8e35-84fb14d23c54",
- "rule_type": "time",
- "rule_units": "hours",
- "geographies": [
- "0c77c813-bece-4e8a-84fd-f99af777d198"
- ],
- "statuses": {
- "available": [],
- "non_operational": []
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ],
- "maximum": 0,
- "rate_amount": 200,
- "rate_recurrence": "each_time_unit"
- }
- ]
- }
- ]
- }
-}
diff --git a/policy/examples/tiered-parking-fees-total.json b/policy/examples/tiered-parking-fees-total.json
deleted file mode 100644
index dac70774..00000000
--- a/policy/examples/tiered-parking-fees-total.json
+++ /dev/null
@@ -1,81 +0,0 @@
-{
- "updated": 0,
- "version": "1.2.0",
- "data": {
- "policies": [
- {
- "name": "Tiered Dwell Time Example",
- "description": "If parked for <1hr $2 upon exit, if parked for 1-2 hours $4 upon exit, if parked for longer than 2 hours $10 upon exit",
- "policy_id": "2800cd0a-7827-4110-9713-b9e5bf29e9a1",
- "start_date": 1558389669540,
- "publish_date": 1558389669540,
- "end_date": null,
- "prev_policies": null,
- "provider_ids": [],
- "currency": "USD",
- "rules": [
- {
- "name": "> 2 hours",
- "rule_id": "9cd1768c-ab9e-484c-93f8-72a7078aa7b9",
- "rule_type": "time",
- "rule_units": "hours",
- "geographies": [
- "0c77c813-bece-4e8a-84fd-f99af777d198"
- ],
- "statuses": {
- "available": [],
- "non_operational": []
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ],
- "maximum": 2,
- "rate_amount": 1000,
- "rate_recurrence": "once_on_unmatch"
- },
- {
- "name": "1-2 Hours",
- "rule_id": "edd6a195-bb30-4eb5-a2cc-44e5a18798a2",
- "rule_type": "time",
- "rule_units": "hours",
- "geographies": [
- "0c77c813-bece-4e8a-84fd-f99af777d198"
- ],
- "statuses": {
- "available": [],
- "non_operational": []
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ],
- "maximum": 1,
- "rate_amount": 400,
- "rate_recurrence": "once_on_unmatch"
- },
- {
- "name": "0-1 Hour",
- "rule_id": "6b6fe61b-dbe5-4367-8e35-84fb14d23c54",
- "rule_type": "time",
- "rule_units": "hours",
- "geographies": [
- "0c77c813-bece-4e8a-84fd-f99af777d198"
- ],
- "statuses": {
- "available": [],
- "non_operational": []
- },
- "vehicle_types": [
- "bicycle",
- "scooter"
- ],
- "maximum": 0,
- "rate_amount": 200,
- "rate_recurrence": "once_on_unmatch"
- }
- ]
- }
- ]
- }
-}
diff --git a/policy/examples/vehicle-row-fees.json b/policy/examples/vehicle-row-fees.json
deleted file mode 100644
index ec6ea351..00000000
--- a/policy/examples/vehicle-row-fees.json
+++ /dev/null
@@ -1,51 +0,0 @@
-{
- "updated": 0,
- "version": "1.2.0",
- "data": {
- "policies": [
- {
- "policy_id": "4137a47c-836a-11ea-bc55-0242ac130003",
- "published_date": 1586736000000,
- "name": "Right of Way Fees",
- "description": "This policy sets a Right-of-Way fee that is charged once a day for vehicles deployed in a given area. It charges a 25 cents per day for vehicles deployed downtown, and 5 cents per day for vehicles deployed in a historically underserved neighborhood.",
- "start_date": 1586822400000,
- "end_date": 1587427200000,
- "prev_policies": null,
- "rules": [
- {
- "rule_id": "96033eb2-eff7-4ed3-bb93-0101aff3bb6a",
- "name": "Downtown Right of Way Fee",
- "rule_type": "rate",
- "rate_amount": 25,
- "rate_recurrence": "each_time_unit",
- "rule_units": "days",
- "geographies": [
- "1f943d59-ccc9-4d91-b6e2-0c5e771cbc49"
- ],
- "states": {
- "available": [
- "on_hours"
- ]
- }
- },
- {
- "rule_id": "62778174-97f6-4a2b-a949-070709b4190a",
- "name": "Decreased Right of Way Fee",
- "rule_type": "rate",
- "rate_amount": 5,
- "rate_recurrence": "each_time_unit",
- "rule_units": "days",
- "geographies": [
- "e3ed0a0e-61d3-4887-8b6a-4af4f3769c14"
- ],
- "states": {
- "available": [
- "on_hours"
- ]
- }
- }
- ]
- }
- ]
- }
-}
\ No newline at end of file
diff --git a/policy/policy.json b/policy/policy.json
deleted file mode 100644
index b937f00e..00000000
--- a/policy/policy.json
+++ /dev/null
@@ -1,649 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/policy/policy.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "The MDS Policy Schema",
- "type": "object",
- "definitions": {
- "policy": {
- "$id": "#/definitions/policy",
- "type": "object",
- "title": "The policy object schema",
- "additionalProperties": false,
- "required": [
- "name",
- "policy_id",
- "description",
- "start_date",
- "published_date",
- "rules"
- ],
- "properties": {
- "name": {
- "$id": "#/definitions/policy/properties/name",
- "$ref": "#/definitions/string",
- "description": "Name of policy"
- },
- "policy_id": {
- "$id": "#/definitions/policy/properties/policy_id",
- "$ref": "#/definitions/uuid",
- "description": "Unique ID of policy"
- },
- "provider_ids": {
- "$id": "#/definitions/policy/properties/provider_ids",
- "$ref": "#/definitions/null_uuid_array",
- "description": "Providers for whom this policy is applicable; empty arrays and null/absent implies all Providers.",
- "uniqueItems": true
- },
- "description": {
- "$id": "#/definitions/policy/properties/description",
- "$ref": "#/definitions/string",
- "description": "Description of policy"
- },
- "currency": {
- "$id": "#/definitions/policy/properties/currency",
- "$ref": "#/definitions/currency"
- },
- "start_date": {
- "$id": "#/definitions/policy/properties/start_date",
- "$ref": "#/definitions/timestamp",
- "description": "Beginning date/time of policy enforcement"
- },
- "end_date": {
- "$id": "#/definitions/policy/properties/end_date",
- "$ref": "#/definitions/null_timestamp",
- "description": "End date/time of policy enforcement"
- },
- "published_date": {
- "$id": "#/definitions/policy/properties/published_date",
- "$ref": "#/definitions/timestamp",
- "description": "Timestamp at which the policy was published"
- },
- "prev_policies": {
- "$id": "#/definitions/policy/properties/prev_policies",
- "$ref": "#/definitions/null_uuid_array",
- "description": "Unique IDs of prior policies replaced by this one",
- "uniqueItems": true
- },
- "rules": {
- "$id": "#/definitions/rules",
- "type": "array",
- "description": "Array of applicable Rule objects",
- "items": {
- "$id": "#/definitions/policy/properties/rules/items",
- "$ref": "#/definitions/rule"
- },
- "minItems": 1
- }
- }
- },
- "rule": {
- "$id": "#/definitions/rule",
- "type": "object",
- "description": "An individual rule in a policy",
- "additionalProperties": false,
- "required": [
- "name",
- "rule_id",
- "rule_type",
- "geographies",
- "states"
- ],
- "properties": {
- "name": {
- "$id": "#/definitions/rule/properties/name",
- "$ref": "#/definitions/string",
- "description": "Name of rule"
- },
- "rule_id": {
- "$id": "#/definitions/rule/properties/rule_id",
- "$ref": "#/definitions/uuid",
- "description": "Unique ID of rule"
- },
- "rule_type": {
- "$id": "#/definitions/rule/properties/rule_type",
- "type": "string",
- "description": "The type of rule",
- "enum": [
- "count",
- "time",
- "speed",
- "rate",
- "user"
- ]
- },
- "geographies": {
- "$id": "#/definitions/rule/properties/geographies",
- "$ref": "#/definitions/uuid_array",
- "description": "List of Geography UUIDs (non-overlapping) specifying the covered geography",
- "minItems": 1,
- "uniqueItems": true
- },
- "states": {
- "$id": "#/definitions/rule/properties/states",
- "type": "object",
- "description": "Vehicle state to which this rule applies. Optionally provide a list of specific vehicle events as a subset of a given state for the rule to apply to. An empty list or null/absent defaults to \"all\" for the state.",
- "propertyNames": {
- "$id": "#/definitions/rule/properties/states/propertyNames",
- "$ref": "#/definitions/vehicle_state"
- },
- "properties": {},
- "additionalProperties": {
- "type": "array",
- "uniqueItems": true,
- "items": {
- "$ref": "#/definitions/vehicle_event"
- }
- }
- },
- "rule_units": {
- "$id": "#/definitions/rule/properties/rule_units",
- "type": "string",
- "description": "Measured units of policy",
- "enum": [
- "seconds",
- "minutes",
- "hours",
- "days",
- "mph",
- "kph",
- "devices",
- "amount"
- ]
- },
- "vehicle_types": {
- "$id": "#/definitions/rule/properties/vehicle_types",
- "$ref": "#/definitions/null_vehicle_types",
- "description": "Applicable vehicle types, default \"all\""
- },
- "propulsion_types": {
- "$id": "#/definitions/rule/properties/propulsion_types",
- "$ref": "#/definitions/null_propulsion_types",
- "description": "Applicable vehicle propulsion types, default \"all\""
- },
- "minimum": {
- "$id": "#/definitions/rule/properties/minimum",
- "type": [
- "null",
- "integer"
- ],
- "description": "Minimum value, if applicable (default 0)"
- },
- "maximum": {
- "$id": "#/definitions/rule/properties/maximum",
- "type": [
- "null",
- "integer"
- ],
- "description": "Maximum value, if applicable (default unlimited)"
- },
- "inclusive_minimum": {
- "$id": "#/definitions/rule/properties/inclusive_minimum",
- "type": [
- "null",
- "boolean"
- ],
- "description": "Whether the rule minimum is considered in-bounds (default true)"
- },
- "inclusive_maximum": {
- "$id": "#/definitions/rule/properties/inclusive_maximum",
- "type": [
- "null",
- "boolean"
- ],
- "description": "Whether the rule maximum is considered in-bounds (default true)"
- },
- "rate_amount": {
- "$id": "#/definitions/rule/properties/rate_amount",
- "type": [
- "null",
- "integer"
- ],
- "description": "The amount of a rate applied when this rule applies, if applicable (default zero). A positive integer rate amount represents a fee, while a negative integer represents a subsidy. Rate amounts are given in the currency defined in the Policy."
- },
- "rate_recurrence": {
- "$id": "#/definitions/rule/properties/rate_recurrence",
- "type": [
- "string",
- "null"
- ],
- "description": "Specify how a rate is applied \u00e2\u20ac\u201c either once, or periodically according to a time unit specified using rule_units",
- "enum": [
- "once_on_match",
- "once_on_unmatch",
- "each_time_unit",
- "per_complete_time_unit"
- ]
- },
- "rate_applies_when": {
- "$id": "#/definitions/rule/properties/rate_applies_when",
- "type": [
- "string",
- "null"
- ],
- "description": "Specify when a rate is applicable to an event or count: when it's within rule bounds or when it is not",
- "enum": [
- "in_bounds",
- "out_of_bounds"
- ]
- },
- "start_time": {
- "$id": "#/definitions/rule/properties/start_time",
- "$ref": "#/definitions/null_iso_time",
- "description": "Beginning time-of-day when the rule is in effect (default 00:00:00)"
- },
- "end_time": {
- "$id": "#/definitions/rule/properties/end_time",
- "$ref": "#/definitions/null_iso_time",
- "description": "Ending time-of-day when the rule is in effect (default 23:59:59)"
- },
- "days": {
- "$id": "#/definitions/rule/properties/days",
- "$ref": "#/definitions/null_days",
- "description": "Days when the rule is in effect (default all)"
- },
- "messages": {
- "$id": "#/definitions/rule/properties/messages",
- "type": [
- "null",
- "object"
- ],
- "description": "Message to rider user, if desired, in various languages, keyed by BCP 47 language tag",
- "propertyNames": {
- "pattern": "([A-Za-z]{2,3})([-][A-Za-z]{3}){0,3}([-]([A-Za-z]{4}))?([-]([A-Za-z]{2}|[0-9]{3}))?"
- }
- },
- "value_url": {
- "$id": "#/definitions/rule/properties/value_url",
- "type": [
- "null",
- "string"
- ],
- "description": "URL to an API endpoint that can provide dynamic information for the measured value",
- "format": "uri"
- }
- },
- "allOf": [
- {
- "description": "Valid rule_type and rule_unit values for this rule",
- "oneOf": [
- {
- "properties": {
- "rule_type": {
- "const": "user"
- }
- }
- },
- {
- "allOf": [
- {
- "required": [
- "rule_units"
- ]
- },
- {
- "oneOf": [
- {
- "properties": {
- "rule_type": {
- "const": "time"
- },
- "rule_units": {
- "enum": [
- "seconds",
- "minutes",
- "hours",
- "days"
- ]
- }
- }
- },
- {
- "properties": {
- "rule_type": {
- "const": "speed"
- },
- "rule_units": {
- "enum": [
- "mph",
- "kph"
- ]
- }
- }
- },
- {
- "properties": {
- "rule_type": {
- "const": "count"
- },
- "rule_units": {
- "enum": [
- "devices"
- ]
- }
- }
- },
- {
- "required": [
- "rate_amount",
- "rate_recurrence"
- ],
- "properties": {
- "rule_type": {
- "const": "rate"
- },
- "rule_units": {
- "enum": [
- "amount",
- "seconds",
- "minutes",
- "hours",
- "days"
- ]
- }
- }
- }
- ]
- }
- ]
- }
- ]
- }
- ]
- },
- "currency": {
- "$id": "#/definitions/currency",
- "type": [
- "string",
- "null"
- ],
- "pattern": "^[A-Z]{3}$",
- "default": "USD",
- "description": "An ISO 4217 Alphabetic Currency Code representing currency of the payee. If null, USD cents is implied.",
- "examples": [
- "USD",
- "EUR",
- "GBP"
- ]
- },
- "day": {
- "$id": "#/definitions/day",
- "type": "string",
- "description": "A day of the week",
- "enum": [
- "sun",
- "mon",
- "tue",
- "wed",
- "thu",
- "fri",
- "sat"
- ]
- },
- "propulsion_type": {
- "$id": "#/definitions/propulsion_type",
- "type": "string",
- "description": "The type of propulsion",
- "enum": [
- "combustion",
- "electric",
- "electric_assist",
- "human"
- ]
- },
- "string": {
- "$id": "#/definitions/string",
- "type": "string",
- "description": "A length-limited string type",
- "maxLength": 255,
- "default": "",
- "examples": [
- "ABC123"
- ],
- "pattern": "^(.*)$"
- },
- "timestamp": {
- "$id": "#/definitions/timestamp",
- "type": "number",
- "description": "Integer milliseconds since Unix epoch",
- "multipleOf": 1.0,
- "minimum": 1514764800000
- },
- "uuid": {
- "$id": "#/definitions/uuid",
- "type": "string",
- "description": "A UUID used to uniquely identifty an object",
- "default": "",
- "examples": [
- "3c9604d6-b5ee-11e8-96f8-529269fb1459"
- ],
- "pattern": "^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$"
- },
- "uuid_array": {
- "$id": "#/definitions/uuid_array",
- "type": "array",
- "description": "Array of UUID",
- "items": {
- "$id": "#/definitions/uuid_array/items",
- "$ref": "#/definitions/uuid"
- }
- },
- "vehicle_event": {
- "$id": "#/definitions/vehicle_event",
- "type": "string",
- "description": "An event that changes a vehicle's state",
- "enum": [
- "agency_drop_off",
- "agency_pick_up",
- "battery_charged",
- "battery_low",
- "comms_lost",
- "comms_restored",
- "compliance_pick_up",
- "decommissioned",
- "located",
- "maintenance",
- "maintenance_pick_up",
- "missing",
- "off_hours",
- "on_hours",
- "provider_drop_off",
- "rebalance_pick_up",
- "reservation_cancel",
- "reservation_start",
- "system_resume",
- "system_suspend",
- "trip_cancel",
- "trip_end",
- "trip_enter_jurisdiction",
- "trip_leave_jurisdiction",
- "trip_start",
- "unspecified"
- ]
- },
- "vehicle_state": {
- "$id": "#/definitions/vehicle_state",
- "type": "string",
- "description": "The state of a vehicle",
- "enum": [
- "available",
- "elsewhere",
- "non_operational",
- "on_trip",
- "removed",
- "reserved",
- "unknown"
- ]
- },
- "vehicle_type": {
- "$id": "#/definitions/vehicle_type",
- "type": "string",
- "description": "The type of vehicle",
- "enum": [
- "bicycle",
- "cargo_bicycle",
- "car",
- "scooter",
- "moped",
- "other"
- ]
- },
- "version": {
- "$id": "#/definitions/version",
- "type": "string",
- "description": "The version of MDS this data represents",
- "examples": [
- "1.2.0"
- ],
- "pattern": "^1\\.2\\.[0-9]+$"
- },
- "days": {
- "$id": "#/definitions/days",
- "type": "array",
- "description": "Array of days of the week",
- "items": {
- "$id": "#/definitions/days/items",
- "$ref": "#/definitions/day"
- },
- "uniqueItems": true
- },
- "iso_time": {
- "$id": "#/definitions/iso_time",
- "type": "string",
- "description": "Time-of-day expressed as ISO 8601 hh:mm:ss",
- "pattern": "([0-2][0-3]|[0-1][0-9]):[0-5][0-9]:[0-5][0-9]"
- },
- "propulsion_types": {
- "$id": "#/definitions/propulsion_types",
- "type": "array",
- "description": "Array of propulsion types, allowing multiple values",
- "items": {
- "$id": "#/definitions/propulsion_types/items",
- "$ref": "#/definitions/propulsion_type"
- },
- "uniqueItems": true
- },
- "vehicle_types": {
- "$id": "#/definitions/vehicle_types",
- "type": "array",
- "description": "Array of vehicle types",
- "items": {
- "$id": "#/definitions/vehicle_types/items",
- "$ref": "#/definitions/vehicle_type"
- },
- "uniqueItems": true
- },
- "null_days": {
- "$id": "#/definitions/null_days",
- "type": [
- "array",
- "null"
- ],
- "description": "Array of days of the week",
- "items": {
- "$id": "#/definitions/days/items",
- "$ref": "#/definitions/day"
- },
- "uniqueItems": true
- },
- "null_iso_time": {
- "$id": "#/definitions/null_iso_time",
- "type": [
- "string",
- "null"
- ],
- "description": "Time-of-day expressed as ISO 8601 hh:mm:ss",
- "pattern": "([0-2][0-3]|[0-1][0-9]):[0-5][0-9]:[0-5][0-9]"
- },
- "null_propulsion_types": {
- "$id": "#/definitions/null_propulsion_types",
- "type": [
- "array",
- "null"
- ],
- "description": "Array of propulsion types, allowing multiple values",
- "items": {
- "$id": "#/definitions/propulsion_types/items",
- "$ref": "#/definitions/propulsion_type"
- },
- "uniqueItems": true
- },
- "null_timestamp": {
- "$id": "#/definitions/null_timestamp",
- "type": [
- "number",
- "null"
- ],
- "description": "Integer milliseconds since Unix epoch",
- "multipleOf": 1.0,
- "minimum": 1514764800000
- },
- "null_uuid_array": {
- "$id": "#/definitions/null_uuid_array",
- "type": [
- "array",
- "null"
- ],
- "description": "Array of UUID",
- "items": {
- "$id": "#/definitions/uuid_array/items",
- "$ref": "#/definitions/uuid"
- }
- },
- "null_vehicle_types": {
- "$id": "#/definitions/null_vehicle_types",
- "type": [
- "array",
- "null"
- ],
- "description": "Array of vehicle types",
- "items": {
- "$id": "#/definitions/vehicle_types/items",
- "$ref": "#/definitions/vehicle_type"
- },
- "uniqueItems": true
- }
- },
- "required": [
- "data",
- "updated",
- "version"
- ],
- "properties": {
- "data": {
- "$id": "#/properties/data",
- "type": "object",
- "description": "The data records in this payload",
- "required": [
- "policies"
- ],
- "properties": {
- "policies": {
- "$id": "#/properties/data/properties/policies",
- "type": "array",
- "title": "The array of policy objects in this payload",
- "items": {
- "$id": "#/properties/data/properties/policies/items",
- "$ref": "#/definitions/policy"
- }
- }
- },
- "additionalProperties": false
- },
- "end_date": {
- "$id": "#/properties/end_date",
- "$ref": "#/definitions/null_timestamp",
- "description": "The timestamp after which the Policy is no longer effective"
- },
- "updated": {
- "$id": "#/properties/updated",
- "$ref": "#/definitions/timestamp",
- "description": "The timestamp when the Policy was last updated"
- },
- "version": {
- "$id": "#/properties/version",
- "$ref": "#/definitions/version",
- "description": "The version of MDS that the Policy represents"
- }
- },
- "additionalProperties": false
-}
diff --git a/provider/README.md b/provider/README.md
index f854b65e..e4f7b09a 100644
--- a/provider/README.md
+++ b/provider/README.md
@@ -2,72 +2,91 @@
-The Provider API endpoints are intended to be implemented by mobility providers and consumed by regulatory agencies. When a municipality queries information from a mobility provider, the Provider API has a historical view of operations in a standard format.
+The Provider API endpoints are intended to be implemented by mobility providers and consumed by regulatory agencies. Data is **pulled** from providers by agencies. When a municipality queries information from a mobility provider, the Provider API has a historical view of operations in a standard format.
This specification contains a data standard for *mobility as a service* providers to define a RESTful API for municipalities to access on-demand.
## Table of Contents
* [General Information](#general-information)
+ * [Authorization](#authorization)
* [Versioning](#versioning)
+ * [Modes](#modes)
* [Responses and Error Messages](#responses-and-error-messages)
- * [JSON Schema](#json-schema)
+ * [GBFS](#GBFS)
+ * [Data Latency Requirements][data-latency]
+ * [Data Schema](#data-schema)
* [Pagination](#pagination)
* [Municipality Boundary](#municipality-boundary)
- * [Event Times](#event-times)
* [Other Data Types](#other-data-types)
-* [Trips][trips]
+* [Vehicles](#vehicles)
+ * [Vehicle Status](#vehicle-status)
+* [Trips](#trips)
* [Trips - Query Parameters](#trips---query-parameters)
- * [Routes](#routes)
-* [Status Changes][status]
- * [Status Changes - Query Parameters](#status-changes---query-parameters)
+ * [Trips - Responses](#trips---responses)
+* [Telemetry](#telemetry)
+ * [Telemetry - Query Parameters](#telemetry---query-parameters)
+* [Events](#events)
+ * [Historical Events - Query Parameters](#historical-events---query-parameters)
+ * [Historical Events - Responses](#historical-events---responses)
+ * [Recent Events](#recent-events)
+ * [Recent Events - Query Parameters](#recent-events---query-parameters)
+* [Stops](#stops)
* [Reports](#reports)
* [Reports - Response](#reports---response)
* [Reports - Example](#reports---example)
- * [Special Group Type](#special-group-type)
- * [Data Redaction](#data-redaction)
-* [Realtime Data](#realtime-data)
- * [GBFS](#GBFS)
- * [Data Latency Requirements][data-latency]
- * [Events][events]
- * [Stops](#stops)
- * [Vehicles][vehicles]
## General Information
-The following information applies to all `provider` API endpoints. Details on providing authorization to endpoints is specified in the [auth](auth.md) document.
+The following information applies to all `provider` API endpoints.
This specification uses data types including timestamps, UUIDs, and vehicle state definitions as described in the MDS [General Information][general-information] document.
[Top][toc]
+### Authorization
+
+MDS Provider endpoint producers **SHALL** provide authorization for API endpoints via a bearer token based auth system. When making requests, the endpoints expect `provider_id` to be part of the claims in a [JSON Web Token](https://jwt.io/) (JWT) `access_token` in the `Authorization` header, in the form `Authorization: Bearer `. The token issuance, expiration and revocation policies are at the discretion of the agency. [JSON Web Token](/general-information.md#json-web-tokens) is the recommended format.
+
+General authorization details are specified in the [Authorization section](/general-information.md#authorization) in MDS General Information.
+
+[Top][toc]
+
### Versioning
-`provider` APIs must handle requests for specific versions of the specification from clients.
+`Provider` APIs must handle requests for specific versions of the specification from clients.
Versioning must be implemented as specified in the [Versioning section][versioning].
[Top][toc]
+### Modes
+
+MDS is intended to be used for multiple transportation modes, including its original micromobility (e-scooters, bikes, etc.) mode, as well as additional modes such as taxis, car share, and delivery bots. A given `provider_id` shall be associated with a single mobility [mode], so that the mode does not have to be specified in each data structure and API call. A provider implementing more than one mode shall [register](/README.md#providers-using-mds) a unique `provider_id` for each mode.
+
+[Top][toc]
+
### Responses and Error Messages
The response to a client request must include a valid HTTP status code defined in the [IANA HTTP Status Code Registry][iana].
-See [Responses][responses] for information on valid MDS response codes and [Error Messages][error-messages] for information on formatting error messages.
-
The response must set the `Content-Type` header as specified in the [Versioning section][versioning].
-Response bodies must be a `UTF-8` encoded JSON object and must minimally include the MDS `version` and a `data` payload:
+Response bodies must be a `UTF-8` encoded JSON object
+
+See the [Responses][responses], [Error Messages][error-messages], and [Bulk Responses][bulk-responses] sections, and the [schema][schema] for more details.
+
+Response bodies must be a `UTF-8` encoded JSON object and must minimally include the MDS `version` and an object payload:
```json
{
"version": "x.y.z",
- "data": {
- "trips": [{
- "provider_id": "...",
- "trip_id": "...",
- }]
- }
+ "trips": [
+ {
+ "provider_id": "...",
+ "trip_id": "..."
+ }
+ ]
}
```
@@ -75,17 +94,32 @@ All response fields must use `lower_case_with_underscores`.
[Top][toc]
-### JSON Schema
+### GBFS
-MDS defines [JSON Schema][json-schema] files for each endpoint.
+See the [GBFS Requirement](/README.md#gbfs-requirement) language for more details.
-`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.
+[Top][toc]
+
+### Data Latency Requirements
+
+The data returned by a near-realtime endpoint should be as close to realtime as possible, but in no case should it be more than 5 minutes out-of-date. Near-realtime endpoints must contain `last_updated` and `ttl` properties in the top-level of the response body. These properties are defined as:
+
+Field Name | Required | Defines
+--------------------| ----------| ----------
+last_updated | Yes | Timestamp indicating the last time the data in this feed was updated
+ttl | Yes | Integer representing the number of milliseconds before the data in this feed will be updated again (0 if the data should always be refreshed).
+
+[Top][toc]
+
+### Data Schema
+
+See the [Endpoints](#endpoints) below for information on their specific schema, and the [`mds-openapi`](https://github.com/openmobilityfoundation/mds-openapi) repository for full details and interactive documentation.
[Top][toc]
### Pagination
-The `/trips` and `/status_changes` endpoints must not use pagination.
+The `/trips` and `/events/historical` endpoints must not use pagination.
If Providers choose to use pagination for either of the `/events` or `/vehicles` endpoints, the pagination must comply with the [JSON API][json-api-pagination] specification.
@@ -101,12 +135,10 @@ At a minimum, paginated payloads must include a `next` key, which must be set to
```json
{
"version": "x.y.z",
- "data": {
- "trips": [{
- "provider_id": "...",
- "trip_id": "...",
- }]
- },
+ "trips": [{
+ "provider_id": "...",
+ "trip_id": "...",
+ }],
"links": {
"first": "https://...",
"last": "https://...",
@@ -128,21 +160,120 @@ Providers are not required to recalculate the set of historical data that is inc
[Top][toc]
-### Event Times
+### Other Data Types
-Because of the unreliability of device clocks, the Provider is unlikely to know with total confidence what time an event occurred at. However, Providers are responsible for constructing as accurate a timeline as possible. Most importantly, the order of the timestamps for a particular device's events must reflect the Provider's best understanding of the order in which those events occurred.
+For Timestamps, Vehicle Types, Propulsion Types, UUIDs, Costs, and Currencies, refer to the MDS [General Information][general-information] document.
[Top][toc]
-### Other Data Types
+## Vehicles
-For Timestamps, Vehicle Types, Propulsion Types, UUIDs, Costs, and Currencies, refer to the MDS [General Information][general-information] document.
+The `/vehicles` is a near-realtime endpoint and returns the current status of vehicles in an agency's [Jurisdiction](/general-information.md#definitions) and/or area of agency responsibility. All vehicles that are currently in any [`vehicle_state`][vehicle-states] should be returned in this payload. Since all states are returned, care should be taken to filter out states not in the [PROW](/general-information.md#definitions) if doing vehicle counts. For the states `elsewhere` and `removed` which include vehicles not in the [PROW](/general-information.md#definitions) but provide some operational clarity for agencies, these must only persist in the feed for 90 minutes before being removed.
+
+As with other MDS APIs, `/vehicles` is intended for use by regulators, not by the general public. `/vehicles` can be deployed by providers as a standalone MDS endpoint for agencies without requiring the use of other endpoints, due to the [modularity](/README.md#modularity) of MDS. See our [MDS Vehicles Guide](https://github.com/openmobilityfoundation/mobility-data-specification/wiki/MDS-Vehicles) for how this compares to GBFS `/free_bike_status`. Note that using authenticated `/vehicles` does not replace the role of a public [GBFS][gbfs] feed in enabling consumer-facing applications. If a provider is using both `/vehicles` and GBFS endpoints, the `/vehicles` endpoint should be considered source of truth regarding an agency's compliance checks.
+
+In addition to the standard [Provider payload wrapper](#response-format), responses from this endpoint should contain the last update timestamp and amount of time until the next update in accordance with the [Data Latency Requirements][data-latency]:
+
+```json
+{
+ "version": "x.y.z",
+ "last_updated": "12345",
+ "ttl": "12345",
+ "vehicles": []
+}
+```
+
+The `/vehicles` endpoint returns the specified vehicle (if a device_id is provided) or a list of known vehicles. Contains vehicle properties that do not change often.
+
+**Endpoint:** `/vehicles/{device_id}`
+**Method:** `GET`
+**[Beta feature][beta]:** No (as of 1.2.0)
+**Schema:** See [`mds-openapi`](https://github.com/openmobilityfoundation/mds-openapi) repository for schema.
+**`data` Payload:** `{ "vehicles": [] }`, an array of [Vehicle][vehicles] objects
+
+_Path Parameters:_
+
+| Path Parameters | Type | Required/Optional | Description |
+| ------------ | ---- | ----------------- | ------------------------------------------- |
+| `device_id` | UUID | Optional | If provided, retrieve the specified vehicle |
+
+If `device_id` is specified, `GET` will return an array with a single vehicle record, otherwise it will be a list of vehicle records with pagination details per the [JSON API](https://jsonapi.org/format/#fetching-pagination) spec:
+
+```json
+{
+ "version": "x.y.z",
+ "vehicles": [ ... ]
+ "links": {
+ "first": "https://...",
+ "last": "https://...",
+ "prev": "https://...",
+ "next": "https://..."
+ }
+}
+```
+
+#### Responses
+
+_Possible HTTP Status Codes_:
+200,
+400 (with parameter),
+401,
+404,
+406,
+500
+
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
+
+[Top][toc]
+
+### Vehicle Status
+
+The `/vehicles/status` endpoint returns the specified vehicle (if a device_id is provided) or a list of known vehicles. Contains specific vehicle status records that are updated frequently.
+
+**Endpoint:** `/vehicles/status/{device_id}`
+**Method:** `GET`
+**[Beta feature][beta]:** No (as of 1.2.0)
+**Schema:** See [`mds-openapi`](https://github.com/openmobilityfoundation/mds-openapi) repository for schema.
+**`data` Payload:** `{ "vehicles_status": [] }`, an array of [Vehicle Status][vehicle-status] objects
+
+_Path Parameters:_
+
+| Path Parameter | Type | Required/Optional | Description |
+| ------------ | ---- | ----------------- | ------------------------------------------- |
+| `device_id` | UUID | Optional | If provided, retrieve the specified vehicle |
+
+If `device_id` is specified, `GET` will return an array with a vehicle status record, otherwise it will be a list of vehicle records with pagination details per the [JSON API](https://jsonapi.org/format/#fetching-pagination) spec:
+
+```json
+{
+ "version": "x.y.z",
+ "vehicles": [ ... ]
+ "links": {
+ "first": "https://...",
+ "last": "https://...",
+ "prev": "https://...",
+ "next": "https://..."
+ }
+}
+```
+
+#### Responses
+
+_Possible HTTP Status Codes_:
+200,
+400 (with parameter),
+401,
+404,
+406,
+500
+
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
[Top][toc]
## Trips
-A trip represents a journey taken by a *mobility as a service* customer with a geo-tagged start and stop point.
+A [trip][trips-general-info] represents a journey taken by a *mobility as a service* customer with a geo-tagged start and stop point.
The trips endpoint allows a user to query historical trip data.
@@ -151,42 +282,21 @@ Unless stated otherwise by the municipality, the trips endpoint must return all
**Endpoint:** `/trips`
**Method:** `GET`
**[Beta feature][beta]:** No
-**Schema:** [`trips` 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. See MDS [provider list](/providers.csv). |
-| `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][vehicle-types] table |
-| `propulsion_types` | Enum[] | Required | Array of [propulsion types][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](#routes) detail below |
-| `accuracy` | Integer | Required | The approximate level of accuracy, in meters, of `Points` within `route` |
-| `start_time` | [timestamp][ts] | Required | |
-| `end_time` | [timestamp][ts] | Required | |
-| `publication_time` | [timestamp][ts] | Optional | Date/time that trip became available through the trips endpoint |
-| `parking_verification_url` | String | Optional | A URL to a photo (or other evidence) of proper vehicle parking |
-| `standard_cost` | Integer | Optional | The cost, in the currency defined in `currency`, that it would cost to perform that trip in the standard operation of the System (see [Costs & Currencies][costs-and-currencies]) |
-| `actual_cost` | Integer | Optional | The actual cost, in the currency defined in `currency`, paid by the customer of the *mobility as a service* provider (see [Costs & Currencies][costs-and-currencies]) |
-| `currency` | String | Optional, USD cents is implied if null.| An [ISO 4217 Alphabetic Currency Code][iso4217] representing the currency of the payee (see [Costs & Currencies][costs-and-currencies]) |
-
-[Top][toc]
+**Schema:** See [`mds-openapi`](https://github.com/openmobilityfoundation/mds-openapi) repository for schema.
+**`data` Payload:** `{ "trips": [] }`, an array of [Trip][trips] objects
### Trips - Query Parameters
The `/trips` API should allow querying trips with the following query parameters:
-| Parameter | Format | Expected Output |
+| Query Parameter | Format | Expected Output |
| --------------- | ------ | --------------- |
| `end_time` | `YYYY-MM-DDTHH`, an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) extended datetime representing an UTC hour between 00 and 23. | All trips with an end time occurring within the hour. For example, requesting `end_time=2019-10-01T07` returns all trips where `2019-10-01T07:00:00 <= trip.end_time < 2019-10-01T08:00:00` UTC. |
Without an `end_time` query parameter, `/trips` shall return a `400 Bad Request` error.
+[Top][toc]
+
### Trips - Responses
The API's response will depend on the hour queried and the status of data
@@ -197,7 +307,7 @@ processing for that hour:
* For hours in which the provider was not operating the API shall return a
`404 Not Found` response.
* For hours that are in the past but for which data is not yet available
- the API shall return a `102 Processing` response.
+ the API shall return a `202 Accepted` response.
* For all other hours the API shall return a `200 OK` response with a fully
populated body, even for hours that contain no trips to report.
If the hour has no trips to report the response shall contain an empty
@@ -206,109 +316,90 @@ processing for that hour:
```json
{
"version": "x.y.z",
- "data": {
- "trips": []
- }
+ "trips": []
}
```
For the near-ish real time use cases, please use the [events][events] endpoint.
+#### Responses
+
+_Possible HTTP Status Codes_:
+200,
+202,
+400 (with parameter),
+401,
+404,
+406,
+500
+
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
+
[Top][toc]
-### Routes
-
-To represent a route, MDS `provider` APIs must create a GeoJSON [`FeatureCollection`][geojson-feature-collection], which includes every [observed point][point-geo] in the route, even those which occur outside the [municipality boundary][muni-boundary].
-
-Routes must include at least 2 points: the start point and end point. Routes must include all possible GPS or GNSS 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][agps] is accurate to 5 decimal places, [differential GPS][dgps] is generally accurate to 6 decimal places. Providers may round those readings to the appropriate number for their systems.
-
-Trips that start or end at a [Stop][stops] must include a `stop_id` property in the first (when starting) and last (when ending) Feature of the `route`. See [Stop-based Geographic Data][stop-based-geo] for more information.
-
-```js
-"route": {
- "type": "FeatureCollection",
- "features": [{
- "type": "Feature",
- "properties": {
- "timestamp": 1529968782421,
- // Required for Trips starting at a Stop
- "stop_id": "95084833-6a3f-4770-9919-de1ab4b8989b",
- },
- "geometry": {
- "type": "Point",
- "coordinates": [
- -118.46710503101347,
- 33.9909333514159
- ]
- }
- },
- {
- "type": "Feature",
- "properties": {
- "timestamp": 1531007628377,
- // Required for Trips ending at a Stop
- "stop_id": "b813cde2-a41c-4ae3-b409-72ff221e003d"
- },
- "geometry": {
- "type": "Point",
- "coordinates": [
- -118.464851975441,
- 33.990366257735
- ]
- }
- }]
-}
-```
+## Telemetry
+
+The `/telemetry` endpoint is a feed of vehicle telemetry data for publishing all available location data. For privacy reasons, in-trip telemetry may be delayed at the discretion of the regulating body.
+
+To represent [trip](#trip) telemetry, the data should include every [observed point][point-geo] in the trip, even those which occur outside the [municipality boundary][muni-boundary], as long as any part of the trip [intersects][intersection] with the [municipality boundary][muni-boundary].
+
+Telemetry for a [trip](#trip) must include at least 2 points: the start point and end point. Trips must include all additional GPS or GNSS 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][agps] is accurate to 5 decimal places, [differential GPS][dgps] is generally accurate to 6 decimal places. Providers may round those readings to the appropriate number for their systems.
+
+**Endpoint:** `/telemetry`
+**Method:** `GET`
+**Schema:** See [`mds-openapi`](https://github.com/openmobilityfoundation/mds-openapi) repository for schema.
+**`data` Payload:** `{ "telemetry": [] }`, an array of [Vehicle Telemetry][vehicle-telemetry] objects
[Top][toc]
-## Status Changes
+### Telemetry - Query Parameters
+
+| Query Parameter | Format | Expected Output |
+| --------- | ------ | --------------- |
+| `telemetry_time` | `YYYY-MM-DDTHH`, an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) extended datetime representing an UTC hour between 00 and 23. | All telemetry with timestamp occurring within the hour. For example, requesting `telemetry_time=2019-10-01T07` returns all telemetry where `2019-10-01T07:00:00 <= telemetry.timestamp < 2019-10-01T08:00:00` UTC. |
+
+Without a `telemetry_time` query parameter, `/telemetry` shall return a `400 Bad Request` error.
+
+#### Responses
-The status of the inventory of vehicles available for customer use.
+_Possible HTTP Status Codes_:
+200,
+400 (with parameter),
+401,
+406,
+500
-The status changes endpoint allows a user to query the historical availability for a system within a time range.
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
+
+[Top][toc]
+
+## Events
+
+The `/events/recent` and `/events/historical/` endpoints return a list of Event objects, describing the activity of the Provider's vehicles. Recent events are at most two weeks old and can be queried with start/stop time, and historical events are packaged in hour-sized chunks for ease of implementation.
Unless stated otherwise by the municipality, this endpoint must return only those status changes with a `event_location` that [intersects](#intersection-operation) with the [municipality boundary](#municipality-boundary).
-> Note: As a result of this definition, consumers should query the [trips endpoint][trips] to infer when vehicles enter or leave the municipality boundary.
+> Note: As a result of this definition, consumers should query the [trips endpoint](#trips) to infer when vehicles enter or leave the municipality boundary.
-**Endpoint:** `/status_changes`
+**Endpoint:** `/events/historical`
**Method:** `GET`
**[Beta feature][beta]:** No
-**Schema:** [`status_changes` schema][status-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. See MDS [provider list](/providers.csv). |
-| `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][vehicle-types] table |
-| `propulsion_types` | Enum[] | Required | Array of [propulsion types][propulsion-types]; allows multiple values |
-| `vehicle_state` | Enum | Required | See [vehicle state][vehicle-states] table |
-| `event_types` | Enum[] | Required | [Vehicle event(s)][vehicle-events] for state change, allowable values determined by `vehicle_state` |
-| `event_time` | [timestamp][ts] | Required | Date/time that event occurred at. See [Event Times][event-times] |
-| `publication_time` | [timestamp][ts] | Optional | Date/time that event became available through the status changes endpoint |
-| `event_location` | GeoJSON [Point Feature][point-geo] | Required | See also [Stop-based Geographic Data][stop-based-geo]. |
-| `event_geographies` | UUID[] | Optional | **[Beta feature](/general-information.md#beta-features):** *Yes (as of 1.1.0)*. Array of Geography UUIDs consisting of every Geography that contains the location of the status change. See [Geography Driven Events][geography-driven-events]. Required if `event_location` is not present. |
-| `battery_pct` | Float | Required if Applicable | Percent battery charge of device, expressed between 0 and 1 |
-| `trip_id` | UUID | Required if Applicable | Trip UUID (foreign key to Trips API), required if `event_types` contains `trip_start`, `trip_end`, `trip_cancel`, `trip_enter_jurisdiction`, or `trip_leave_jurisdiction` |
-| `associated_ticket` | String | Optional | Identifier for an associated ticket inside an Agency-maintained 311 or CRM system |
+**Schema:** See [`mds-openapi`](https://github.com/openmobilityfoundation/mds-openapi) repository for schema.
+**`data` Payload:** `{ "events": [] }`, an array of [Events](/data-types.md#events) object
[Top][toc]
-### Status Changes - Query Parameters
+### Historical Events - Query Parameters
-The `/status_changes` API should allow querying status changes with the following query parameters:
+The `/events/historical` API uses the following query parameter:
-| Parameter | Format | Expected Output |
-| --------------- | ------ | --------------- |
+| Query Parameter | Format | Expected Output |
+| --------- | ------ | --------------- |
| `event_time` | `YYYY-MM-DDTHH`, an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) extended datetime representing an UTC hour between 00 and 23. | All status changes with an event time occurring within the hour. For example, requesting `event_time=2019-10-01T07` returns all status changes where `2019-10-01T07:00:00 <= status_change.event_time < 2019-10-01T08:00:00` UTC. |
-Without an `event_time` query parameter, `/status_changes` shall return a `400 Bad Request` error.
+Without an `event_time` query parameter, `/events` shall return a `400 Bad Request` error.
-### Status Changes - Responses
+### Historical Events - Responses
The API's response will depend on the hour queried and the status of data
processing for that hour:
@@ -318,7 +409,7 @@ processing for that hour:
* For hours in which the provider was not operating the API shall return a
`404 Not Found` response.
* For hours that are in the past but for which data is not yet available
- the API shall return a `102 Processing` response.
+ the API shall return a `202 Accepted` response.
* For all other hours the API shall return a `200 OK` response with a fully
populated body, even for hours that contain no status changes to report.
If the hour has no status changes to report the response shall contain an
@@ -327,191 +418,64 @@ processing for that hour:
```json
{
"version": "x.y.z",
- "data": {
- "status_changes": []
- }
+ "status_changes": []
}
```
-[Top][toc]
-
-## Reports
-
-Reports are information that providers can send back to agencies containing aggregated data that is not contained within other MDS endpoints, like counts of special groups of riders. These supplemental reports are not a substitute for other MDS Provider endpoints.
-
-The authenticated reports are monthly, historic flat files that may be pre-generated by the provider.
-
-### Reports - Response
-
-**Endpoint:** `/reports`
-**Method:** `GET`
-**[Beta feature][beta]:** Yes (as of 1.1.0). [Leave feedback](https://github.com/openmobilityfoundation/mobility-data-specification/issues/672)
-**Schema:** TBD when out of beta
-**`data` Filename:** monthly file named by year and month, e.g. `/reports/YYYY-MM.csv`
-**`data` Payload:** monthly CSV files with the following structure:
-
-| Name | Type | Comments |
-| ------------------ | ----------------------------------------- | ------------------------------------------------ |
-| StartDate | date | Start date of trip the data row, ISO 8601 format, local timezone |
-| Duration | string | Value is always `P1M` for monthly. Based on [ISO 8601 duration](https://en.wikipedia.org/wiki/ISO_8601#Durations) |
-| Special Group Type | [Special Group Type](#special-group-type) | Type that applies to this row |
-| Geography ID | [Geography](/geography) | ID that applies to this row. Includes all IDs in /geography. When there is no /geography then return `null` for this value and return counts based on the entire operating area. |
-| Vehicle Type | [Vehicle Type](/agency#vehicle-type) | Type that applies to this row |
-| Trip Count | integer | Count of trips taken for this row |
-| Rider Count | integer | Count of unique riders for this row |
-
-#### Data Notes
-
-Report contents include every combination of special group types, geography IDs, and vehicle types in operation for each month since the provider began operations in the jurisdiction. New files are added monthly in addition to the previous monthly historic files.
-
-Counts are calculated based the agency's local time zone, and this time zone is returned within the `StartDate` value. For months where there is a Daylight Saving Time change, use the timezone that is in the majority of the month. Note that StartDate is based on the moment the trip starts.
-
-All geography IDs included in the city published [Geography](/geography) API endpoint are included in the report results. In lieu of serving an API, this can alternately be a [flat file](/geography#file-format) created by the city and sent to the provider via link. If there is no `/geography` available, then counts are for the entire agency operating area, and `null` is returned for each Geography ID.
-
-[Top][toc]
-
-### Reports - Example
-
-For 3 months of provider operation in a city (September 2019 through November 2019) for 3 geographies, 2 vehicle types, and 1 special group. Timezone is Eastern Time in the US which is _-4_ from UTC before November 3, 2019, and _-5_ after. Values of `-1` represent [redacted data](#data-redaction) counts.
-
-**September 2019** `/reports/2019-09.csv`
-
-```csv
-StartDate,Duration,Special Group Type,Geography ID,Vehicle Type,Trip Count,Rider Count
-2019-09-01T00:00-04,P1M,all_riders,44428624-186b-4fc3-a7fb-124f487464a1,scooter,1302,983
-2019-09-01T00:00-04,P1M,low_income,44428624-186b-4fc3-a7fb-124f487464a1,scooter,201,104
-2019-09-01T00:00-04,P1M,all_riders,44428624-186b-4fc3-a7fb-124f487464a1,bicycle,530,200
-2019-09-01T00:00-04,P1M,low_income,44428624-186b-4fc3-a7fb-124f487464a1,bicycle,75,26
-2019-09-01T00:00-04,P1M,all_riders,03db06d0-3998-406a-92c7-25a83fc2784a,scooter,687,450
-2019-09-01T00:00-04,P1M,low_income,03db06d0-3998-406a-92c7-25a83fc2784a,scooter,98,45
-2019-09-01T00:00-04,P1M,all_riders,03db06d0-3998-406a-92c7-25a83fc2784a,bicycle,256,104
-2019-09-01T00:00-04,P1M,low_income,03db06d0-3998-406a-92c7-25a83fc2784a,bicycle,41,16
-2019-09-01T00:00-04,P1M,all_riders,8ad39dc3-005b-4348-9d61-c830c54c161b,scooter,201,140
-2019-09-01T00:00-04,P1M,low_income,8ad39dc3-005b-4348-9d61-c830c54c161b,scooter,35,21
-2019-09-01T00:00-04,P1M,all_riders,8ad39dc3-005b-4348-9d61-c830c54c161b,bicycle,103,39
-2019-09-01T00:00-04,P1M,low_income,8ad39dc3-005b-4348-9d61-c830c54c161b,bicycle,15,-1
-```
-
-**October 2019** `/reports/2019-10.csv`
-
-```csv
-StartDate,Duration,Special Group Type,Geography ID,Vehicle Type,Trip Count,Rider Count
-2019-10-01T00:00-04,P1M,all_riders,44428624-186b-4fc3-a7fb-124f487464a1,scooter,1042,786
-2019-10-01T00:00-04,P1M,low_income,44428624-186b-4fc3-a7fb-124f487464a1,scooter,161,83
-2019-10-01T00:00-04,P1M,all_riders,44428624-186b-4fc3-a7fb-124f487464a1,bicycle,424,160
-2019-10-01T00:00-04,P1M,low_income,44428624-186b-4fc3-a7fb-124f487464a1,bicycle,60,0
-2019-10-01T00:00-04,P1M,all_riders,03db06d0-3998-406a-92c7-25a83fc2784a,scooter,550,360
-2019-10-01T00:00-04,P1M,low_income,03db06d0-3998-406a-92c7-25a83fc2784a,scooter,78,36
-2019-10-01T00:00-04,P1M,all_riders,03db06d0-3998-406a-92c7-25a83fc2784a,bicycle,205,83
-2019-10-01T00:00-04,P1M,low_income,03db06d0-3998-406a-92c7-25a83fc2784a,bicycle,33,13
-2019-10-01T00:00-04,P1M,all_riders,8ad39dc3-005b-4348-9d61-c830c54c161b,scooter,161,112
-2019-10-01T00:00-04,P1M,low_income,8ad39dc3-005b-4348-9d61-c830c54c161b,scooter,28,-1
-2019-10-01T00:00-04,P1M,all_riders,8ad39dc3-005b-4348-9d61-c830c54c161b,bicycle,82,31
-2019-10-01T00:00-04,P1M,low_income,8ad39dc3-005b-4348-9d61-c830c54c161b,bicycle,-1,0
-```
-
-**November 2019** `/reports/2019-11.csv`
-
-```csv
-StartDate,Duration,Special Group Type,Geography ID,Vehicle Type,Trip Count,Rider Count
-2019-11-01T00:00-05,P1M,all_riders,44428624-186b-4fc3-a7fb-124f487464a1,scooter,834,629
-2019-11-01T00:00-05,P1M,low_income,44428624-186b-4fc3-a7fb-124f487464a1,scooter,129,66
-2019-11-01T00:00-05,P1M,all_riders,44428624-186b-4fc3-a7fb-124f487464a1,bicycle,339,128
-2019-11-01T00:00-05,P1M,low_income,44428624-186b-4fc3-a7fb-124f487464a1,bicycle,48,-1
-2019-11-01T00:00-05,P1M,all_riders,03db06d0-3998-406a-92c7-25a83fc2784a,scooter,440,288
-2019-11-01T00:00-05,P1M,low_income,03db06d0-3998-406a-92c7-25a83fc2784a,scooter,62,29
-2019-11-01T00:00-05,P1M,all_riders,03db06d0-3998-406a-92c7-25a83fc2784a,bicycle,164,66
-2019-11-01T00:00-05,P1M,low_income,03db06d0-3998-406a-92c7-25a83fc2784a,bicycle,26,0
-2019-11-01T00:00-05,P1M,all_riders,8ad39dc3-005b-4348-9d61-c830c54c161b,scooter,129,90
-2019-11-01T00:00-05,P1M,low_income,8ad39dc3-005b-4348-9d61-c830c54c161b,scooter,22,-1
-2019-11-01T00:00-05,P1M,all_riders,8ad39dc3-005b-4348-9d61-c830c54c161b,bicycle,-1,25
-2019-11-01T00:00-05,P1M,low_income,8ad39dc3-005b-4348-9d61-c830c54c161b,bicycle,0,0
-```
-
-[Top][toc]
-
-### Special Group Type
-
-Here are the possible values for the `special_group_type` dimension field:
-
-| Name | Description |
-| ---------- | --------------------------------------------------------------------------------------------------------------------- |
-| low_income | Trips where a low income discount is applied by the provider, e.g., a discount from a qualified provider equity plan. |
-| all_riders | All riders from any group |
-
-Other special group types may be added in future MDS releases as relevant agency and provider use cases are identified. When additional special group types or metrics are proposed, a thorough review of utility and relevance in program oversight, evaluation, and policy development should be done by OMF Working Groups, as well as any privacy implications by the OMF Privacy Committee.
-
-[Top][toc]
-
-### Data Redaction
-
-Some combinations of parameters may return a small count of trips, which could increase a privacy risk of re-identification. To correct for that, Reports does not return data below a certain count of results. This data redaction is called k-anonymity, and the threshold is set at a k-value of 10. For more explanation of this methodology, see our [Data Redaction Guidance document](https://github.com/openmobilityfoundation/mobility-data-specification/wiki/MDS-Data-Redaction).
-
-**If the query returns fewer than `10` trips in a count, then that row's count value is returned as "-1".** Note "0" values are also returned as "-1" since the goal is to group both low and no count values for privacy.
-
-As Reports is in [beta][beta], this value may be adjusted in future releases and/or may become dynamic to account for specific categories of use cases and users. To improve the specification and to inform future guidance, beta users are encouraged to share their feedback and questions about k-values on this [discussion thread](https://github.com/openmobilityfoundation/mobility-data-specification/discussions/622).
+#### Responses
-Using k-anonymity will reduce, but not necessarily eliminate the risk that an individual could be re-identified in a dataset, and this data should still be treated as sensitive. This is just one part of good privacy protection practices, which you can read more about in our [MDS Privacy Guide for Cities](https://github.com/openmobilityfoundation/governance/blob/main/documents/OMF-MDS-Privacy-Guide-for-Cities.pdf).
+_Possible HTTP Status Codes_:
+200,
+202,
+400 (with parameter),
+401,
+404,
+406,
+500
-[Top][toc]
-
-## Realtime Data
-
-### GBFS
-
-All MDS compatible `provider` APIs must expose a public [GBFS](https://github.com/NABSA/gbfs) feed as well. Compatibility with [GBFS 2.0](https://github.com/NABSA/gbfs/blob/v2.0/gbfs.md) or greater is advised due to privacy concerns and support for micromobility.
-
-GBFS 2.0 includes some changes that may make it less useful for regulatory purposes (specifically, the automatic rotation of vehicle IDs). The [`/vehicles`](#vehicles) endpoint offers an alternative to GBFS that may more effectively meet the use cases of regulators. See our [MDS Vehicles Guide](https://github.com/openmobilityfoundation/mobility-data-specification/wiki/MDS-Vehicles) for how this compares to GBFS `/free_bike_status`. Additional information on MDS and GBFS can be found in this [guidance document](https://github.com/openmobilityfoundation/governance/blob/main/technical/GBFS_and_MDS.md).
-
-[Top][toc]
-
-### Data Latency Requirements
-
-The data returned by a near-realtime endpoint should be as close to realtime as possible, but in no case should it be more than 5 minutes out-of-date. Near-realtime endpoints must contain `last_updated` and `ttl` properties in the top-level of the response body. These properties are defined as:
-
-Field Name | Required | Defines
---------------------| ----------| ----------
-last_updated | Yes | Timestamp indicating the last time the data in this feed was updated
-ttl | Yes | Integer representing the number of milliseconds before the data in this feed will be updated again (0 if the data should always be refreshed).
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
[Top][toc]
-### Events
-
-The `/events` endpoint is a near-realtime feed of status changes, designed to give access to as recent as possible series of events.
-
-The `/events` endpoint functions similarly to `/status_changes`, but shall not include data older than 2 weeks (that should live in `/status_changes.`)
-
-Unless stated otherwise by the municipality, this endpoint must return only those events with an `event_location` that [intersects][intersection] with the [municipality boundary][muni-boundary].
+### Recent Events
-> Note: As a result of this definition, consumers should query the [trips endpoint][trips] to infer when vehicles enter or leave the municipality boundary.
+The `/events/recent` endpoint is a near-realtime feed of events less than two weeks old.
See also [Stop-based Geographic Data][stop-based-geo].
-The schema and datatypes are the same as those defined for [`/status_changes`][status].
-
-**Endpoint:** `/events`
+**Endpoint:** `/events/recent`
**Method:** `GET`
**[Beta feature][beta]:** No (as of 1.0.0)
-**Schema:** [`events` schema][events-schema]
-**`data` Payload:** `{ "status_changes": [] }`, an array of objects with the same structure as in [`/status_changes`][status]
+**Schema:** See [`mds-openapi`](https://github.com/openmobilityfoundation/mds-openapi) repository for schema.
+**`data` Payload:** `{ "events": [] }`, an array of [Events](/data-types.md#events) object objects
-#### Events Query Parameters
+#### Recent Events - Query Parameters
-The events API should allow querying with a combination of query parameters:
+The Recent Events API requires two parameters:
-| Parameter | Type | Expected Output |
+| Query Parameter | Type | Expected Output |
| ----- | ---- | -------- |
-| `start_time` | [timestamp][ts] | status changes where `start_time <= status_change.event_time` |
-| `end_time` | [timestamp][ts] | status changes where `status_change.event_time < end_time` |
+| `start_time` | [timestamp][ts] | status changes where `start_time <= event.timestamp` |
+| `end_time` | [timestamp][ts] | status changes where `event.timestamp < end_time` |
+
+Should either side of the requested time range be missing, `/events/recent` shall return a `400 Bad Request` error.
+
+Should either side of the requested time range be greater than 2 weeks before the time of the request, `/events/recent` shall return a `400 Bad Request` error.
-Should either side of the requested time range be missing, `/events` shall return a `400 Bad Request` error.
+#### Responses
-Should either side of the requested time range be greater than 2 weeks before the time of the request, `/events` shall return a `400 Bad Request` error.
+_Possible HTTP Status Codes_:
+200,
+400 (with parameter),
+401,
+406,
+500
+
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
[Top][toc]
-### Stops
+## Stops
Stop information should be updated on a near-realtime basis by providers who operate _docked_ mobility devices in a given municipality.
@@ -520,76 +484,79 @@ In addition to the standard [Provider payload wrapper](#response-format), respon
```json
{
"version": "x.y.z",
- "data": {
- "stops": []
- },
"last_updated": "12345",
- "ttl": "12345"
+ "ttl": "12345",
+ "stops": []
}
```
-**Endpoint:** `/stops/:stop_id`
+**Endpoint:** `/stops/{stop_id}`
**Method:** `GET`
**[Beta feature][beta]:** Yes (as of 1.0.0). [Leave feedback](https://github.com/openmobilityfoundation/mobility-data-specification/issues/638)
-**Schema:** [`stops` schema][stops-schema]
+**Schema:** See [`mds-openapi`](https://github.com/openmobilityfoundation/mds-openapi) repository for schema.
**`data` Payload:** `{ "stops": [] }`, an array of [Stops][stops]
-In the case that a `stop_id` query parameter is specified, the `stops` array returned will only have one entry. In the case that no `stop_id` query parameter is specified, all stops will be returned.
+In the case that a `stop_id` path parameter is specified, the `stops` array returned will only have one entry. In the case that no `stop_id` query parameter is specified, all stops will be returned.
-[Top][toc]
+#### Responses
+
+_Possible HTTP Status Codes_:
+200,
+400 (with parameter),
+401,
+404 (with parameter),
+406,
+500
-### Vehicles
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
-The `/vehicles` is a near-realtime endpoint and returns the current status of vehicles in an agency's [Jurisdiction](/general-information.md#definitions) and/or area of agency responsibility. All vehicles that are currently in any [`vehicle_state`](/general-information.md#vehicle-states) should be returned in this payload. Since all states are returned, care should be taken to filter out states not in the [PROW](/general-information.md#definitions) if doing vehicle counts. For the states `elsewhere` and `removed` which include vehicles not in the [PROW](/general-information.md#definitions) but provide some operational clarity for agencies, these must only persist in the feed for 90 minutes before being removed.
+[Top][toc]
-Data in this endpoint should reconcile with data from the historic [`/status_changes`](/provider#status-changes) enpdoint, though `/status_changes` is the source of truth if there are discrepancies.
+## Reports
-As with other MDS APIs, `/vehicles` is intended for use by regulators, not by the general public. `/vehicles` can be deployed by providers as a standalone MDS endpoint for agencies without requiring the use of other endpoints, due to the [modularity](/README.md#modularity) of MDS. See our [MDS Vehicles Guide](https://github.com/openmobilityfoundation/mobility-data-specification/wiki/MDS-Vehicles) for how this compares to GBFS `/free_bike_status`. Note that using authenticated `/vehicles` does not replace the role of a public [GBFS][gbfs] feed in enabling consumer-facing applications. If a provider is using both `/vehicles` and GBFS endpoints, the `/vehicles` endpoint should be considered source of truth regarding an agency's compliance checks.
+Reports are information that providers can send back to agencies containing aggregated data that is not contained within other MDS endpoints, like counts of special groups of riders. These supplemental reports are not a substitute for other MDS Provider endpoints.
-In addition to the standard [Provider payload wrapper](#response-format), responses from this endpoint should contain the last update timestamp and amount of time until the next update in accordance with the [Data Latency Requirements][data-latency]:
+The authenticated reports are monthly, historic flat files that may be pre-generated by the provider.
-```json
-{
- "version": "x.y.z",
- "data": {
- "vehicles": []
- },
- "last_updated": "12345",
- "ttl": "12345"
-}
-```
+[Top][toc]
-**Endpoint:** `/vehicles`
+### Reports - Response
+
+**Endpoint:** `/reports`
**Method:** `GET`
-**[Beta feature][beta]:** No (as of 1.2.0)
-**Schema:** [`vehicles` schema][vehicles-schema]
-**`data` Payload:** `{ "vehicles": [] }`, 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. See MDS [provider list](/providers.csv). |
-| `provider_name` | String | Required | The public-facing name of the Provider |
-| `device_id` | UUID | Required | A unique device ID in UUID format, should match this device in Provider |
-| `vehicle_id` | String | Required | The Vehicle Identification Number visible on the vehicle itself, should match this device in provider |
-| `vehicle_type` | Enum | Required | see [vehicle types][vehicle-types] table |
-| `propulsion_types` | Enum[] | Required | Array of [propulsion types][propulsion-types]; allows multiple values |
-| `last_event_time` | [timestamp][ts] | Required | Date/time when last state change occurred. See [Event Times][event-times] |
-| `last_vehicle_state` | Enum | Required | [Vehicle state][vehicle-states] of most recent state change. |
-| `last_event_types` | Enum[] | Required | [Vehicle event(s)][vehicle-events] of most recent state change, allowable values determined by `last_vehicle_state`. |
-| `last_event_location` | GeoJSON [Point Feature][point-geo]| Required | Location of vehicle's last event. See also [Stop-based Geographic Data][stop-based-geo]. |
-| `current_location` | GeoJSON [Point Feature][point-geo] | Required if Applicable | Current location of vehicle if different from last event, and the vehicle is not currently on a trip. See also [Stop-based Geographic Data][stop-based-geo]. |
-| `battery_pct` | Float | Required if Applicable | Percent battery charge of device, expressed between 0 and 1 |
+**[Beta feature][beta]:** No (as of 2.0.0). [Leave feedback](https://github.com/openmobilityfoundation/mobility-data-specification/issues/672)
+**Usage note:** This endpoint uses media-type `text/vnd.mds+csv` instead of `application/vnd.mds+json`, see [Versioning][versioning].
+**Schema:** See [`mds-openapi`](https://github.com/openmobilityfoundation/mds-openapi) repository for schema.
+**`data` Filename:** monthly file named by year and month, e.g. `/reports/YYYY-MM.csv`
+**`data` Payload:** monthly CSV files of [Report](/data-types.md#Reports) objects
+
+#### Responses
+
+_Possible HTTP Status Codes_:
+200,
+401,
+404,
+500
+
+See [Responses][responses], [Bulk Responses][bulk-responses], and [schema][schema] for details.
+
+[Top][toc]
+
+### Reports - Example
+
+See [Provider examples](examples.md#reports).
[Top][toc]
[agps]: https://en.wikipedia.org/wiki/Assisted_GPS
[beta]: /general-information.md#beta-features
+[bulk-responses]: /general-information.md#bulk-responses
[costs-and-currencies]: /general-information.md#costs-and-currencies
[data-latency]: #data-latency-requirements
[dgps]: https://en.wikipedia.org/wiki/Differential_GPS
[error-messages]: /general-information.md#error-messages
-[events]: #events
-[events-schema]: events.json
+[events]: /data-types.md#events
+[events---query-parameters]: #events---query-parameters
[event-times]: #event-times
[gbfs]: https://github.com/NABSA/gbfs
[general-information]: /general-information.md
@@ -601,21 +568,24 @@ In addition to the standard [Provider payload wrapper](#response-format), respon
[json-api-pagination]: http://jsonapi.org/format/#fetching-pagination
[json-schema]: https://json-schema.org
[muni-boundary]: #municipality-boundary
-[point-geo]: /general-information.md#geographic-telemetry-data
+[mode]: /modes/README.md
+[point-geo]: /data-types.md#gps-data
[propulsion-types]: /general-information.md#propulsion-types
[responses]: /general-information.md#responses
-[status]: #status-changes
-[status-schema]: status_changes.json
-[stops]: /general-information.md#stops
+[schema]: /schema/
+[stops]: /data-types.md#stops
[stop-based-geo]: /general-information.md#stop-based-geographic-data
-[stops-schema]: stops.json
+[telemetry]: /data-types.md#telemetry
+[telemetry---query-parameters]: #telemetry-query-parameters
[toc]: #table-of-contents
-[trips]: #trips
-[trips-schema]: trips.json
+[trips]: /data-types.md#trips
+[trips-general-info]: /general-information.md#stop-based-geographic-data
[ts]: /general-information.md#timestamps
-[vehicles]: #vehicles
-[vehicle-types]: /general-information.md#vehicle-types
-[vehicle-states]: /general-information.md#vehicle-states
-[vehicle-events]: /general-information.md#vehicle-state-events
-[vehicles-schema]: vehicles.json
+[vehicles]: /data-types.md#vehicles
+[vehicle-types]: /data-types.md#vehicle-types
+[vehicle-status]: /data-types.md#vehicle-status
+[vehicle-states]: /modes#vehicle-states
+[vehicle-events]: /modes#event-types
+[vehicle-event-data]: /general-information.md#event-data
+[vehicle-telemetry]: /data-types.md#telemetry
[versioning]: /general-information.md#versioning
diff --git a/provider/auth.md b/provider/auth.md
deleted file mode 100644
index cad8fa33..00000000
--- a/provider/auth.md
+++ /dev/null
@@ -1,39 +0,0 @@
-# Authorization
-
-MDS `providers` **SHALL** provide authorization for API endpoints via a bearer token based auth system.
-
-For example, the `Authorization` header sent as part of an HTTP request:
-
-```
-GET /trips HTTP/1.1
-Host: api.provider.co
-Authorization: Bearer
-```
-
-More info on how to document [Bearer Auth in swagger](https://swagger.io/docs/specification/authentication/bearer-authentication/)
-
-## JSON Web Tokens
-
-JSON Web Token ([JWT](https://jwt.io/introduction/)) is **RECOMMENDED** as the token format.
-
-JWTs provide a safe, secure way to verify the identity of an agency and provide access to MDS resources without providing access to other, potentially sensitive data.
-
-> JSON Web Token (JWT) is an open standard ([RFC 7519](https://tools.ietf.org/html/rfc7519)) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.
-
-MDS `providers` **MAY** include any metadata in the JWT they wish that helps to route, log, permission, or debug agency requests, leaving their internal implementation flexible.
-
-JWT provides a helpful [debugger](https://jwt.io/#debugger) for testing your token and verifying security.
-
-## OAuth 2.0
-
-OAuth 2.0's `client_credentials` grant type (outlined in [RFC6749](https://tools.ietf.org/html/rfc6749#section-4.4)) is **RECOMMENDED** as the authentication and authorization scheme.
-
-OAuth 2.0 is an industry standard authorization framework with a variety of existing tooling. The `client_credentials` grant type facilitates generation of tokens that can be used for access by agencies and distributed to data partners.
-
-If an MDS `provider` implements this auth scheme, it **MAY** choose to specify token scopes that define access parameters like allowable time ranges. These guidelines **SHOULD** be encoded into the returned token in a parseable way.
-
-## Endpoint Authentication Requirements
-
-All Provider endpoints must be authenticated, to protect potentially sensitive information.
-
-As of MDS 0.3.0, `gbfs.json` is required. The required GBFS endpoints should be made available publicly. See [#realtime-data](https://github.com/openmobilityfoundation/mobility-data-specification/tree/main/provider#realtime-data) for more information about how to implement GBFS for dockless systems.
diff --git a/provider/events.json b/provider/events.json
deleted file mode 100644
index b97fe883..00000000
--- a/provider/events.json
+++ /dev/null
@@ -1,610 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/provider/events.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "Schema for MDS Provider events payloads",
- "type": "object",
- "definitions": {
- "string": {
- "$id": "#/definitions/string",
- "type": "string",
- "description": "A length-limited string type",
- "maxLength": 255,
- "default": "",
- "examples": [
- "ABC123"
- ],
- "pattern": "^(.*)$"
- },
- "timestamp": {
- "$id": "#/definitions/timestamp",
- "type": "number",
- "description": "Integer milliseconds since Unix epoch",
- "multipleOf": 1.0,
- "minimum": 1514764800000
- },
- "uuid": {
- "$id": "#/definitions/uuid",
- "type": "string",
- "description": "A UUID used to uniquely identifty an object",
- "default": "",
- "examples": [
- "3c9604d6-b5ee-11e8-96f8-529269fb1459"
- ],
- "pattern": "^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$"
- },
- "version": {
- "$id": "#/definitions/version",
- "type": "string",
- "description": "The version of MDS this data represents",
- "examples": [
- "1.2.0"
- ],
- "pattern": "^1\\.2\\.[0-9]+$"
- },
- "MDS_Feature_Point": {
- "$id": "#/definitions/MDS_Feature_Point",
- "title": "MDS GeoJSON Feature Point",
- "type": "object",
- "required": [
- "type",
- "properties",
- "geometry"
- ],
- "properties": {
- "type": {
- "type": "string",
- "enum": [
- "Feature"
- ]
- },
- "id": {
- "oneOf": [
- {
- "type": "number"
- },
- {
- "type": "string"
- }
- ]
- },
- "properties": {
- "type": "object",
- "required": [
- "timestamp"
- ],
- "properties": {
- "timestamp": {
- "$ref": "#/definitions/timestamp"
- },
- "stop_id": {
- "$ref": "#/definitions/uuid"
- },
- "altitude": {
- "type": "number",
- "description": "Altitude above mean sea level in meters"
- },
- "heading": {
- "type": "number",
- "description": "Degrees - clockwise starting at 0 degrees at true North"
- },
- "speed": {
- "type": "number",
- "description": "Estimated speed in meters / sec as reported by the GPS chipset"
- },
- "accuracy": {
- "type": "number",
- "description": "Horizontal accuracy, in meters"
- },
- "hdop": {
- "type": "number",
- "description": "Horizontal GPS or GNSS accuracy value"
- },
- "satellites": {
- "type": "integer",
- "description": "Number of GPS or GNSS satellites"
- }
- }
- },
- "geometry": {
- "$ref": "#/definitions/Point"
- },
- "bbox": {
- "type": "array",
- "minItems": 4,
- "items": {
- "type": "number"
- }
- }
- }
- },
- "Point": {
- "$id": "#/definitions/Point",
- "title": "GeoJSON Point",
- "type": "object",
- "required": [
- "type",
- "coordinates"
- ],
- "properties": {
- "type": {
- "type": "string",
- "enum": [
- "Point"
- ]
- },
- "coordinates": {
- "type": "array",
- "minItems": 2,
- "items": [
- {
- "type": "number",
- "minimum": -180.0,
- "maximum": 180.0
- },
- {
- "type": "number",
- "minimum": -90.0,
- "maximum": 90.0
- }
- ],
- "maxItems": 2
- },
- "bbox": {
- "type": "array",
- "minItems": 4,
- "items": {
- "type": "number"
- }
- }
- }
- },
- "propulsion_type": {
- "$id": "#/definitions/propulsion_type",
- "type": "string",
- "description": "The type of propulsion",
- "enum": [
- "combustion",
- "electric",
- "electric_assist",
- "human"
- ]
- },
- "propulsion_types": {
- "$id": "#/definitions/propulsion_types",
- "type": "array",
- "description": "Array of propulsion types, allowing multiple values",
- "items": {
- "$id": "#/definitions/propulsion_types/items",
- "$ref": "#/definitions/propulsion_type"
- },
- "uniqueItems": true
- },
- "vehicle_type": {
- "$id": "#/definitions/vehicle_type",
- "type": "string",
- "description": "The type of vehicle",
- "enum": [
- "bicycle",
- "cargo_bicycle",
- "car",
- "scooter",
- "moped",
- "other"
- ]
- },
- "vehicle_state": {
- "$id": "#/definitions/vehicle_state",
- "type": "string",
- "description": "The state of a vehicle",
- "enum": [
- "available",
- "elsewhere",
- "non_operational",
- "on_trip",
- "removed",
- "reserved",
- "unknown"
- ]
- },
- "vehicle_event": {
- "$id": "#/definitions/vehicle_event",
- "type": "string",
- "description": "An event that changes a vehicle's state",
- "enum": [
- "agency_drop_off",
- "agency_pick_up",
- "battery_charged",
- "battery_low",
- "comms_lost",
- "comms_restored",
- "compliance_pick_up",
- "decommissioned",
- "located",
- "maintenance",
- "maintenance_pick_up",
- "missing",
- "off_hours",
- "on_hours",
- "provider_drop_off",
- "rebalance_pick_up",
- "reservation_cancel",
- "reservation_start",
- "system_resume",
- "system_suspend",
- "trip_cancel",
- "trip_end",
- "trip_enter_jurisdiction",
- "trip_leave_jurisdiction",
- "trip_start",
- "unspecified"
- ]
- },
- "vehicle_events": {
- "$id": "#/definitions/vehicle_events",
- "type": "array",
- "description": "Array of events indicating a change to a vehicle's state",
- "uniqueItems": true,
- "minItems": 1,
- "items": {
- "$ref": "#/definitions/vehicle_event"
- }
- },
- "links": {
- "$id": "#/definitions/links",
- "type": "object",
- "required": [
- "next"
- ],
- "properties": {
- "first": {
- "$id": "#/definitions/links/first",
- "type": [
- "null",
- "string"
- ],
- "title": "The URL to the first page of data",
- "examples": [
- "https://data.provider.co/trips/first"
- ],
- "format": "uri"
- },
- "last": {
- "$id": "#/definitions/links/last",
- "type": [
- "null",
- "string"
- ],
- "title": "The URL to the last page of data",
- "examples": [
- "https://data.provider.co/trips/last"
- ],
- "format": "uri"
- },
- "prev": {
- "$id": "#/definitions/links/prev",
- "type": [
- "null",
- "string"
- ],
- "title": "The URL to the previous page of data",
- "examples": [
- "https://data.provider.co/trips/prev"
- ],
- "format": "uri"
- },
- "next": {
- "$id": "#/definitions/links/next",
- "type": [
- "null",
- "string"
- ],
- "title": "The URL to the next page of data",
- "examples": [
- "https://data.provider.co/trips/next"
- ],
- "format": "uri",
- "pattern": "^(.*)$"
- }
- },
- "additionalProperties": false
- }
- },
- "required": [
- "data",
- "version"
- ],
- "properties": {
- "data": {
- "$id": "#/properties/data",
- "type": "object",
- "description": "The data records in this payload",
- "required": [
- "status_changes"
- ],
- "properties": {
- "status_changes": {
- "$id": "#/properties/data/properties/status_changes",
- "type": "array",
- "title": "The status_changes payload",
- "items": {
- "$id": "#/properties/data/properties/status_changes/items",
- "type": "object",
- "title": "The status_change item schema",
- "additionalProperties": false,
- "required": [
- "provider_name",
- "provider_id",
- "device_id",
- "vehicle_id",
- "vehicle_type",
- "propulsion_types",
- "vehicle_state",
- "event_types",
- "event_time",
- "event_location"
- ],
- "properties": {
- "provider_name": {
- "$id": "#/definitions/vehicle/properties/provider_name",
- "$ref": "#/definitions/string",
- "description": "The public-facing name of the Provider"
- },
- "provider_id": {
- "$id": "#/definitions/vehicle/properties/provider_id",
- "$ref": "#/definitions/uuid",
- "description": "The UUID for the Provider, unique within MDS"
- },
- "device_id": {
- "$id": "#/definitions/vehicle/properties/device_id",
- "$ref": "#/definitions/uuid",
- "description": "A unique device ID in UUID format"
- },
- "vehicle_id": {
- "$id": "#/definitions/vehicle/properties/vehicle_id",
- "$ref": "#/definitions/string",
- "description": "The Vehicle Identification Number visible on the vehicle itself"
- },
- "vehicle_type": {
- "$id": "#/definitions/vehicle/properties/vehicle_type",
- "$ref": "#/definitions/vehicle_type",
- "description": "The type of vehicle"
- },
- "propulsion_types": {
- "$id": "#/definitions/vehicle/properties/propulsion_types",
- "$ref": "#/definitions/propulsion_types",
- "description": "The type of propulsion; allows multiple values",
- "minItems": 1
- },
- "event_time": {
- "$id": "#/properties/data/properties/status_changes/items/properties/event_time",
- "$ref": "#/definitions/timestamp",
- "description": "The time the event occurred, expressed as a Unix Timestamp"
- },
- "publication_time": {
- "$id": "#/properties/data/properties/status_changes/items/properties/publication_time",
- "$ref": "#/definitions/timestamp",
- "description": "The time the event became available through the status changes endpoint, expressed as a Unix Timestamp"
- },
- "event_location": {
- "$id": "#/properties/data/properties/status_changes/items/properties/event_location",
- "$ref": "#/definitions/MDS_Feature_Point",
- "description": "The GPS or GNSS coordinates of where the event occurred"
- },
- "vehicle_state": {
- "$id": "#/properties/data/properties/status_changes/items/properties/vehicle_state",
- "$ref": "#/definitions/vehicle_state",
- "description": "The state of the vehicle"
- },
- "event_types": {
- "$id": "#/properties/data/properties/status_changes/items/properties/event_types",
- "$ref": "#/definitions/vehicle_events",
- "description": "The event(s) that caused a change in the vehicle's state"
- },
- "battery_pct": {
- "$id": "#/properties/data/properties/status_changes/items/properties/battery_pct",
- "type": [
- "number",
- "null"
- ],
- "description": "Percent charge of device battery, expressed between 0 and 1",
- "examples": [
- 0.89
- ],
- "minimum": 0,
- "maximum": 1
- },
- "trip_id": {
- "$id": "#/properties/data/properties/status_changes/items/properties/trip_id",
- "$ref": "#/definitions/uuid",
- "description": "Trip UUID (foreign key to Trips API), required if event_types contains trip_start, trip_end, trip_cancel, trip_enter_jurisdiction, or trip_leave_jurisdiction"
- },
- "associated_ticket": {
- "$id": "#/properties/data/properties/status_changes/items/properties/associated_ticket",
- "$ref": "#/definitions/string",
- "description": "Identifier for an associated ticket inside an Agency-maintained 311 or CRM system."
- }
- },
- "allOf": [
- {
- "description": "valid vehicle_state and vehicle_events combinations",
- "oneOf": [
- {
- "properties": {
- "vehicle_state": {
- "const": "available"
- },
- "event_types": {
- "contains": {
- "enum": [
- "agency_drop_off",
- "battery_charged",
- "comms_restored",
- "located",
- "maintenance",
- "on_hours",
- "provider_drop_off",
- "reservation_cancel",
- "system_resume",
- "trip_cancel",
- "trip_end",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "vehicle_state": {
- "const": "elsewhere"
- },
- "event_types": {
- "contains": {
- "enum": [
- "comms_restored",
- "located",
- "trip_leave_jurisdiction",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "vehicle_state": {
- "const": "non_operational"
- },
- "event_types": {
- "contains": {
- "enum": [
- "battery_low",
- "comms_restored",
- "located",
- "maintenance",
- "off_hours",
- "system_suspend",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "vehicle_state": {
- "const": "on_trip"
- },
- "event_types": {
- "contains": {
- "enum": [
- "comms_restored",
- "located",
- "trip_enter_jurisdiction",
- "trip_start",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "vehicle_state": {
- "const": "removed"
- },
- "event_types": {
- "contains": {
- "enum": [
- "agency_pick_up",
- "comms_restored",
- "compliance_pick_up",
- "decommissioned",
- "located",
- "maintenance_pick_up",
- "rebalance_pick_up",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "vehicle_state": {
- "const": "reserved"
- },
- "event_types": {
- "contains": {
- "enum": [
- "comms_restored",
- "located",
- "reservation_start",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "vehicle_state": {
- "const": "unknown"
- },
- "event_types": {
- "contains": {
- "enum": [
- "comms_lost",
- "missing",
- "unspecified"
- ]
- }
- }
- }
- }
- ]
- },
- {
- "description": "Conditionally require a trip_id reference",
- "anyOf": [
- {
- "not": {
- "properties": {
- "event_types": {
- "contains": {
- "enum": [
- "trip_cancel",
- "trip_end",
- "trip_enter_jurisdiction",
- "trip_leave_jurisdiction",
- "trip_start"
- ]
- }
- }
- }
- }
- },
- {
- "required": [
- "trip_id"
- ]
- }
- ]
- }
- ]
- }
- }
- },
- "additionalProperties": false
- },
- "version": {
- "$id": "#/properties/version",
- "$ref": "#/definitions/version"
- },
- "links": {
- "$id": "#/properties/links",
- "$ref": "#/definitions/links"
- }
- },
- "additionalProperties": false
-}
diff --git a/provider/examples.md b/provider/examples.md
new file mode 100644
index 00000000..d67c6bf4
--- /dev/null
+++ b/provider/examples.md
@@ -0,0 +1,70 @@
+
+# Provider Examples
+
+This file presents a series of [Provider examples](/provider).
+
+## Table of Contents
+
+- [Reports](#reports)
+
+## Reports
+
+For 3 months of provider operation in a city (September 2019 through November 2019) for 3 geographies, 2 vehicle types, and 1 special group. Values of `-1` represent [redacted data](#data-redaction) counts.
+
+**September 2019** `/reports/2019-09.csv`
+
+```csv
+provider_id,start_date,duration,special_group_type,geography_id,vehicle_type,trip_count,rider_count
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-09-01,P1M,all_riders,44428624-186b-4fc3-a7fb-124f487464a1,scooter,1302,983
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-09-01,P1M,low_income,44428624-186b-4fc3-a7fb-124f487464a1,scooter,201,104
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-09-01,P1M,all_riders,44428624-186b-4fc3-a7fb-124f487464a1,bicycle,530,200
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-09-01,P1M,low_income,44428624-186b-4fc3-a7fb-124f487464a1,bicycle,75,26
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-09-01,P1M,all_riders,03db06d0-3998-406a-92c7-25a83fc2784a,scooter,687,450
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-09-01,P1M,low_income,03db06d0-3998-406a-92c7-25a83fc2784a,scooter,98,45
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-09-01,P1M,all_riders,03db06d0-3998-406a-92c7-25a83fc2784a,bicycle,256,104
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-09-01,P1M,low_income,03db06d0-3998-406a-92c7-25a83fc2784a,bicycle,41,16
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-09-01,P1M,all_riders,8ad39dc3-005b-4348-9d61-c830c54c161b,scooter,201,140
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-09-01,P1M,low_income,8ad39dc3-005b-4348-9d61-c830c54c161b,scooter,35,21
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-09-01,P1M,all_riders,8ad39dc3-005b-4348-9d61-c830c54c161b,bicycle,103,39
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-09-01,P1M,low_income,8ad39dc3-005b-4348-9d61-c830c54c161b,bicycle,15,-1
+```
+
+**October 2019** `/reports/2019-10.csv`
+
+```csv
+provider_id,start_date,duration,special_group_type,geography_id,vehicle_type,trip_count,rider_count
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-10-01,P1M,all_riders,44428624-186b-4fc3-a7fb-124f487464a1,scooter,1042,786
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-10-01,P1M,low_income,44428624-186b-4fc3-a7fb-124f487464a1,scooter,161,83
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-10-01,P1M,all_riders,44428624-186b-4fc3-a7fb-124f487464a1,bicycle,424,160
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-10-01,P1M,low_income,44428624-186b-4fc3-a7fb-124f487464a1,bicycle,60,0
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-10-01,P1M,all_riders,03db06d0-3998-406a-92c7-25a83fc2784a,scooter,550,360
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-10-01,P1M,low_income,03db06d0-3998-406a-92c7-25a83fc2784a,scooter,78,36
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-10-01,P1M,all_riders,03db06d0-3998-406a-92c7-25a83fc2784a,bicycle,205,83
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-10-01,P1M,low_income,03db06d0-3998-406a-92c7-25a83fc2784a,bicycle,33,13
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-10-01,P1M,all_riders,8ad39dc3-005b-4348-9d61-c830c54c161b,scooter,161,112
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-10-01,P1M,low_income,8ad39dc3-005b-4348-9d61-c830c54c161b,scooter,28,-1
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-10-01,P1M,all_riders,8ad39dc3-005b-4348-9d61-c830c54c161b,bicycle,82,31
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-10-01,P1M,low_income,8ad39dc3-005b-4348-9d61-c830c54c161b,bicycle,-1,0
+```
+
+**November 2019** `/reports/2019-11.csv`
+
+```csv
+provider_id,start_date,duration,special_group_type,geography_id,vehicle_type,trip_count,rider_count
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-11-01,P1M,all_riders,44428624-186b-4fc3-a7fb-124f487464a1,scooter,834,629
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-11-01,P1M,low_income,44428624-186b-4fc3-a7fb-124f487464a1,scooter,129,66
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-11-01,P1M,all_riders,44428624-186b-4fc3-a7fb-124f487464a1,bicycle,339,128
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-11-01,P1M,low_income,44428624-186b-4fc3-a7fb-124f487464a1,bicycle,48,-1
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-11-01,P1M,all_riders,03db06d0-3998-406a-92c7-25a83fc2784a,scooter,440,288
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-11-01,P1M,low_income,03db06d0-3998-406a-92c7-25a83fc2784a,scooter,62,29
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-11-01,P1M,all_riders,03db06d0-3998-406a-92c7-25a83fc2784a,bicycle,164,66
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-11-01,P1M,low_income,03db06d0-3998-406a-92c7-25a83fc2784a,bicycle,26,0
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-11-01,P1M,all_riders,8ad39dc3-005b-4348-9d61-c830c54c161b,scooter,129,90
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-11-01,P1M,low_income,8ad39dc3-005b-4348-9d61-c830c54c161b,scooter,22,-1
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-11-01,P1M,all_riders,8ad39dc3-005b-4348-9d61-c830c54c161b,bicycle,-1,25
+48415839-3e38-4ba5-a557-e45fb4e6a0a3,2019-11-01,P1M,low_income,8ad39dc3-005b-4348-9d61-c830c54c161b,bicycle,0,0
+```
+
+[Top][toc]
+
+[toc]: #table-of-contents
\ No newline at end of file
diff --git a/provider/status_changes.json b/provider/status_changes.json
deleted file mode 100644
index 68faca22..00000000
--- a/provider/status_changes.json
+++ /dev/null
@@ -1,547 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/provider/status_changes.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "Schema for MDS Provider status_changes payloads",
- "type": "object",
- "definitions": {
- "string": {
- "$id": "#/definitions/string",
- "type": "string",
- "description": "A length-limited string type",
- "maxLength": 255,
- "default": "",
- "examples": [
- "ABC123"
- ],
- "pattern": "^(.*)$"
- },
- "timestamp": {
- "$id": "#/definitions/timestamp",
- "type": "number",
- "description": "Integer milliseconds since Unix epoch",
- "multipleOf": 1.0,
- "minimum": 1514764800000
- },
- "uuid": {
- "$id": "#/definitions/uuid",
- "type": "string",
- "description": "A UUID used to uniquely identifty an object",
- "default": "",
- "examples": [
- "3c9604d6-b5ee-11e8-96f8-529269fb1459"
- ],
- "pattern": "^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$"
- },
- "version": {
- "$id": "#/definitions/version",
- "type": "string",
- "description": "The version of MDS this data represents",
- "examples": [
- "1.2.0"
- ],
- "pattern": "^1\\.2\\.[0-9]+$"
- },
- "MDS_Feature_Point": {
- "$id": "#/definitions/MDS_Feature_Point",
- "title": "MDS GeoJSON Feature Point",
- "type": "object",
- "required": [
- "type",
- "properties",
- "geometry"
- ],
- "properties": {
- "type": {
- "type": "string",
- "enum": [
- "Feature"
- ]
- },
- "id": {
- "oneOf": [
- {
- "type": "number"
- },
- {
- "type": "string"
- }
- ]
- },
- "properties": {
- "type": "object",
- "required": [
- "timestamp"
- ],
- "properties": {
- "timestamp": {
- "$ref": "#/definitions/timestamp"
- },
- "stop_id": {
- "$ref": "#/definitions/uuid"
- },
- "altitude": {
- "type": "number",
- "description": "Altitude above mean sea level in meters"
- },
- "heading": {
- "type": "number",
- "description": "Degrees - clockwise starting at 0 degrees at true North"
- },
- "speed": {
- "type": "number",
- "description": "Estimated speed in meters / sec as reported by the GPS chipset"
- },
- "accuracy": {
- "type": "number",
- "description": "Horizontal accuracy, in meters"
- },
- "hdop": {
- "type": "number",
- "description": "Horizontal GPS or GNSS accuracy value"
- },
- "satellites": {
- "type": "integer",
- "description": "Number of GPS or GNSS satellites"
- }
- }
- },
- "geometry": {
- "$ref": "#/definitions/Point"
- },
- "bbox": {
- "type": "array",
- "minItems": 4,
- "items": {
- "type": "number"
- }
- }
- }
- },
- "Point": {
- "$id": "#/definitions/Point",
- "title": "GeoJSON Point",
- "type": "object",
- "required": [
- "type",
- "coordinates"
- ],
- "properties": {
- "type": {
- "type": "string",
- "enum": [
- "Point"
- ]
- },
- "coordinates": {
- "type": "array",
- "minItems": 2,
- "items": [
- {
- "type": "number",
- "minimum": -180.0,
- "maximum": 180.0
- },
- {
- "type": "number",
- "minimum": -90.0,
- "maximum": 90.0
- }
- ],
- "maxItems": 2
- },
- "bbox": {
- "type": "array",
- "minItems": 4,
- "items": {
- "type": "number"
- }
- }
- }
- },
- "propulsion_type": {
- "$id": "#/definitions/propulsion_type",
- "type": "string",
- "description": "The type of propulsion",
- "enum": [
- "combustion",
- "electric",
- "electric_assist",
- "human"
- ]
- },
- "propulsion_types": {
- "$id": "#/definitions/propulsion_types",
- "type": "array",
- "description": "Array of propulsion types, allowing multiple values",
- "items": {
- "$id": "#/definitions/propulsion_types/items",
- "$ref": "#/definitions/propulsion_type"
- },
- "uniqueItems": true
- },
- "vehicle_type": {
- "$id": "#/definitions/vehicle_type",
- "type": "string",
- "description": "The type of vehicle",
- "enum": [
- "bicycle",
- "cargo_bicycle",
- "car",
- "scooter",
- "moped",
- "other"
- ]
- },
- "vehicle_state": {
- "$id": "#/definitions/vehicle_state",
- "type": "string",
- "description": "The state of a vehicle",
- "enum": [
- "available",
- "elsewhere",
- "non_operational",
- "on_trip",
- "removed",
- "reserved",
- "unknown"
- ]
- },
- "vehicle_event": {
- "$id": "#/definitions/vehicle_event",
- "type": "string",
- "description": "An event that changes a vehicle's state",
- "enum": [
- "agency_drop_off",
- "agency_pick_up",
- "battery_charged",
- "battery_low",
- "comms_lost",
- "comms_restored",
- "compliance_pick_up",
- "decommissioned",
- "located",
- "maintenance",
- "maintenance_pick_up",
- "missing",
- "off_hours",
- "on_hours",
- "provider_drop_off",
- "rebalance_pick_up",
- "reservation_cancel",
- "reservation_start",
- "system_resume",
- "system_suspend",
- "trip_cancel",
- "trip_end",
- "trip_enter_jurisdiction",
- "trip_leave_jurisdiction",
- "trip_start",
- "unspecified"
- ]
- },
- "vehicle_events": {
- "$id": "#/definitions/vehicle_events",
- "type": "array",
- "description": "Array of events indicating a change to a vehicle's state",
- "uniqueItems": true,
- "minItems": 1,
- "items": {
- "$ref": "#/definitions/vehicle_event"
- }
- }
- },
- "required": [
- "data",
- "version"
- ],
- "properties": {
- "data": {
- "$id": "#/properties/data",
- "type": "object",
- "description": "The data records in this payload",
- "required": [
- "status_changes"
- ],
- "properties": {
- "status_changes": {
- "$id": "#/properties/data/properties/status_changes",
- "type": "array",
- "title": "The status_changes payload",
- "items": {
- "$id": "#/properties/data/properties/status_changes/items",
- "type": "object",
- "title": "The status_change item schema",
- "additionalProperties": false,
- "required": [
- "provider_name",
- "provider_id",
- "device_id",
- "vehicle_id",
- "vehicle_type",
- "propulsion_types",
- "vehicle_state",
- "event_types",
- "event_time",
- "event_location"
- ],
- "properties": {
- "provider_name": {
- "$id": "#/definitions/vehicle/properties/provider_name",
- "$ref": "#/definitions/string",
- "description": "The public-facing name of the Provider"
- },
- "provider_id": {
- "$id": "#/definitions/vehicle/properties/provider_id",
- "$ref": "#/definitions/uuid",
- "description": "The UUID for the Provider, unique within MDS"
- },
- "device_id": {
- "$id": "#/definitions/vehicle/properties/device_id",
- "$ref": "#/definitions/uuid",
- "description": "A unique device ID in UUID format"
- },
- "vehicle_id": {
- "$id": "#/definitions/vehicle/properties/vehicle_id",
- "$ref": "#/definitions/string",
- "description": "The Vehicle Identification Number visible on the vehicle itself"
- },
- "vehicle_type": {
- "$id": "#/definitions/vehicle/properties/vehicle_type",
- "$ref": "#/definitions/vehicle_type",
- "description": "The type of vehicle"
- },
- "propulsion_types": {
- "$id": "#/definitions/vehicle/properties/propulsion_types",
- "$ref": "#/definitions/propulsion_types",
- "description": "The type of propulsion; allows multiple values",
- "minItems": 1
- },
- "event_time": {
- "$id": "#/properties/data/properties/status_changes/items/properties/event_time",
- "$ref": "#/definitions/timestamp",
- "description": "The time the event occurred, expressed as a Unix Timestamp"
- },
- "publication_time": {
- "$id": "#/properties/data/properties/status_changes/items/properties/publication_time",
- "$ref": "#/definitions/timestamp",
- "description": "The time the event became available through the status changes endpoint, expressed as a Unix Timestamp"
- },
- "event_location": {
- "$id": "#/properties/data/properties/status_changes/items/properties/event_location",
- "$ref": "#/definitions/MDS_Feature_Point",
- "description": "The GPS or GNSS coordinates of where the event occurred"
- },
- "vehicle_state": {
- "$id": "#/properties/data/properties/status_changes/items/properties/vehicle_state",
- "$ref": "#/definitions/vehicle_state",
- "description": "The state of the vehicle"
- },
- "event_types": {
- "$id": "#/properties/data/properties/status_changes/items/properties/event_types",
- "$ref": "#/definitions/vehicle_events",
- "description": "The event(s) that caused a change in the vehicle's state"
- },
- "battery_pct": {
- "$id": "#/properties/data/properties/status_changes/items/properties/battery_pct",
- "type": [
- "number",
- "null"
- ],
- "description": "Percent charge of device battery, expressed between 0 and 1",
- "examples": [
- 0.89
- ],
- "minimum": 0,
- "maximum": 1
- },
- "trip_id": {
- "$id": "#/properties/data/properties/status_changes/items/properties/trip_id",
- "$ref": "#/definitions/uuid",
- "description": "Trip UUID (foreign key to Trips API), required if event_types contains trip_start, trip_end, trip_cancel, trip_enter_jurisdiction, or trip_leave_jurisdiction"
- },
- "associated_ticket": {
- "$id": "#/properties/data/properties/status_changes/items/properties/associated_ticket",
- "$ref": "#/definitions/string",
- "description": "Identifier for an associated ticket inside an Agency-maintained 311 or CRM system."
- }
- },
- "allOf": [
- {
- "description": "valid vehicle_state and vehicle_events combinations",
- "oneOf": [
- {
- "properties": {
- "vehicle_state": {
- "const": "available"
- },
- "event_types": {
- "contains": {
- "enum": [
- "agency_drop_off",
- "battery_charged",
- "comms_restored",
- "located",
- "maintenance",
- "on_hours",
- "provider_drop_off",
- "reservation_cancel",
- "system_resume",
- "trip_cancel",
- "trip_end",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "vehicle_state": {
- "const": "elsewhere"
- },
- "event_types": {
- "contains": {
- "enum": [
- "comms_restored",
- "located",
- "trip_leave_jurisdiction",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "vehicle_state": {
- "const": "non_operational"
- },
- "event_types": {
- "contains": {
- "enum": [
- "battery_low",
- "comms_restored",
- "located",
- "maintenance",
- "off_hours",
- "system_suspend",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "vehicle_state": {
- "const": "on_trip"
- },
- "event_types": {
- "contains": {
- "enum": [
- "comms_restored",
- "located",
- "trip_enter_jurisdiction",
- "trip_start",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "vehicle_state": {
- "const": "removed"
- },
- "event_types": {
- "contains": {
- "enum": [
- "agency_pick_up",
- "comms_restored",
- "compliance_pick_up",
- "decommissioned",
- "located",
- "maintenance_pick_up",
- "rebalance_pick_up",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "vehicle_state": {
- "const": "reserved"
- },
- "event_types": {
- "contains": {
- "enum": [
- "comms_restored",
- "located",
- "reservation_start",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "vehicle_state": {
- "const": "unknown"
- },
- "event_types": {
- "contains": {
- "enum": [
- "comms_lost",
- "missing",
- "unspecified"
- ]
- }
- }
- }
- }
- ]
- },
- {
- "description": "Conditionally require a trip_id reference",
- "anyOf": [
- {
- "not": {
- "properties": {
- "event_types": {
- "contains": {
- "enum": [
- "trip_cancel",
- "trip_end",
- "trip_enter_jurisdiction",
- "trip_leave_jurisdiction",
- "trip_start"
- ]
- }
- }
- }
- }
- },
- {
- "required": [
- "trip_id"
- ]
- }
- ]
- }
- ]
- }
- }
- },
- "additionalProperties": false
- },
- "version": {
- "$id": "#/properties/version",
- "$ref": "#/definitions/version"
- }
- },
- "additionalProperties": false
-}
diff --git a/provider/stops.json b/provider/stops.json
deleted file mode 100644
index 5f913970..00000000
--- a/provider/stops.json
+++ /dev/null
@@ -1,392 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/provider/stops.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "Schema for MDS Provider stops payloads",
- "type": "object",
- "definitions": {
- "string": {
- "$id": "#/definitions/string",
- "type": "string",
- "description": "A length-limited string type",
- "maxLength": 255,
- "default": "",
- "examples": [
- "ABC123"
- ],
- "pattern": "^(.*)$"
- },
- "timestamp": {
- "$id": "#/definitions/timestamp",
- "type": "number",
- "description": "Integer milliseconds since Unix epoch",
- "multipleOf": 1.0,
- "minimum": 1514764800000
- },
- "uuid": {
- "$id": "#/definitions/uuid",
- "type": "string",
- "description": "A UUID used to uniquely identifty an object",
- "default": "",
- "examples": [
- "3c9604d6-b5ee-11e8-96f8-529269fb1459"
- ],
- "pattern": "^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$"
- },
- "version": {
- "$id": "#/definitions/version",
- "type": "string",
- "description": "The version of MDS this data represents",
- "examples": [
- "1.2.0"
- ],
- "pattern": "^1\\.2\\.[0-9]+$"
- },
- "MDS_Feature_Point": {
- "$id": "#/definitions/MDS_Feature_Point",
- "title": "MDS GeoJSON Feature Point",
- "type": "object",
- "required": [
- "type",
- "properties",
- "geometry"
- ],
- "properties": {
- "type": {
- "type": "string",
- "enum": [
- "Feature"
- ]
- },
- "id": {
- "oneOf": [
- {
- "type": "number"
- },
- {
- "type": "string"
- }
- ]
- },
- "properties": {
- "type": "object",
- "required": [
- "timestamp"
- ],
- "properties": {
- "timestamp": {
- "$ref": "#/definitions/timestamp"
- },
- "stop_id": {
- "$ref": "#/definitions/uuid"
- },
- "altitude": {
- "type": "number",
- "description": "Altitude above mean sea level in meters"
- },
- "heading": {
- "type": "number",
- "description": "Degrees - clockwise starting at 0 degrees at true North"
- },
- "speed": {
- "type": "number",
- "description": "Estimated speed in meters / sec as reported by the GPS chipset"
- },
- "accuracy": {
- "type": "number",
- "description": "Horizontal accuracy, in meters"
- },
- "hdop": {
- "type": "number",
- "description": "Horizontal GPS or GNSS accuracy value"
- },
- "satellites": {
- "type": "integer",
- "description": "Number of GPS or GNSS satellites"
- }
- }
- },
- "geometry": {
- "$ref": "#/definitions/Point"
- },
- "bbox": {
- "type": "array",
- "minItems": 4,
- "items": {
- "type": "number"
- }
- }
- }
- },
- "Point": {
- "$id": "#/definitions/Point",
- "title": "GeoJSON Point",
- "type": "object",
- "required": [
- "type",
- "coordinates"
- ],
- "properties": {
- "type": {
- "type": "string",
- "enum": [
- "Point"
- ]
- },
- "coordinates": {
- "type": "array",
- "minItems": 2,
- "items": [
- {
- "type": "number",
- "minimum": -180.0,
- "maximum": 180.0
- },
- {
- "type": "number",
- "minimum": -90.0,
- "maximum": 90.0
- }
- ],
- "maxItems": 2
- },
- "bbox": {
- "type": "array",
- "minItems": 4,
- "items": {
- "type": "number"
- }
- }
- }
- },
- "ttl": {
- "$id": "#/definitions/ttl",
- "type": "integer",
- "description": "Integer milliseconds until next data update (0 if the data is always refreshed)",
- "minimum": 0,
- "maximum": 300000
- },
- "stop": {
- "$id": "#/definitions/stop",
- "type": "object",
- "description": "The common schema elements for a Stop in MDS",
- "required": [
- "stop_id",
- "name",
- "last_reported",
- "location",
- "status",
- "capacity",
- "num_vehicles_available",
- "num_vehicles_disabled"
- ],
- "properties": {
- "stop_id": {
- "$id": "#/definitions/stop/properties/stop_id",
- "$ref": "#/definitions/uuid",
- "description": "UUID for the Stop"
- },
- "name": {
- "$id": "#/definitions/stop/properties/name",
- "$ref": "#/definitions/string",
- "description": "Name of the Stop"
- },
- "last_reported": {
- "$id": "#/definitions/stop/properties/last_reported",
- "$ref": "#/definitions/timestamp",
- "description": "Date/Time of the last status update for this Stop"
- },
- "location": {
- "$id": "#/definitions/stop/properties/location",
- "$ref": "#/definitions/MDS_Feature_Point",
- "description": "Location of the stop"
- },
- "status": {
- "$id": "#/definitions/stop/properties/status",
- "$ref": "#/definitions/stop_status",
- "description": "The status of the Stop"
- },
- "capacity": {
- "$id": "#/definitions/stop/properties/capacity",
- "$ref": "#/definitions/vehicle_type_counts",
- "description": "Number of total places per vehicle_type"
- },
- "num_vehicles_available": {
- "$id": "#/definitions/stop/properties/num_vehicles_available",
- "$ref": "#/definitions/vehicle_type_counts",
- "description": "Number of available vehicles per vehicle_type"
- },
- "num_vehicles_disabled": {
- "$id": "#/definitions/stop/properties/num_vehicles_disabled",
- "$ref": "#/definitions/vehicle_type_counts",
- "description": "Number of non_operational/reserved vehicles per vehicle_type"
- },
- "provider_id": {
- "$id": "#/definitions/stop/properties/provider_id",
- "$ref": "#/definitions/uuid",
- "description": "UUID for the Provider managing this Stop. Null/undefined if managed by an Agency."
- },
- "geography_id": {
- "$id": "#/definitions/stop/properties/geography_id",
- "$ref": "#/definitions/uuid",
- "description": "UUID for the Stop"
- },
- "region_id": {
- "$id": "#/definitions/stop/properties/region_id",
- "$ref": "#/definitions/string",
- "description": "ID of the region where the Stop is located. See GBFS Station Information."
- },
- "short_name": {
- "$id": "#/definitions/stop/properties/short_name",
- "$ref": "#/definitions/string",
- "description": "Abbreviated Stop name"
- },
- "address": {
- "$id": "#/definitions/stop/properties/address",
- "$ref": "#/definitions/string",
- "description": "Postal address (useful for directions)"
- },
- "post_code": {
- "$id": "#/definitions/stop/properties/post_code",
- "$ref": "#/definitions/string",
- "description": "Postal code (e.g. 10036)"
- },
- "cross_street": {
- "$id": "#/definitions/stop/properties/cross_street",
- "$ref": "#/definitions/string",
- "description": "Cross street of where Stop is located"
- },
- "num_places_available": {
- "$id": "#/definitions/stop/properties/num_places_available",
- "$ref": "#/definitions/vehicle_type_counts",
- "description": "Number of places free to be populated per vehicle_type"
- },
- "num_places_disabled": {
- "$id": "#/definitions/stop/properties/num_places_disabled",
- "$ref": "#/definitions/vehicle_type_counts",
- "description": "Number of places disabled an unable to accept vehicles per vehicle_type"
- },
- "parent_stop": {
- "$id": "#/definitions/stop/properties/parent_stop",
- "$ref": "#/definitions/uuid",
- "description": "Describe a basic hierarchy of Stops (e.g. a Stop inside a greater Stop)"
- },
- "devices": {
- "$id": "#/definitions/stop/properties/devices",
- "$ref": "#/definitions/uuid_array",
- "description": "List of device_id for vehicles currently at this Stop."
- }
- }
- },
- "stop_status": {
- "$id": "#/definitions/stop_status",
- "type": "object",
- "description": "Status object for a Stop in MDS",
- "required": [
- "is_installed",
- "is_renting",
- "is_returning"
- ],
- "properties": {
- "is_installed": {
- "$id": "#/definitions/stop_status/properties/is_installed",
- "type": "boolean"
- },
- "is_renting": {
- "$id": "#/definitions/stop_status/properties/is_renting",
- "type": "boolean"
- },
- "is_returning": {
- "$id": "#/definitions/stop_status/properties/is_returning",
- "type": "boolean"
- }
- }
- },
- "uuid_array": {
- "$id": "#/definitions/uuid_array",
- "type": "array",
- "description": "Array of UUID",
- "items": {
- "$id": "#/definitions/uuid_array/items",
- "$ref": "#/definitions/uuid"
- }
- },
- "vehicle_type_counts": {
- "$id": "#/definitions/vehicle_type_counts",
- "type": "object",
- "properties": {
- "bicycle": {
- "$id": "#/definitions/vehicle_type_counts/properties/bicycle",
- "type": "integer",
- "minimum": 0
- },
- "cargo_bicycle": {
- "$id": "#/definitions/vehicle_type_counts/properties/cargo_bicycle",
- "type": "integer",
- "minimum": 0
- },
- "car": {
- "$id": "#/definitions/vehicle_type_counts/properties/car",
- "type": "integer",
- "minimum": 0
- },
- "scooter": {
- "$id": "#/definitions/vehicle_type_counts/properties/scooter",
- "type": "integer",
- "minimum": 0
- },
- "moped": {
- "$id": "#/definitions/vehicle_type_counts/properties/moped",
- "type": "integer",
- "minimum": 0
- },
- "other": {
- "$id": "#/definitions/vehicle_type_counts/properties/other",
- "type": "integer",
- "minimum": 0
- }
- },
- "additionalProperties": false
- }
- },
- "required": [
- "data",
- "version",
- "last_updated",
- "ttl"
- ],
- "properties": {
- "data": {
- "$id": "#/properties/data",
- "type": "object",
- "description": "The data records in this payload",
- "required": [
- "stops"
- ],
- "properties": {
- "stops": {
- "$id": "#/properties/data/properties/stops",
- "type": "array",
- "title": "The stops payload",
- "items": {
- "$id": "#/properties/data/properties/stops/items",
- "$ref": "#/definitions/stop"
- }
- }
- },
- "additionalProperties": false
- },
- "version": {
- "$id": "#/properties/version",
- "$ref": "#/definitions/version"
- },
- "last_updated": {
- "$id": "#/properties/last_updated",
- "$ref": "#/definitions/timestamp"
- },
- "ttl": {
- "$id": "#/properties/ttl",
- "$ref": "#/definitions/ttl"
- }
- },
- "additionalProperties": false
-}
diff --git a/provider/trips.json b/provider/trips.json
deleted file mode 100644
index f89c8748..00000000
--- a/provider/trips.json
+++ /dev/null
@@ -1,413 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/provider/trips.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "Schema for MDS Provider trips payloads",
- "type": "object",
- "definitions": {
- "string": {
- "$id": "#/definitions/string",
- "type": "string",
- "description": "A length-limited string type",
- "maxLength": 255,
- "default": "",
- "examples": [
- "ABC123"
- ],
- "pattern": "^(.*)$"
- },
- "timestamp": {
- "$id": "#/definitions/timestamp",
- "type": "number",
- "description": "Integer milliseconds since Unix epoch",
- "multipleOf": 1.0,
- "minimum": 1514764800000
- },
- "uuid": {
- "$id": "#/definitions/uuid",
- "type": "string",
- "description": "A UUID used to uniquely identifty an object",
- "default": "",
- "examples": [
- "3c9604d6-b5ee-11e8-96f8-529269fb1459"
- ],
- "pattern": "^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$"
- },
- "version": {
- "$id": "#/definitions/version",
- "type": "string",
- "description": "The version of MDS this data represents",
- "examples": [
- "1.2.0"
- ],
- "pattern": "^1\\.2\\.[0-9]+$"
- },
- "MDS_Feature_Point": {
- "$id": "#/definitions/MDS_Feature_Point",
- "title": "MDS GeoJSON Feature Point",
- "type": "object",
- "required": [
- "type",
- "properties",
- "geometry"
- ],
- "properties": {
- "type": {
- "type": "string",
- "enum": [
- "Feature"
- ]
- },
- "id": {
- "oneOf": [
- {
- "type": "number"
- },
- {
- "type": "string"
- }
- ]
- },
- "properties": {
- "type": "object",
- "required": [
- "timestamp"
- ],
- "properties": {
- "timestamp": {
- "$ref": "#/definitions/timestamp"
- },
- "stop_id": {
- "$ref": "#/definitions/uuid"
- },
- "altitude": {
- "type": "number",
- "description": "Altitude above mean sea level in meters"
- },
- "heading": {
- "type": "number",
- "description": "Degrees - clockwise starting at 0 degrees at true North"
- },
- "speed": {
- "type": "number",
- "description": "Estimated speed in meters / sec as reported by the GPS chipset"
- },
- "accuracy": {
- "type": "number",
- "description": "Horizontal accuracy, in meters"
- },
- "hdop": {
- "type": "number",
- "description": "Horizontal GPS or GNSS accuracy value"
- },
- "satellites": {
- "type": "integer",
- "description": "Number of GPS or GNSS satellites"
- }
- }
- },
- "geometry": {
- "$ref": "#/definitions/Point"
- },
- "bbox": {
- "type": "array",
- "minItems": 4,
- "items": {
- "type": "number"
- }
- }
- }
- },
- "Point": {
- "$id": "#/definitions/Point",
- "title": "GeoJSON Point",
- "type": "object",
- "required": [
- "type",
- "coordinates"
- ],
- "properties": {
- "type": {
- "type": "string",
- "enum": [
- "Point"
- ]
- },
- "coordinates": {
- "type": "array",
- "minItems": 2,
- "items": [
- {
- "type": "number",
- "minimum": -180.0,
- "maximum": 180.0
- },
- {
- "type": "number",
- "minimum": -90.0,
- "maximum": 90.0
- }
- ],
- "maxItems": 2
- },
- "bbox": {
- "type": "array",
- "minItems": 4,
- "items": {
- "type": "number"
- }
- }
- }
- },
- "currency": {
- "$id": "#/definitions/currency",
- "type": [
- "string",
- "null"
- ],
- "pattern": "^[A-Z]{3}$",
- "default": "USD",
- "description": "An ISO 4217 Alphabetic Currency Code representing currency of the payee. If null, USD cents is implied.",
- "examples": [
- "USD",
- "EUR",
- "GBP"
- ]
- },
- "MDS_FeatureCollection_Route": {
- "$id": "#/definitions/MDS_FeatureCollection_Route",
- "title": "MDS GeoJSON FeatureCollection Route",
- "type": "object",
- "required": [
- "type",
- "features"
- ],
- "properties": {
- "type": {
- "type": "string",
- "enum": [
- "FeatureCollection"
- ]
- },
- "features": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/MDS_Feature_Point"
- },
- "minItems": 2
- },
- "bbox": {
- "type": "array",
- "minItems": 4,
- "items": {
- "type": "number"
- }
- }
- }
- },
- "propulsion_type": {
- "$id": "#/definitions/propulsion_type",
- "type": "string",
- "description": "The type of propulsion",
- "enum": [
- "combustion",
- "electric",
- "electric_assist",
- "human"
- ]
- },
- "propulsion_types": {
- "$id": "#/definitions/propulsion_types",
- "type": "array",
- "description": "Array of propulsion types, allowing multiple values",
- "items": {
- "$id": "#/definitions/propulsion_types/items",
- "$ref": "#/definitions/propulsion_type"
- },
- "uniqueItems": true
- },
- "vehicle_type": {
- "$id": "#/definitions/vehicle_type",
- "type": "string",
- "description": "The type of vehicle",
- "enum": [
- "bicycle",
- "cargo_bicycle",
- "car",
- "scooter",
- "moped",
- "other"
- ]
- }
- },
- "required": [
- "data",
- "version"
- ],
- "properties": {
- "data": {
- "$id": "#/properties/data",
- "type": "object",
- "description": "The data records in this payload",
- "required": [
- "trips"
- ],
- "properties": {
- "trips": {
- "$id": "#/properties/data/properties/trips",
- "type": "array",
- "title": "The trips payload",
- "items": {
- "$id": "#/properties/data/properties/trips/items",
- "type": "object",
- "title": "The trip item schema",
- "additionalProperties": false,
- "required": [
- "provider_name",
- "provider_id",
- "device_id",
- "vehicle_id",
- "vehicle_type",
- "propulsion_types",
- "trip_id",
- "trip_duration",
- "trip_distance",
- "route",
- "accuracy",
- "start_time",
- "end_time"
- ],
- "properties": {
- "provider_name": {
- "$id": "#/definitions/vehicle/properties/provider_name",
- "$ref": "#/definitions/string",
- "description": "The public-facing name of the Provider"
- },
- "provider_id": {
- "$id": "#/definitions/vehicle/properties/provider_id",
- "$ref": "#/definitions/uuid",
- "description": "The UUID for the Provider, unique within MDS"
- },
- "device_id": {
- "$id": "#/definitions/vehicle/properties/device_id",
- "$ref": "#/definitions/uuid",
- "description": "A unique device ID in UUID format"
- },
- "vehicle_id": {
- "$id": "#/definitions/vehicle/properties/vehicle_id",
- "$ref": "#/definitions/string",
- "description": "The Vehicle Identification Number visible on the vehicle itself"
- },
- "vehicle_type": {
- "$id": "#/definitions/vehicle/properties/vehicle_type",
- "$ref": "#/definitions/vehicle_type",
- "description": "The type of vehicle"
- },
- "propulsion_types": {
- "$id": "#/definitions/vehicle/properties/propulsion_types",
- "$ref": "#/definitions/propulsion_types",
- "description": "The type of propulsion; allows multiple values",
- "minItems": 1
- },
- "trip_id": {
- "$id": "#/properties/data/properties/trips/items/properties/trip_id",
- "description": "A unique ID for each trip",
- "$ref": "#/definitions/uuid"
- },
- "trip_duration": {
- "$id": "#/properties/data/properties/trips/items/properties/trip_duration",
- "type": "integer",
- "description": "The length of time, in seconds, that the trip lasted",
- "default": 0,
- "examples": [
- 600
- ]
- },
- "trip_distance": {
- "$id": "#/properties/data/properties/trips/items/properties/trip_distance",
- "type": "integer",
- "description": "The distance, in meters, that the trip covered",
- "default": 0,
- "examples": [
- 1000
- ]
- },
- "route": {
- "$id": "#/properties/data/properties/trips/items/properties/route",
- "title": "The Route Schema",
- "$ref": "#/definitions/MDS_FeatureCollection_Route"
- },
- "accuracy": {
- "$id": "#/properties/data/properties/trips/items/properties/accuracy",
- "type": "integer",
- "title": "The approximate level of accuracy, in meters, of Points within route",
- "default": 0,
- "examples": [
- 15
- ]
- },
- "start_time": {
- "$id": "#/properties/data/properties/trips/items/properties/start_time",
- "description": "The time the trip began, expressed as a Unix Timestamp",
- "$ref": "#/definitions/timestamp"
- },
- "end_time": {
- "$id": "#/properties/data/properties/trips/items/properties/end_time",
- "description": "The time the trip ended, expressed as a Unix Timestamp",
- "$ref": "#/definitions/timestamp"
- },
- "publication_time": {
- "$id": "#/properties/data/properties/trips/items/properties/publication_time",
- "description": "The time the trip became available through the trips endpoint, expressed as a Unix Timestamp",
- "$ref": "#/definitions/timestamp"
- },
- "parking_verification_url": {
- "$id": "#/properties/data/properties/trips/items/properties/parking_verification_url",
- "type": [
- "string",
- "null"
- ],
- "format": "uri",
- "description": "A URL to a photo (or other evidence) of proper vehicle parking",
- "examples": [
- "https://data.provider.co/parking_verify/1234.jpg"
- ]
- },
- "standard_cost": {
- "$id": "#/properties/data/properties/trips/items/properties/standard_cost",
- "type": [
- "integer",
- "null"
- ],
- "description": "The cost, in the currency defined in `currency`, that it would cost to perform that trip in the standard operation of the System. If no currency is given, USD cents is implied.",
- "examples": [
- 500
- ]
- },
- "actual_cost": {
- "$id": "#/properties/data/properties/trips/items/properties/actual_cost",
- "type": [
- "integer",
- "null"
- ],
- "description": "The actual cost, in the currency defined in `currency`, paid by the customer of the *mobility as a service* provider. If no currency is given, USD cents is implied.",
- "examples": [
- 520
- ]
- },
- "currency": {
- "$id": "#/properties/data/properties/trips/items/properties/currency",
- "$ref": "#/definitions/currency"
- }
- }
- }
- }
- },
- "additionalProperties": false
- },
- "version": {
- "$id": "#/properties/version",
- "$ref": "#/definitions/version"
- }
- },
- "additionalProperties": false
-}
diff --git a/provider/vehicles.json b/provider/vehicles.json
deleted file mode 100644
index 6bda6bc3..00000000
--- a/provider/vehicles.json
+++ /dev/null
@@ -1,605 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/provider/vehicles.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "Schema for MDS Provider vehicles payloads",
- "type": "object",
- "definitions": {
- "string": {
- "$id": "#/definitions/string",
- "type": "string",
- "description": "A length-limited string type",
- "maxLength": 255,
- "default": "",
- "examples": [
- "ABC123"
- ],
- "pattern": "^(.*)$"
- },
- "timestamp": {
- "$id": "#/definitions/timestamp",
- "type": "number",
- "description": "Integer milliseconds since Unix epoch",
- "multipleOf": 1.0,
- "minimum": 1514764800000
- },
- "uuid": {
- "$id": "#/definitions/uuid",
- "type": "string",
- "description": "A UUID used to uniquely identifty an object",
- "default": "",
- "examples": [
- "3c9604d6-b5ee-11e8-96f8-529269fb1459"
- ],
- "pattern": "^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$"
- },
- "version": {
- "$id": "#/definitions/version",
- "type": "string",
- "description": "The version of MDS this data represents",
- "examples": [
- "1.2.0"
- ],
- "pattern": "^1\\.2\\.[0-9]+$"
- },
- "MDS_Feature_Point": {
- "$id": "#/definitions/MDS_Feature_Point",
- "title": "MDS GeoJSON Feature Point",
- "type": "object",
- "required": [
- "type",
- "properties",
- "geometry"
- ],
- "properties": {
- "type": {
- "type": "string",
- "enum": [
- "Feature"
- ]
- },
- "id": {
- "oneOf": [
- {
- "type": "number"
- },
- {
- "type": "string"
- }
- ]
- },
- "properties": {
- "type": "object",
- "required": [
- "timestamp"
- ],
- "properties": {
- "timestamp": {
- "$ref": "#/definitions/timestamp"
- },
- "stop_id": {
- "$ref": "#/definitions/uuid"
- },
- "altitude": {
- "type": "number",
- "description": "Altitude above mean sea level in meters"
- },
- "heading": {
- "type": "number",
- "description": "Degrees - clockwise starting at 0 degrees at true North"
- },
- "speed": {
- "type": "number",
- "description": "Estimated speed in meters / sec as reported by the GPS chipset"
- },
- "accuracy": {
- "type": "number",
- "description": "Horizontal accuracy, in meters"
- },
- "hdop": {
- "type": "number",
- "description": "Horizontal GPS or GNSS accuracy value"
- },
- "satellites": {
- "type": "integer",
- "description": "Number of GPS or GNSS satellites"
- }
- }
- },
- "geometry": {
- "$ref": "#/definitions/Point"
- },
- "bbox": {
- "type": "array",
- "minItems": 4,
- "items": {
- "type": "number"
- }
- }
- }
- },
- "Point": {
- "$id": "#/definitions/Point",
- "title": "GeoJSON Point",
- "type": "object",
- "required": [
- "type",
- "coordinates"
- ],
- "properties": {
- "type": {
- "type": "string",
- "enum": [
- "Point"
- ]
- },
- "coordinates": {
- "type": "array",
- "minItems": 2,
- "items": [
- {
- "type": "number",
- "minimum": -180.0,
- "maximum": 180.0
- },
- {
- "type": "number",
- "minimum": -90.0,
- "maximum": 90.0
- }
- ],
- "maxItems": 2
- },
- "bbox": {
- "type": "array",
- "minItems": 4,
- "items": {
- "type": "number"
- }
- }
- }
- },
- "links": {
- "$id": "#/definitions/links",
- "type": "object",
- "required": [
- "next"
- ],
- "properties": {
- "first": {
- "$id": "#/definitions/links/first",
- "type": [
- "null",
- "string"
- ],
- "title": "The URL to the first page of data",
- "examples": [
- "https://data.provider.co/trips/first"
- ],
- "format": "uri"
- },
- "last": {
- "$id": "#/definitions/links/last",
- "type": [
- "null",
- "string"
- ],
- "title": "The URL to the last page of data",
- "examples": [
- "https://data.provider.co/trips/last"
- ],
- "format": "uri"
- },
- "prev": {
- "$id": "#/definitions/links/prev",
- "type": [
- "null",
- "string"
- ],
- "title": "The URL to the previous page of data",
- "examples": [
- "https://data.provider.co/trips/prev"
- ],
- "format": "uri"
- },
- "next": {
- "$id": "#/definitions/links/next",
- "type": [
- "null",
- "string"
- ],
- "title": "The URL to the next page of data",
- "examples": [
- "https://data.provider.co/trips/next"
- ],
- "format": "uri",
- "pattern": "^(.*)$"
- }
- },
- "additionalProperties": false
- },
- "ttl": {
- "$id": "#/definitions/ttl",
- "type": "integer",
- "description": "Integer milliseconds until next data update (0 if the data is always refreshed)",
- "minimum": 0,
- "maximum": 300000
- },
- "vehicle_state": {
- "$id": "#/definitions/vehicle_state",
- "type": "string",
- "description": "The state of a vehicle",
- "enum": [
- "available",
- "elsewhere",
- "non_operational",
- "on_trip",
- "removed",
- "reserved",
- "unknown"
- ]
- },
- "vehicle_event": {
- "$id": "#/definitions/vehicle_event",
- "type": "string",
- "description": "An event that changes a vehicle's state",
- "enum": [
- "agency_drop_off",
- "agency_pick_up",
- "battery_charged",
- "battery_low",
- "comms_lost",
- "comms_restored",
- "compliance_pick_up",
- "decommissioned",
- "located",
- "maintenance",
- "maintenance_pick_up",
- "missing",
- "off_hours",
- "on_hours",
- "provider_drop_off",
- "rebalance_pick_up",
- "reservation_cancel",
- "reservation_start",
- "system_resume",
- "system_suspend",
- "trip_cancel",
- "trip_end",
- "trip_enter_jurisdiction",
- "trip_leave_jurisdiction",
- "trip_start",
- "unspecified"
- ]
- },
- "vehicle_events": {
- "$id": "#/definitions/vehicle_events",
- "type": "array",
- "description": "Array of events indicating a change to a vehicle's state",
- "uniqueItems": true,
- "minItems": 1,
- "items": {
- "$ref": "#/definitions/vehicle_event"
- }
- },
- "propulsion_type": {
- "$id": "#/definitions/propulsion_type",
- "type": "string",
- "description": "The type of propulsion",
- "enum": [
- "combustion",
- "electric",
- "electric_assist",
- "human"
- ]
- },
- "propulsion_types": {
- "$id": "#/definitions/propulsion_types",
- "type": "array",
- "description": "Array of propulsion types, allowing multiple values",
- "items": {
- "$id": "#/definitions/propulsion_types/items",
- "$ref": "#/definitions/propulsion_type"
- },
- "uniqueItems": true
- },
- "vehicle_type": {
- "$id": "#/definitions/vehicle_type",
- "type": "string",
- "description": "The type of vehicle",
- "enum": [
- "bicycle",
- "cargo_bicycle",
- "car",
- "scooter",
- "moped",
- "other"
- ]
- }
- },
- "required": [
- "data",
- "version",
- "last_updated",
- "ttl"
- ],
- "properties": {
- "data": {
- "$id": "#/properties/data",
- "type": "object",
- "description": "The data records in this payload",
- "required": [
- "vehicles"
- ],
- "properties": {
- "vehicles": {
- "$id": "#/properties/data/properties/vehicles",
- "type": "array",
- "title": "The vehicles payload",
- "items": {
- "$id": "#/properties/data/properties/vehicles/items",
- "type": "object",
- "title": "The vehicle item schema",
- "required": [
- "provider_name",
- "provider_id",
- "device_id",
- "vehicle_id",
- "vehicle_type",
- "propulsion_types",
- "last_event_time",
- "last_vehicle_state",
- "last_event_types",
- "last_event_location"
- ],
- "properties": {
- "provider_name": {
- "$id": "#/definitions/vehicle/properties/provider_name",
- "$ref": "#/definitions/string",
- "description": "The public-facing name of the Provider"
- },
- "provider_id": {
- "$id": "#/definitions/vehicle/properties/provider_id",
- "$ref": "#/definitions/uuid",
- "description": "The UUID for the Provider, unique within MDS"
- },
- "device_id": {
- "$id": "#/definitions/vehicle/properties/device_id",
- "$ref": "#/definitions/uuid",
- "description": "A unique device ID in UUID format"
- },
- "vehicle_id": {
- "$id": "#/definitions/vehicle/properties/vehicle_id",
- "$ref": "#/definitions/string",
- "description": "The Vehicle Identification Number visible on the vehicle itself"
- },
- "vehicle_type": {
- "$id": "#/definitions/vehicle/properties/vehicle_type",
- "$ref": "#/definitions/vehicle_type",
- "description": "The type of vehicle"
- },
- "propulsion_types": {
- "$id": "#/definitions/vehicle/properties/propulsion_types",
- "$ref": "#/definitions/propulsion_types",
- "description": "The type of propulsion; allows multiple values",
- "minItems": 1
- },
- "last_event_time": {
- "$id": "#/properties/data/properties/vehicles/items/properties/last_event_time",
- "$ref": "#/definitions/timestamp",
- "description": "The time the most recent status change event occurred, expressed as a Unix Timestamp"
- },
- "last_vehicle_state": {
- "$id": "#/properties/data/properties/vehicles/items/properties/last_vehicle_state",
- "$ref": "#/definitions/vehicle_state",
- "description": "The last known state of the vehicle"
- },
- "last_event_types": {
- "$id": "#/properties/data/properties/vehicles/items/properties/last_event_types",
- "$ref": "#/definitions/vehicle_events",
- "description": "The most recent event(s) that caused a change in the vehicle's state"
- },
- "last_event_location": {
- "$id": "#/properties/data/properties/vehicles/items/properties/last_event_location",
- "$ref": "#/definitions/MDS_Feature_Point",
- "description": "Location of the vehicle's last status change event"
- },
- "current_location": {
- "$id": "#/properties/data/properties/vehicles/items/properties/current_location",
- "$ref": "#/definitions/MDS_Feature_Point",
- "description": "Current location of vehicle if different from last event, and the vehicle is not currently on a trip"
- },
- "battery_pct": {
- "$id": "#/properties/data/properties/vehicles/items/properties/battery_pct",
- "type": [
- "number",
- "null"
- ],
- "description": "Percent charge of device battery, expressed between 0 and 1",
- "examples": [
- 0.89
- ],
- "minimum": 0,
- "maximum": 1
- }
- },
- "allOf": [
- {
- "description": "Valid last_vehicle_state values for this endpoint",
- "properties": {
- "last_vehicle_state": {
- "enum": [
- "available",
- "elsewhere",
- "non_operational",
- "on_trip",
- "removed",
- "reserved",
- "unknown"
- ]
- }
- }
- },
- {
- "description": "valid vehicle_state and vehicle_events combinations",
- "oneOf": [
- {
- "properties": {
- "last_vehicle_state": {
- "const": "available"
- },
- "last_event_types": {
- "contains": {
- "enum": [
- "agency_drop_off",
- "battery_charged",
- "comms_restored",
- "located",
- "maintenance",
- "on_hours",
- "provider_drop_off",
- "reservation_cancel",
- "system_resume",
- "trip_cancel",
- "trip_end",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "last_vehicle_state": {
- "const": "elsewhere"
- },
- "last_event_types": {
- "contains": {
- "enum": [
- "comms_restored",
- "located",
- "trip_leave_jurisdiction",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "last_vehicle_state": {
- "const": "non_operational"
- },
- "last_event_types": {
- "contains": {
- "enum": [
- "battery_low",
- "comms_restored",
- "located",
- "maintenance",
- "off_hours",
- "system_suspend",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "last_vehicle_state": {
- "const": "on_trip"
- },
- "last_event_types": {
- "contains": {
- "enum": [
- "comms_restored",
- "located",
- "trip_enter_jurisdiction",
- "trip_start",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "last_vehicle_state": {
- "const": "removed"
- },
- "last_event_types": {
- "contains": {
- "enum": [
- "agency_pick_up",
- "comms_restored",
- "compliance_pick_up",
- "decommissioned",
- "located",
- "maintenance_pick_up",
- "rebalance_pick_up",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "last_vehicle_state": {
- "const": "reserved"
- },
- "last_event_types": {
- "contains": {
- "enum": [
- "comms_restored",
- "located",
- "reservation_start",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "last_vehicle_state": {
- "const": "unknown"
- },
- "last_event_types": {
- "contains": {
- "enum": [
- "comms_lost",
- "missing",
- "unspecified"
- ]
- }
- }
- }
- }
- ]
- }
- ]
- }
- }
- },
- "additionalProperties": false
- },
- "version": {
- "$id": "#/properties/version",
- "$ref": "#/definitions/version"
- },
- "links": {
- "$id": "#/properties/links",
- "$ref": "#/definitions/links"
- },
- "last_updated": {
- "$id": "#/properties/last_updated",
- "$ref": "#/definitions/timestamp"
- },
- "ttl": {
- "$id": "#/properties/ttl",
- "$ref": "#/definitions/ttl"
- }
- },
- "additionalProperties": false
-}
diff --git a/providers.csv b/providers.csv
index dad60d11..b61e6dd1 100644
--- a/providers.csv
+++ b/providers.csv
@@ -1,33 +1,52 @@
-provider_name,provider_id,url,mds_api_url,gbfs_api_url
-JUMP,c20e08cf-8488-46a6-a66c-5d8fb827f7e0,https://jump.com,https://api.uber.com/v0.2/emobility/mds,
-Lime,63f13c48-34ff-49d2-aca7-cf6a5b6171c3,https://li.me,https://data.lime.bike/api/partners/v1/mds,
-Bird,2411d395-04f2-47c9-ab66-d09e9e3c3251,https://www.bird.co,https://mds.bird.co,https://mds.bird.co/gbfs
-Razor,6ddcc0ad-1d66-4046-bba4-d1d96bb8ca4d,https://www.razor.com/share,https://razor-200806.appspot.com/api/v2/mds,
-Lyft,e714f168-ce56-4b41-81b7-0b6a4bd26128,https://www.lyft.com,https://api.lyft.com/v1/last-mile/mds,
-Skip,d73fcf80-22b1-450f-b535-042b4e30aac7,https://www.skipscooters.com,https://api.skipscooters.com/mds,
-HOPR,2e4cb206-b475-4a9d-80fb-0880c9a033e0,https://gohopr.com,https://gbfs.hopr.city/api/mds,
-Wheels,b79f8687-526d-4ae6-80bf-89b4c44dc071,https://wheels.co,https://mds.getwheelsapp.com,
-Spin,70aa475d-1fcd-4504-b69c-2eeb2107f7be,https://www.spin.app,https://web.spin.pm/api/mds/v1,
-WIND,d56d2df6-fa92-43de-ab61-92c3a84acd7d,https://www.wind.co,https://partners.wind.co/v1/mds,
-Tier,264aad41-b47c-415d-8585-0208d436516e,https://www.tier.app,https://partner.tier-services.io/mds,
-Cloud,bf95148b-d1d1-464e-a140-6d2563ac43d4,https://www.cloud.tt,https://mds.cloud.tt,https://mds.cloud.tt/gbfs
-BlueLA,f3c5a65d-fd85-463e-9564-fc95ea473f7d,https://www.bluela.com,https://api.bluela.com/mds/v0,https://api.bluela.com/gbfs/v1/meta
-Bolt,3291c288-c9c8-42f1-bc3e-8502b077cd7f,https://www.micromobility.com/,https://bolt.miami/bolt2/api/mds,
-CLEVR,daecbe87-a9f2-4a5a-b5df-8e3e14180513,https://clevrmobility.com,https://portal.clevrmobility.com/api/mds,
-SherpaLA,3c95765d-4da6-41c6-b61e-1954472ec6c9,,https://mds.bird.co,https://mds.bird.co/gbfs/platform-partner/sherpa-la
-OjO Electric,8d293326-8464-4256-8312-617ebcd0efad,https://www.ojoelectric.com,https://api.ojoelectric.com/api/mds,https://api.ojoelectric.com/api/mds/gbfs.json
-VOI,1f129e3f-158f-4df5-af9c-a80de238e334,https://www.voiscooters.com/,https://mds.voiapp.io,https://mds.voiapp.io/v1/gbfs
-MOVO,40dad54c-e199-4fd8-9f5b-cff93ffced63,https://movo.me,https://mds.movo.me,https://gbfs.movo.me
-Baus,638ba503-4006-4c53-bf34-cd625cc03d61,https://bausmoves.com,https://mds.bird.co,https://mds.bird.co/gbfs/platform-partner/v2/baus
-Bolt Technology,7ea695ca-9de7-4b3b-9f3c-241b2045a1fe,https://bolt.eu,https://mds.bolt.eu,https://mds.bolt.eu/gbfs/1
-Grin,8a0ecfce-5fb3-451e-8069-434b79c8b01a,https://ongrin.com,https://open-data.grow.mobi/mds/,https://open-data.grow.mobi/api/v1/gbfs/
-Dott,0a899e3a-705a-46f2-9189-d78cc83a2db4,https://ridedott.com,https://mds.api.ridedott.com,https://gbfs.api.ridedott.com
-Superpedestrian,420e6e94-55a6-4946-b6b3-4398fe22e912,https://www.superpedestrian.com,https://mds.linkyour.city/mds,
-Circ,03d5d605-e5c9-45a1-a1dd-144aa8649525,https://www.circ.com,https://mds.bird.co,
-GIG,42475742-8618-4fc0-aa8f-3b3948b84b85,https://gigcarshare.com/,https://global.us.prod.svc.ridecell.io/reporting/api/mds,
-Zisch,fb62cfe6-757c-4e5b-a264-18b43b3fc40b,https://www.e-zisch.ch,https://mds.bird.co,
-Seven Group,7fca7812-c718-48dd-b9f2-d1ae160f2ae4,https://www.group-seven.ch,https://mds.bird.co,
-Pony,f190d330-b49e-4590-871b-0bcbec565a8c,https://getapony.com/,https://mds.getapony.com/v1,
-SHARE-NOW,d8f880d6-96d8-4cdc-8069-32a683b2bce6,https://www.share-now.com,https://external.share-now.com/api/rental/mds/,https://external.share-now.com/api/rental/mds/gbfs/
-Boaz Bikes,7c96bc58-fb63-433a-b77f-84ccb1c9d737,https://www.boazbikes.com/,https://mds.movatic.co/,https://gbsf.movatic.co/en/1.1/576347857979998215
-VeoRide INC.,6e39f9db-751b-5cea-ae7e-486f579a56bc,https://www.veoride.com/,https://cluster-prod.veoride.com/api/shares/mds,https://cluster-prod.veoride.com/api/shares/gbfs
+provider_name,mode_id,provider_id,url,mds_api_url,gbfs_api_url
+JUMP,micromobility,c20e08cf-8488-46a6-a66c-5d8fb827f7e0,https://jump.com,https://api.uber.com/v0.2/emobility/mds,
+Lime,micromobility,63f13c48-34ff-49d2-aca7-cf6a5b6171c3,https://li.me,https://data.lime.bike/api/partners/v1/mds,
+Bird,micromobility,2411d395-04f2-47c9-ab66-d09e9e3c3251,https://www.bird.co,https://mds.bird.co,https://mds.bird.co/gbfs
+Razor,micromobility,6ddcc0ad-1d66-4046-bba4-d1d96bb8ca4d,https://www.razor.com/share,https://razor-200806.appspot.com/api/v2/mds,
+Lyft,micromobility,e714f168-ce56-4b41-81b7-0b6a4bd26128,https://www.lyft.com,https://api.lyft.com/v1/last-mile/mds,
+Skip,micromobility,d73fcf80-22b1-450f-b535-042b4e30aac7,https://www.skipscooters.com,https://api.skipscooters.com/mds,
+HOPR,micromobility,2e4cb206-b475-4a9d-80fb-0880c9a033e0,https://gohopr.com,https://gbfs.hopr.city/api/mds,
+Wheels,micromobility,b79f8687-526d-4ae6-80bf-89b4c44dc071,https://wheels.co,https://mds.getwheelsapp.com,
+Spin,micromobility,70aa475d-1fcd-4504-b69c-2eeb2107f7be,https://www.spin.app,https://web.spin.pm/api/mds/v1,
+WIND,micromobility,d56d2df6-fa92-43de-ab61-92c3a84acd7d,https://www.wind.co,https://partners.wind.co/v1/mds,
+Tier,micromobility,264aad41-b47c-415d-8585-0208d436516e,https://www.tier.app,https://partner.tier-services.io/mds,
+Cloud,micromobility,bf95148b-d1d1-464e-a140-6d2563ac43d4,https://www.cloud.tt,https://mds.cloud.tt,https://mds.cloud.tt/gbfs
+BlueLA,micromobility,f3c5a65d-fd85-463e-9564-fc95ea473f7d,https://www.bluela.com,https://api.bluela.com/mds/v0,https://api.bluela.com/gbfs/v1/meta
+Bolt,micromobility,3291c288-c9c8-42f1-bc3e-8502b077cd7f,https://www.micromobility.com/,https://bolt.miami/bolt2/api/mds,
+CLEVR,micromobility,daecbe87-a9f2-4a5a-b5df-8e3e14180513,https://clevrmobility.com,https://portal.clevrmobility.com/api/mds,
+SherpaLA,micromobility,3c95765d-4da6-41c6-b61e-1954472ec6c9,,https://mds.bird.co,https://mds.bird.co/gbfs/platform-partner/sherpa-la
+OjO Electric,micromobility,8d293326-8464-4256-8312-617ebcd0efad,https://www.ojoelectric.com,https://api.ojoelectric.com/api/mds,https://api.ojoelectric.com/api/mds/gbfs.json
+VOI,micromobility,1f129e3f-158f-4df5-af9c-a80de238e334,https://www.voiscooters.com/,https://mds.voiapp.io,https://mds.voiapp.io/v1/gbfs
+MOVO,micromobility,40dad54c-e199-4fd8-9f5b-cff93ffced63,https://movo.me,https://mds.movo.me,https://gbfs.movo.me
+Baus,micromobility,638ba503-4006-4c53-bf34-cd625cc03d61,https://bausmoves.com,https://mds.bird.co,https://mds.bird.co/gbfs/platform-partner/v2/baus
+Bolt Technology,micromobility,7ea695ca-9de7-4b3b-9f3c-241b2045a1fe,https://bolt.eu,https://mds.bolt.eu,https://mds.bolt.eu/gbfs/1
+Grin,micromobility,8a0ecfce-5fb3-451e-8069-434b79c8b01a,https://ongrin.com,https://open-data.grow.mobi/mds/,https://open-data.grow.mobi/api/v1/gbfs/
+Dott,micromobility,0a899e3a-705a-46f2-9189-d78cc83a2db4,https://ridedott.com,https://mds.api.ridedott.com,https://gbfs.api.ridedott.com
+Superpedestrian,micromobility,420e6e94-55a6-4946-b6b3-4398fe22e912,https://www.superpedestrian.com,https://mds.linkyour.city/mds,
+Circ,micromobility,03d5d605-e5c9-45a1-a1dd-144aa8649525,https://www.circ.com,https://mds.bird.co,
+GIG,car-share,42475742-8618-4fc0-aa8f-3b3948b84b85,https://gigcarshare.com/,https://global.us.prod.svc.ridecell.io/reporting/api/mds,
+Zisch,micromobility,fb62cfe6-757c-4e5b-a264-18b43b3fc40b,https://www.e-zisch.ch,https://mds.bird.co,
+Seven Group,micromobility,7fca7812-c718-48dd-b9f2-d1ae160f2ae4,https://www.group-seven.ch,https://mds.bird.co,
+Pony,micromobility,f190d330-b49e-4590-871b-0bcbec565a8c,https://getapony.com/,https://mds.getapony.com/v1,
+SHARE-NOW,car-share,d8f880d6-96d8-4cdc-8069-32a683b2bce6,https://www.share-now.com,https://external.share-now.com/api/rental/mds/,https://external.share-now.com/api/rental/mds/gbfs/
+Boaz Bikes,micromobility,7c96bc58-fb63-433a-b77f-84ccb1c9d737,https://www.boazbikes.com/,https://mds.movatic.co/,https://gbsf.movatic.co/en/1.1/576347857979998215
+VeoRide INC.,micromobility,6e39f9db-751b-5cea-ae7e-486f579a56bc,https://www.veoride.com/,https://cluster-prod.veoride.com/api/shares/mds,https://cluster-prod.veoride.com/api/shares/gbfs
+LEO Ride,micromobility,b0eedf6-c7a5-4262-9222-ab2484ad214e,https://leoride.co/,https://mobile.leoriders.com/mds,https://mobile.leoriders.com/gbpf
+LEO Explore,micromobility,7c653014-2f33-4f5b-98de-30ea66430986,https://leoride.co/,,
+ATOM Mobility,micromobility,4d88272c-032e-487c-9f58-ab5951a23427,https://atommobility.com/,https://mds.rideatom.com/mds,
+Zig Zag Sharing,micromobility,39977af0-4b94-11ec-81d3-0242ac130003,https://www.zigzagsharing.com/,https://mds.zigzagsharing.com/,
+TukTuk,micromobility,1a99bf67-14a0-48a1-98d1-77147a88c3d2,https://tuktukscooters.com/,https://app.tuktukscooters.com/mds-feed,
+Helbiz,micromobility,3aece8c6-416a-4d39-bcc4-d02524cb8004,https://helbiz.com,https://mds.helbiz.com,
+Kiwibot,delivery-robots,5f19acae-d7e9-4b57-96bd-f6406712d654,https://www.kiwibot.com/,,
+Yego,micromobility,da99028e-28b7-4dd3-ad23-41b7a045db8a,https://www.rideyego.com/,https://mds.yego.app/mds,https://services.rideyego.com/gbfs
+Leo&Go,micromobility,84b174c4-eb74-5d07-bdeb-27f4215d2aa9,https://www.leoandgo.com,https://mds.vulog.io/mds/fleets/LEONGO-FRLIO,
+Scoot,micromobility,07a25fe6-d0be-11e8-a8d5-f2801f1b9fd1,https://scoot.co/san-francisco/,https://mds.bird.co/,https://mds.bird.co/gbfs/
+Revel,micromobility,89301314-1210-4126-a213-3c41423f2ac5,https://gorevel.com/,https://opendata.gorevel.com/opendata/mds/,https://gbfs.gorevel.com/gbfs/v2/
+Troopy,micromobility,2b684c7c-f8ad-4c65-92f0-b9e57aaa7dd3,https://www.troopy.com,https://mds.vulog.io/mds/fleets/TROOPY-FRPAR,https://gbfs.vulog.io/mds/fleets/TROOPY-FRPAR/gbfs
+BCycle,micromobility,938D9F8B-B8D3-46CC-9276-F4A8C4FA3610,https://www.bcycle.com,https://mds.bcycle.com,https://gbfs.bcycle.com
+Tembici,micromobility,46b28e68-8ecb-4875-b97e-836fd5e1930f,https://www.tembici.com.br/,https://api.tembici.com.br/mds,https://api.tembici.com.br/gbfs
+POPPY Mobility,micromobility,5c869736-797f-4244-9132-fb50a22d1bfd,https://www.poppy.be/,https://poppy.red/mds,
+Whoosh,micromobility,3f8908a7-86fa-450d-8889-5d49077e06cd,https://whoosh.bike,https://mds.whoosh.bike,
+Telofun,micromobility,3dd253d3-557c-4fcb-98da-9af3edeaaae6,https://www.tel-o-fun.co.il/,https://mds.fsmctmobility.com/api/mds/v1/,
+Gbike,micromobility,a50b796e-bca2-11ed-afa1-0242ac120002,https://gcoo.io/,https://mds.gcoo.io/,https://mds.gcoo.io/gbfs
+SURF,micromobility,66c43ccb-f9f9-4f70-9707-37301b9f49a8,https://www.surfingscooters.com,https://api.app.surf/mds,https://api.app.surf/gbfs/en
diff --git a/schema/README.md b/schema/README.md
index 04200056..c3707631 100644
--- a/schema/README.md
+++ b/schema/README.md
@@ -1,34 +1,5 @@
# MDS Schema Definitions
-This directory contains the templates and code that _generate_ the official JSON schemas for the Mobility Data Specification. However, the official schema documents live inside the `provider`, `agency` or appropriate folder.
+See the external OMF GitHub repository [`mds-openapi`](https://github.com/openmobilityfoundation/mds-openapi) for more details and schema definitions, and browse the interactive API documentation on our [MDS Stoplight workspace](https://openmobilityfnd.stoplight.io/docs/mds-openapi/).
-## Regenerating the Schemas
-
-At a command prompt within this `schema` directory run:
-
-```bash
-python generate_schemas.py [--agency] [--geography] [--policy] [--provider]
-```
-
-The optional flags `--agency`, `--geography`, `--policy`, and `--provider` can be used to specify which
-set of schemas to generate. The default is to generate all schemas.
-
-## Updating Schemas
-
-1. Edit the appropriate file(s) inside the the [`templates/`][templates] directory.
-
-1. Run the command to regenerate the schema(s).
-
-## Adding New Schemas
-
-1. Create a new template in the appropriate folder inside [`templates/`][templates]. See the existing templates for ideas. Remember to reference shared definitions from [`templates/common.json`][common-template].
-
-1. Edit the appropriate `.py` file to add a function that creates the new schema as a `dict`. See the existing functions for ideas. The [`common` module][common-module] defines some shared functionality.
-
-1. Add your schema name and generator function to the collection in the `schema_generators()` function at the top of each `.py` file.
-
-1. Run the command to regenerate the schema(s).
-
-[common-module]: common.py
-[common-template]: templates/common.json
-[templates]: templates/
+Starting with MDS 2.0, [OpenAPI](https://www.openapis.org/) documents describe MDS endpoints and allow for schema validation, expanding on the prior JSON Schemas work.
diff --git a/schema/__init__.py b/schema/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/schema/agency.py b/schema/agency.py
deleted file mode 100644
index 9c7e41c0..00000000
--- a/schema/agency.py
+++ /dev/null
@@ -1,193 +0,0 @@
-"""
-Schema generators for Agency endpoints.
-"""
-
-import json
-
-import common
-
-
-def vehicle_telemetry():
- telemetry = common.load_definitions("telemetry")
- vehicle_telemetry = common.load_definitions("vehicle_telemetry")
-
- # merge the standard telemetry props into vehicle_telemetry.gps
- vehicle_telemetry["properties"]["gps"]["properties"].update(telemetry["properties"])
-
- return vehicle_telemetry
-
-
-def get_stops_schema():
- """
- Create the schema for the Agency GET /stops endpoint.
- """
- # load schema template and insert definitions
- schema = common.load_json("./templates/agency/get_stops.json")
- stops = common.stop_definitions()
- schema["definitions"].update(stops)
-
- # verify and return
- return common.check_schema(schema)
-
-
-def post_stops_schema():
- """
- Create the schema for the Agency POST /stops endpoint.
- """
- # load schema template and insert definitions
- schema = common.load_json("./templates/agency/post_stops.json")
- stops = common.stop_definitions()
- schema["definitions"].update(stops)
-
- # verify and return
- return common.check_schema(schema)
-
-
-def put_stops_schema():
- """
- Create the schema for the Agency POST /stops endpoint.
- """
- # load schema template and insert definitions
-
- # the PUT body allows a small subset of fields
- schema = common.load_json("./templates/agency/put_stops.json")
-
- stops = common.stop_definitions()
- needed_defs = ["stop_status", "uuid", "vehicle_type_counts"]
- for key in [k for k in stops.keys() if k not in needed_defs]:
- del stops[key]
-
- schema["definitions"].update(stops)
-
- # verify and return
- return common.check_schema(schema)
-
-
-def get_vehicle_schema():
- """
- Create the schema for the Agency GET /vehicles endpoint.
- """
- # load schema template and insert definitions
- schema = common.load_json("./templates/agency/get_vehicle.json")
- definitions = common.load_definitions(
- "propulsion_types",
- "string",
- "timestamp",
- "vehicle_type",
- "uuid"
- )
- schema["definitions"].update(definitions)
-
- # merge the state machine definitions and transition combinations rule
- state_machine_defs, transitions = common.vehicle_state_machine("state", "prev_events")
- schema["definitions"].update(state_machine_defs)
- schema["allOf"].append(transitions)
-
- # merge common vehicle information, with Agency tweaks
- vehicle = common.vehicle_definition(provider_name=False)
- schema["required"] = vehicle["required"] + schema["required"]
- schema["properties"] = { **vehicle["properties"], **schema["properties"] }
-
- # verify and return
- return common.check_schema(schema)
-
-
-def post_vehicle_schema():
- """
- Create the schema for the Agency POST /vehicles endpoint.
- """
- # load schema template and insert definitions
- schema = common.load_json("./templates/agency/post_vehicle.json")
- definitions = common.load_definitions(
- "propulsion_types",
- "string",
- "vehicle_type",
- "uuid"
- )
- schema["definitions"].update(definitions)
-
- # merge common vehicle information, with Agency tweaks
- vehicle = common.vehicle_definition(provider_name=False, provider_id=False)
-
- schema["required"] = vehicle["required"] + schema["required"]
- schema["properties"] = { **vehicle["properties"], **schema["properties"] }
-
- # verify and return
- return common.check_schema(schema)
-
-
-def post_vehicle_event_schema():
- """
- Create the schema for the Agency POST /vehicles/:id/event endpoint.
- """
- # load schema template and insert definitions
- schema = common.load_json("./templates/agency/post_vehicle_event.json")
- definitions = common.load_definitions(
- "timestamp",
- "uuid"
- )
- definitions["vehicle_telemetry"] = vehicle_telemetry()
- schema["definitions"].update(definitions)
-
- # merge the state machine definitions and transition combinations rule
- state_machine_defs, transitions = common.vehicle_state_machine("vehicle_state", "event_types")
- schema["definitions"].update(state_machine_defs)
- schema["allOf"].append(transitions)
-
- # add the conditionally-required trip_id rule
- trip_id_ref = common.load_definitions("trip_id_reference")
- schema["allOf"].append(trip_id_ref)
-
- # verify and return
- return common.check_schema(schema)
-
-
-def post_vehicle_telemetry_schema():
- """
- Create the schema for the Agency POST /vehicles/telemetry endpoint.
- """
- # load schema template and insert definitions
- schema = common.load_json("./templates/agency/post_vehicle_telemetry.json")
- definitions = common.load_definitions(
- "timestamp",
- "uuid"
- )
- definitions["vehicle_telemetry"] = vehicle_telemetry()
- schema["definitions"].update(definitions)
-
- # verify and return
- return common.check_schema(schema)
-
-
-def schema_generators():
- """
- The dict of schema generators for Agency.
-
- The key is the name of the schema file/template file.
- The value is the generator function, taking a dict of common definitions as an argument.
- The generator function should return the complete, validated schema document as a dict.
- """
- return {
- "get_vehicle": get_vehicle_schema,
- "post_vehicle": post_vehicle_schema,
- "post_vehicle_event": post_vehicle_event_schema,
- "post_vehicle_telemetry": post_vehicle_telemetry_schema,
- "post_stops": post_stops_schema,
- "put_stops": put_stops_schema,
- "get_stops": get_stops_schema
- }
-
-
-def write_schema_files():
- """
- Create each of the Agency endpoint schema files in the appropriate directory.
- """
- print("\nStarting to generate Agency JSON Schemas...\n")
-
- for name, generator in schema_generators().items():
- schema = generator()
- with open(f"../agency/{name}.json", "w") as schemafile:
- schemafile.write(json.dumps(schema, indent=2))
- print(f"Wrote {name}.json")
-
- print("\nFinished generating Agency JSON Schemas")
diff --git a/schema/common.py b/schema/common.py
deleted file mode 100644
index cd0184fc..00000000
--- a/schema/common.py
+++ /dev/null
@@ -1,282 +0,0 @@
-"""
-Shared functionality for schema generation.
-"""
-
-import copy
-import json
-import jsonschema
-import requests
-
-
-COMMON_DEFINITIONS = {}
-
-
-MDS_FEATURE_POINT = "MDS_Feature_Point"
-
-
-def load_json(path):
- """
- Load a JSON file from disk.
- """
- with open(path) as f:
- data = json.load(f)
- return data
-
-
-def definition_id(id):
- """
- Generate a JSON Schema definition reference for the given id.
- """
- return f"#/definitions/{id}"
-
-
-def vehicle_definition(provider_name=True, provider_id=True):
- """
- Extract a deep-copy of the common vehicle model definition to allow for customization.
- """
- vehicle = copy.deepcopy(load_definitions("vehicle"))
-
- if not provider_name:
- vehicle["required"].remove("provider_name")
- del vehicle["properties"]["provider_name"]
-
- if not provider_id:
- vehicle["required"].remove("provider_id")
- del vehicle["properties"]["provider_id"]
-
- return vehicle
-
-
-def vehicle_state_machine(vehicle_state=None, vehicle_events=None):
- """
- Return a tuple (definitions, transitions) with the common vehicle state schema.
- * defitions is the common definitions for vehicle state fields
- * transitions is the rule for valid state/event combinations
-
- Optionally pass field names for the vehicle_state and vehicle_events schemas
- to override those in transitions.
- """
- state_machine_defs = load_definitions("vehicle_state", "vehicle_event", "vehicle_events")
- transitions = copy.deepcopy(load_definitions("vehicle_state_transitions"))
-
- if vehicle_state:
- for option in transitions["oneOf"]:
- state = option["properties"]["vehicle_state"]
- del option["properties"]["vehicle_state"]
- option["properties"][vehicle_state] = state
-
- if vehicle_events:
- for option in transitions["oneOf"]:
- events = option["properties"]["vehicle_events"]
- del option["properties"]["vehicle_events"]
- option["properties"][vehicle_events] = events
-
- return (state_machine_defs, transitions)
-
-
-def vehicle_type_counts_definition(definitions):
- """
- Generate a definition for a dict of vehicle_type: int.
- """
- vehicle_type_counts = {}
- def_name = "vehicle_type_counts"
- def_id = definition_id(def_name)
- vehicle_types = definitions["vehicle_type"]
-
- for vehicle_type in vehicle_types["enum"]:
- vehicle_type_counts[vehicle_type] = {
- "$id": f"{def_id}/properties/{vehicle_type}",
- "type": "integer",
- "minimum": 0
- }
-
- return {
- def_name: {
- "$id": def_id,
- "type": "object",
- "properties": vehicle_type_counts,
- "additionalProperties": False
- }
- }
-
-
-def point_definition():
- """
- Get the canonical schema definition for a GeoJSON point.
- """
- name = "Point"
- point = requests.get("http://geojson.org/schema/Point.json").json()
-
- # Modify some metadata
- point.pop("$schema")
- point["$id"] = definition_id("Point")
-
- # enforce lat/lon bounds
- point["properties"]["coordinates"]["maxItems"] = 2
- point["properties"]["coordinates"]["items"] = [
- {
- "type": "number",
- "minimum": -180.0,
- "maximum": 180.0
- },
- {
- "type": "number",
- "minimum": -90.0,
- "maximum": 90.0
- }
- ]
-
- return {
- name: point
- }
-
-
-def mds_feature_point_definition(definitions):
- """
- Create a customized definition of the GeoJSON Feature schema for MDS Points.
- """
- # Get the canonical Feature schema
- feature = requests.get("http://geojson.org/schema/Feature.json").json()
-
- # Modify metadata
- feature.pop("$schema")
- feature["$id"] = definition_id(MDS_FEATURE_POINT)
- feature["title"] = "MDS GeoJSON Feature Point"
-
- # Only allow GeoJSON Point feature geometry
- feature["properties"]["geometry"] = { "$ref": definition_id("Point") }
-
- # Modfy properties definition/requirements
- f_properties = feature["properties"]["properties"]
- del f_properties["oneOf"]
- f_properties["type"] = "object"
-
- # Point features must include the timestamp
- f_properties["required"] = ["timestamp"]
-
- f_properties["properties"] = {
- "timestamp": {
- "$ref": definition_id("timestamp")
- },
- # Locations corresponding to Stops must include a stop_id reference
- "stop_id": {
- "$ref": definition_id("uuid")
- }
- }
-
- # merge telemetry props
- telemetry = definitions["telemetry"]
- f_properties["properties"].update(telemetry["properties"])
-
- return {MDS_FEATURE_POINT: feature}
-
-
-def stop_definitions():
- """
- Return a dict of definitions needed for stops.
- """
- definitions = load_definitions(
- "stop",
- "stop_status",
- "string",
- "timestamp",
- "uuid",
- "uuid_array",
- "vehicle_type_counts",
- MDS_FEATURE_POINT
- )
-
- return definitions
-
-
-def property_definition(property_id, ref=""):
- """
- Return a tuple (property, definition) of schema elements for the given id.
- """
- # property ref definition
- definition = { property_id: load_definitions(property_id) }
- # the property
- ref = ref or definition_id(property_id)
- prop = { property_id: { "$id": f"#/properties/{property_id}", "$ref": ref } }
-
- return prop, definition
-
-
-def load_definitions(*args, allow_null=False):
- """
- Load the common.json definitions file, with some generated additions.
-
- If args are provided, filter to a dictionary of definitions using the args as keys.
-
- With only a single arg, return the definition with that key directly.
-
- If allow_null is True, override definition types to allow null.
- """
- # store the definitions once globally after reading from the source file
- global COMMON_DEFINITIONS
-
- if COMMON_DEFINITIONS == {}:
- common = load_json("./templates/common.json")
- common_definitions = common["definitions"]
-
- # MDS specific geography definition
- mds_feature = mds_feature_point_definition(common_definitions)
- common_definitions.update(mds_feature)
-
- # vehicle_type -> count definition
- veh_type_counts = vehicle_type_counts_definition(common_definitions)
- common_definitions.update(veh_type_counts)
-
- COMMON_DEFINITIONS = common_definitions
-
- # filter all definitions to those requested as args
- if args and len(args) > 0:
- _d = { key: COMMON_DEFINITIONS.get(key) for key in args }
- else:
- _d = COMMON_DEFINITIONS
-
- # create a deepcopy for possible modifications
- definitions = copy.deepcopy(_d)
-
- # modify definitions to allow null
- if allow_null:
- # get all definitions with a type property
- typekey = "type"
- typedefs = { k: v for k, v in definitions.items() if typekey in v }
- for key, defn in typedefs.items():
- nullkey = f"null_{key}"
-
- # for reference definitions, override the reference to the null version
- if "$ref" in defn:
- refid = defn["$ref"].split("/")
- refid[-1] = f"null_{refid[-1]}"
-
- defn["$ref"] = "/".join(refid)
- # for type definitions, create a new definition allowing null
- else:
- defnid = defn["$id"].split("/")
- defnid[-1] = f"null_{defnid[-1]}"
-
- nulldefn = copy.deepcopy(defn)
- nulldefn["$id"] = "/".join(defnid)
-
- if isinstance(nulldefn[typekey], str):
- nulldefn[typekey] = [nulldefn[typekey]]
- if "null" not in nulldefn[typekey]:
- nulldefn[typekey].append("null")
- # add the null definition to the definitions dict
- definitions[nullkey] = nulldefn
-
- # if there was only one arg, return the definition directly
- return definitions.get(args[0]) if len(args) == 1 else definitions
-
-
-def check_schema(schema):
- """
- Check the validity of the given schema document under Draft 7 of the JSON Schema spec.
-
- Returns the (valid) schema instance.
- """
- jsonschema.Draft7Validator.check_schema(schema)
-
- return schema
diff --git a/schema/generate_schemas.py b/schema/generate_schemas.py
deleted file mode 100644
index 01454588..00000000
--- a/schema/generate_schemas.py
+++ /dev/null
@@ -1,36 +0,0 @@
-"""
-Generate the JSON Schema documents for MDS endpoints.
-
-USAGE:
- python generate_schemas.py [--agency] [--geography] [--policy] [--provider]
-"""
-
-import sys
-
-import agency
-import geography
-import policy
-import provider
-
-
-if __name__ == "__main__":
- if len(sys.argv) == 1:
- agency.write_schema_files()
- geography.write_schema_files()
- policy.write_schema_files()
- provider.write_schema_files()
- else:
- if "--agency" in sys.argv:
- agency.write_schema_files()
- sys.argv.remove("--agency")
- if "--geography" in sys.argv:
- geography.write_schema_files()
- sys.argv.remove("--geography")
- if "--policy" in sys.argv:
- policy.write_schema_files()
- sys.argv.remove("--policy")
- if "--provider" in sys.argv:
- provider.write_schema_files()
- sys.argv.remove("--provider")
- if len(sys.argv) > 1:
- print(__doc__)
diff --git a/schema/geography.py b/schema/geography.py
deleted file mode 100644
index 125402fd..00000000
--- a/schema/geography.py
+++ /dev/null
@@ -1,71 +0,0 @@
-"""
-Schema generators for Geography endpoints.
-"""
-
-import json
-
-import common
-
-
-def geography_schema():
- """
- Create the schema for the Geography endpoint.
- """
- # load schema template and insert definitions
- schema = common.load_json("./templates/geography/geography.json")
- definitions = common.load_definitions(
- "string",
- "timestamp",
- "uuid",
- "version"
- )
- definitions.update(common.load_definitions(
- "timestamp",
- "uuid_array",
- allow_null=True
- ))
- schema["definitions"].update(definitions)
-
- # verify and return
- return common.check_schema(schema)
-
-
-def geographies_schema():
- """
- Create the schema for the Geographies endpoint.
- """
- # load schema template and insert definitions from geography
- geography = geography_schema()
- schema = common.load_json("./templates/geography/geographies.json")
- schema["definitions"].update(geography["definitions"])
-
- return common.check_schema(schema)
-
-
-def schema_generators():
- """
- The dict of schema generators for Geography.
-
- The key is the name of the schema file/template file.
- The value is the generator function, taking a dict of common definitions as an argument.
- The generator function should return the complete, validated schema document as a dict.
- """
- return {
- "geography": geography_schema,
- "geographies": geographies_schema
- }
-
-
-def write_schema_files():
- """
- Create each of the Geography endpoint schema files in the appropriate directory.
- """
- print("\nStarting to generate Geography JSON Schemas...\n")
-
- for name, generator in schema_generators().items():
- schema = generator()
- with open(f"../geography/{name}.json", "w") as schemafile:
- schemafile.write(json.dumps(schema, indent=2))
- print(f"Wrote {name}.json")
-
- print("\nFinished generating Geography JSON Schemas")
diff --git a/schema/policy.py b/schema/policy.py
deleted file mode 100644
index 5d2ae8b4..00000000
--- a/schema/policy.py
+++ /dev/null
@@ -1,69 +0,0 @@
-"""
-Schema generators for Policy endpoints.
-"""
-
-import json
-
-import common
-
-
-def policy_schema():
- """
- Create the schema for the Policy endpoint.
- """
- # load schema template and insert definitions
- schema = common.load_json("./templates/policy/policy.json")
- definitions = common.load_definitions(
- "currency",
- "day",
- "propulsion_type",
- "string",
- "timestamp",
- "uuid",
- "uuid_array",
- "vehicle_event",
- "vehicle_state",
- "vehicle_type",
- "version"
- )
- definitions.update(common.load_definitions(
- "days",
- "iso_time",
- "propulsion_types",
- "timestamp",
- "uuid_array",
- "vehicle_types",
- allow_null=True
- ))
- schema["definitions"].update(definitions)
-
- # verify and return
- return common.check_schema(schema)
-
-
-def schema_generators():
- """
- The dict of schema generators for Policy.
-
- The key is the name of the schema file/template file.
- The value is the generator function, taking a dict of common definitions as an argument.
- The generator function should return the complete, validated schema document as a dict.
- """
- return {
- "policy": policy_schema
- }
-
-
-def write_schema_files():
- """
- Create each of the Policy endpoint schema files in the appropriate directory.
- """
- print("\nStarting to generate Policy JSON Schemas...\n")
-
- for name, generator in schema_generators().items():
- schema = generator()
- with open(f"../policy/{name}.json", "w") as schemafile:
- schemafile.write(json.dumps(schema, indent=2))
- print(f"Wrote {name}.json")
-
- print("\nFinished generating Policy JSON Schemas")
diff --git a/schema/provider.py b/schema/provider.py
deleted file mode 100644
index cb8efad9..00000000
--- a/schema/provider.py
+++ /dev/null
@@ -1,226 +0,0 @@
-"""
-Schema generators for Provider endpoints.
-"""
-
-import json
-import requests
-
-import common
-
-
-def feature_collection_schema(id=None, title=None, features=None):
- """
- Get the canonical schema for a GeoJSON Feature Collection,
- and make any given modifications.
-
- :id: overrides the `$id` metadata
- :title: overrides the `title` metadata
- :features: overrides the allowed `features` for the FeatureCollection
- """
- # Get the canonical FeatureCollection schema
- feature_collection = requests.get("http://geojson.org/schema/FeatureCollection.json").json()
-
- # Modify some metadata
- feature_collection.pop("$schema")
- if id is not None:
- feature_collection["$id"] = id
- if title is not None:
- feature_collection["title"] = title
-
- if features is not None:
- fc_features = feature_collection["properties"]["features"]
- feature_collection["properties"]["features"] = { **fc_features, **features }
-
- return feature_collection
-
-
-def endpoint_schema(endpoint, extra_definitions={}):
- """
- Generate the Provider payload schema for the given endpoint.
- """
- # load common schema template and update metadata
- schema = common.load_json("./templates/provider/endpoint.json")
- schema["$id"] = schema["$id"].replace("endpoint.json", f"{endpoint}.json")
- schema["title"] = schema["title"].replace("endpoint", endpoint)
-
- # merge custom definitions with relevant common definitions
- definitions = common.load_definitions(
- "string",
- "timestamp",
- "uuid",
- "version",
- common.MDS_FEATURE_POINT
- )
- definitions.update(common.point_definition())
- definitions.update(extra_definitions)
-
- endpoint_schema = common.load_json(f"./templates/provider/{endpoint}.json")
-
- # for all but stops, merge standard vehicle info with items schema
- if endpoint not in ["stops"]:
- items = endpoint_schema[endpoint]["items"]
- vehicle = common.vehicle_definition()
- items["required"] = vehicle["required"] + items["required"]
- items["properties"] = { **vehicle["properties"], **items["properties"] }
- definitions.update(common.load_definitions("propulsion_type", "propulsion_types", "vehicle_type"))
-
- # merge endpoint schema into the endpoint template
- data_schema = schema["properties"]["data"]
- data_schema["required"] = [endpoint]
- data_schema["properties"] = endpoint_schema
-
- # insert definitions
- schema["definitions"].update(definitions)
-
- return schema
-
-
-def trips_schema():
- """
- Create the schema for the /trips endpoint.
- """
- # generate the route definition
- mds_feature_collection_route = feature_collection_schema(
- id = common.definition_id("MDS_FeatureCollection_Route"),
- title = "MDS GeoJSON FeatureCollection Route",
- # 1. Only allow MDS Feature Points
- # 2. There must be *at least* two Features in the FeatureCollection.
- features = { "items": { "$ref": common.definition_id("MDS_Feature_Point") }, "minItems": 2 }
- )
- trips_definitions = {
- "currency": common.load_definitions("currency"),
- "MDS_FeatureCollection_Route": mds_feature_collection_route
- }
-
- # create the trips schema
- schema = endpoint_schema("trips", trips_definitions)
-
- # verify and return
- return common.check_schema(schema)
-
-
-def status_changes_schema():
- """
- Create the schema for the /status_changes endpoint.
- """
- schema = endpoint_schema("status_changes")
- items = schema["properties"]["data"]["properties"]["status_changes"]["items"]
-
- # merge the state machine definitions and transition combinations rule
- state_machine_defs, transitions = common.vehicle_state_machine("vehicle_state", "event_types")
- schema["definitions"].update(state_machine_defs)
- items["allOf"].append(transitions)
-
- trip_id_ref = common.load_definitions("trip_id_reference")
- items["allOf"].append(trip_id_ref)
-
- # verify and return
- return common.check_schema(schema)
-
-
-def events_schema():
- """
- Create the schema for the /events endpoint.
- """
- links_prop, links_def = common.property_definition("links")
-
- # events is the same as status_changes, but allows paging
- schema = status_changes_schema()
- schema["$id"] = schema["$id"].replace("status_changes", "events")
- schema["title"] = schema["title"].replace("status_changes", "events")
- schema["definitions"].update(links_def)
- schema["properties"].update(links_prop)
-
- # verify and return
- return common.check_schema(schema)
-
-
-def stops_schema():
- """
- Create the schema for the /stops endpoint.
- """
- definitions, properties = {}, {}
-
- prop, _ = common.property_definition("last_updated", ref=common.definition_id("timestamp"))
- properties.update(prop)
-
- prop, defn = common.property_definition("ttl")
- definitions.update(defn)
- properties.update(prop)
-
- stop_defs = common.stop_definitions()
- definitions.update(stop_defs)
-
- schema = endpoint_schema("stops", definitions)
-
- # update list of required and properties object
- schema["required"].extend(["last_updated", "ttl"])
- schema["properties"].update(properties)
-
- # verify and return
- return common.check_schema(schema)
-
-
-def vehicles_schema():
- """
- Create the schema for the /vehicles endpoint.
- """
- definitions, properties = {}, {}
-
- prop, defn = common.property_definition("links")
- definitions.update(defn)
- properties.update(prop)
-
- prop, _ = common.property_definition("last_updated", ref=common.definition_id("timestamp"))
- properties.update(prop)
-
- prop, defn = common.property_definition("ttl")
- definitions.update(defn)
- properties.update(prop)
-
- state_defs, transitions = common.vehicle_state_machine("last_vehicle_state", "last_event_types")
- definitions.update(state_defs)
-
- schema = endpoint_schema("vehicles", definitions)
-
- # update list of required and properties object
- schema["required"].extend(["last_updated", "ttl"])
- schema["properties"].update(properties)
-
- # add state machine transition rules
- schema["properties"]["data"]["properties"]["vehicles"]["items"]["allOf"].append(transitions)
-
- # verify and return
- return common.check_schema(schema)
-
-
-def schema_generators():
- """
- The dict of schema generators for Provider.
-
- The key is the name of the schema file/template file.
- The value is the generator function, taking a dict of common definitions as an argument.
- The generator function should return the complete, validated schema document as a dict.
- """
- return {
- "trips": trips_schema,
- "status_changes": status_changes_schema,
- "events": events_schema,
- "vehicles": vehicles_schema,
- "stops": stops_schema
- }
-
-
-def write_schema_files():
- """
- Create each of the Provider endpoint schema files in the appropriate directory.
- """
- print("\nStarting to generate Provider JSON Schemas...\n")
-
- for name, generator in schema_generators().items():
- schema = generator()
- with open(f"../provider/{name}.json", "w") as schemafile:
- schemafile.write(json.dumps(schema, indent=2))
- print(f"Wrote {name}.json")
-
- print("\nFinished generating Provider JSON Schemas")
diff --git a/schema/requirements.txt b/schema/requirements.txt
deleted file mode 100644
index fb758e7a..00000000
--- a/schema/requirements.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-jsonschema==3.0.1
-requests
diff --git a/schema/templates/agency/get_stops.json b/schema/templates/agency/get_stops.json
deleted file mode 100644
index 128930ae..00000000
--- a/schema/templates/agency/get_stops.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/agency/get_stops.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "The MDS Agency Schema, GET stops payload",
- "type": "object",
- "definitions": {},
- "required": [
- "stops"
- ],
- "properties": {
- "stops": {
- "$id": "#/properties/stops",
- "type": "array",
- "description": "The array of stops",
- "items": {
- "$ref": "#/definitions/stop"
- }
- }
- },
- "additionalProperties": false
-}
\ No newline at end of file
diff --git a/schema/templates/agency/get_vehicle.json b/schema/templates/agency/get_vehicle.json
deleted file mode 100644
index 048fff66..00000000
--- a/schema/templates/agency/get_vehicle.json
+++ /dev/null
@@ -1,52 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/agency/get_vehicle.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "The MDS Agency Schema, GET vehicle payload",
- "type": "object",
- "definitions": {},
- "required": [
- "year",
- "mfgr",
- "model",
- "state",
- "prev_events",
- "updated"
- ],
- "properties": {
- "year": {
- "$id": "#/properties/year",
- "type": "integer",
- "description": "The year the vehicle was manufactured",
- "default": 1970,
- "examples": [
- 2018
- ]
- },
- "mfgr": {
- "$id": "#/properties/mfgr",
- "$ref": "#/definitions/string",
- "description": "The vehicle manufacturer"
- },
- "model": {
- "$id": "#/properties/model",
- "$ref": "#/definitions/string",
- "description": "The vehicle model"
- },
- "state": {
- "$id": "#/properties/state",
- "$ref": "#/definitions/vehicle_state",
- "description": "Current vehicle state"
- },
- "prev_events": {
- "$id": "#/properties/prev_events",
- "$ref": "#/definitions/vehicle_events",
- "description": "Last vehicle event"
- },
- "updated": {
- "$id": "#/properties/updated",
- "$ref": "#/definitions/timestamp"
- }
- },
- "additionalProperties": false,
- "allOf": []
-}
diff --git a/schema/templates/agency/post_stops.json b/schema/templates/agency/post_stops.json
deleted file mode 100644
index ba53da2d..00000000
--- a/schema/templates/agency/post_stops.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/agency/post_stops.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "The MDS Agency Schema, register Stops",
- "type": "object",
- "definitions": {},
- "required": [
- "stops"
- ],
- "properties": {
- "stops": {
- "$id": "#/properties/stops",
- "type": "array",
- "description": "The array of stops",
- "items": {
- "$ref": "#/definitions/stop"
- }
- }
- },
- "additionalProperties": false
- }
-
\ No newline at end of file
diff --git a/schema/templates/agency/post_vehicle.json b/schema/templates/agency/post_vehicle.json
deleted file mode 100644
index ec58eba8..00000000
--- a/schema/templates/agency/post_vehicle.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/agency/post_vehicle.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "The MDS Agency Schema, register vehicle body",
- "type": "object",
- "definitions": {},
- "required": [],
- "properties": {
- "year": {
- "$id": "#/properties/year",
- "type": "integer",
- "description": "The year the vehicle was manufactured",
- "default": 1970,
- "examples": [
- 2018
- ]
- },
- "mfgr": {
- "$id": "#/properties/mfgr",
- "$ref": "#/definitions/string",
- "description": "The vehicle manufacturer"
- },
- "model": {
- "$id": "#/properties/model",
- "$ref": "#/definitions/string",
- "description": "The vehicle model"
- }
- },
- "additionalProperties": false
-}
diff --git a/schema/templates/agency/post_vehicle_event.json b/schema/templates/agency/post_vehicle_event.json
deleted file mode 100644
index d7b4dfdc..00000000
--- a/schema/templates/agency/post_vehicle_event.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/agency/post_vehicle_event.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "The MDS Agency Schema, POST vehicle status body",
- "type": "object",
- "definitions": {},
- "required": [
- "vehicle_state",
- "event_types",
- "timestamp",
- "telemetry"
- ],
- "properties": {
- "vehicle_state": {
- "$ref": "#/definitions/vehicle_state"
- },
- "event_types": {
- "$ref": "#/definitions/vehicle_events"
- },
- "timestamp": {
- "$ref": "#/definitions/timestamp"
- },
- "telemetry": {
- "$ref": "#/definitions/vehicle_telemetry"
- },
- "trip_id": {
- "$ref": "#/definitions/uuid"
- }
- },
- "additionalProperties": false,
- "allOf": []
-}
diff --git a/schema/templates/agency/post_vehicle_telemetry.json b/schema/templates/agency/post_vehicle_telemetry.json
deleted file mode 100644
index f7ad99f9..00000000
--- a/schema/templates/agency/post_vehicle_telemetry.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/agency/post_vehicle_telemetry.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "The MDS Agency Schema, POST vehicle telemetry body",
- "type": "object",
- "definitions": {},
- "required": [
- "data"
- ],
- "properties": {
- "data": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/vehicle_telemetry"
- }
- }
- },
- "additionalProperties": false
-}
diff --git a/schema/templates/agency/put_stops.json b/schema/templates/agency/put_stops.json
deleted file mode 100644
index cf904d10..00000000
--- a/schema/templates/agency/put_stops.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/agency/put_stops.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "The MDS Agency Schema, update Stops",
- "type": "object",
- "definitions": {},
- "required": [
- "stops"
- ],
- "properties": {
- "stops": {
- "$id": "#/properties/stops",
- "type": "array",
- "description": "The array of stops",
- "items": {
- "type": "object",
- "required": [
- "stop_id"
- ],
- "properties": {
- "stop_id": {
- "$ref": "#/definitions/uuid"
- },
- "status": {
- "$ref": "#/definitions/stop_status"
- },
- "num_spots_disabled": {
- "$ref": "#/definitions/vehicle_type_counts"
- }
- }
- }
- }
- },
- "additionalProperties": false
- }
-
\ No newline at end of file
diff --git a/schema/templates/common.json b/schema/templates/common.json
deleted file mode 100644
index 08919fd1..00000000
--- a/schema/templates/common.json
+++ /dev/null
@@ -1,722 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/schema/templates/common.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "Common schema definitions for MDS",
- "definitions": {
- "area_type": {
- "$id": "#/definitions/area_type",
- "type": "string",
- "description": "The type of a service area",
- "enum": [
- "unrestricted",
- "restricted",
- "preferred_pick_up",
- "preferred_drop_off"
- ]
- },
- "currency": {
- "$id": "#/definitions/currency",
- "type": [
- "string",
- "null"
- ],
- "pattern": "^[A-Z]{3}$",
- "default": "USD",
- "description": "An ISO 4217 Alphabetic Currency Code representing currency of the payee. If null, USD cents is implied.",
- "examples": [
- "USD",
- "EUR",
- "GBP"
- ]
- },
- "day": {
- "$id": "#/definitions/day",
- "type": "string",
- "description": "A day of the week",
- "enum": [
- "sun",
- "mon",
- "tue",
- "wed",
- "thu",
- "fri",
- "sat"
- ]
- },
- "days": {
- "$id": "#/definitions/days",
- "type": "array",
- "description": "Array of days of the week",
- "items": {
- "$id": "#/definitions/days/items",
- "$ref": "#/definitions/day"
- },
- "uniqueItems": true
- },
- "iso_time": {
- "$id": "#/definitions/iso_time",
- "type": "string",
- "description": "Time-of-day expressed as ISO 8601 hh:mm:ss",
- "pattern": "([0-2][0-3]|[0-1][0-9]):[0-5][0-9]:[0-5][0-9]"
- },
- "links": {
- "$id": "#/definitions/links",
- "type": "object",
- "required": [
- "next"
- ],
- "properties": {
- "first": {
- "$id": "#/definitions/links/first",
- "type": [
- "null",
- "string"
- ],
- "title": "The URL to the first page of data",
- "examples": [
- "https://data.provider.co/trips/first"
- ],
- "format": "uri"
- },
- "last": {
- "$id": "#/definitions/links/last",
- "type": [
- "null",
- "string"
- ],
- "title": "The URL to the last page of data",
- "examples": [
- "https://data.provider.co/trips/last"
- ],
- "format": "uri"
- },
- "prev": {
- "$id": "#/definitions/links/prev",
- "type": [
- "null",
- "string"
- ],
- "title": "The URL to the previous page of data",
- "examples": [
- "https://data.provider.co/trips/prev"
- ],
- "format": "uri"
- },
- "next": {
- "$id": "#/definitions/links/next",
- "type": [
- "null",
- "string"
- ],
- "title": "The URL to the next page of data",
- "examples": [
- "https://data.provider.co/trips/next"
- ],
- "format": "uri",
- "pattern": "^(.*)$"
- }
- },
- "additionalProperties": false
- },
- "propulsion_type": {
- "$id": "#/definitions/propulsion_type",
- "type": "string",
- "description": "The type of propulsion",
- "enum": [
- "combustion",
- "electric",
- "electric_assist",
- "human"
- ]
- },
- "propulsion_types": {
- "$id": "#/definitions/propulsion_types",
- "type": "array",
- "description": "Array of propulsion types, allowing multiple values",
- "items": {
- "$id": "#/definitions/propulsion_types/items",
- "$ref": "#/definitions/propulsion_type"
- },
- "uniqueItems": true
- },
- "rental_methods": {
- "$id": "#/definitions/rental_methods",
- "type": "array",
- "description": "Payment methods accepted at this Stop. From GBFS Station Information.",
- "items": {
- "enum": [
- "KEY",
- "CREDITCARD",
- "PAYPASS",
- "APPLEPAY",
- "ANDROIDPAY",
- "TRANSITCARD",
- "ACCOUNTNUMBER",
- "PHONE"
- ]
- },
- "uniqueItems": true
- },
- "stop": {
- "$id": "#/definitions/stop",
- "type": "object",
- "description": "The common schema elements for a Stop in MDS",
- "required": [
- "stop_id",
- "name",
- "last_reported",
- "location",
- "status",
- "capacity",
- "num_vehicles_available",
- "num_vehicles_disabled"
- ],
- "properties": {
- "stop_id": {
- "$id": "#/definitions/stop/properties/stop_id",
- "$ref": "#/definitions/uuid",
- "description": "UUID for the Stop"
- },
- "name": {
- "$id": "#/definitions/stop/properties/name",
- "$ref": "#/definitions/string",
- "description": "Name of the Stop"
- },
- "last_reported": {
- "$id": "#/definitions/stop/properties/last_reported",
- "$ref": "#/definitions/timestamp",
- "description": "Date/Time of the last status update for this Stop"
- },
- "location": {
- "$id": "#/definitions/stop/properties/location",
- "$ref": "#/definitions/MDS_Feature_Point",
- "description": "Location of the stop"
- },
- "status": {
- "$id": "#/definitions/stop/properties/status",
- "$ref": "#/definitions/stop_status",
- "description": "The status of the Stop"
- },
- "capacity": {
- "$id": "#/definitions/stop/properties/capacity",
- "$ref": "#/definitions/vehicle_type_counts",
- "description": "Number of total places per vehicle_type"
- },
- "num_vehicles_available": {
- "$id": "#/definitions/stop/properties/num_vehicles_available",
- "$ref": "#/definitions/vehicle_type_counts",
- "description": "Number of available vehicles per vehicle_type"
- },
- "num_vehicles_disabled": {
- "$id": "#/definitions/stop/properties/num_vehicles_disabled",
- "$ref": "#/definitions/vehicle_type_counts",
- "description": "Number of non_operational/reserved vehicles per vehicle_type"
- },
- "provider_id": {
- "$id": "#/definitions/stop/properties/provider_id",
- "$ref": "#/definitions/uuid",
- "description": "UUID for the Provider managing this Stop. Null/undefined if managed by an Agency."
- },
- "geography_id": {
- "$id": "#/definitions/stop/properties/geography_id",
- "$ref": "#/definitions/uuid",
- "description": "UUID for the Stop"
- },
- "region_id": {
- "$id": "#/definitions/stop/properties/region_id",
- "$ref": "#/definitions/string",
- "description": "ID of the region where the Stop is located. See GBFS Station Information."
- },
- "short_name": {
- "$id": "#/definitions/stop/properties/short_name",
- "$ref": "#/definitions/string",
- "description": "Abbreviated Stop name"
- },
- "address": {
- "$id": "#/definitions/stop/properties/address",
- "$ref": "#/definitions/string",
- "description": "Postal address (useful for directions)"
- },
- "post_code": {
- "$id": "#/definitions/stop/properties/post_code",
- "$ref": "#/definitions/string",
- "description": "Postal code (e.g. 10036)"
- },
- "cross_street": {
- "$id": "#/definitions/stop/properties/cross_street",
- "$ref": "#/definitions/string",
- "description": "Cross street of where Stop is located"
- },
- "num_places_available": {
- "$id": "#/definitions/stop/properties/num_places_available",
- "$ref": "#/definitions/vehicle_type_counts",
- "description": "Number of places free to be populated per vehicle_type"
- },
- "num_places_disabled": {
- "$id": "#/definitions/stop/properties/num_places_disabled",
- "$ref": "#/definitions/vehicle_type_counts",
- "description": "Number of places disabled an unable to accept vehicles per vehicle_type"
- },
- "parent_stop": {
- "$id": "#/definitions/stop/properties/parent_stop",
- "$ref": "#/definitions/uuid",
- "description": "Describe a basic hierarchy of Stops (e.g. a Stop inside a greater Stop)"
- },
- "devices": {
- "$id": "#/definitions/stop/properties/devices",
- "$ref": "#/definitions/uuid_array",
- "description": "List of device_id for vehicles currently at this Stop."
- }
- }
- },
- "stop_status": {
- "$id": "#/definitions/stop_status",
- "type": "object",
- "description": "Status object for a Stop in MDS",
- "required": [
- "is_installed",
- "is_renting",
- "is_returning"
- ],
- "properties": {
- "is_installed": {
- "$id": "#/definitions/stop_status/properties/is_installed",
- "type": "boolean"
- },
- "is_renting": {
- "$id": "#/definitions/stop_status/properties/is_renting",
- "type": "boolean"
- },
- "is_returning": {
- "$id": "#/definitions/stop_status/properties/is_returning",
- "type": "boolean"
- }
- }
- },
- "string": {
- "$id": "#/definitions/string",
- "type": "string",
- "description": "A length-limited string type",
- "maxLength": 255,
- "default": "",
- "examples": [
- "ABC123"
- ],
- "pattern": "^(.*)$"
- },
- "telemetry": {
- "$id": "#/definitions/telemetry",
- "type": "object",
- "description": "A telemetry datum",
- "additionalProperties": false,
- "properties": {
- "altitude": {
- "type": "number",
- "description": "Altitude above mean sea level in meters"
- },
- "heading": {
- "type": "number",
- "description": "Degrees - clockwise starting at 0 degrees at true North"
- },
- "speed": {
- "type": "number",
- "description": "Estimated speed in meters / sec as reported by the GPS chipset"
- },
- "accuracy": {
- "type": "number",
- "description": "Horizontal accuracy, in meters"
- },
- "hdop": {
- "type": "number",
- "description": "Horizontal GPS or GNSS accuracy value"
- },
- "satellites": {
- "type": "integer",
- "description": "Number of GPS or GNSS satellites"
- }
- }
- },
- "timestamp": {
- "$id": "#/definitions/timestamp",
- "type": "number",
- "description": "Integer milliseconds since Unix epoch",
- "multipleOf": 1.0,
- "minimum": 1514764800000
- },
- "trip_id_reference": {
- "description": "Conditionally require a trip_id reference",
- "anyOf": [
- {
- "not": {
- "properties": {
- "event_types": {
- "contains": {
- "enum": [
- "trip_cancel",
- "trip_end",
- "trip_enter_jurisdiction",
- "trip_leave_jurisdiction",
- "trip_start"
- ]
- }
- }
- }
- }
- },
- {
- "required": [
- "trip_id"
- ]
- }
- ]
- },
- "ttl": {
- "$id": "#/definitions/ttl",
- "type": "integer",
- "description": "Integer milliseconds until next data update (0 if the data is always refreshed)",
- "minimum": 0,
- "maximum": 300000
- },
- "uuid": {
- "$id": "#/definitions/uuid",
- "type": "string",
- "description": "A UUID used to uniquely identifty an object",
- "default": "",
- "examples": [
- "3c9604d6-b5ee-11e8-96f8-529269fb1459"
- ],
- "pattern": "^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$"
- },
- "uuid_array": {
- "$id": "#/definitions/uuid_array",
- "type": "array",
- "description": "Array of UUID",
- "items": {
- "$id": "#/definitions/uuid_array/items",
- "$ref": "#/definitions/uuid"
- }
- },
- "vehicle": {
- "$id": "#/definitions/vehicle",
- "type": "object",
- "description": "The common schema elements for a Vehicle in MDS",
- "required": [
- "provider_name",
- "provider_id",
- "device_id",
- "vehicle_id",
- "vehicle_type",
- "propulsion_types"
- ],
- "properties": {
- "provider_name": {
- "$id": "#/definitions/vehicle/properties/provider_name",
- "$ref": "#/definitions/string",
- "description": "The public-facing name of the Provider"
- },
- "provider_id": {
- "$id": "#/definitions/vehicle/properties/provider_id",
- "$ref": "#/definitions/uuid",
- "description": "The UUID for the Provider, unique within MDS"
- },
- "device_id": {
- "$id": "#/definitions/vehicle/properties/device_id",
- "$ref": "#/definitions/uuid",
- "description": "A unique device ID in UUID format"
- },
- "vehicle_id": {
- "$id": "#/definitions/vehicle/properties/vehicle_id",
- "$ref": "#/definitions/string",
- "description": "The Vehicle Identification Number visible on the vehicle itself"
- },
- "vehicle_type": {
- "$id": "#/definitions/vehicle/properties/vehicle_type",
- "$ref": "#/definitions/vehicle_type",
- "description": "The type of vehicle"
- },
- "propulsion_types": {
- "$id": "#/definitions/vehicle/properties/propulsion_types",
- "$ref": "#/definitions/propulsion_types",
- "description": "The type of propulsion; allows multiple values",
- "minItems": 1
- }
- },
- "additionalProperties": false
- },
- "vehicle_event": {
- "$id": "#/definitions/vehicle_event",
- "type": "string",
- "description": "An event that changes a vehicle's state",
- "enum": [
- "agency_drop_off",
- "agency_pick_up",
- "battery_charged",
- "battery_low",
- "comms_lost",
- "comms_restored",
- "compliance_pick_up",
- "decommissioned",
- "located",
- "maintenance",
- "maintenance_pick_up",
- "missing",
- "off_hours",
- "on_hours",
- "provider_drop_off",
- "rebalance_pick_up",
- "reservation_cancel",
- "reservation_start",
- "system_resume",
- "system_suspend",
- "trip_cancel",
- "trip_end",
- "trip_enter_jurisdiction",
- "trip_leave_jurisdiction",
- "trip_start",
- "unspecified"
- ]
- },
- "vehicle_events": {
- "$id": "#/definitions/vehicle_events",
- "type": "array",
- "description": "Array of events indicating a change to a vehicle's state",
- "uniqueItems": true,
- "minItems": 1,
- "items": {
- "$ref": "#/definitions/vehicle_event"
- }
- },
- "vehicle_state": {
- "$id": "#/definitions/vehicle_state",
- "type": "string",
- "description": "The state of a vehicle",
- "enum": [
- "available",
- "elsewhere",
- "non_operational",
- "on_trip",
- "removed",
- "reserved",
- "unknown"
- ]
- },
- "vehicle_state_transitions": {
- "description": "valid vehicle_state and vehicle_events combinations",
- "oneOf": [
- {
- "properties": {
- "vehicle_state": {
- "const": "available"
- },
- "vehicle_events": {
- "contains": {
- "enum": [
- "agency_drop_off",
- "battery_charged",
- "comms_restored",
- "located",
- "maintenance",
- "on_hours",
- "provider_drop_off",
- "reservation_cancel",
- "system_resume",
- "trip_cancel",
- "trip_end",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "vehicle_state": {
- "const": "elsewhere"
- },
- "vehicle_events": {
- "contains": {
- "enum": [
- "comms_restored",
- "located",
- "trip_leave_jurisdiction",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "vehicle_state": {
- "const": "non_operational"
- },
- "vehicle_events": {
- "contains": {
- "enum": [
- "battery_low",
- "comms_restored",
- "located",
- "maintenance",
- "off_hours",
- "system_suspend",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "vehicle_state": {
- "const": "on_trip"
- },
- "vehicle_events": {
- "contains": {
- "enum": [
- "comms_restored",
- "located",
- "trip_enter_jurisdiction",
- "trip_start",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "vehicle_state": {
- "const": "removed"
- },
- "vehicle_events": {
- "contains": {
- "enum": [
- "agency_pick_up",
- "comms_restored",
- "compliance_pick_up",
- "decommissioned",
- "located",
- "maintenance_pick_up",
- "rebalance_pick_up",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "vehicle_state": {
- "const": "reserved"
- },
- "vehicle_events": {
- "contains": {
- "enum": [
- "comms_restored",
- "located",
- "reservation_start",
- "unspecified"
- ]
- }
- }
- }
- },
- {
- "properties": {
- "vehicle_state": {
- "const": "unknown"
- },
- "vehicle_events": {
- "contains": {
- "enum": [
- "comms_lost",
- "missing",
- "unspecified"
- ]
- }
- }
- }
- }
- ]
- },
- "vehicle_telemetry": {
- "$id": "#/definitions/vehicle_telemetry",
- "type": "object",
- "description": "A telemetry datum for a specific vehicle at a specific time",
- "required": [
- "device_id",
- "timestamp",
- "gps"
- ],
- "additionalProperties": false,
- "properties": {
- "device_id": {
- "$ref": "#/definitions/uuid"
- },
- "timestamp": {
- "$ref": "#/definitions/timestamp"
- },
- "gps": {
- "type": "object",
- "required": [
- "lat",
- "lng"
- ],
- "additionalProperties": false,
- "properties": {
- "lat": {
- "type": "number",
- "description": "Latitude of the location",
- "minimum": -90,
- "maximum": 90
- },
- "lng": {
- "type": "number",
- "description": "Longitude of the location",
- "minimum": -180,
- "maximum": 180
- }
- }
- },
- "charge": {
- "type": "number",
- "description": "Fraction of charge of the vehicle (required if applicable)",
- "minimum": 0,
- "maximum": 1
- }
- }
- },
- "vehicle_type": {
- "$id": "#/definitions/vehicle_type",
- "type": "string",
- "description": "The type of vehicle",
- "enum": [
- "bicycle",
- "cargo_bicycle",
- "car",
- "scooter",
- "moped",
- "other"
- ]
- },
- "vehicle_types": {
- "$id": "#/definitions/vehicle_types",
- "type": "array",
- "description": "Array of vehicle types",
- "items": {
- "$id": "#/definitions/vehicle_types/items",
- "$ref": "#/definitions/vehicle_type"
- },
- "uniqueItems": true
- },
- "version": {
- "$id": "#/definitions/version",
- "type": "string",
- "description": "The version of MDS this data represents",
- "examples": [
- "1.2.0"
- ],
- "pattern": "^1\\.2\\.[0-9]+$"
- }
- }
-}
diff --git a/schema/templates/geography/geographies.json b/schema/templates/geography/geographies.json
deleted file mode 100644
index 13380181..00000000
--- a/schema/templates/geography/geographies.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/geography/geographies.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "The MDS Geographies Schema",
- "type": "object",
- "definitions": {
- },
- "required": [
- "geographies",
- "updated",
- "version"
- ],
- "properties": {
- "geographies": {
- "$id": "#/properties/geographies",
- "type": "array",
- "title": "The array of policy objects in this payload",
- "items": {
- "$id": "#/properties/geographies/items",
- "$ref": "#/definitions/geography"
- }
- },
- "updated": {
- "$id": "#/properties/updated",
- "$ref": "#/definitions/timestamp",
- "description": "The timestamp when geographies was last updated"
- },
- "version": {
- "$id": "#/properties/version",
- "$ref": "#/definitions/version",
- "description": "The version of MDS that the geographies represents"
- }
- },
- "additionalProperties": false
-}
diff --git a/schema/templates/geography/geography.json b/schema/templates/geography/geography.json
deleted file mode 100644
index e5987bcc..00000000
--- a/schema/templates/geography/geography.json
+++ /dev/null
@@ -1,86 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/geography/geography.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "The MDS Geography Schema",
- "type": "object",
- "definitions": {
- "geography": {
- "$id": "#/definitions/geography",
- "type": "object",
- "title": "The geography object schema",
- "additionalProperties": false,
- "required": [
- "name",
- "geography_id",
- "geography_json",
- "published_date"
- ],
- "properties": {
- "name": {
- "$id": "#/definitions/geography/properties/name",
- "$ref": "#/definitions/string",
- "description": "Name of geography"
- },
- "description": {
- "$id": "#/definitions/geography/properties/description",
- "$ref": "#/definitions/string",
- "description": "Description of geography"
- },
- "geography_type": {
- "$id": "#/definitions/geography/properties/geography_type",
- "type": "string",
- "description": "The type of geography"
- },
- "geography_id": {
- "$id": "#/definitions/geography/properties/geography_id",
- "$ref": "#/definitions/uuid",
- "description": "Unique ID of geography"
- },
- "geography_json": {
- "$id": "#/definitions/geography/properties/geography_json",
- "$ref": "https://geojson.org/schema/FeatureCollection.json",
- "description": "The GeoJSON FeatureCollection that defines the geographical coordinates"
- },
- "effective_date":{
- "$id": "#/definitions/geography/properties/effective_date",
- "$ref": "#/definitions/null_timestamp",
- "description": "The date at which a Geography is considered 'live'. Must be at or after published_date."
- },
- "published_date": {
- "$id": "#/definitions/geography/properties/published_date",
- "$ref": "#/definitions/timestamp",
- "description": "Timestamp at which the geography was published i.e. made immutable"
- },
- "retire_date": {
- "$id": "#/definitions/geography/properties/end_date",
- "$ref": "#/definitions/null_timestamp",
- "description": "Time that the geography is slated to retire. Once the retire date is passed, new policies can no longer reference it and old policies referencing it should be updated. Retired geographies should continue to be returned in the geographies list. Must be after effective_date."
- },
- "prev_geographies": {
- "$id": "#/definitions/geography/properties/prev_geographies",
- "$ref": "#/definitions/null_uuid_array",
- "description": "Unique IDs of prior geographies replaced by this one",
- "uniqueItems": true
- }
- }
- }
- },
- "required": [
- "geography",
- "version"
- ],
- "properties": {
- "geography": {
- "$id": "#/properties/geography",
- "$ref": "#/definitions/geography",
- "description": "The geography in this payload",
- "additionalProperties": false
- },
- "version": {
- "$id": "#/properties/version",
- "$ref": "#/definitions/version",
- "description": "The version of MDS that the geography represents"
- }
- },
- "additionalProperties": false
-}
diff --git a/schema/templates/policy/policy.json b/schema/templates/policy/policy.json
deleted file mode 100644
index 408b8818..00000000
--- a/schema/templates/policy/policy.json
+++ /dev/null
@@ -1,371 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/policy/policy.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "The MDS Policy Schema",
- "type": "object",
- "definitions": {
- "policy": {
- "$id": "#/definitions/policy",
- "type": "object",
- "title": "The policy object schema",
- "additionalProperties": false,
- "required": [
- "name",
- "policy_id",
- "description",
- "start_date",
- "published_date",
- "rules"
- ],
- "properties": {
- "name": {
- "$id": "#/definitions/policy/properties/name",
- "$ref": "#/definitions/string",
- "description": "Name of policy"
- },
- "policy_id": {
- "$id": "#/definitions/policy/properties/policy_id",
- "$ref": "#/definitions/uuid",
- "description": "Unique ID of policy"
- },
- "provider_ids":{
- "$id": "#/definitions/policy/properties/provider_ids",
- "$ref": "#/definitions/null_uuid_array",
- "description": "Providers for whom this policy is applicable; empty arrays and null/absent implies all Providers.",
- "uniqueItems": true
- },
- "description": {
- "$id": "#/definitions/policy/properties/description",
- "$ref": "#/definitions/string",
- "description": "Description of policy"
- },
- "currency": {
- "$id": "#/definitions/policy/properties/currency",
- "$ref": "#/definitions/currency"
- },
- "start_date":{
- "$id": "#/definitions/policy/properties/start_date",
- "$ref": "#/definitions/timestamp",
- "description": "Beginning date/time of policy enforcement"
- },
- "end_date": {
- "$id": "#/definitions/policy/properties/end_date",
- "$ref": "#/definitions/null_timestamp",
- "description": "End date/time of policy enforcement"
- },
- "published_date": {
- "$id": "#/definitions/policy/properties/published_date",
- "$ref": "#/definitions/timestamp",
- "description": "Timestamp at which the policy was published"
- },
- "prev_policies": {
- "$id": "#/definitions/policy/properties/prev_policies",
- "$ref": "#/definitions/null_uuid_array",
- "description": "Unique IDs of prior policies replaced by this one",
- "uniqueItems": true
- },
- "rules": {
- "$id": "#/definitions/rules",
- "type": "array",
- "description": "Array of applicable Rule objects",
- "items": {
- "$id": "#/definitions/policy/properties/rules/items",
- "$ref": "#/definitions/rule"
- },
- "minItems": 1
- }
- }
- },
- "rule": {
- "$id": "#/definitions/rule",
- "type": "object",
- "description": "An individual rule in a policy",
- "additionalProperties": false,
- "required": [
- "name",
- "rule_id",
- "rule_type",
- "geographies",
- "states"
- ],
- "properties": {
- "name": {
- "$id": "#/definitions/rule/properties/name",
- "$ref": "#/definitions/string",
- "description": "Name of rule"
- },
- "rule_id": {
- "$id": "#/definitions/rule/properties/rule_id",
- "$ref": "#/definitions/uuid",
- "description": "Unique ID of rule"
- },
- "rule_type": {
- "$id": "#/definitions/rule/properties/rule_type",
- "type": "string",
- "description": "The type of rule",
- "enum": [
- "count",
- "time",
- "speed",
- "rate",
- "user"
- ]
- },
- "geographies": {
- "$id": "#/definitions/rule/properties/geographies",
- "$ref": "#/definitions/uuid_array",
- "description": "List of Geography UUIDs (non-overlapping) specifying the covered geography",
- "minItems": 1,
- "uniqueItems": true
- },
- "states": {
- "$id": "#/definitions/rule/properties/states",
- "type": "object",
- "description": "Vehicle state to which this rule applies. Optionally provide a list of specific vehicle events as a subset of a given state for the rule to apply to. An empty list or null/absent defaults to \"all\" for the state.",
- "propertyNames": {
- "$id": "#/definitions/rule/properties/states/propertyNames",
- "$ref": "#/definitions/vehicle_state"
- },
- "properties": {
- },
- "additionalProperties": {
- "type": "array",
- "uniqueItems": true,
- "items": {
- "$ref": "#/definitions/vehicle_event"
- }
- }
- },
- "rule_units": {
- "$id": "#/definitions/rule/properties/rule_units",
- "type": "string",
- "description": "Measured units of policy",
- "enum": [
- "seconds",
- "minutes",
- "hours",
- "days",
- "mph",
- "kph",
- "devices",
- "amount"
- ]
- },
- "vehicle_types": {
- "$id": "#/definitions/rule/properties/vehicle_types",
- "$ref": "#/definitions/null_vehicle_types",
- "description": "Applicable vehicle types, default \"all\""
- },
- "propulsion_types": {
- "$id": "#/definitions/rule/properties/propulsion_types",
- "$ref": "#/definitions/null_propulsion_types",
- "description": "Applicable vehicle propulsion types, default \"all\""
- },
- "minimum": {
- "$id": "#/definitions/rule/properties/minimum",
- "type": ["null", "integer"],
- "description": "Minimum value, if applicable (default 0)"
- },
- "maximum": {
- "$id": "#/definitions/rule/properties/maximum",
- "type": ["null", "integer"],
- "description": "Maximum value, if applicable (default unlimited)"
- },
- "inclusive_minimum": {
- "$id": "#/definitions/rule/properties/inclusive_minimum",
- "type": ["null", "boolean"],
- "description": "Whether the rule minimum is considered in-bounds (default true)"
- },
- "inclusive_maximum": {
- "$id": "#/definitions/rule/properties/inclusive_maximum",
- "type": ["null", "boolean"],
- "description": "Whether the rule maximum is considered in-bounds (default true)"
- },
- "rate_amount": {
- "$id": "#/definitions/rule/properties/rate_amount",
- "type": ["null", "integer"],
- "description": "The amount of a rate applied when this rule applies, if applicable (default zero). A positive integer rate amount represents a fee, while a negative integer represents a subsidy. Rate amounts are given in the currency defined in the Policy."
- },
- "rate_recurrence": {
- "$id": "#/definitions/rule/properties/rate_recurrence",
- "type": ["string", "null"],
- "description": "Specify how a rate is applied – either once, or periodically according to a time unit specified using rule_units",
- "enum": [
- "once_on_match",
- "once_on_unmatch",
- "each_time_unit",
- "per_complete_time_unit"
- ]
- },
- "rate_applies_when": {
- "$id": "#/definitions/rule/properties/rate_applies_when",
- "type": ["string", "null"],
- "description": "Specify when a rate is applicable to an event or count: when it's within rule bounds or when it is not",
- "enum": [
- "in_bounds",
- "out_of_bounds"
- ]
- },
- "start_time": {
- "$id": "#/definitions/rule/properties/start_time",
- "$ref": "#/definitions/null_iso_time",
- "description": "Beginning time-of-day when the rule is in effect (default 00:00:00)"
- },
- "end_time": {
- "$id": "#/definitions/rule/properties/end_time",
- "$ref": "#/definitions/null_iso_time",
- "description": "Ending time-of-day when the rule is in effect (default 23:59:59)"
- },
- "days": {
- "$id": "#/definitions/rule/properties/days",
- "$ref": "#/definitions/null_days",
- "description": "Days when the rule is in effect (default all)"
- },
- "messages": {
- "$id": "#/definitions/rule/properties/messages",
- "type": ["null", "object"],
- "description": "Message to rider user, if desired, in various languages, keyed by BCP 47 language tag",
- "propertyNames": {
- "pattern": "([A-Za-z]{2,3})([-][A-Za-z]{3}){0,3}([-]([A-Za-z]{4}))?([-]([A-Za-z]{2}|[0-9]{3}))?"
- }
- },
- "value_url": {
- "$id": "#/definitions/rule/properties/value_url",
- "type": ["null", "string"],
- "description": "URL to an API endpoint that can provide dynamic information for the measured value",
- "format": "uri"
- }
- },
- "allOf": [
- {
- "description": "Valid rule_type and rule_unit values for this rule",
- "oneOf": [
- {
- "properties": {
- "rule_type": {
- "const": "user"
- }
- }
- },
- {
- "allOf": [
- {
- "required": [
- "rule_units"
- ]
- },
- {
- "oneOf": [
- {
- "properties": {
- "rule_type": {
- "const": "time"
- },
- "rule_units": {
- "enum": [
- "seconds",
- "minutes",
- "hours",
- "days"
- ]
- }
- }
- },
- {
- "properties": {
- "rule_type": {
- "const": "speed"
- },
- "rule_units": {
- "enum": [
- "mph",
- "kph"
- ]
- }
- }
- },
- {
- "properties": {
- "rule_type": {
- "const": "count"
- },
- "rule_units": {
- "enum": [
- "devices"
- ]
- }
- }
- },
- {
- "required": [
- "rate_amount",
- "rate_recurrence"
- ],
- "properties": {
- "rule_type": {
- "const": "rate"
- },
- "rule_units": {
- "enum": [
- "amount",
- "seconds",
- "minutes",
- "hours",
- "days"
- ]
- }
- }
- }
- ]
- }
- ]
- }
- ]
- }
- ]
- }
- },
- "required": [
- "data",
- "updated",
- "version"
- ],
- "properties": {
- "data": {
- "$id": "#/properties/data",
- "type": "object",
- "description": "The data records in this payload",
- "required": [
- "policies"
- ],
- "properties": {
- "policies": {
- "$id": "#/properties/data/properties/policies",
- "type": "array",
- "title": "The array of policy objects in this payload",
- "items": {
- "$id": "#/properties/data/properties/policies/items",
- "$ref": "#/definitions/policy"
- }
- }
- },
- "additionalProperties": false
- },
- "end_date": {
- "$id": "#/properties/end_date",
- "$ref": "#/definitions/null_timestamp",
- "description": "The timestamp after which the Policy is no longer effective"
- },
- "updated": {
- "$id": "#/properties/updated",
- "$ref": "#/definitions/timestamp",
- "description": "The timestamp when the Policy was last updated"
- },
- "version": {
- "$id": "#/properties/version",
- "$ref": "#/definitions/version",
- "description": "The version of MDS that the Policy represents"
- }
- },
- "additionalProperties": false
-}
diff --git a/schema/templates/provider/endpoint.json b/schema/templates/provider/endpoint.json
deleted file mode 100644
index 1a2dc8f3..00000000
--- a/schema/templates/provider/endpoint.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "$id": "https://raw.githubusercontent.com/openmobilityfoundation/mobility-data-specification/main/provider/endpoint.json",
- "$schema": "http://json-schema.org/draft-06/schema#",
- "title": "Schema for MDS Provider endpoint payloads",
- "type": "object",
- "definitions": {},
- "required": [
- "data",
- "version"
- ],
- "properties": {
- "data": {
- "$id": "#/properties/data",
- "type": "object",
- "description": "The data records in this payload",
- "required": [],
- "properties": {},
- "additionalProperties": false
- },
- "version": {
- "$id": "#/properties/version",
- "$ref": "#/definitions/version"
- }
- },
- "additionalProperties": false
-}
\ No newline at end of file
diff --git a/schema/templates/provider/status_changes.json b/schema/templates/provider/status_changes.json
deleted file mode 100644
index c289a7cb..00000000
--- a/schema/templates/provider/status_changes.json
+++ /dev/null
@@ -1,70 +0,0 @@
-{
- "status_changes": {
- "$id": "#/properties/data/properties/status_changes",
- "type": "array",
- "title": "The status_changes payload",
- "items": {
- "$id": "#/properties/data/properties/status_changes/items",
- "type": "object",
- "title": "The status_change item schema",
- "additionalProperties": false,
- "required": [
- "vehicle_state",
- "event_types",
- "event_time",
- "event_location"
- ],
- "properties": {
- "event_time": {
- "$id": "#/properties/data/properties/status_changes/items/properties/event_time",
- "$ref": "#/definitions/timestamp",
- "description": "The time the event occurred, expressed as a Unix Timestamp"
- },
- "publication_time": {
- "$id": "#/properties/data/properties/status_changes/items/properties/publication_time",
- "$ref": "#/definitions/timestamp",
- "description": "The time the event became available through the status changes endpoint, expressed as a Unix Timestamp"
- },
- "event_location": {
- "$id": "#/properties/data/properties/status_changes/items/properties/event_location",
- "$ref": "#/definitions/MDS_Feature_Point",
- "description": "The GPS or GNSS coordinates of where the event occurred"
- },
- "vehicle_state": {
- "$id": "#/properties/data/properties/status_changes/items/properties/vehicle_state",
- "$ref": "#/definitions/vehicle_state",
- "description": "The state of the vehicle"
- },
- "event_types": {
- "$id": "#/properties/data/properties/status_changes/items/properties/event_types",
- "$ref": "#/definitions/vehicle_events",
- "description": "The event(s) that caused a change in the vehicle's state"
- },
- "battery_pct": {
- "$id": "#/properties/data/properties/status_changes/items/properties/battery_pct",
- "type": [
- "number",
- "null"
- ],
- "description": "Percent charge of device battery, expressed between 0 and 1",
- "examples": [
- 0.89
- ],
- "minimum": 0,
- "maximum": 1
- },
- "trip_id": {
- "$id": "#/properties/data/properties/status_changes/items/properties/trip_id",
- "$ref": "#/definitions/uuid",
- "description": "Trip UUID (foreign key to Trips API), required if event_types contains trip_start, trip_end, trip_cancel, trip_enter_jurisdiction, or trip_leave_jurisdiction"
- },
- "associated_ticket": {
- "$id": "#/properties/data/properties/status_changes/items/properties/associated_ticket",
- "$ref": "#/definitions/string",
- "description": "Identifier for an associated ticket inside an Agency-maintained 311 or CRM system."
- }
- },
- "allOf": []
- }
- }
-}
\ No newline at end of file
diff --git a/schema/templates/provider/stops.json b/schema/templates/provider/stops.json
deleted file mode 100644
index d2fcbb5f..00000000
--- a/schema/templates/provider/stops.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "stops": {
- "$id": "#/properties/data/properties/stops",
- "type": "array",
- "title": "The stops payload",
- "items": {
- "$id": "#/properties/data/properties/stops/items",
- "$ref": "#/definitions/stop"
- }
- }
-}
\ No newline at end of file
diff --git a/schema/templates/provider/trips.json b/schema/templates/provider/trips.json
deleted file mode 100644
index d271332a..00000000
--- a/schema/templates/provider/trips.json
+++ /dev/null
@@ -1,114 +0,0 @@
-{
- "trips": {
- "$id": "#/properties/data/properties/trips",
- "type": "array",
- "title": "The trips payload",
- "items": {
- "$id": "#/properties/data/properties/trips/items",
- "type": "object",
- "title": "The trip item schema",
- "additionalProperties": false,
- "required": [
- "trip_id",
- "trip_duration",
- "trip_distance",
- "route",
- "accuracy",
- "start_time",
- "end_time"
- ],
- "properties": {
- "trip_id": {
- "$id": "#/properties/data/properties/trips/items/properties/trip_id",
- "description": "A unique ID for each trip",
- "$ref": "#/definitions/uuid"
- },
- "trip_duration": {
- "$id": "#/properties/data/properties/trips/items/properties/trip_duration",
- "type": "integer",
- "description": "The length of time, in seconds, that the trip lasted",
- "default": 0,
- "examples": [
- 600
- ]
- },
- "trip_distance": {
- "$id": "#/properties/data/properties/trips/items/properties/trip_distance",
- "type": "integer",
- "description": "The distance, in meters, that the trip covered",
- "default": 0,
- "examples": [
- 1000
- ]
- },
- "route": {
- "$id": "#/properties/data/properties/trips/items/properties/route",
- "title": "The Route Schema",
- "$ref": "#/definitions/MDS_FeatureCollection_Route"
- },
- "accuracy": {
- "$id": "#/properties/data/properties/trips/items/properties/accuracy",
- "type": "integer",
- "title": "The approximate level of accuracy, in meters, of Points within route",
- "default": 0,
- "examples": [
- 15
- ]
- },
- "start_time": {
- "$id": "#/properties/data/properties/trips/items/properties/start_time",
- "description": "The time the trip began, expressed as a Unix Timestamp",
- "$ref": "#/definitions/timestamp"
- },
- "end_time": {
- "$id": "#/properties/data/properties/trips/items/properties/end_time",
- "description": "The time the trip ended, expressed as a Unix Timestamp",
- "$ref": "#/definitions/timestamp"
- },
- "publication_time": {
- "$id": "#/properties/data/properties/trips/items/properties/publication_time",
- "description": "The time the trip became available through the trips endpoint, expressed as a Unix Timestamp",
- "$ref": "#/definitions/timestamp"
- },
- "parking_verification_url": {
- "$id": "#/properties/data/properties/trips/items/properties/parking_verification_url",
- "type": [
- "string",
- "null"
- ],
- "format": "uri",
- "description": "A URL to a photo (or other evidence) of proper vehicle parking",
- "examples": [
- "https://data.provider.co/parking_verify/1234.jpg"
- ]
- },
- "standard_cost": {
- "$id": "#/properties/data/properties/trips/items/properties/standard_cost",
- "type": [
- "integer",
- "null"
- ],
- "description": "The cost, in the currency defined in `currency`, that it would cost to perform that trip in the standard operation of the System. If no currency is given, USD cents is implied.",
- "examples": [
- 500
- ]
- },
- "actual_cost": {
- "$id": "#/properties/data/properties/trips/items/properties/actual_cost",
- "type": [
- "integer",
- "null"
- ],
- "description": "The actual cost, in the currency defined in `currency`, paid by the customer of the *mobility as a service* provider. If no currency is given, USD cents is implied.",
- "examples": [
- 520
- ]
- },
- "currency": {
- "$id": "#/properties/data/properties/trips/items/properties/currency",
- "$ref": "#/definitions/currency"
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/schema/templates/provider/vehicles.json b/schema/templates/provider/vehicles.json
deleted file mode 100644
index e9117524..00000000
--- a/schema/templates/provider/vehicles.json
+++ /dev/null
@@ -1,76 +0,0 @@
-{
- "vehicles": {
- "$id": "#/properties/data/properties/vehicles",
- "type": "array",
- "title": "The vehicles payload",
- "items": {
- "$id": "#/properties/data/properties/vehicles/items",
- "type": "object",
- "title": "The vehicle item schema",
- "required": [
- "last_event_time",
- "last_vehicle_state",
- "last_event_types",
- "last_event_location"
- ],
- "properties": {
- "last_event_time": {
- "$id": "#/properties/data/properties/vehicles/items/properties/last_event_time",
- "$ref": "#/definitions/timestamp",
- "description": "The time the most recent status change event occurred, expressed as a Unix Timestamp"
- },
- "last_vehicle_state": {
- "$id": "#/properties/data/properties/vehicles/items/properties/last_vehicle_state",
- "$ref": "#/definitions/vehicle_state",
- "description": "The last known state of the vehicle"
- },
- "last_event_types": {
- "$id": "#/properties/data/properties/vehicles/items/properties/last_event_types",
- "$ref": "#/definitions/vehicle_events",
- "description": "The most recent event(s) that caused a change in the vehicle's state"
- },
- "last_event_location": {
- "$id": "#/properties/data/properties/vehicles/items/properties/last_event_location",
- "$ref": "#/definitions/MDS_Feature_Point",
- "description": "Location of the vehicle's last status change event"
- },
- "current_location": {
- "$id": "#/properties/data/properties/vehicles/items/properties/current_location",
- "$ref": "#/definitions/MDS_Feature_Point",
- "description": "Current location of vehicle if different from last event, and the vehicle is not currently on a trip"
- },
- "battery_pct": {
- "$id": "#/properties/data/properties/vehicles/items/properties/battery_pct",
- "type": [
- "number",
- "null"
- ],
- "description": "Percent charge of device battery, expressed between 0 and 1",
- "examples": [
- 0.89
- ],
- "minimum": 0,
- "maximum": 1
- }
- },
- "allOf": [
- {
- "description": "Valid last_vehicle_state values for this endpoint",
- "properties": {
- "last_vehicle_state": {
- "enum": [
- "available",
- "elsewhere",
- "non_operational",
- "on_trip",
- "removed",
- "reserved",
- "unknown"
- ]
- }
- }
- }
- ]
- }
- }
-}