Migration from Azure Maps Route API 1.0 to 2025-01-01 – Waypoint Limit Reduced

Nilesh Khonde 85 Reputation points
2025-04-02T12:57:25.44+00:00

We are currently migrating from the Azure Maps Route API (version 1.0) to the latest version (2025-01-01). However, we have encountered a significant limitation regarding waypoints:

In API version 1.0, we were able to add up to 150 waypoints in a single route request.

In API version 2025-01-01, the maximum number of waypoints is now limited to 25 (except for truck routes, which still support up to 150 waypoints).

This change is impacting our implementation, as we rely on routing with up to 150 waypoints, which is critical for our use case

  1. Is there an alternative approach or workaround to support more than 25 waypoints in the latest API version?
  2. Can we continue using API version 1.0 as a temporary solution, or is there a deprecation deadline that we should be aware of?
  3. Are there any recommendations from Microsoft for handling complex routes that exceed the new waypoint limit?

Reference Links:

Azure Maps Route API (1.0) – Deprecated

Azure Maps Route API (2025-01-01)

Any guidance on how to handle this limitation would be greatly appreciated!

Is there an alternative approach or workaround to support more than 25 waypoints in the latest API version?

Can we continue using API version 1.0 as a temporary solution, or is there a deprecation deadline that we should be aware of?

Are there any recommendations from Microsoft for handling complex routes that exceed the new waypoint limit?

Reference Links:

Azure Maps Route API (1.0) – Deprecated

Azure Maps Route API (2025-01-01)

Any guidance on how to handle this limitation would be greatly appreciated!

here is the sample code which I am using with latest Api


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Azure Maps Route API</title>
    <script src="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.js"></script>
    <link rel="stylesheet" href="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.css">
    <style>
        body {
            font-family: Arial, sans-serif;
            text-align: center;
            margin: 20px;
        }
        #map {
            width: 100%;
            height: 600px;
            margin-top: 20px;
            border: 2px solid #ccc;
            border-radius: 10px;
        }
        button {
            padding: 10px 20px;
            font-size: 16px;
            background-color: #0078D4;
            color: white;
            border: none;
            cursor: pointer;
            border-radius: 5px;
        }
        button:hover {
            background-color: #005A9E;
        }
    </style>
</head>
<body>
    <h2>Azure Maps Route API - New York State</h2>
    <button onclick="getRoute()">Get Route</button>
    <div id="map"></div>

    <script>
        const subscriptionKey = "Your_Azure_Maps_Subscription_Key"; // Replace with your Azure Maps subscription key
        
        let map = new atlas.Map("map", {
            center: [-75.5, 42.9], // Centered in New York State
            zoom: 7,
            view: "Auto",
            authOptions: {
                authType: "subscriptionKey",
                subscriptionKey: subscriptionKey
            }
        });

        async function getRoute() {
            const url = "https://atlas.microsoft.com/route/directions?api-version=2025-01-01";
            
            // 26 waypoints within New York State
            const waypoints = [
                [-74.006, 40.7128], [-73.9352, 40.7306], [-73.9808, 40.7648], [-73.9982, 40.7265], 
                [-74.0355, 40.7282], [-74.0589, 40.7458], [-74.0781, 40.7608], [-74.1211, 40.8362], 
                [-74.1686, 40.8471], [-74.1915, 40.8598], [-74.2003, 40.8798], [-74.2131, 40.8952], 
                [-74.2331, 40.9108], [-74.2525, 40.9202], [-74.2728, 40.9328], [-74.3002, 40.9501], 
                [-74.3282, 40.9608], [-74.3525, 40.9705], [-74.3811, 40.9801], [-74.4005, 40.9902], 
                [-74.4258, 41.0001], [-74.4505, 41.0108], [-74.4752, 41.0205], [-74.4982, 41.0301], 
                [-74.5202, 41.0408], [-74.3122, 40.967]
            ];

            try {
                const response = await fetch(url, {
                    method: "POST",
                    headers: {
                        "Content-Type": "application/json",
                        "Subscription-Key": subscriptionKey
                    },
                    body: JSON.stringify({
                        "type": "FeatureCollection",
                        "features": waypoints.map((coords, index) => ({
                            "type": "Feature",
                            "geometry": { "coordinates": coords, "type": "Point" },
                            "properties": { "pointIndex": index, "pointType": "waypoint" }
                        }))
                    })
                });

                if (!response.ok) {
                    throw new Error(`HTTP error! Status: ${response.status} - ${await response.text()}`);
                }

                const data = await response.json();
                
                if (data.features && data.features.length > 0) {
                    const dataSource = new atlas.source.DataSource();
                    map.sources.add(dataSource);
                    
                    // Add route line
                    dataSource.add(new atlas.data.LineString(waypoints));
                    map.layers.add(new atlas.layer.LineLayer(dataSource, null, {
                        strokeColor: "red",
                        strokeWidth: 3
                    }));

                    // Add waypoints as markers with labels A, B, C...
                    waypoints.forEach((coord, index) => {
                        dataSource.add(new atlas.data.Feature(new atlas.data.Point(coord), {
                            label: String.fromCharCode(65 + index) // Converts 0 → 'A', 1 → 'B', etc.
                        }));
                    });

                    // Add custom marker icon
                    map.imageSprite.add("marker_icon", "<svg xmlns='http://www.w3.org/2000/svg' width='26' height='28' viewBox='-4 0 36 36'><g fill='none' fill-rule='evenodd'><path d='M14 0c7.732 0 14 5.641 14 12.6C28 23.963 14 36 14 36S0 24.064 0 12.6C0 5.641 6.268 0 14 0Z' fill='#fff' stroke='#000' stroke-width='1'/><circle fill='dodgerblue' fill-rule='nonzero' cx='14' cy='14' r='10' /></g></svg>");

                    // Add SymbolLayer for displaying markers with labels
                    map.layers.add(new atlas.layer.SymbolLayer(dataSource, null, {
                        iconOptions: {
                            image: "marker_icon",
                            anchor: "center",
                            allowOverlap: true,
                            ignorePlacement: true
                        },
                        textOptions: {
                            textField: ["get", "label"], // Get waypoint label from properties
                            color: "black",
                            offset: [0, 1.2], // Adjust label position
                            font: ["StandardFont-Bold"],
                            allowOverlap: true
                        }
                    }));

                    // Adjust map view to fit the route
                    map.setCamera({ bounds: atlas.data.BoundingBox.fromData(waypoints), padding: 50 });
                } else {
                    console.error("No route data returned.");
                    alert("No route data returned.");
                }
            } catch (error) {
                console.error("Error fetching route:", error.message);
                alert("Route API Error: " + error.message);
            }
        }
    </script>
