Skip to main content

Overview

Get routing options that integrate live bike-share availability. Returns multiple route alternatives:
  • Personal bike: direct cycling route, returned in both the SuperSafe and the direct variant
  • Docked bike-share: walk to station, cycle, then walk to the destination. Pickup and drop-off are always in the same system.
  • Docked e-bike: the same shape, from the nearest station with an e-bike available. Marked is_electric: true.
  • Dockless bike-share: walk to the bike, then cycle to the destination. One option per provider. Marked is_electric: true when the nearest vehicle is electric, which is every Lime and Forest bike.
Behavior:
  • Every response includes both the supersafe: true and supersafe: false personal variants, collapsed to one when they are identical, plus the other option types once at supersafe: true. Filter locally on each option’s supersafe flag; there is no request parameter for it.
  • Alternatives more than 3× slower than the personal bike route are filtered out
  • Bike availability is fetched in real time from bike-share system feeds and provider APIs
  • Assumed speeds: walking 5 km/h, cycling 15 km/h, e-bike 22 km/h
  • Maximum bike/station search radius: 1,500 m
  • Results are ordered Personal (SuperSafe first), then docked, docked e-bike, dockless
Versions are a per-endpoint path segment; this page documents v2 (POST /multi-modal/v2/). See API versioning.

Authentication

This endpoint requires an API key. Include it in the apikey header:
A valid user session is also accepted and grants higher rate limits.

Rate limits

Requests are rate-limited; authenticated requests are allowed a higher rate than anonymous ones. Multi-modal has a stricter limit than directions. On 429, honor the Retry-After header.

Performance

  • Typical response time: 800–1500 ms
  • Routing segments are computed in parallel

Request body

array
required
Starting point as [longitude, latitude]
array
required
Ending point as [longitude, latitude]
string
Identifier of a saved custom route, a UUID string (for example "a3b8c9d0-1e2f-4a5b-8c7d-6e5f4a3b2c1d"). When it resolves to a route, that route is appended as one or more non-reroutable cycling legs — one per stop on the route (see Custom routes) — and its details are returned in each option’s event field.
string
Destination ID for enriched destination information in the response, a UUID string (for example "3f9c6a1e-8b2d-4c5f-9e7a-1d2b3c4d5e6f").
string
Display name for the destination (used if destination_id not provided)
string
Display name for the origin waypoint
string
Planned departure as "YYYY-MM-DDTHH:mm" with no timezone offset, interpreted in the route city’s timezone. Determines night routing (see nighttime) and which temporary road avoidances apply; nearby active or imminent closures are surfaced per option as disruptions. Omit to route for now. Unparseable values return 400.
string
Navigate-to-parking mode: "ebike" (designated rental e-bike bays) or "regular" (cycle racks/stands). The Personal option becomes cycle-to-spot + walk-to-destination, ending at the nearest qualifying spot within 1,500 m of the destination; the spot is returned in parking. If none is found, or the destination borough does not mandate bays for "ebike", the option stays direct with parking: null. Use destination_parking to tell “park anywhere” from “no parking found”. Ignored when a custom route is attached. Other option types are unaffected.
string
Rental e-bike operator (London): "lime" or "forest". Restricts the "ebike" bay search to boroughs the operator serves; when the destination borough isn’t served, the route ends at the nearest bay inside the operator’s area and walks the rest (destination_parking.covered: false).

Response body

string
Unique identifier (UUID) for this request. Include it in support enquiries.
array
Array of route option objects. An empty array with a 200 status means no viable option exists between the requested points; a temporary routing outage returns 503 instead.
object | null
The destination borough’s rental e-bike parking rule. Set on every request whose destination falls inside a bounded area (a London borough), whatever parking_type is, so a rider comparing a rental e-bike option can see the rule they will park under; null elsewhere.
  • ebike_parking_rule: "bay_mandatory" (hires must end in a designated bay) or "free_floating" (park anywhere; render as “park anywhere in area_name”, not an error).
  • With an operator in the request, also carries operator and covered, indicating whether that operator serves the borough.
The response example is captured from a real request. Long arrays in it are abridged with . Each leg’s steps follows the same step shape as a Get directions response.

Variants

With a custom route

JavaScript

Route types

Personal bike

  • Direct cycling route, always first in results, in both the SuperSafe and direct variant
  • With parking_type set: cycle to the returned parking spot, then walk to the destination

Docked bike-share (GBFS/TFL)

  • Walk → cycle station-to-station → walk
  • Included only when suitable stations exist within 1.5 km
  • Omitted when the pickup and drop-off resolve to the same station — there is no bike-share leg to ride. A custom route still allows it, since the route itself is the ride

Docked e-bike

  • Same shape, from the nearest station with an e-bike available; cycling legs use the e-bike speed
  • Marked is_electric: true; name is "{system name} E-bike"

Dockless bike-share

  • Walk to the nearest available bike → cycle to destination, one option per provider
  • Marked is_electric: true when the vehicle is electric; its cycling legs then use the e-bike speed
  • Included only when a bike exists within 1.5 km and is standing inside its operator’s service area. A bike parked outside that area is skipped, because a rental cannot start there

Custom routes

When event_id resolves to a custom route:
  1. All cycling legs route to the custom route’s starting point
  2. Non-reroutable cycling legs are appended for the custom route itself — one leg per stop on the route, so a route with two intermediate stops arrives as three consecutive legs. Each leg ends with an arrive step named after its stop ("Arrive at Look Mum No Hands"); a route with no stops stays a single leg. Sum the non-reroutable legs for the route’s total distance and duration
  3. Custom route details are included in each option’s event field
  4. For docked bike-share, the final walking leg goes to the nearest station to the custom route’s endpoint
Set parking_type to end the personal route at a real parking spot near the destination, with a walking leg the rest of the way. The chosen spot comes back in parking and the cycling leg’s end_label is "Park bike".
destination_parking reports the destination borough’s rule on every request. For "ebike" requests it lets you tell “park anywhere” (free_floating, no bay returned) from “no parking found” (parking: null in a bay_mandatory borough); for other requests it is the rule a dockless e-bike option will end its hire under.

Step semantics

Each leg’s steps follows the same turn-by-turn shape as the directions endpoint:
  • step.distance is the length of the road after the maneuver. To render “in X metres, …”, use the previous step’s distance.
  • step.maneuver.location equals step.geometry.coordinates[0].
  • The final step of every leg is "Arrive at destination".
  • voice_instructions and banner_instructions are generated per leg independently, because every leg ends in its own arrive step.

Error responses

400 Bad request

Out-of-coverage routing carries a machine-readable code and the request’s search_id:

401 Unauthorized

404 Unknown version

Returned for a version sub-path that does not exist (e.g. POST /multi-modal/v3/). See API versioning.

405 Method not allowed

Returned for any HTTP method other than POST.

429 Too many requests

Includes a Retry-After header with the seconds until the current window closes:

500 Internal server error

503 Service unavailable

Routing is temporarily unavailable. This is distinct from a genuine no-route result, which returns 200 with an empty options array. Retry after a short delay.