API reference

Every endpoint TransCAPI exposes, with its parameters and response shape. For a runnable, always-current version of this generated from the server itself, see the OpenAPI document and the Swagger UI.

Conventions

Base URLhttps://api.transcapi.com
AuthX-Api-Key header, or api_key query parameter. See authentication.
FormatJSON. All endpoints are GET.
TimestampsISO 8601 with offset, e.g. 2026-08-05T16:41:00+01:00.
CoordinatesWGS84 decimal degrees.
Rate limitsPer key, per minute, by tier. See rate limits.

List endpoints share a pagination envelope: page, limit, results_count and a member array of results. Pass page and limit to page through. Every response carries a request_time.

Errors use a consistent envelope and an HTTP status to match:

{ "error": { "code": "missing_api_key", "message": "Missing API key. ..." } }

See error codes for the full list.


Places

GET /v1/places.json

Search stops, settlements, postcodes and addresses across Great Britain. Combines NaPTAN stop data with geocoding. Supply a query, a lat/lon, or a bounding box.

ParameterDefaultDescription
queryFree-text search term.
typeallRepeatable. One of bus_stop, train_station, tram_stop, settlement, postcode.
lat, lonBias and sort results by distance from this point.
min_lat, min_lon, max_lat, max_lonBounding box. All four required together.
limit201–100.
page1
{
  "request_time": "2026-08-05T15:40:05Z",
  "query": "Sheffield",
  "page": 1, "limit": 1, "results_count": 1,
  "member": [
    {
      "type": "bus_stop",
      "name": "Airport Access Road/Hurst Lane",
      "description": "Doncaster Sheffield Airport",
      "latitude": 53.484269965,
      "longitude": -1.026033473,
      "atcocode": "370046721"
    }
  ]
}

distance (metres) is included on each result when lat/lon is supplied, and omitted otherwise.


Bus

GET /v1/bus/stops.json

Find bus, tram and rail stops near a point or within a bounding box. Nationwide, backed by NaPTAN.

ParameterDefaultDescription
lat, lonCentre point for a radius search.
radius400Metres from lat/lon.
min_lat, min_lon, max_lat, max_lonBounding box instead of a radius.
typeallRepeatable stop type filter.
limit20
page1
{
  "member": [
    {
      "type": "bus_stop",
      "atcocode": "370027633",
      "naptan_code": "37027633",
      "name": "Leopold Street/Orchard Lane",
      "short_name": "Leopold Street",
      "indicator": "27633",
      "street": "Leopold Street",
      "locality": "Sheffield Centre",
      "town": "Sheffield",
      "latitude": 53.381315404,
      "longitude": -1.470926487,
      "distance": 59.8
    }
  ]
}

GET /v1/bus/stop_timetables/{atcocode}.json

Departures for a stop, combining the scheduled timetable with live BODS SIRI-VM vehicle positions.

ParameterDefaultDescription
atcocoderequiredIn the path. NaPTAN ATCO code, e.g. 370023169.
datetimenowISO 8601 anchor for the departure window.
from_offset0Window start, minutes relative to datetime.
to_offset60Window end, minutes.
livefalseMatch live vehicles onto departures.
limit20
{
  "atcocode": "370023169",
  "live_requested": true,
  "live_error": null,
  "departures": [
    {
      "line": "X1",
      "line_name": "X1",
      "operator": "First South Yorkshire",
      "destination": "Maltby",
      "direction": 0,
      "mode": "bus",
      "aimed_departure_time":    "2026-08-05T15:41:00+00:00",
      "expected_departure_time": "2026-08-05T15:41:00+00:00",
      "best_departure_estimate": "2026-08-05T15:41:00+00:00",
      "status": "on_time",
      "source": "siri_vm",
      "dated_vehicle_journey_ref": "VJfde1c8a6f4a5b81dfb398429a6ef7793",
      "live_vehicle": {
        "vehicle_ref": "FSYO-35126",
        "operator_ref": "FSYO",
        "latitude": 53.376426,
        "longitude": -1.471027,
        "bearing": "28",
        "destination_name": "Quilter_Road",
        "recorded_at_time": "2026-08-05T15:39:49+00:00"
      }
    }
  ]
}

Use best_departure_estimate when you want a single time to display: it is the live estimate where one exists and the timetabled time otherwise. source tells you which you got — siri_vm for live, gtfs_scheduled for timetable. live_vehicle is null on departures with no vehicle matched, and live_error is non-null if the live feed itself failed, so a feed outage is distinguishable from a quiet stop.


