{
  "openapi": "3.0.3",
  "info": {
    "title": "Transit Departures",
    "version": "1",
    "description": "Departures from the Bay Area Rapid Transit GTFS feed (2026-08-10 through 2027-01-10, America/Los_Angeles). /v1/departures is the static timetable. /v1/realtime and /v1/alerts are the agency GTFS-Realtime feeds, fetched by this service so browsers are not blocked by CORS."
  },
  "servers": [
    {
      "url": "https://transit-departures.over9000.cc",
      "description": "Canonical door"
    }
  ],
  "paths": {
    "/health": {
      "get": {
        "summary": "Liveness",
        "responses": {
          "200": {
            "description": "Health",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                }
              }
            }
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "summary": "This document",
        "responses": {
          "200": {
            "description": "OpenAPI document"
          }
        }
      }
    },
    "/v1": {
      "get": {
        "summary": "API index",
        "responses": {
          "200": {
            "description": "Index",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Index"
                }
              }
            }
          }
        }
      }
    },
    "/v1/feed": {
      "get": {
        "summary": "Bundled feed metadata",
        "responses": {
          "200": {
            "description": "Feed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Feed"
                }
              }
            }
          }
        }
      }
    },
    "/v1/routes": {
      "get": {
        "summary": "All routes",
        "responses": {
          "200": {
            "description": "RouteList",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RouteList"
                }
              }
            }
          }
        }
      }
    },
    "/v1/routes/{route_id}": {
      "get": {
        "summary": "One route",
        "parameters": [
          {
            "name": "route_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "RouteOne",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RouteOne"
                }
              }
            }
          },
          "404": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stops": {
      "get": {
        "summary": "Search stops by name or nearest coordinates",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Case-insensitive match on name, stop code, or id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "lat",
            "in": "query",
            "required": false,
            "description": "With lon, sort by distance.",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "lon",
            "in": "query",
            "required": false,
            "description": "With lat, sort by distance.",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1–100, default 25.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Default 0.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "StopList",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StopList"
                }
              }
            }
          },
          "400": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stops/{stop_id}": {
      "get": {
        "summary": "One stop and the routes that call there",
        "parameters": [
          {
            "name": "stop_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "StopOne",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StopOne"
                }
              }
            }
          },
          "404": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/departures": {
      "get": {
        "summary": "Next departures at a stop",
        "parameters": [
          {
            "name": "stop_id",
            "in": "query",
            "required": true,
            "description": "Stop id from /v1/stops.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "when",
            "in": "query",
            "required": false,
            "description": "ISO time. A Z or numeric offset is absolute. Without a zone, the clock is America/Los_Angeles.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "route_id",
            "in": "query",
            "required": false,
            "description": "Only this route.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1–40, default 10.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "within",
            "in": "query",
            "required": false,
            "description": "Horizon in minutes. Default 2160 (36 hours), max 2880.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Departures",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Departures"
                }
              }
            }
          },
          "400": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/realtime": {
      "get": {
        "summary": "GTFS-Realtime trip updates, decoded to JSON",
        "responses": {
          "200": {
            "description": "Realtime",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Realtime"
                }
              }
            }
          },
          "502": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/alerts": {
      "get": {
        "summary": "GTFS-Realtime service alerts, decoded to JSON",
        "responses": {
          "200": {
            "description": "Alerts",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Alerts"
                }
              }
            }
          },
          "502": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "bad_request",
                  "not_found",
                  "method_not_allowed",
                  "upstream"
                ]
              },
              "message": {
                "type": "string"
              }
            }
          }
        }
      },
      "Health": {
        "type": "object"
      },
      "Index": {
        "type": "object"
      },
      "Feed": {
        "type": "object"
      },
      "Route": {
        "type": "object"
      },
      "RouteList": {
        "type": "object"
      },
      "RouteOne": {
        "type": "object"
      },
      "Stop": {
        "type": "object"
      },
      "StopList": {
        "type": "object"
      },
      "StopOne": {
        "type": "object"
      },
      "Departure": {
        "type": "object",
        "required": [
          "route_id",
          "headsign",
          "departure_at",
          "minutes"
        ],
        "properties": {
          "route_id": {
            "type": "string"
          },
          "route_short_name": {
            "type": "string"
          },
          "headsign": {
            "type": "string"
          },
          "departure_time": {
            "type": "string",
            "description": "Clock time HH:MM:SS in the feed timezone."
          },
          "departure_at": {
            "type": "string",
            "description": "ISO timestamp with numeric offset."
          },
          "trip_id": {
            "type": "string",
            "description": "GTFS trip_id, used to join /v1/realtime."
          },
          "service_date": {
            "type": "string",
            "description": "Service date YYYY-MM-DD. Past-midnight trips keep that date."
          },
          "wait_seconds": {
            "type": "integer"
          },
          "minutes": {
            "type": "integer"
          },
          "mode": {
            "type": "string"
          }
        }
      },
      "Departures": {
        "type": "object"
      },
      "Realtime": {
        "type": "object"
      },
      "Alerts": {
        "type": "object"
      }
    }
  }
}
