{
  "openapi": "3.0.3",
  "info": {
    "title": "Transport for London Unified API — DevDocify playground",
    "version": "playground-1.0.0",
    "description": "OpenAPI description for the unauthenticated GET operations used in the DevDocify TfL API playground.\n\n**Scope:** Covers `GET /Line/Mode/{modes}/Status`, `GET /StopPoint/Search/{query}`, `GET /BikePoint`, `GET /AirQuality`, and `GET /Journey/JourneyResults/{from}/to/{to}`. The live TfL Unified API offers many more paths and query options; they are **not** included in this file.\n\n**Audience:** Integrators validating the demo surface, and technical writers maintaining the portal. Prefer this file when you need a single artifact that matches the playground exactly.\n\n**Transport:** HTTPS only (`TLS 1.2+` on `api.tfl.gov.uk`). Responses are UTF-8 JSON unless otherwise negotiated.\n\n**Rate limiting:** Production use may receive `429 Too Many Requests`. Respect `Retry-After` when present and reduce concurrency."
  },
  "servers": [
    {
      "url": "https://api.tfl.gov.uk",
      "description": "TfL Unified API (public)."
    }
  ],
  "tags": [
    {
      "name": "Lines",
      "description": "Line-level status aggregated by mode (for example tube, bus, dlr)."
    },
    {
      "name": "Stop points",
      "description": "Search and resolution of stops and stations."
    },
    {
      "name": "Cycle hire",
      "description": "Santander Cycles (bike point) availability and locations."
    },
    {
      "name": "Air quality",
      "description": "London air quality forecast and index data."
    },
    {
      "name": "Journey",
      "description": "Point-to-point journey planning across all TfL modes."
    }
  ],
  "paths": {
    "/Line/Mode/{modes}/Status": {
      "get": {
        "tags": ["Lines"],
        "summary": "Line status by mode",
        "description": "Returns an array of **line status** objects for every line that belongs to the comma-separated **modes** path segment (for example `tube` for London Underground).\n\nEach item typically includes line identifiers, human-readable names, and `lineStatuses` (disruptions, severity, and reason text). Use the optional `detail` query parameter when you need expanded disruption detail from the upstream API.\n\n**Authentication:** This playground documents anonymous requests only. No API keys or tokens are required for the operations in this file.",
        "operationId": "lineModeStatus",
        "parameters": [
          {
            "name": "modes",
            "in": "path",
            "required": true,
            "description": "One or more mode identifiers, comma-separated (no spaces). Examples: `tube`, `bus`, `dlr`, `overground`, `tram`, `national-rail`.",
            "schema": {
              "type": "string",
              "default": "tube"
            },
            "example": "tube"
          },
          {
            "name": "detail",
            "in": "query",
            "required": false,
            "description": "When `true`, the API returns richer disruption detail where supported.",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "example": false
          }
        ],
        "responses": {
          "200": {
            "description": "Success. JSON array of line status objects.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/TflLineStatus"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request. The `modes` value may be unknown or malformed."
          },
          "404": {
            "description": "No data found for the requested mode combination."
          },
          "429": {
            "description": "Rate limited. Slow down and retry after a delay; respect `Retry-After` when the server sends it."
          },
          "500": {
            "description": "TfL server error. Retry with exponential backoff."
          }
        }
      }
    },
    "/StopPoint/Search/{query}": {
      "get": {
        "tags": ["Stop points"],
        "summary": "Search stops and stations by name",
        "description": "Returns a **search payload** matching the free-text `query` (for example a station name like `waterloo`).\n\nTypical matches include stop point identifiers, display names, modes served, and coordinates. Exact JSON shape is defined by the live API; consumers should tolerate additional properties.\n\n**Tip:** Combine with journey planning by taking `id` or `icsCode` from a match and using it as an endpoint in other TfL journey APIs (outside this playground spec).",
        "operationId": "stopPointSearch",
        "parameters": [
          {
            "name": "query",
            "in": "path",
            "required": true,
            "description": "Case-insensitive search string (URL-encoded when special characters appear).",
            "schema": {
              "type": "string",
              "default": "waterloo"
            },
            "example": "waterloo"
          }
        ],
        "responses": {
          "200": {
            "description": "Success. JSON object containing matches and metadata (structure varies; see live response).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TflSearchResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request. The query may be empty or invalid after decoding."
          },
          "404": {
            "description": "No stop points matched the query."
          },
          "429": {
            "description": "Rate limited."
          },
          "500": {
            "description": "Server error."
          }
        }
      }
    },
    "/BikePoint": {
      "get": {
        "tags": ["Cycle hire"],
        "summary": "List bike point locations",
        "description": "Returns an array of **bike points** (Santander Cycles docking stations) with availability and geographic data.\n\nUse this operation to populate maps or dashboards without specifying a search term. For a single dock, other TfL paths exist on the full API (not included in this subset).\n\n**Data freshness:** Availability counts change frequently; treat responses as point-in-time.",
        "operationId": "bikePointList",
        "responses": {
          "200": {
            "description": "Success. JSON array of bike point objects.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/TflBikePoint"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited."
          },
          "500": {
            "description": "Server error."
          }
        }
      }
    },
    "/AirQuality": {
      "get": {
        "tags": ["Air quality"],
        "summary": "London air quality forecast",
        "description": "Returns the current **air quality forecast** for London, including pollution index levels and health advice for sensitive groups.\n\nThe response includes today's and tomorrow's forecast broken down by pollutant (nitrogen dioxide, ozone, PM2.5, PM10). No parameters are required.\n\n**Authentication:** Anonymous request — no API key needed.",
        "operationId": "airQuality",
        "responses": {
          "200": {
            "description": "Success. JSON object containing current and forecast air quality data.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TflAirQuality"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Respect `Retry-After` when present."
          },
          "500": {
            "description": "Server error."
          }
        }
      }
    },
    "/Journey/JourneyResults/{from}/to/{to}": {
      "get": {
        "tags": ["Journey"],
        "summary": "Plan a journey between two points",
        "description": "Returns a set of **journey options** between `from` and `to`, covering all available TfL modes (tube, bus, Overground, DLR, Elizabeth line, and more).\n\n`from` and `to` can be:\n- A stop point ID (for example `1000032` for King's Cross St. Pancras)\n- A postcode (for example `SW1A2AA`)\n- A free-text location name (resolved by TfL)\n\nEach journey option includes legs, durations, departure/arrival times, and line information.\n\n**Authentication:** Anonymous request — no API key needed for the playground.",
        "operationId": "journeyResults",
        "parameters": [
          {
            "name": "from",
            "in": "path",
            "required": true,
            "description": "Origin — stop point ID, postcode, or place name.",
            "schema": {
              "type": "string",
              "default": "1000032"
            },
            "example": "1000032"
          },
          {
            "name": "to",
            "in": "path",
            "required": true,
            "description": "Destination — stop point ID, postcode, or place name.",
            "schema": {
              "type": "string",
              "default": "1000123"
            },
            "example": "1000123"
          },
          {
            "name": "mode",
            "in": "query",
            "required": false,
            "description": "Comma-separated list of modes to include (for example `tube,bus`). Omit to allow all modes.",
            "schema": {
              "type": "string"
            },
            "example": "tube"
          },
          {
            "name": "timeIs",
            "in": "query",
            "required": false,
            "description": "Whether `time` represents departure or arrival. Defaults to `Departing`.",
            "schema": {
              "type": "string",
              "enum": ["Departing", "Arriving"],
              "default": "Departing"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. JSON object containing an array of journey options with legs, durations, and line details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TflJourneyResult"
                }
              }
            }
          },
          "300": {
            "description": "Disambiguation required. `from` or `to` matched multiple locations — the response body lists candidates to choose from."
          },
          "400": {
            "description": "Bad request. `from` or `to` could not be resolved."
          },
          "429": {
            "description": "Rate limited."
          },
          "500": {
            "description": "Server error."
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "TflLineStatus": {
        "type": "object",
        "description": "Line with nested status and disruption information (subset of fields; additional properties allowed).",
        "additionalProperties": true,
        "properties": {
          "id": {
            "type": "string",
            "description": "Stable line identifier."
          },
          "name": {
            "type": "string",
            "description": "Human-readable line name."
          },
          "modeName": {
            "type": "string",
            "description": "Mode label (for example tube, dlr)."
          },
          "created": {
            "type": "string",
            "description": "Timestamp associated with the status payload (format as returned by API)."
          },
          "lineStatuses": {
            "type": "array",
            "description": "List of status and disruption entries.",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        }
      },
      "TflSearchResponse": {
        "type": "object",
        "description": "Wrapper for stop search results; fields vary. Always parse defensively.",
        "additionalProperties": true,
        "properties": {
          "matches": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "query": {
            "type": "string"
          },
          "total": {
            "type": "integer"
          }
        }
      },
      "TflBikePoint": {
        "type": "object",
        "description": "Cycle hire docking station. Property names often include `id`, `commonName`, `lat`, `lon`, and `additionalProperties` for bays and bikes.",
        "additionalProperties": true,
        "properties": {
          "id": {
            "type": "string"
          },
          "commonName": {
            "type": "string"
          },
          "lat": {
            "type": "number",
            "format": "double"
          },
          "lon": {
            "type": "number",
            "format": "double"
          }
        }
      },
      "TflAirQuality": {
        "type": "object",
        "description": "Air quality forecast for London. Additional properties allowed — parse defensively.",
        "additionalProperties": true,
        "properties": {
          "updatePeriod": {
            "type": "string",
            "description": "How frequently the forecast is updated."
          },
          "updateFrequency": {
            "type": "string"
          },
          "forecastURL": {
            "type": "string",
            "format": "uri",
            "description": "Link to the detailed forecast page."
          },
          "currentForecast": {
            "type": "array",
            "description": "Array of forecast periods (today, tomorrow, etc.).",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        }
      },
      "TflJourneyResult": {
        "type": "object",
        "description": "Journey planner result containing one or more route options. Additional properties allowed.",
        "additionalProperties": true,
        "properties": {
          "journeys": {
            "type": "array",
            "description": "Array of journey options, each with legs, duration, and line details.",
            "items": {
              "type": "object",
              "additionalProperties": true,
              "properties": {
                "startDateTime": { "type": "string" },
                "arrivalDateTime": { "type": "string" },
                "duration": { "type": "integer", "description": "Total journey time in minutes." },
                "legs": {
                  "type": "array",
                  "items": { "type": "object", "additionalProperties": true }
                }
              }
            }
          }
        }
      }
    }
  }
}
