Route clustering

Group nearby stops into compact clusters, so each driver, vehicle or day gets its own area. Send a list of stops or select your POIs with the same filters as listing POIs.

How it works

Lanewise groups the stops by straight-line distance with k-means, starting from well-spread centers. You choose either how many clusters you want (clusters) or the most stops a cluster can hold (max_stops, and Lanewise uses the fewest clusters that fit them). With balanced, clusters are equal in size: they differ by at most one stop.

  • The result is deterministic: the same stops, in the same order, always give the same clusters.
  • Clustering does not use the road network, so it is always available and fast, even for thousands of stops. To order the stops of a cluster, send them to delivery optimization.
  • Stops at the same position can leave a cluster empty; empty clusters are dropped, so you can get fewer than you asked for.

Clustering requires the plan-routes permission. When a stop is a POI or you send pois, the key also needs read-pois. Each call counts as one request towards your rate limit.

Limits

  • Name
    Stops
    Description

    Up to 2,000 per request, as a list or as a POI selection. A selection matching more POIs returns a 422.

  • Name
    Clusters
    Description

    Between 1 and 100, and no more than the number of stops.


POST/v1/routes/clusters

Cluster stops

Group the stops into clusters. Send either stops or pois, and either clusters or max_stops. Requires the plan-routes permission, plus read-pois when you use POIs.

Attributes

  • Name
    stops
    Type
    array
    Description

    Up to 2,000 locations. Each is { "latitude", "longitude" } or { "poi_id" }, with an optional id of yours (up to 100 characters, unique) that is echoed back.

  • Name
    pois
    Type
    object
    Description

    Your POIs to cluster instead of stops, selected with attributes, category_id or category_name, latitude/longitude/distance, country_id/city_id/zipcode_id and poi_ids, as in avoid POIs. All filters combine; {} selects all your POIs.

  • Name
    clusters
    Type
    integer
    Description

    Number of clusters, between 1 and 100.

  • Name
    max_stops
    Type
    integer
    Description

    Most stops per cluster. The number of clusters is the fewest that hold every stop.

  • Name
    balanced
    Type
    boolean
    Description

    Make the clusters equal in size. Defaults to false.

Request

POST
/v1/routes/clusters
curl https://api.lanewise.app/v1/routes/clusters \
  -H "X-API-KEY: {YOUR_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "stops": [
      { "id": "order-1", "latitude": 41.3870, "longitude": 2.1701 },
      { "id": "order-2", "latitude": 41.4036, "longitude": 2.1744 },
      { "id": "order-3", "poi_id": "01JGZ8Q3N5T9B2C4D6F8H0K2M4" }
    ],
    "clusters": 2,
    "balanced": true
  }'

Response

{
  "data": {
    "summary": {
      "stops": 3,
      "clusters": 2,
      "balanced": true,
      "max_stops": 2
    },
    "clusters": [
      {
        "id": 1,
        "centroid": { "latitude": 41.40905, "longitude": 2.16355 },
        "count": 2,
        "radius": 1089.1,
        "stops": [
          { "index": 1, "id": "order-2", "poi_id": null, "latitude": 41.4036, "longitude": 2.1744 },
          {
            "index": 2,
            "id": "order-3",
            "poi_id": "01JGZ8Q3N5T9B2C4D6F8H0K2M4",
            "latitude": 41.4145,
            "longitude": 2.1527
          }
        ]
      },
      {
        "id": 2,
        "centroid": { "latitude": 41.387, "longitude": 2.1701 },
        "count": 1,
        "radius": 0,
        "stops": [
          { "index": 0, "id": "order-1", "poi_id": null, "latitude": 41.387, "longitude": 2.1701 }
        ]
      }
    ]
  }
}

Response

  • Name
    summary
    Type
    object
    Description

    stops clustered, clusters returned, whether balanced was requested, and max_stops: the most stops a cluster can hold (your max_stops, or the balanced size), or null when sizes are not capped.

  • Name
    clusters[].id
    Type
    integer
    Description

    Number of the cluster, from 1.

  • Name
    clusters[].centroid
    Type
    object
    Description

    Center of the cluster: the mean latitude and longitude of its stops.

  • Name
    clusters[].count
    Type
    integer
    Description

    Number of stops in the cluster.

  • Name
    clusters[].radius
    Type
    float
    Description

    Straight-line distance in meters from the centroid to the farthest stop.

  • Name
    clusters[].stops
    Type
    array
    Description

    The stops of the cluster: index (position in your stops, or in the POI selection sorted by ID), your id, poi_id, latitude and longitude.