WayMatrix

Matrix · Directions · Isochrones

The distance matrix API for real road travel times.

Travel-time matrices, directions and isochrones across North America — request and response compatible with the Openrouteservice API. Change the base URL, add a key, keep your code.

170× cheaper per element than Google's entry price, and bigger per-call size limits.

50,000 matrix elements a month on the free tier, up to 50 × 50 per request. No card, no sales call.

matrix.shup to 300 × 300 in one call
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"
  }'
response.jsondurations, distances, and the graph build date
{
  "durations": [
    [0, 421.3, 782.6],
    [402.9, 0, 897.4],
    [768.1, 881.5, 0]
  ],
  "distances": [
    [0, 2.61, 6.42],
    [2.68, 0, 8.13],
    [6.35, 8.21, 0]
  ],
  "sources": [
    {
      "location": [-87.6298, 41.8781],
      "snapped_distance": 4.31
    },
    {
      "location": [-87.6244, 41.8796],
      "snapped_distance": 11.82
    },
    {
      "location": [-87.6722, 41.9227],
      "snapped_distance": 6.09
    }
  ],
  "destinations": [
    {
      "location": [-87.6298, 41.8781],
      "snapped_distance": 4.31
    },
    {
      "location": [-87.6244, 41.8796],
      "snapped_distance": 11.82
    },
    {
      "location": [-87.6722, 41.9227],
      "snapped_distance": 6.09
    }
  ],
  "metadata": {
    "attribution": "© openrouteservice by HeiGIT | Data from OpenStreetMap",
    "service": "matrix",
    "timestamp": 1788412800000,
    "query": {
      "locations": [
        [-87.6298, 41.8781],
        [-87.6244, 41.8796],
        [-87.6722, 41.9227]
      ],
      "metrics": ["duration", "distance"],
      "units": "km",
      "profile": "driving-car"
    },
    "engine": {
      "version": "9.10.0",
      "build_date": "2026-07-28T00:00:00Z",
      "graph_date": "2026-07-31T00:00:00Z",
      "osm_date": "2026-07-30T00:00:00Z"
    },
    "element_count": 9
  }
}
  • No surprise bill

    every plan stops at its allowance

  • Drop-in

    same paths, bodies and response shapes as Openrouteservice

  • 90,000

    matrix elements in one call — 300 × 300 origins by destinations

Wiring this up

Wire it up with one block of text.

Get the block

Three endpoints. That's the whole product.

Narrow on purpose. Each one is the same shape Openrouteservice returns, so your parsing code doesn't change either.

Matrix

Hero

POST /v2/matrix/{profile}

priced by origins × destinations

Every origin to every destination, duration and distance, in one request. This is the call Google charges five dollars a thousand for and caps at 625 elements — a 25 by 25 matrix.

Directions

POST /v2/directions/{profile}

10 elements per call

Geometry, turn-by-turn instructions, and alternative routes. Encoded polyline or GeoJSON, whichever your map wants.

Isochrones

POST /v2/isochrones/{profile}

priced by how far it reaches

An isochrone is the shape of everywhere you can reach within a given time: hand it a point and fifteen minutes, and it returns the polygon you could drive to. Site selection, service-area maps, “commute time” filters on a listings site.

Before you switch

What the price buys, and what it doesn't.

What the price buys

The numbers are yours to keep

The durations, distances and geometries you get back are yours to use in your application. Cache them, store them, build tables from them, keep them as long as they are useful to you.

That is worth checking against whoever you use now. Google’s terms allow caching latitude and longitude for 30 days: the coordinates you sent them, not the answers they sent back.

Priced for volume

$29 a month for 1,000,000 elements — 170× less per element than Google's entry price.

An element is one origin paired with one destination, and elements cost the same whether you ask for them in one large matrix or a hundred small ones. So you can work out what a plan covers for your own workload before you spend anything.

That gap is not an introductory rate. It is what routing costs when you are not also paying for live traffic and worldwide coverage — which is the first trade below, and if you need either of those, Google is worth its price.

A free tier that isn't a dead end

