> ## Documentation Index
> Fetch the complete documentation index at: https://docs.justrouting.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# Directions

> Get road-following routes between coordinates — distance, duration, geometry, and turn-by-turn steps.

## Overview

Directions API returns the real road route between two points (or ordered waypoints): distance (meters), estimated duration (seconds), route geometry (polyline or GeoJSON), and optional turn-by-turn steps.

<Tip>
  **Want to try it first?** Open the [Live Demo](https://justrouting.tech) and drag the A/B markers on the map.
</Tip>

## Endpoint

```
GET https://api.justrouting.tech/route/v1/{profile}/{coordinates}
```

| URL parameter | Description |
| - | - |
| `profile` | `driving` (car) or `motorcycle` |
| `coordinates` | `{lng},{lat};{lng},{lat}[;...]`, visited in order, up to 100 |

## Quickstart

<CodeGroup>
  ```bash curl theme={null}
  curl "https://api.justrouting.tech/route/v1/driving/103.708362,1.357371;103.984748,1.352212?overview=full&steps=true" \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```python Python theme={null}
  import justrouting

  client = justrouting.Client("YOUR_API_KEY")

  route = client.routes.get(justrouting.RouteRequest(
      origin=[103.708362, 1.357371],
      destination=[103.984748, 1.352212],
      steps=True,
  ))

  print(f"{route.distance / 1000:.1f} km, {route.duration / 60:.0f} min")
  ```

  ```ts JavaScript theme={null}
  import { Client } from '@justrouting/client';

  const client = new Client("YOUR_API_KEY");

  const route = await client.routes.get({
    origin: [103.708362, 1.357371],
    destination: [103.984748, 1.352212],
    steps: true,
  });

  console.log(`${(route.distance / 1000).toFixed(1)} km, ${Math.round(route.duration / 60)} min`);
  ```

  ```go Go theme={null}
  route, err := client.Routes.Get(ctx, &justrouting.RouteRequest{
      Origin:      []float64{103.708362, 1.357371},
      Destination: []float64{103.984748, 1.352212},
      Steps:       true,
  })
  ```
</CodeGroup>

## Request Parameters

### Service options

| Parameter | Type | Default | Description |
| - | - | - | - |
| `overview` | string | `simplified` | `full` (full geometry) / `simplified` (display-precision geometry) / `false` (no geometry) / `by_legs` (geometry split by leg) |
| `steps` | bool | `false` | Return per-leg turn instructions (see [Turn-by-Turn](/guides/turn-by-turn)) |
| `alternatives` | bool/int | `false` | Alternative routes; `alternatives=2` requests up to 2 (not guaranteed) |
| `geometries` | string | `polyline` | `polyline` / `polyline6` / `geojson` |
| `annotations` | string | `false` | Per-coordinate metadata along the route geometry: `true`, or a comma-separated list of `nodes`, `distance`, `duration`, `datasources`, `weight`, `speed` |
| `continue_straight` | string | `default` | Force straight continuation at waypoints, constraining U-turns there even if it would be faster; default depends on the profile |
| `waypoints` | string | — | Indices of input coordinates to treat as waypoints in the response, e.g. `0;3`. Default is to treat all input coordinates as waypoints |

### General options

These options apply to all routing services. Options that take one value per coordinate use the array-like encoding `{option}={element};{element}[;...]` — the number of elements must match the number of coordinates (except `generate_hints` and `exclude`). Pass an empty element to use the default for that coordinate, e.g. `bearings=;90,20;`.

| Parameter | Type | Default | Description |
| - | - | - | - |
| `bearings` | string | — | Limit snapping to segments with the given bearing; each element is `{value},{range}` with value 0–360° clockwise from true north and range 0–180° |
| `radiuses` | string | — | Limit snapping to the given radius in meters per coordinate, `unlimited` for no limit |
| `generate_hints` | bool | `true` | Add a `hint` to each response waypoint for reuse in later requests via `hints` |
| `hints` | string | — | Base64 `hint` from a previous response; speeds up snapping significantly |
| `approaches` | string | — | Restrict the road direction at a waypoint; per element `curb` / `opposite` / `unrestricted` (default) |
| `exclude` | string | — | Additive list of road classes to avoid, e.g. `exclude=motorway` |
| `snapping` | string | `default` | `any` snaps to any edge in the graph; `default` avoids edges that cannot be used as start/end points |
| `skip_waypoints` | bool | `false` | Remove waypoints from the response (they are still calculated, just not serialized) |

### Examples

<Tabs>
  <Tab title="Waypoints (multi-stop)">
    ```bash theme={null}
    # A → B → C, in order
    curl "https://api.justrouting.tech/route/v1/driving/103.708362,1.357371;103.8514,1.2897;103.984748,1.352212" \
      -H "Authorization: Bearer YOUR_API_KEY"
    ```
  </Tab>

  <Tab title="Avoid motorways">
    ```bash theme={null}
    curl "https://api.justrouting.tech/route/v1/driving/103.708362,1.357371;103.984748,1.352212?exclude=motorway" \
      -H "Authorization: Bearer YOUR_API_KEY"
    ```
  </Tab>

  <Tab title="GeoJSON geometry">
    ```bash theme={null}
    curl "https://api.justrouting.tech/route/v1/driving/103.708362,1.357371;103.984748,1.352212?geometries=geojson&overview=full" \
      -H "Authorization: Bearer YOUR_API_KEY"
    ```
  </Tab>
</Tabs>

## Response

```json response-example.json theme={null}
{
  "code": "Ok",
  "data_version": "2025-06-01T21:43:02Z",
  "routes": [
    {
      "legs": [
        {
          "steps": [],
          "weight": 2222.6,
          "summary": "",
          "duration": 2225.6,
          "distance": 36911.2
        }
      ],
      "weight_name": "routability",
      "geometry": "_bhGmo~wRPMNKNIXQvHsErAw@...",
      "distance": 36911.2,
      "duration": 2225.6
    }
  ],
  "waypoints": [
    { "name": "", "location": [103.708362, 1.357371] },
    { "name": "", "location": [103.984748, 1.352212] }
  ]
}
```

### Response fields

| Field | Type | Unit | Description |
| - | - | - | - |
| `code` | string | — | `Ok` on success; see [Errors](/errors) otherwise |
| `data_version` | string | — | Timestamp of the OpenStreetMap data used (optional) |
| `routes` | array | — | Alternative routes, best first |
| `routes[].distance` | float | **meters** | Total route distance |
| `routes[].duration` | float | **seconds** | Estimated travel time |
| `routes[].weight` | float | — | Routing weight (engine-internal; usually equals duration) |
| `routes[].weight_name` | string | — | Name of the weight profile used during extraction |
| `routes[].geometry` | string | — | Encoded polyline (precision 5) that decodes to `[lat, lng]` pairs; with `geometries=geojson` this is a GeoJSON LineString |
| `routes[].legs` | array | — | One entry per waypoint pair; contains steps when `steps=true` |
| `routes[].legs[].summary` | string | — | Names of the two major roads used (with `steps=true`, else empty) |
| `routes[].legs[].annotation` | object | — | Per-coordinate metadata when `annotations` is set; see the Annotation object below |
| `routes[].legs[].steps[]` | array | — | Turn instructions with `maneuver` (direction), `name` (street name), `distance`, `duration` |
| `waypoints[]` | array | — | Each input coordinate snapped to the road network; `distance` is the snap offset in meters, `hint` is reusable via the `hints` parameter |

<Accordion title="Decoding geometry">
  Precision-5 polyline — decodable with any `polyline` library:

  ```python theme={null}
  import polyline
  coords = polyline.decode(route["geometry"])  # -> [(lat, lng), ...]
  ```

  ```js theme={null}
  import polyline from '@mapbox/polyline';
  const coords = polyline.decode(route.geometry); // -> [[lat, lng], ...]
  ```

  Note the decoded pairs are `[lat, lng]` — the opposite order of the `lng,lat` request input.
</Accordion>

<Accordion title="Annotation object">
  When `annotations` is requested, each leg gets an `annotation` object with arrays aligned to the route geometry coordinates:

  | Field | Description |
  | - | - |
  | `distance` | Distance between each pair of coordinates, in **meters** |
  | `duration` | Duration between each pair of coordinates, in **seconds** (excludes turn costs) |
  | `weight` | Routing weight between each pair of coordinates (excludes turn costs) |
  | `speed` | Convenience field: `distance / duration` rounded to one decimal place |
  | `nodes` | OSM node id of each coordinate along the route |
  | `datasources` | Index of the speed source for each segment (`0` = the profile); names are in `metadata.datasource_names` |

  ```json theme={null}
  {
    "distance": [5, 5, 10, 5, 5],
    "duration": [15, 15, 40, 15, 15],
    "weight": [15, 15, 40, 15, 15],
    "speed": [0.3, 0.3, 0.3, 0.3, 0.3],
    "nodes": [49772551, 49772552, 49786799, 49786800, 49786801, 49786802],
    "datasources": [1, 0, 0, 0, 1],
    "metadata": { "datasource_names": ["traffic", "lua profile", "lua profile", "lua profile", "traffic"] }
  }
  ```
</Accordion>

<Info>
  Coordinates use `lng,lat` order, and all coordinates in one request **must be in the same country**. See [Coverage](/coverage).
</Info>

## Errors

| HTTP | code | Meaning |
| - | - | - |
| 401 | — | Authentication failed (`error` field in the body), see [Authentication](/authentication) |
| 400 | `NoRoute` | No route between the points |
| 400 | `NoSegment` | A coordinate could not be snapped to a road |
| 400 | `TooBig` | More than 100 coordinates |
| 429 | `rate_limited` | Quota exceeded, see [Rate Limits](/rate-limits) |

## Recipes

* **Draw a line**: `geometries=geojson` + [Draw a Route on a Map](/guides/draw-route-on-map)
* **Navigation**: `steps=true` + [Turn-by-Turn Navigation](/guides/turn-by-turn)
* **Multi-stop ordering**: route 3+ waypoints in order, or let [Fleet Optimization](/api-reference/fleet-optimization) solve the optimal sequence

## Related

<CardGroup cols={3}>
  <Card title="Distance Matrix" icon="table" href="/api-reference/distance-matrix">
    Travel time and distance between many points in one call
  </Card>

  <Card title="Fleet Optimization" icon="truck" href="/api-reference/fleet-optimization">
    VROOM vehicle routing with time windows and capacity
  </Card>

  <Card title="Map Matching" icon="crosshair" href="/api-reference/map-matching">
    Snap GPS traces to real roads
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.