Applies to: Avail GTFS static feeds and GTFS-Realtime feeds
Audience: Transit agencies, trip planners and other GTFS data consumers
An Avail merged feed puts more than one set of schedule data into a single GTFS feed. This article explains how to recognize a merged feed, how its IDs are structured, how schedule versions hand over on the calendar, and how to match GTFS-Realtime data to the static feed.
In this article
- Overview
- How to recognize a merged feed
- ID structure
- Calendar
- GTFS-Realtime
- Guidance for consumers
- FAQ
Overview
A merged feed combines more than one set of schedule data, and a suffix on each affected ID tells the sets apart. There are two kinds of merge, and one feed can use both.
| Kind | What's combined | How the sets relate in time | ID suffix |
|---|---|---|---|
| Schedule change | The current schedule and the next published schedule | One after the other, with no shared dates | -v<version> |
| Multi-agency | Schedules for separate parts of one operation, such as different yards. Each part is published as its own agency | At the same time, on the same dates | -v<version>-a<agency_id> |
With a schedule-change merge, the new schedule is in the feed before it starts. Trip planners can show it ahead of time, and there's no gap when it takes over. With a multi-agency merge, riders get one feed for the whole operation.
How to recognize a merged feed
Look at trip_id in trips.txt. If the IDs end in -v followed by a version, the feed is merged. If they also end in -a followed by a number, it's a multi-agency feed.
| Check | Merged feed | Non-merged feed |
|---|---|---|
trip_id |
t140-b1-sl1C-v64 or t266-b162B2-sl2-v4A-a1
|
t1A9-b4E85-sl2 |
service_id |
28-v64, 3-v50-a2
|
2, 3
|
shape_id |
27337_shp-v64 |
3800_shp |
Rows in agency.txt
|
One per agency in the merge | One |
ID structure
IDs that belong to one schedule version end in -v<version>. In a multi-agency feed, -a<agency_id> comes after that. Treat every ID as an opaque string: the suffix is part of the ID.
The version is hexadecimal. It goes up by one with each schedule publish, so v9 is followed by vA through vF, then v10. Read it as text or as base 16. A script that only accepts digits will miss a version like vC. In a multi-agency feed, each agency has its own version number.
| Field | Schedule-change merge | Multi-agency merge |
|---|---|---|
trip_id, service_id, block_id, shape_id
|
-v<version> |
-v<version>-a<agency_id> |
service_id in calendar.txt and calendar_dates.txt
|
-v<version> |
-v<version>-a<agency_id> |
stop_id, parent_station
|
No suffix; shared by all versions |
-a<agency_id>; each agency has its own copy |
route_id |
No suffix; shared by all versions | Unique to one agency |
agency.txt |
One row | One row per agency |
feed_info.txt |
One row covering every version | One row for the whole feed |
Same base ID, different trip. Apart from the suffix, a trip ID often stays the same from one version to the next, for example t219-bD-sl1C-v63 and t219-bD-sl1C-v64. These are different trips. A system that strips or ignores the suffix will merge them by mistake.
Stops in multi-agency feeds. A stop that two agencies both serve appears once for each agency. The copies have the same stop code, name and location but different IDs, such as 1005-a1 and 1005-a2. A trip planner may show both.
Calendar
In a schedule-change merge, the two versions never share a service date. The current version covers every date before the new schedule's start date, and the new version covers the start date onward. In a multi-agency merge, the agencies' schedules run side by side on the same dates.
Service days past midnight. Avail assigns each trip to a service day using the agency's own service-day boundary, not the calendar day. A trip that starts late and runs past midnight belongs to the service date it started on. At a changeover, late-night trips from the old version's last day keep the old version's IDs until they finish.
Service is defined either in calendar_dates.txt alone, which lists every service date, or in calendar.txt with exceptions in calendar_dates.txt. Which one a feed uses varies by agency. Both are valid GTFS.
GTFS-Realtime
Avail's realtime feeds use the same suffixed IDs as the static feed, so they match it directly. Join realtime to static on the full ID, suffix included.
-
Trip IDs:
trip.trip_idin TripUpdates and VehiclePositions carries the full suffix of the version running that service day, for examplet219-bD-sl1C-v64ort2E4-b277C-sl3-v50-a2. -
Stop IDs: in a multi-agency feed, stop references use the agency's stop ID, such as
750-a2. -
Service day:
start_datein TripUpdates is the service day, not the calendar date. It follows the agency's service-day boundary, so overnight trips keep their original date. -
Vehicles: in a multi-agency feed, the vehicle ID carries the agency suffix (
1800-a2) and the label riders see doesn't (1800). -
Alerts: alerts target routes or a whole agency. In a multi-agency feed, each alert names the
agency_idit applies to.
Each feed is served as protobuf from one endpoint. FeedLabel names the feed and FeedType names the message type. A multi-agency feed uses one label for all its agencies.
| Feed type | URL |
|---|---|
| Alerts | http://gtfs-rt.myavail.cloud/GtfsProtoBuf?FeedLabel=<FeedLabel>&FeedType=Alerts |
| TripUpdates | http://gtfs-rt.myavail.cloud/GtfsProtoBuf?FeedLabel=<FeedLabel>&FeedType=TripUpdates |
| VehiclePositions | http://gtfs-rt.myavail.cloud/GtfsProtoBuf?FeedLabel=<FeedLabel>&FeedType=VehiclePositions |
Guidance for consumers
- Keep IDs exactly as published. Never strip or parse the
-vand-asuffixes. - Filter trips by service date, using
calendar.txtandcalendar_dates.txt. A merged feed holds trips that don't run on a given day. - Match realtime to static on the full
trip_idandstop_id, and usestart_datefor the service day. - If you check versions in code, accept hexadecimal (0–9 and A–F).
FAQ
| Question | Answer |
|---|---|
| Why does every trip seem to appear twice? | In a schedule-change merge, the current and the future version of a trip are both in the feed. Each runs only on its own dates. Filter by service date. |
| Why is the feed larger than before? | It holds more than one schedule set, and shapes are included once for each version. |
| Why is the new schedule already in the feed? | That's the point of a schedule-change merge. Trip planners can show the new schedule before it starts. |
| A validator flags trips that look like duplicates. | The IDs are different because of the suffix, and the versions don't share dates. They aren't duplicates. |
| Why does the same stop appear twice? | In a multi-agency feed, each agency publishes its own copy of a stop they share. The copies have different IDs. |
| Why are there several agencies with the same name? | Each part of the operation is published as its own agency in the merged feed. |
Why is there no calendar.txt? |
Some feeds list every service date in calendar_dates.txt instead. Both forms are valid GTFS. |