50,000 elements a month, free and without a credit card. The plan directly above it is $29.

Nothing you build on the free tier stops working when you start paying. The paid plans are the same endpoints, the same request bodies and the same key — a bigger allowance and a larger matrix per request, nothing to re-integrate. Going live is a plan change rather than a project.

That is worth asking about wherever you evaluate. A free tier with no commercial plan above it is a fine place to prototype and nowhere to launch from, and you find out which kind you picked on the day you are least able to change it.

What it doesn't

No live traffic

Durations come from speed profiles on the road network, not from cars on it right now. If your product hinges on a minute-accurate ETA in rush hour, buy Google. If you are planning a day’s work, comparing options, or ranking by travel time, you will not miss it.

Rural coverage varies

Excellent in metros, where most routing happens and where OpenStreetMap is often better than commercial data. More variable on rural roads and brand-new subdivisions. Every response carries the date of the map data behind it, so how fresh your answer is stays something you can read rather than something you have to take on trust.

No address lookup

There is no geocoder and no places database here. You send longitude and latitude, we send back numbers. Most teams already have coordinates from the system that created the address — if you don’t, geocode once and cache.

Measured, not asserted

Ninety thousand pairs in three seconds.

Three hundred origins against three hundred destinations, in a single call to the production API.

MatrixElementsTypicalSlowest in ten
10 × 10 100 287 ms 299 ms
50 × 50 2,500 358 ms 500 ms
100 × 100 10,000 612 ms 642 ms
300 × 300 90,000 3,024 ms 3,141 ms
Each dot is one request. The bar is the middle half of the ten runs at that size; the line through it is the typical one.

Ten runs at each size, one request after another from a single machine, timed from the client — so each number includes everything between your code and ours. Measured .

What the numbers mean

  • 900× the work at ten times the time. Cost grows far more slowly than size, right across the range — and the effect holds at every step of it, not just the ends: the step from the second-largest matrix here to the largest is nine times the work for five times the time. That is the argument for asking in one call rather than chunking.
  • The spread is narrow at every size. The middle half of every run sits within six percent of its own typical time, and the largest matrix is the tightest of the four. One request in forty was slow — a single 50 × 50 that took 500 ms against a typical 358, and it is in the chart rather than averaged away.

Already on Openrouteservice?

The migration is one line.

The hosted free tier allows 500 matrix requests a day, and there is no paid plan above it to move up to. That is a generous place to prototype and nowhere to launch from. We speak the same protocol with a far higher ceiling.

Your existing client library, your existing request bodies, your existing parsing. Point it somewhere else — and note that this really is only the base URL.

Works unchanged with:

  • openrouteservice-py
  • Openrouteservice-js
  • plain HTTP

client.py

Removed: - base_url = "https://api.openrouteservice.org"
Added: + base_url = "https://api.waymatrix.io"  headers   = {"Authorization": API_KEY}

That is the entire diff. Everything below the base URL is unchanged.

Priced on elements.

An element is one origin paired with one destination. A 200 × 150 matrix is 30,000 of them, whether you ask in one request or thirty.

Full pricing

Free

$0

no card required

  • 50,000 elements / month
  • Up to 5 requests / minute

Starter

$29

per month

  • 1,000,000 elements / month
  • Up to 60 requests / minute

Scale

Proposed

$299

per month

  • 20,000,000 elements / month
  • Up to 180 requests / minute
AN Optimiciti PRODUCT
Same engine, different job

Need the routes, not just the numbers?

This API is the routing layer underneath Optimiciti, a route planner for dispatchers and small fleets. If you need to solve a routing optimization problem, use Optimiciti — a problem where the answer is which vehicle goes where, in what order, under constraints like these:

  • Time windows — a delivery that has to land between 9am and noon
  • Capacity limits — how many pallets, or how much weight, fits in each van
  • Vehicle types — a box truck that can't use a residential street, or a refrigerated unit
  • Driver shifts — hours, breaks, and where each driver starts and ends
  • Many stops at once — 400 stops split across 12 vans