WayMatrix

Migration guide

Moving from Google Distance Matrix

WayMatrix is a hosted routing API — matrices, directions and isochrones — for road travel times across North America.

Results you can store, and a free allowance to test the rewrite on before you commit to it.

Get a free API key

This one is not a base URL change. The request shape, the response shape and the auth header all differ, so here is every field, and the two behaviours that will bite you if nobody points at them first.

Most teams arriving here are not leaving Google because it is bad. They are leaving because the matrix call is the line on the bill that keeps growing, and because almost nothing they compute with it needs a live traffic estimate.

The work below is real — this is a different API, not a different hostname — but it is mostly deletion. Two of the seven items on the checklist are code you get to remove.

The change

migrate.diff

Removed: - POST https://routes.googleapis.com/distanceMatrix/v2:computeRouteMatrix
Added: + POST https://api.waymatrix.io/v2/matrix/driving-car  # and the body changes shape — see the mapping below

Everything below the base URL is unchanged.

matrix.shgenerated from the API description
curl -X POST \
  https://api.waymatrix.io/v2/matrix/driving-car \
  -H "Authorization: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "locations": [
      [-87.6298, 41.8781],
      [-87.6244, 41.8796],
      [-87.6722, 41.9227]
    ],
    "metrics": ["duration", "distance"],
    "units": "km"
  }'

Every field, translated

Left is Google's field, quoted from their reference. Right is ours. An empty right-hand side means we have no equivalent.

Theirs Ours Notes
origins[].waypoint.location.latLng locations[] Google nests an object per origin and names the numbers. We take a flat array of pairs. This is where the order flips — see below.
destinations[].waypoint.location.latLng destinations A different model, and usually less work. We take one locations array and optional sources and destinations arrays holding INDICES into it. A point that is both an origin and a destination is sent once, not twice.
travelMode: "DRIVE" the driving-car path segment A path segment rather than a body field. WALK, BICYCLE, TWO_WHEELER and TRANSIT have no equivalent — we serve driving only.
routingPreference: TRAFFIC_AWARE No equivalent No equivalent, deliberately. We have no live traffic. If this field is why you pay Google, that is a reason to stay.
routeModifiers.avoid_ferries No equivalent Not supported today.
X-Goog-Api-Key header Authorization header The raw key, with no Bearer prefix. That matches the Openrouteservice client libraries, which is the point.
X-Goog-FieldMask header metrics Not the same thing. Google's mask is mandatory and selects response fields; ours is optional and selects which matrices to compute. We return the whole matrix either way.
response: [] of RouteMatrixElement durations and distances The biggest change in your code. Google returns a flat list of elements; we return arrays of arrays, already in the order you sent.
element.duration ("123s") durations[i][j] A string with a trailing s in Google, a number of seconds here. The parse goes away.
element.distanceMeters distances[i][j] Metres by default here too. Send units to change it.
element.originIndex / destinationIndex No equivalent Not needed. Our row and column positions are the positions you sent, so there is nothing to reindex.
element.status / element.condition HTTP status, and null in the matrix A failed pair comes back as null in the matrix rather than as a per-element status. A failed REQUEST is an HTTP error with a code in the body.

What changes and what does not

Unchanged

  • What you are computing. Origins against destinations, durations and distances between every pair. The concept survives the move; only its spelling changes.
  • Coordinates are the input. Neither service will geocode for you in this call. If you send Google latitudes and longitudes today, you already have what we need.
  • Metres and seconds. Distances are metres and durations are seconds on both sides, once you have parsed Google's duration string.

Different

  • The coordinate order flips, and this is the bug you will actually hit. Google names its numbers — latitude and longitude, as an object. We take a two-element array, and it is longitude first, which is what GeoJSON and the Openrouteservice clients use. A pair sent the wrong way round is usually still a valid coordinate, so nothing errors; you simply get durations for somewhere in the ocean. Check one result against a road you know before you trust a batch.
  • Their response is unordered. Ours is not. Google's own documentation says the elements returned by the stream are not guaranteed to be returned in any order, which is why every element carries originIndex and destinationIndex. Our response is arrays of arrays in the order you sent, so the code that reindexes their output has nothing to do here. Delete it rather than porting it.
  • No live traffic. This is the one that decides it. If a driver is moving right now and a customer is watching an ETA, traffic is the product and we do not have it. Most matrix work is not that — it is scoring options before anyone sets off — but you should be sure which one you are doing.
  • A matrix with routing options can run out of searching. Google fails an element at a time, inside a 200. We fail the request: a matrix carrying routing options searches once per source, and one that reaches the ceiling returns `500` with code `6020`, partway through, uncharged. Treat it as a request to make smaller rather than one to retry — the same request reaches the same ceiling, and a larger plan does not lift it, because it is not a plan limit.
  • A 403 does not always mean your key is wrong. Google tells you what failed per element, inside a 200. We use status codes, and two of our refusals share one message: `{"error":"Access to this API has been disallowed"}` is both an invalid key, code `5002`, and the free plan sending an `options` block on a matrix, code `5011`. Branch on the code rather than the text — `5002` means fix the key, `5011` means your plan may not send that field.
  • You may keep what you compute. Google's terms let you cache latitude and longitude for 30 days and do not let you store the durations and distances themselves. Ours are yours: cache them, build tables from them, keep them.

Errors

These are read off the live gateway on the date below, rather than copied from a document. Google returns per-element statuses inside a 200; we do not, so error handling moves from inside the response to around it.

When Status Body
No key at all 401 {"error":"Authorization field missing","code":5001}
Key present but rejected 403 {"error":"Access to this API has been disallowed","code":5002}
Rate limited 429 {"error":"Rate Limit Exceeded","code":5003}
Monthly quota exhausted 403 {"error":"Quota exceeded","code":5004}
Request larger than your tier allows 400 {"error":{"code":6004,"message":"…Only a total of N routes are allowed."}}
A path we do not serve 404 {"error":"Not found","code":5010}
Your plan may not send that field checked 403 {"error":"Access to this API has been disallowed","code":5011}
Routing engine unreachable 502 {"error":"The routing engine is unavailable","code":5008}

Read off a running gateway on . Google's side was read off their own reference and guide on the date shown, and every field name below is quoted from them rather than remembered. Our side is read from the API description this site generates its samples from. Google changes this API; check theirs before you commit to anything.

Before you switch traffic

  1. Flip your coordinates to longitude first, and check one duration against a road you know.
  2. Collapse origins and destinations into one locations array with index arrays, if your points overlap.
  3. Delete the code that reindexes elements by originIndex and destinationIndex.
  4. Delete the code that parses the trailing s off a duration.
  5. Move error handling from per-element status to the HTTP status around the call.
  6. Decide honestly whether anything you build needs live traffic.
  7. Confirm your coordinates are in North America.