diff --git a/gtfs/spec/en/examples/boarding-permissions.md b/gtfs/spec/en/examples/boarding-permissions.md
new file mode 100644
index 000000000..2847e59fb
--- /dev/null
+++ b/gtfs/spec/en/examples/boarding-permissions.md
@@ -0,0 +1,73 @@
+## Introduction
+
+The examples below describe how to use `stop_times.txt` and `boarding_permissions.txt` effectively to describe where and when passengers can bring a vehicle on board.
+
+### Example: London Underground
+
+London Underground does not allow bicycles to be carried in the "deep tube" sections of the network, and only allows bicycles to be carried outside peak hours on Monday to Friday.
+
+These can be specified in the following way, using trips on the Jubilee line as an example where the "deep tube" runs between Finchley Road and Canning Town:
+
+`stop_times.txt`
+
+| `trip_id` | `service_id` | `stop_id` | `stop_sequence` | `boarding_permission_id` |
+|-----------|--------------|-----------------|-----------------|--------------------------|
+| 924 | Mon to Fri | Stanmore | `0` | `tfl_weekday` |
+| 924 | Mon to Fri | Canons Park | `1` | `tfl_weekday` |
+| ... | ... | ... | ... | ... |
+| 924 | Mon to Fri | West Hampstead | `9` | `tfl_weekday` |
+| 924 | Mon to Fri | Finchley Road | `10` | `deep_tube` |
+| 924 | Mon to Fri | Swiss Cottage | `11` | `deep_tube` |
+| 924 | ... | ... | ... | ... |
+| 924 | Mon to Fri | North Greenwich | `23` | `deep_tube` |
+| 924 | Mon to Fri | Canning Town | `24` | `tfl_weekday` |
+| 924 | Mon to Fri | West Ham | `25` | `tfl_weekday` |
+| 924 | Mon to Fri | Stratford | `26` | `tfl_weekday` |
+| 925 | Sun | Stanmore | `0` | `tfl_weekend` |
+| 925 | Sun | Canons Park | `1` | `tfl_weekend` |
+| ... | ... | ... | ... | ... |
+| 925 | Sun | West Hampstead | `9` | `tfl_weekend` |
+| 925 | Sun | Finchley Road | `10` | `deep_tube` |
+| 925 | Sun | Swiss Cottage | `11` | `deep_tube` |
+| 925 | ... | ... | ... | ... |
+| 925 | Sun | North Greenwich | `23` | `deep_tube` |
+| 925 | Sun | Canning Town | `24` | `tfl_weekend` |
+| 925 | Sun | West Ham | `25` | `tfl_weekend` |
+| 925 | Sun | Stratford | `26` | `tfl_weekend` |
+
+`boarding_permissions.txt`
+
+| `boarding_permission_id` | `vehicle` | `carriage_permission` | `start_time` | `end_time` |
+|--------------------------|-----------|-----------------------|--------------|------------|
+| tfl_weekday | `1` | `1` | `07:30:00` | `09:30:00` |
+| tfl_weekday | `1` | `1` | `16:00:00` | `19:00:00` |
+| tfl_weekday | `1` | `0` | | |
+| tfl_weekend | `1` | `0` | | |
+| deep_tube | `1` | `1` | | |
+
+In the above table, `deep_tube` is used for all stop times where bikes cannot be carried further at any time,
+`tfl_weekday` is used for all stop times where bikes cannot be carried during peak hours, but can be carried at other times without reservation,
+and `tfl_weekend` is used for all stop times where bikes can be freely carried.
+
+### Example: ferries which do not accept foot passengers
+
+The following ferry does not accept foot passengers. Passengers with a bike or a motorcycle can turn up without making a reservation,
+but passenger with a car must book with the agency to arrange pick up and drop off at specific piers.
+
+`stop_times.txt`
+
+| `trip_id` | `stop_id` | `stop_sequence` | `pickup_type` | `drop_off_type` | `boarding_permission_id` |
+|-----------|-----------|-----------------|---------------|-----------------|--------------------------|
+| X | A | 0 | 1 | 1 | ferry |
+| X | B | 1 | 1 | 1 | ferry |
+| X | C | 2 | 1 | 1 | ferry |
+| X | D | 3 | 1 | 1 | ferry |
+| X | E | 4 | 1 | 1 | ferry |
+
+`boarding_permissions.txt`
+
+| `boarding_permission_id` | `vehicle` | `pickup_permission` | `drop_off_permission` |
+|--------------------------|-----------|---------------------|-----------------------|
+| ferry | 1 | 0 | 0 |
+| ferry | 2 | 0 | 0 |
+| ferry | 3 | 2 | 2 |
\ No newline at end of file
diff --git a/gtfs/spec/en/reference.md b/gtfs/spec/en/reference.md
index 8489f357f..7dbb77c5f 100644
--- a/gtfs/spec/en/reference.md
+++ b/gtfs/spec/en/reference.md
@@ -16,6 +16,7 @@ This document defines the format and structure of the files that comprise a GTFS
- [routes.txt](#routestxt)
- [trips.txt](#tripstxt)
- [stop\_times.txt](#stop_timestxt)
+ - [boarding\_permissions.txt](#boarding_permissionstxt)
- [calendar.txt](#calendartxt)
- [calendar\_dates.txt](#calendar_datestxt)
- [fare\_attributes.txt](#fare_attributestxt)
@@ -255,8 +256,8 @@ Primary key (`trip_id`)
| `direction_id` | Enum | Optional | Indicates the direction of travel for a trip. This field should not be used in routing; it provides a way to separate trips by direction when publishing time tables. Valid options are:
`0` - Travel in one direction (e.g. outbound travel).
`1` - Travel in the opposite direction (e.g. inbound travel).
*Example: The `trip_headsign` and `direction_id` fields may be used together to assign a name to travel in each direction for a set of trips. A [trips.txt](#tripstxt) file could contain these records for use in time tables:*
`trip_id,...,trip_headsign,direction_id`
`1234,...,Airport,0`
`1505,...,Downtown,1` |
| `block_id` | ID | Optional | Identifies the block to which the trip belongs. A block consists of a single trip or many sequential trips made using the same vehicle, defined by shared service days and `block_id`. A `block_id` may have trips with different service days, making distinct blocks. See the [example below](#example-blocks-and-service-day). To provide in-seat transfers information, [transfers](#transferstxt) of `transfer_type` `4` should be provided instead. |
| `shape_id` | Foreign ID referencing `shapes.shape_id` | **Conditionally Required** | Identifies a geospatial shape describing the vehicle travel path for a trip.
Conditionally Required:
- **Required** if the trip has a continuous pickup or drop-off behavior defined either in [routes.txt](#routestxt) or in [stop_times.txt](#stop_timestxt).
- Optional otherwise. |
-| `wheelchair_accessible` | Enum | Optional | Indicates wheelchair accessibility. Valid options are:
`0` or empty - No accessibility information for the trip.
`1` - Vehicle being used on this particular trip can accommodate at least one rider in a wheelchair.
`2` - No riders in wheelchairs can be accommodated on this trip. |
-| `bikes_allowed` | Enum | Optional | Indicates whether bikes are allowed. Valid options are:
`0` or empty - No bike information for the trip.
`1` - Vehicle being used on this particular trip can accommodate at least one bicycle.
`2` - No bicycles are allowed on this trip. |
+| `wheelchair_accessible` | Enum | **Conditionally Forbidden** | Indicates wheelchair accessibility. Valid options are:
`0` or empty - No accessibility information for the trip.
`1` - Vehicle being used on this particular trip can accommodate at least one rider in a wheelchair.
`2` - No riders in wheelchairs can be accommodated on this trip.
**Forbidden** if `boarding_permission_id` referring to an entry in `boarding_permissions.txt` with `vehicle_type` = `0` is defined for any stop time of the trip, optional otherwise. |
+| `bikes_allowed` | Enum | **Conditionally Forbidden** | Indicates whether bikes are allowed. Valid options are:
`0` or empty - No bike information for the trip.
`1` - Vehicle being used on this particular trip can accommodate at least one bicycle.
`2` - No bicycles are allowed on this trip.
**Forbidden** if `boarding_permission_id` referring to an entry in `boarding_permissions.txt` with `vehicle_type` = `1` is defined for any stop time of the trip, optional otherwise. |
#### Example: Blocks and service day
@@ -293,19 +294,53 @@ Primary key (`trip_id`, `stop_sequence`)
| `stop_headsign` | Text | Optional | Text that appears on signage identifying the trip's destination to riders. This field overrides the default `trips.trip_headsign` when the headsign changes between stops. If the headsign is displayed for an entire trip, `trips.trip_headsign` should be used instead.
A `stop_headsign` value specified for one `stop_time` does not apply to subsequent `stop_time`s in the same trip. If you want to override the `trip_headsign` for multiple `stop_time`s in the same trip, the `stop_headsign` value must be repeated in each `stop_time` row. |
| `start_pickup_drop_off_window` | Time | **Conditionally Required** | Time that on-demand service becomes available in a GeoJSON location, location group, or stop.
**Conditionally Required**:
- **Required** if `stop_times.location_group_id` or `stop_times.location_id` is defined.
- **Required** if `end_pickup_drop_off_window` is defined.
- **Forbidden** if `arrival_time` or `departure_time` is defined.
- Optional otherwise. |
| `end_pickup_drop_off_window` | Time | **Conditionally Required** | Time that on-demand service ends in a GeoJSON location, location group, or stop.
**Conditionally Required**:
- **Required** if `stop_times.location_group_id` or `stop_times.location_id` is defined.
- **Required** if `start_pickup_drop_off_window` is defined.
- **Forbidden** if `arrival_time` or `departure_time` is defined.
- Optional otherwise. |
-| `pickup_type` | Enum | **Conditionally Forbidden** | Indicates pickup method. Valid options are:
`0` or empty - Regularly scheduled pickup.
`1` - No pickup available.
`2` - Must phone agency to arrange pickup.
`3` - Must coordinate with driver to arrange pickup.
**Conditionally Forbidden**:
- `pickup_type=0` **forbidden** if `start_pickup_drop_off_window` or `end_pickup_drop_off_window` are defined.
- `pickup_type=3` **forbidden** if `start_pickup_drop_off_window` or `end_pickup_drop_off_window` are defined.
- Optional otherwise. |
-| `drop_off_type` | Enum | **Conditionally Forbidden** | Indicates drop off method. Valid options are:
`0` or empty - Regularly scheduled drop off.
`1` - No drop off available.
`2` - Must phone agency to arrange drop off.
`3` - Must coordinate with driver to arrange drop off.
**Conditionally Forbidden**:
- `drop_off_type=0` **forbidden** if `start_pickup_drop_off_window` or `end_pickup_drop_off_window` are defined.
- Optional otherwise. |
+| `pickup_type` | Enum | **Conditionally Forbidden** | Indicates pickup method. Can be overridden by `boarding_permission_id` if the passenger is travelling with a vehicle. Valid options are:
`0` or empty - Regularly scheduled pickup.
`1` - No pickup available.
`2` - Must phone agency to arrange pickup.
`3` - Must coordinate with driver to arrange pickup.
**Conditionally Forbidden**:
- `pickup_type=0` **forbidden** if `start_pickup_drop_off_window` or `end_pickup_drop_off_window` are defined.
- `pickup_type=3` **forbidden** if `start_pickup_drop_off_window` or `end_pickup_drop_off_window` are defined.
- Optional otherwise. |
+| `drop_off_type` | Enum | **Conditionally Forbidden** | Indicates drop off method. Can be overridden by `boarding_permission_id` if the passenger is travelling with a vehicle. Valid options are:
`0` or empty - Regularly scheduled drop off.
`1` - No drop off available.
`2` - Must phone agency to arrange drop off.
`3` - Must coordinate with driver to arrange drop off.
**Conditionally Forbidden**:
- `drop_off_type=0` **forbidden** if `start_pickup_drop_off_window` or `end_pickup_drop_off_window` are defined.
- Optional otherwise. |
| `continuous_pickup` | Enum | **Conditionally Forbidden** | Indicates that the rider can board the transit vehicle at any point along the vehicle’s travel path as described by [shapes.txt](#shapestxt), from this `stop_time` to the next `stop_time` in the trip’s `stop_sequence`. Valid options are:
`0` - Continuous stopping pickup.
`1` or empty - No continuous stopping pickup.
`2` - Must phone agency to arrange continuous stopping pickup.
`3` - Must coordinate with driver to arrange continuous stopping pickup.
If this field is populated, it overrides any continuous pickup behavior defined in [routes.txt](#routestxt). If this field is empty, the `stop_time` inherits any continuous pickup behavior defined in [routes.txt](#routestxt).
**Conditionally Forbidden**:
- **Forbidden** if `start_pickup_drop_off_window` or `end_pickup_drop_off_window` are defined.
- Optional otherwise. |
| `continuous_drop_off` | Enum | **Conditionally Forbidden** | Indicates that the rider can alight from the transit vehicle at any point along the vehicle’s travel path as described by [shapes.txt](#shapestxt), from this `stop_time` to the next `stop_time` in the trip’s `stop_sequence`. Valid options are:
`0` - Continuous stopping drop off.
`1` or empty - No continuous stopping drop off.
`2` - Must phone agency to arrange continuous stopping drop off.
`3` - Must coordinate with driver to arrange continuous stopping drop off.
If this field is populated, it overrides any continuous drop-off behavior defined in [routes.txt](#routestxt). If this field is empty, the `stop_time` inherits any continuous drop-off behavior defined in [routes.txt](#routestxt).
**Conditionally Forbidden**:
- **Forbidden** if `start_pickup_drop_off_window` or `end_pickup_drop_off_window` are defined.
- Optional otherwise. |
| `shape_dist_traveled` | Non-negative float | Optional | Actual distance traveled along the associated shape, from the first stop to the stop specified in this record. This field specifies how much of the shape to draw between any two stops during a trip. Must be in the same units used in [shapes.txt](#shapestxt). Values used for `shape_dist_traveled` must increase along with `stop_sequence`; they must not be used to show reverse travel along a route.
Recommended for routes that have looping or inlining (the vehicle crosses or travels over the same portion of alignment in one trip). See [`shapes.shape_dist_traveled`](#shapestxt).
*Example: If a bus travels a distance of 5.25 kilometers from the start of the shape to the stop,`shape_dist_traveled`=`5.25`.*|
| `timepoint` | Enum | Optional | Indicates if arrival and departure times for a stop are strictly adhered to by the vehicle or if they are instead approximate and/or interpolated times. This field allows a GTFS producer to provide interpolated stop-times, while indicating that the times are approximate. Valid options are:
`0` - Times are considered approximate.
`1` - Times are considered exact.
All records of [stop_times.txt](#stop_timestxt) with defined arrival or departure times should have timepoint values populated. If no timepoint values are provided, all times are considered exact. |
| `pickup_booking_rule_id` | Foreign ID referencing `booking_rules.booking_rule_id` | Optional | Identifies the boarding booking rule at this stop time.
Recommended when `pickup_type=2`. |
| `drop_off_booking_rule_id` | Foreign ID referencing `booking_rules.booking_rule_id` | Optional | Identifies the alighting booking rule at this stop time.
Recommended when `drop_off_type=2`. |
+| `boarding_permission_id` | Foreign ID referencing `boarding_permissions.boarding_permission_id` | Optional | Identifies a boarding permission. |
#### On-demand Service Routing Behavior
- When providing routing or travel time between the origin and destination, data consumers should ignore intermediate stop_times.txt records with the same `trip_id` that have `start_pickup_drop_off_window` and `end_pickup_drop_off_window` defined. For examples that demonstrate what should be ignored, see [the data example page](https://gtfs.org/schedule/examples/flex/#ignoring-intermediate-stop-times-records-with-pickupdrop-off-windows).
- Simultaneous overlap of locations.geojson `id` geometry, `start/end_pickup_drop_off_window` time, and `pickup_type` or `drop_off_type` between two or more stop_times.txt records with the same `trip_id` is forbidden. For examples that demonstrate what is forbidden, see [the data example page](https://gtfs.org/schedule/examples/flex/#zone-overlap-constraint).
+### boarding_permissions.txt
+
+File: **Optional**
+
+Primary key (`boarding_permission_id`, `vehicle`, `start_time`)
+
+The [boarding_permissions.txt](#boarding_permissionstxt) table defines which vehicles may board, alight or be carried on a service.
+
+A vehicle can only be carried if the `pickup_permission` allows it at the origin stop,
+the `carriage_permission` allows it for every stop from the boarding stop until the stop before the alighting stop,
+and the `drop_off_permission` allows it at the alighting stop.
+
+If specified for a vehicle, if overrides the `pickup_type` and `drop_off_type` in `stop_times.txt` for passengers with that vehicle.
+To specify a vehicle is required for a passenger to use a service, set `pickup_type` and `drop_off_type` to be `1` in `stop_times.txt`,
+and set `boarding_permission_id` to reference an entry for the required vehicle in `boarding_permissions.txt`.
+
+| Field Name | Type | Presence | Description |
+|---------------------------|------------|-------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `boarding_permission_id` | Unique ID | Required | Identifies a boarding_permission. |
+| `vehicle` | Enum | Required | Identifies a vehicle. `0` - Wheelchair. `1` - Bike. `2` - Motorcycle. `3` - Car. |
+| `pickup_permission` | Enum | Optional | Indicates whether pickup is available for the specified vehicle.
`0` or empty - Pickup is available.
`1` - No pickup available.
`2` - Must phone agency to arrange pickup.
`3` - Must coordinate with driver to arrange pickup. |
+| `drop_off_permission` | Enum | Optional | Indicates whether drop off is available for the specified vehicle.
`0` or empty - Drop off is available.
`1` - No drop off available.
`2` - Must phone agency to arrange pickup.
`3` - Must coordinate with driver to arrange drop off. |
+| `carriage_permission` | Enum | Optional | Indicates whether the vehicle can remain on board after departing the specified stop.
`0` or empty - The vehicle can remain on board.
`1` - The vehicle cannot remain on board.
`2` - Must phone agency reserve a space on board.
`3` - Must coordinate with driver for a space on board. |
+| `start_time` | Time | Conditionally Required | Defines the beginning of a timeframe for when this permission is valid. **Required** if `end_time` is defined, **forbidden** otherwise.
An entry with `start_time` overrides an entry without `start_time`, which serves as the default at other times. |
+| `end_time` | Time | Conditionally Required | Defines the end of a timeframe for when this permission is valid. **Required** if `start_time` is defined, **forbidden** otherwise.
An entry with `end_time` overrides an entry without `end_time`, which serves as the default at other times. |
+
+#### `start_time` and `end_time` semantics
+
+A boarding permission only takes effect if the event is at or after `start_time`, and before `end_time`, if it is specified for the vehicle.
+An entry with the same `boarding_permission_id` and `vehicle` without `start_time` and `end_time` can be provided by default for a vehicle if the doesn't match any entries with `start_time` and `end_time` defined.
+
+For pickup and carriage, the time of the event is at the departure, for drop off, the time of the event is at the arrival.
+
### calendar.txt
File: **Conditionally Required**