Skip to content

From Google Route Optimization

Unmap Optimize accepts the Google Maps Platform Route Optimization OptimizeToursRequest format and returns an OptimizeToursResponse. A REST integration can keep its request and response handling for supported fields, then replace the host and OAuth credential with Unmap's host and API key. Check the field table first. Unsupported constraints require changes to the request, and travel times, solutions and some failure behaviours differ.

Unmap is not affiliated with Google, and Google does not endorse it. The product names on this page are used only to say which API Unmap's format follows.

Unmap Optimize is live on api.unmap.dev, on both Google's paths and POST /optimize.

Change the base URL

Unmap serves Google's own paths, so the smallest change is the host:

GoogleUnmap
https://routeoptimization.googleapis.com/v1/projects/{project}:optimizeTourshttps://api.unmap.dev/v1/projects/{project}:optimizeTours
https://routeoptimization.googleapis.com/v1/projects/{project}/locations/{location}:optimizeTourshttps://api.unmap.dev/v1/projects/{project}/locations/{location}:optimizeTours

{project} and {location} can stay what they are: Unmap ignores them, and parent in the body, because the API key identifies the account. The same handler also answers at Unmap's own path, POST https://api.unmap.dev/optimize, which is the one to use in new code.

Only optimizeTours is implemented. batchOptimizeTours and the other methods answer 404. Unmap serves the REST binding (JSON over HTTPS) only: a client library that talks gRPC will not connect. Use its REST transport if it has one, or call the endpoint with a plain HTTP client.

Change the credential

Google authenticates this API with OAuth 2.0 access tokens from a Google Cloud account. Unmap uses an API key from your dashboard, with no OAuth token exchange. Save the request as request.json and set UNMAP_API_KEY to your key before running the Unmap example:

curl -X POST "https://routeoptimization.googleapis.com/v1/projects/my-project:optimizeTours" \
  -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  -H "Content-Type: application/json" \
  --data @request.json

Unmap also accepts X-Goog-Api-Key, X-API-Key and ?key=. If a client library manages OAuth credentials automatically, configure its REST transport to send an Unmap key instead, or use a plain HTTP client. Changing the host alone does not replace Google credentials. See Authentication.

What carries over

  • Field names and nesting, camelCase or snake_case, durations as "300s", timestamps as RFC 3339 or { seconds, nanos }, and 64-bit integers as strings.
  • The response: routes with visits, transitions, metrics, routeCosts and routePolyline; skippedShipments with Google's reason codes; and metrics with the cost breakdown under the same keys.
  • solvingMode: VALIDATE_ONLY, which answers validationErrors without solving.
  • Errors in Google's shape, { "error": { "code", "message", "status", "details" } }, with the same status names (INVALID_ARGUMENT, FAILED_PRECONDITION, RESOURCE_EXHAUSTED and so on). Unmap adds its own code string beside error.

What fails loudly

Unmap refuses what it cannot do. A plan that silently dropped a time window or a capacity would look fine and be wrong, so every unsupported constraint is an error you see on the first request:

  • Fields not supported yet are a 400 with FIELD_NOT_SUPPORTED_YET when set to anything but their default: quadratic soft duration limits, loadDemands on a visit, shipment types and precedence rules, injected solutions, maxActiveVehicles, Vehicle.ignore and more. Values not supported yet are VALUE_NOT_SUPPORTED_YET: more than one pickup or delivery alternative per shipment, a second vehicle start or end time window, travelMode: WALKING, and the DETECT_SOME_INFEASIBLE_SHIPMENTS and TRANSFORM_AND_RETURN_REQUEST solving modes. Like quadratic soft duration limits, routeDistanceLimit.costPerKilometerBelowSoftMax is refused, but for good and with INVALID_VALUE, because GMPRO does not support it either. Field support has the full list, generated from the validator.
  • Place IDs (arrivalWaypoint.placeId, startWaypoint.placeId, endWaypoint.placeId) are PLACE_ID_NOT_SUPPORTED. A place ID points into Google's database, and guessing a location for it would route to the wrong place. Geocode the address once with /geocode/search and send coordinates.
  • Cloud Storage URIs (gs://) have nowhere to go: no field of optimizeTours takes one, and the batch methods that read them are not available (they answer 404). The code GCS_URI_NOT_SUPPORTED is reserved for them; nothing returns it today. Send the request body inline.
  • Unknown fields, including typos, are UNKNOWN_FIELD rather than skipped.
  • A mandatory shipment that cannot be served is a 400 FAILED_PRECONDITION that names it, where Google can answer 200 with the shipment skipped and counted in skippedMandatoryShipmentCount. Give a shipment a penaltyCost if it may be skipped.

Run your real requests through VALIDATE_ONLY first. It reports field validation errors up to maxValidationErrors and costs nothing. It does not test road reachability or fleet feasibility; follow it with a solve. Authentication, body size and shipment or vehicle count limits still apply.

What is accepted and ignored

Unmap accepts several fields without applying them. A non-default value produces a warning in the X-Unmap-Optimize-Warnings response header: considerRoadTraffic, parent, populateTransitionPolylines, allowLargeDeadlineDespiteInterruptionRisk, and a waypoint's location.heading, sideOfRoad and vehicleStopover. Review these warnings on each response. Ignored traffic and waypoint settings can affect whether a plan suits your operation. The response body follows Google's format.

Routes and costs will differ

For the supported cost fields, Unmap uses fixedCost once per used vehicle, costPerHour over each route's duration, costPerTraveledHour over its driving time, costPerKilometer over its distance, and penaltyCost for each skipped optional shipment, excluding ignored shipments. These costs appear under the same keys in metrics.costs. What goes into it is not the same:

  • Travel times come from a different road network. Unmap computes driving times from OpenStreetMap data on its own Canada road graph, at free-flow speeds with no traffic (considerRoadTraffic is ignored). The same stops get different travel times than on Google, so routes, arrival times and totalCost differ too.
  • The solver is different. Even with identical travel times (your own durationDistanceMatrices), two solvers given a few seconds each can return different plans of similar cost.
  • Road coverage is Canada. For stops elsewhere, send your own matrices or use useGeodesicDistances.

So do not judge a migration by comparing totalCost to the last Google answer. Check that the plans are feasible and that their cost is reasonable for your operation, then compare on your own travel data.

Limits and billing

Per-plan limits apply to shipments, vehicles, locations, solve time and solves at once: Hobby allows 25 shipments, Growth 2,000. A timeout longer than the plan's is clamped, not refused. Billing is one call per shipment actually served, and re-solving the same shipments within 24 hours is free. The Optimize API page has the numbers.

Checklist

  1. Use https://api.unmap.dev as the host, keeping a supported Google path or using /optimize.
  2. Replace the OAuth token with an Unmap API key.
  3. Send a real request with solvingMode: VALIDATE_ONLY and fix what it reports.
  4. Replace place IDs with coordinates from /geocode/search.
  5. Inspect X-Unmap-Optimize-Warnings on every response for ignored fields and travel warnings.
  6. Check the plan's limits against your largest request.
  7. Run a solve and verify its visit times, loads, skipped shipments and costs.