Delivery fee quotes
Price a delivery by road distance without paying for requests nobody needs: when to quote, one request for many stores, caching, and moving from Google's Distance Matrix.
Base URLhttps://makani-k8s.lamah.com
Quote where the fee matters
A delivery fee depends on the road distance from the store to the customer's door. That distance matters for one store only: the one the customer is ordering from. An app that prices every store of every list makes ten to twenty requests for each order, and all of them are counted.
- Quote in the cart and at order creation. That is one or two requests for each order.
- In lists (stores near me, search results, a category), sort and label with the straight-line distance between the two points. Your server computes it from the coordinates: no request, no cost.
- If a list must show a fee, estimate it from the straight-line distance times a factor you measure on your own past orders, and price exactly in the cart.
- Quote when the address or the store changes, never on a timer or on every position update.
One request for many stores
When several stores do need a road distance at once, for example a cart with items from three stores, send one matrix request: the stores as sources and the customer as the only target. One request answers every store, up to 2,500 pairs.
The answer has one row for each store, in the order you sent them, each with one cell: distanceMeters in meters and durationSeconds in seconds. A store with no road route to the customer has distanceMeters: null and a reason, and is not counted. Three stores are three units whether you send one request or three; one request is one round trip and counts once against your requests a minute.
routing:matrixcurl -X POST "https://makani-k8s.lamah.com/v1/routing/matrix" \ -H "x-api-key: $MAKANI_API_KEY" \ -H "content-type: application/json" \ -d '{ "countryCode": "LY", "sources": [ { "latitude": 32.86, "longitude": 13.23 }, { "latitude": 32.895, "longitude": 13.15 }, { "latitude": 32.87, "longitude": 13.21 } ], "targets": [ { "latitude": 32.8872, "longitude": 13.1913 } ] }'Cache on your side
The road between a store and a door does not change from one order to the next. Keep each answer and ask only when it is missing:
- Key the cache on the store and on the customer's coordinates rounded to four decimal places, about 11 meters. Rounding is what lets a position that is not a saved address hit the cache: two GPS fixes at the same door become the same key.
- Send the customer's exact coordinates in the request; round only in your key.
- Keep an entry for 30 days, and drop a store's entries when the store moves.
- Keep the pairs with no route too, for a shorter time, so a misplaced pin is not asked again on every screen.
- The platform also answers a repeated pair from its own cache, which makes it fast. It is counted like any other request, so your cache is what lowers the bill.
What a quote costs
A quote is counted for each answered pair of the matrix. Your plan's included units are used first, and a pair uses the number of units the price list gives the routing matrix (unitWeight). Beyond the plan, each pair is charged at the price list's price per 1,000.
- One store and one customer: one pair.
- Five stores and one customer in one request: five pairs.
- A pair with no route, a refused request and an answer with a status of 400 or above are not counted.
- At one or two quotes for each order, 100 orders a day are 3,000 to 6,000 pairs a month.
- A bug that quotes in a loop stops at a number you choose: in the console's Quotas, set a daily cap on the routing matrix for the key your quotes use. The pair that would pass it answers
429 QUOTA_EXCEEDEDuntil 00:00 UTC, your other keys keep working, and you are told at 80% and at 100%.
Prices and weights can change, so none is written on this page. Read them from GET /v1/public/prices, which needs no key, or from this table, which is read live:
Loading prices…
Moving from Google's Distance Matrix
Code that already calls Google's Distance Matrix API moves by changing the URL and the key. This endpoint takes the same query parameters and answers in the same JSON shape, so the code that reads rows[0].elements[0].distance.value and duration.value stays as it is:
routing:matrixcurl "https://makani-k8s.lamah.com/v1/routing/compat/google/distancematrix/json?origins=32.86,13.23&destinations=32.8872,13.1913&mode=driving&units=metric®ion=ly" \ -H "x-api-key: $MAKANI_API_KEY"Send the key in the x-api-key header. A key= query parameter is accepted too, as Google's clients send it, but a key in a URL can end up in the logs of whatever the request passes through. The key needs the routing:matrix scope. What differs from Google:
- The country. Send the two-letter country of the points as
region(countryandcountryCodeare read too). A key limited to one country needs no parameter: that country is used. Otherwise a request without a country answersINVALID_REQUEST. - Coordinates only.
originsanddestinationsarelat,lngpoints separated by|, up to 25 each and 100 pairs in a request. Addresses, place ids and encoded polylines answerINVALID_REQUEST. - Travel modes.
driving(the default),walkingandbicycling.transitand its parameters answerINVALID_REQUEST. - No live traffic.
departure_time,traffic_modelandavoidare accepted and ignored, like any parameter the endpoint does not know.durationis the usual travel time, andduration_in_trafficis never returned. - Addresses.
origin_addressesanddestination_addressesrepeat the coordinates you sent. Nothing is geocoded. - Text.
unitsandlanguagechangedistance.textandduration.textonly.valueis always meters and seconds. - Statuses. A refusal is HTTP 200 with a
status, as Google answers, anderror_messagestarts with this platform's error code:INVALID_REQUESTfor a bad request,MAX_DIMENSIONS_EXCEEDEDandMAX_ELEMENTS_EXCEEDEDfor too many points,REQUEST_DENIEDfor the key, its scope, its country or the plan,OVER_QUERY_LIMITfor the requests a minute, andOVER_DAILY_LIMITfor a daily cap, a quota, the plan's units or the balance. A pair with no road route has the element statusZERO_RESULTS. When routing cannot answer, the status isUNKNOWN_ERRORwith HTTP 503 and aRetry-Afterheader.
Road closures, the platform's cache and billing apply as on the matrix: one unit for each answered pair. Changing the URL does not change how often your app asks, so apply the sections above as well: they are what lowers the bill.
The driver's route line
An app that draws the driver's route with Google's Routes API (computeRoutes) replaces that one call with the route request. There is no compatible endpoint for it: client libraries for that API are tied to Google's address, so the call is replaced in code either way. The answer carries the same three things: distanceMeters, durationSeconds (a number, where Google writes a text such as 303s) and shape, the encoded line.
One difference needs care: shape is encoded with six decimal places, not five. A decoder written for five draws the line in the wrong place, so decode with a precision of six, as the Dart sample does. Ask for the route again when the driver leaves it or the destination changes, not on every position update. closures.avoided says why a line goes around a closed road.
routing:routecurl -X POST "https://makani-k8s.lamah.com/v1/routing/route" \ -H "x-api-key: $MAKANI_API_KEY" \ -H "content-type: application/json" \ -d '{ "countryCode": "LY", "from": { "latitude": 32.86, "longitude": 13.23 }, "to": { "latitude": 32.8872, "longitude": 13.1913 } }'