</body>
</html>

.

Azure Maps
Azure Maps
An Azure service that provides geospatial APIs to add maps, spatial analytics, and mobility solutions to apps.
809 questions
{count} votes

6 answers

Sort by: Most helpful
  1. rbrundritt 20,201 Reputation points Microsoft Employee
    2025-04-03T00:24:38.19+00:00

    This is a limitation of the underlying backend service. The latest version of the route API is based on the Bing Maps routing service. It has more data but lower limits on the number of waypoints. The only way to get around this limitation is to split your waypoints up into multiple requests, then merge the results. A batch route request could be used to minimize the number of HTTP connections created and reduce the risk of hitting QPS limits.Here is a modified version of your code that makes multiple route requests:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Azure Maps Route API</title>
        <script src="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.js"></script>
        <link rel="stylesheet" href="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.css">
        <style>
            body {
                font-family: Arial, sans-serif;
                text-align: center;
                margin: 20px;
            }
            #map {
                width: 100%;
                height: 600px;
                margin-top: 20px;
                border: 2px solid #ccc;
                border-radius: 10px;
            }
            button {
                padding: 10px 20px;
                font-size: 16px;
                background-color: #0078D4;
                color: white;
                border: none;
                cursor: pointer;
                border-radius: 5px;
            }
            button:hover {
                background-color: #005A9E;
            }
        </style>
    </head>
    <body>
        <h2>Azure Maps Route API - New York State</h2>
        <button onclick="getRoute()">Get Route</button>
        <div id="map"></div>
    
        <script>
            const subscriptionKey = "<YOUR_AZURE_MAPS_KEY>"; // Replace with your Azure Maps subscription key
            
            let map = new atlas.Map("map", {
                center: [-75.5, 42.9], // Centered in New York State
                zoom: 7,
                view: "Auto",
                authOptions: {
                    authType: "subscriptionKey",
                    subscriptionKey: subscriptionKey
                }
            });
    		
    		function getSubRoute(waypoints){
    			console.log(`Sub-route request created with ${waypoints.length} waypoints.`);
    			
    			return new Promise(async (resolve, reject) => {
    				const url = "https://atlas.microsoft.com/route/directions?api-version=2025-01-01";
    
    				try {
    					const response = await fetch(url, {
    						method: "POST",
    						headers: {
    							"Content-Type": "application/json",
    							"Subscription-Key": subscriptionKey
    						},
    						body: JSON.stringify({
    							"type": "FeatureCollection",
    							"features": waypoints.map((coords, index) => ({
    								"type": "Feature",
    								"geometry": { "coordinates": coords, "type": "Point" },
    								"properties": { "pointIndex": index, "pointType": "waypoint" }
    							})),
    							"routeOutputOptions": ["routePath","itinerary"]
    						})
    					});
    
    					if (!response.ok) {
    						reject(Error(`HTTP error! Status: ${response.status} - ${await response.text()}`));
    					} else {
    						const data = await response.json();
    						resolve(data);
    					}
    				} catch (error) {
    					reject(Error("Error fetching route:", error.message));
    				}
    			});
    		}
    
            async function getRoute() {
    		
                const url = "https://atlas.microsoft.com/route/directions?api-version=2025-01-01";
                
                // 26 waypoints within New York State
                const waypoints = [
                    [-74.006, 40.7128], [-73.9352, 40.7306], [-73.9808, 40.7648], [-73.9982, 40.7265], 
                    [-74.0355, 40.7282], [-74.0589, 40.7458], [-74.0781, 40.7608], [-74.1211, 40.8362], 
                    [-74.1686, 40.8471], [-74.1915, 40.8598], [-74.2003, 40.8798], [-74.2131, 40.8952], 
                    [-74.2331, 40.9108], [-74.2525, 40.9202], [-74.2728, 40.9328], [-74.3002, 40.9501], 
                    [-74.3282, 40.9608], [-74.3525, 40.9705], [-74.3811, 40.9801], [-74.4005, 40.9902], 
                    [-74.4258, 41.0001], [-74.4505, 41.0108], [-74.4752, 41.0205], [-74.4982, 41.0301], 
                    [-74.5202, 41.0408], [-74.3122, 40.967]
                ];
    
    
                try {
    			
    				let data = null;
    				
    				if(waypoints.length <= 25){
    					data = await getSubRoute(waypoints);					
    					
    				} else {
    					var routePromises = [];
    					
    					//Need to split into subsets then merge results.
    					const batchSize = 24;
    					let startIdx = 0;
    					let endIdx = 0;
    					
    					while(endIdx < waypoints.length - 1){
    						endIdx = Math.min(endIdx + batchSize, waypoints.length - 1);
    						routePromises.push(getSubRoute(waypoints.slice(startIdx, endIdx + 1)));
    						console.log(`Sub-route from waypoint ${startIdx} to ${endIdx}`);
    						startIdx = endIdx;
    					}
    					
    					//Requests the routes in parallel (alternatively use the batch route service).
    					var results = await Promise.all(routePromises);
    					
    					//Merge the responses.
    					data = {
    						"type": "FeatureCollection",
    						features: []
    					};
    					
    					var routePath = null;
    					var legOffset = 0;
    					var timeOffset = 0;
    					
    					for(var i=0;i<results.length;i++){
    						//Route data contains a lot of index info that will need to offset based on which route response it belongs to.
    						const idxOffset = i * batchSize;
    												
    						//Extract and merge the points.
    						for(var j=0;j<results[i].features.length;j++){
    							const f = results[i].features[i];
    							
    							if(f.geometry.type === 'Point'){
    								//Offset the leg indices.
    								f.properties.routePathPoint.legIndex += legOffset;
    								
    								f.properties.steps.forEach(s => {
    									s.legIndex += legOffset;
    								});
    								
    								data.features.push(f);
    							} 
    						}
    												
    						//Get the route path.
    						const path = results[i].features.filter(f => f.properties.type == 'RoutePath')[0];
    						
    						//Merge the route path.
    						if(routePath == null){
    							routePath = path;
    						} else {
    							//Each leg is it's own line in the MultiLineString.
    							//Loop through the line coordinates of the path and append to the route path.
    							path.geometry.coordinates.forEach(l => {
    								routePath.geometry.coordinates.push(l);
    							});
    							
    							//Merge the bounding box of the route path.
    							routePath.geometry.bbox[0] = Math.min(routePath.geometry.bbox[0], path.geometry.bbox[0]);
    							routePath.geometry.bbox[1] = Math.min(routePath.geometry.bbox[1], path.geometry.bbox[1]);
    							routePath.geometry.bbox[2] = Math.max(routePath.geometry.bbox[2], path.geometry.bbox[2]);
    							routePath.geometry.bbox[3] = Math.max(routePath.geometry.bbox[3], path.geometry.bbox[3]);
    							
    							//Update metadata properties.
    							routePath.properties.distanceInMeters += path.properties.distanceInMeters;
    							routePath.properties.durationInSeconds += path.properties.durationInSeconds;
    							
    							if(routePath.properties.durationTrafficInSeconds){
    								routePath.properties.durationTrafficInSeconds += path.properties.durationTrafficInSeconds;
    							}
    							
    							//Off set the leg indices and add the route path legs.
    							path.properties.legs.forEach(l => {
    								l.legIndex += legOffset;
    								
    								//Offset arrivalAt/departureAt time of leg.
    								var d = new Date(routePath.properties.departureAt); 
    								d.setSeconds(d.getSeconds() +  timeOffset);
    								routePath.properties.departureAt = d.toISOString();																
    								
    								d.setSeconds(d.getSeconds() + (l.durationTrafficInSeconds || l.durationInSeconds));
    								routePath.properties.arrivalAt = d.toISOString();
    								
    								//Offset the time offset for this leg.
    								timeOffset += l.durationTrafficInSeconds;
    								
    								routePath.properties.legs.push(l);
    							});
    						}						
    						
    						legOffset += path.properties.legs.length;
    						timeOffset = routePath.properties.durationInSeconds;
    					}
    					
    					//Update the route paths arrivalAt time based on the known departureAt and the durationTrafficInSeconds.
    					var d = new Date(routePath.properties.departureAt); 
    					d.setSeconds(d.getSeconds() + (routePath.properties.durationTrafficInSeconds ||routePath.properties.durationInSeconds));
    					routePath.properties.arrivalAt = d.toISOString();
    					
    					//Add the route path the merged data.
    					data.features.push(routePath);
    				}
                    
                    if (data && data.features && data.features.length > 0) {
                        const dataSource = new atlas.source.DataSource();
                        map.sources.add(dataSource);
                        
                        // Add route line
                        dataSource.add(new atlas.data.LineString(waypoints));
                        map.layers.add(new atlas.layer.LineLayer(dataSource, null, {
                            strokeColor: "red",
                            strokeWidth: 3
                        }));
    
                        // Add waypoints as markers with labels A, B, C...
                        waypoints.forEach((coord, index) => {
                            dataSource.add(new atlas.data.Feature(new atlas.data.Point(coord), {
                                label: String.fromCharCode(65 + index) // Converts 0 → 'A', 1 → 'B', etc.
                            }));
                        });
    
                        // Add custom marker icon
                        map.imageSprite.add("marker_icon", "<svg xmlns='http://www.w3.org/2000/svg' width='26' height='28' viewBox='-4 0 36 36'><g fill='none' fill-rule='evenodd'><path d='M14 0c7.732 0 14 5.641 14 12.6C28 23.963 14 36 14 36S0 24.064 0 12.6C0 5.641 6.268 0 14 0Z' fill='#fff' stroke='#000' stroke-width='1'/><circle fill='dodgerblue' fill-rule='nonzero' cx='14' cy='14' r='10' /></g></svg>");
    
                        // Add SymbolLayer for displaying markers with labels
                        map.layers.add(new atlas.layer.SymbolLayer(dataSource, null, {
                            iconOptions: {
                                image: "marker_icon",
                                anchor: "bottom",
                                allowOverlap: true,
                                ignorePlacement: true
                            },
                            textOptions: {
                                textField: ["get", "label"], // Get waypoint label from properties
                                color: "black",
                                offset: [0, -0.7], // Adjust label position
                                font: ["StandardFont-Bold"],
                                allowOverlap: true
                            }
                        }));
    
                        // Adjust map view to fit the route
                        map.setCamera({ bounds: atlas.data.BoundingBox.fromPositions(waypoints), padding: 50 });
                    } else {
                        console.error("No route data returned.");
                        alert("No route data returned.");
                    }
                } catch (error) {
                    console.error("Error fetching route:" + error.message);
                    alert("Route API Error: " + error.message);
                }
            }
        </script>
    </body>
    </html>
    
    0 comments No comments

  2. Faraz Siddiqui 260 Reputation points Microsoft Employee
    2025-04-07T21:09:36.7566667+00:00

    To add, Route 2025-01-01 standard vehicle routing also supports up to additional 10 viawaypoints between any two waypoints which would mean a total of 240 (viawaypoints) +25 (waypoints). The viawaypoints are treated as locations that must be visited along a route, and they generate route sub legs vs waypoints which are treated as stops. The itinerary instructions are also slightly different for viawaypoints compared to waypoints. Depending on your scenario, you could use viawaypoints as an alternative to waypoints in Route v1.

    Route v1.0 deprecation - https://azure.microsoft.com/en-us/updates?id=485819

    0 comments No comments

  3. Deleted

    This answer has been deleted due to a violation of our Code of Conduct. The answer was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.


    Comments have been turned off. Learn more

  4. Deleted

    This answer has been deleted due to a violation of our Code of Conduct. The answer was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.


    Comments have been turned off. Learn more

  5. Deleted

    This answer has been deleted due to a violation of our Code of Conduct. The answer was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.


    Comments have been turned off. Learn more

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.