Rail

GET /v1/rail/stations.json

Find rail stations near a point or within a bounding box. Covers all of Great Britain (~2,600 stations). Stations are keyed by 3-letter CRS code.

ParameterDefaultDescription
lat, lonCentre point.
radius5000Metres.
min_lat, min_lon, max_lat, max_lonBounding box instead of a radius.
limit20
page1
{
  "member": [
    { "crs_code": "SHF", "name": "Sheffield",
      "latitude": 53.3782362148, "longitude": -1.4621101656, "distance": 558.9 }
  ]
}

GET /v1/rail/station_timetables/{crs_code}.json

Scheduled departures for a station.

ParameterDefaultDescription
crs_coderequiredIn the path, e.g. LDS.
datetimenowISO 8601 anchor for the window.
from_offset0Minutes.
to_offset60Minutes.
limit20
{
  "crs_code": "LDS",
  "station": { "crs_code": "LDS", "name": "Leeds",
               "latitude": 53.7956409037, "longitude": -1.5480300934 },
  "departures": [
    { "line": "NT", "line_name": "Northern", "operator": "Northern",
      "destination": "Bradford Forster Square", "mode": "rail",
      "aimed_departure_time": "2026-08-05T15:42:00+00:00",
      "status": "on_time", "source": "gtfs_scheduled" }
  ]
}

Rail is scheduled-timetable data only — there is no live rail feed integrated yet, so source is always gtfs_scheduled and there is no live parameter. Unlike bus, which does have live matching.


Journey planning

GET /v1/journey.json

Plan a door-to-door journey between two coordinates, with fare estimates and live vehicle positions. Covers South and West Yorkshire only, unlike the endpoints above — see the journey planning docs for the full detail on fares, live data and coverage.

ParameterDefaultDescription
from_lat, from_lonrequiredOrigin.
to_lat, to_lonrequiredDestination.
datetimenowDeparture, or arrival when arrive_by=true.
arrive_byfalse
transit_modestram,railOptional sub-modes. Bus and coach always searched.
modeswalk,bicycleNon-transit alternatives.
include_farestrue
include_livetrue
include_intermediate_stopsfalse
max_walk_distanceMetres. Caps the longest single walking leg.
max_total_walk_distanceMetres. Caps total walking across the journey.
include_stepsfalseTurn-by-turn directions on walking legs.
limit51–20.
{
  "coverage": { "area": "South and West Yorkshire",
                "bbox": [53.2989, -2.1755, 53.9649, -0.8529] },
  "next_available": false,
  "itineraries": [
    {
      "start_time": "2026-08-05T16:36:36+01:00",
      "end_time":   "2026-08-05T17:09:14+01:00",
      "duration_s": 1958.0,
      "fare": { "amount_gbp": 2.80, "complete": true },
      "legs": [ /* see journey planning docs */ ]
    }
  ],
  "alternatives": { "walk": { "itineraries": [] },
                    "bicycle": { "itineraries": [] } }
}

An origin or destination outside the covered area returns 422 outside_coverage rather than an empty list, so "we don't plan here yet" is distinguishable from "no journeys found".


Disruptions

GET /v1/disruptions.json

Planned works, incidents and line status, merging the national BODS SIRI-SX situation feed with TfL's line status. See the disruptions docs for the response shape and the caveats on matching a situation to a service.

ParameterDefaultDescription
modeallbus, tram, rail, tube, dlr, overground, elizabeth-line.
severityallsevere, minor, information, good, unknown.
atcocodeOnly situations naming this stop.
operator, lineSubstring match.
lat, lon, radius2000 mMax 50000. Both lat and lon, or neither.
min_lat, min_lon, max_lat, max_lonBounding box instead of a radius.
pathEncoded polyline (precision 5). Only situations naming a stop near it, matched on their complete stop list.
path_radius300 mHow far off the path a stop may be. Maximum 5000.
plannedbothtrue for works only, false for incidents only.
active_onlytrueExclude situations outside their validity period.
include_good_servicefalseInclude healthy TfL lines.
limit, page50Maximum 100 per page.

Ordered most disruptive first, then most recently raised. Only situations naming a stop with coordinates can match a geographic query. National Rail engineering works are not covered.


Service

GET /health

Unauthenticated liveness check. Returns {"status": "ok"}.

GET /openapi.json

The OpenAPI 3.0 document for this API, generated from the running server. Unauthenticated.