All integrations

GraphHopper

DATA · DATA & ANALYTICS

Routing, geocoding, distance matrices, isochrones, and route optimization on their own key.

Connect GraphHopper with Fabriq Developer

Your user pastes their GraphHopper credential on a page Agentic Fabriq hosts, so it never reaches your backend and never becomes one shared key across all of your users. Same call as OAuth, one more argument.

from af_sdk import AgenticFabriq

af = AgenticFabriq()                      # reads AF_APP_ID / AF_APP_SECRET

url = await af.initiate_connection(request, provider="graph_hopper", method="api_key")
return redirect(url)                      # an AF-hosted page, not yours

async with await af.for_user(request) as session:
    tools = await session.get_tools()     # only what this user granted

Provider names are surfaces, not vendors, and the authoritative list is the capabilities endpoint rather than any page including this one — an unknown name returns 400 with the valid list. Fabriq Developer is free to start and needs no provider paperwork. Start free or read the quickstart.

Connecting GraphHopper in practice

GraphHopper bills in credits computed from the size of the problem rather than the number of calls: an isochrone costs 2 credits per minute explored with a minimum of 10, a matrix costs the smaller of origins × destinations ÷ 2 and max(origins, destinations) × 10, and asking a route for optimize=true multiplies its cost by ten. X-RateLimit-Remaining is reported before the current request is charged, so the real balance is Remaining minus X-RateLimit-Credits.

Rate limits

  • The credit budget is daily: X-RateLimit-Limit is the daily credit limit and X-RateLimit-Reset the seconds until the counter resets. The FAQ names 15,000 credits a day on Standard and 50,000 on Premium.
  • Routing: 1 credit for 2–10 locations, locations ÷ 10 above that, +1 for alternative routes, 2 for a round trip, and 10× the standard cost with optimize=true.
  • Matrix: the smaller of (origins × destinations ÷ 2) and (max(origins, destinations) × 10), minimum 1 credit per request.
  • Route Optimization: vehicles × locations, minimum 10 and maximum 10 × locations, plus 0.3 credits for each GET of the solution.
  • Isochrone: 2 credits per minute explored, minimum 10. Map Matching: input locations ÷ 50, minimum 1. Geocoding: 0.3 credits by default, 0.9 with Nominatim, NetToolkit or OpenCageData.
  • Cluster: customers × 10 with a minimum of 10, or 1 credit per customer with the as_the_crow_flies profile.

Worth knowing

  • A 429 means either the daily or the per-minute limit is exhausted and the response does not say which, so backoff has to assume the longer of the two.
  • The Geocoding response uses point.lng while the Route Optimization request expects lon, so coordinates have to be renamed between the two calls in GraphHopper’s own documented delivery workflow.
  • Cost is a function of input size, so a badly filtered stop list does not just run slower — it is priced higher, and a matrix grows quadratically until the ×10 cap kicks in.
  • A custom routing profile has restricted geographic coverage and the maximum coverage depends on the plan, so the same profile definition is not portable between accounts.

Checked against GraphHopper Directions API (2026-09-29), What is one credit? (2026-09-29)

Acts as the person, not as itself

Each user connects their own account. Every call carries both identities — the agent and the person it is acting for — so the agent can never reach past what that individual can already do.

Credentials never touch the agent

Tokens live in the vault and attach server-side at call time. The agent holds a session, not a secret, and revoking access does not mean rotating a key.

Every call on the record

Who asked, which agent acted, which action ran, and the verdict that let it through — one audit trail across every integration, not one per vendor.

What an agent can do

Each action is granted on its own. An agent allowed to read is not thereby allowed to write, and the scope beside each row is what the acting user must have connected for it to run at all.

graph_hopper_get_cluster_solution_by_jobidREAD

Collect a submitted clustering assignment by the `jobId` that submission returned: each cluster with the customer ids in it and its total quantity. Answers with `status` `waiting_in_queue` or `processing` until it is finished, so a caller polls this via GET /cluster/solution/{jobId}

api
graph_hopper_get_geocodeREAD

Turn a place name or address into coordinates (`q`), or a `point` (`lat,lng`) back into an address with `reverse=true`. Returns up to `limit` matches, each with a name, street, housenumber, city, postcode, state, country, an OSM id and a bounding box. `locale` picks the language of the returned names and `provider` selects the geocoding back end. Exactly one of `q` and `point` is what a call means: `q` alone is a forward lookup, and `point` with `reverse=true` is the inverse

api
graph_hopper_get_isochroneREAD

The area reachable from one `point` within a `time_limit` (seconds) or a `distance_limit` (metres), returned as GeoJSON polygons. `buckets` splits it into that many nested rings -- 3 buckets on a 900-second limit gives the 5-, 10- and 15-minute areas in one call. `reverse_flow=true` inverts the question to the area FROM which the point can be reached, which is the right one for catchment analysis on a one-way network via GET /isochrone

api
graph_hopper_get_matrixREAD

Travel times, distances and weights between every origin and every destination. Either give one symmetric set with repeated `point`, or an asymmetric pair with `from_point` and `to_point`. `out_array` chooses which of `weights`, `times` and `distances` come back, and `fail_fast=false` returns the matrix with `null` in the cells that could not be connected instead of failing the whole request. A matrix costs credits in proportion to the number of cells, so this is the expensive tool on the surface via GET /matrix

api
graph_hopper_get_matrix_solution_by_jobidREAD

Collect the result of a matrix submitted for asynchronous calculation, by the `jobId` that submission returned. Answers with a `status` of `waiting_in_queue`, `processing` or `finished`, and the matrix itself only once it is finished -- so a caller polls this rather than expecting an answer first time via GET /matrix/solution/{jobId}

api
graph_hopper_get_routeREAD

Route between two or more `point` values (`lat,lng`, repeated, in visiting order) and get distance, travel time, an encoded geometry and turn-by-turn instructions. This is the GET form, which takes every option as a query parameter: `vehicle` picks the profile, `optimize=true` reorders the intermediate points, `algorithm=alternative_route` or `round_trip` changes what is computed, `elevation` adds a third coordinate, `details` asks for per-segment road attributes, and `avoid` / `block_area` exclude road classes or areas. Note `points_encoded` defaults to true, so the geometry arrives as a polyline string that has to be decoded; send `points_encoded=false` for plain coordinates via GET /route

api
graph_hopper_get_route_infoREAD

Read what this GraphHopper deployment covers: the bounding box of its map data, the build date and data date, its version, its supported vehicle profiles and whether each carries elevation. The cheapest read on the surface -- it takes no arguments at all -- and the natural smoke test for a connection via GET /route/info

api
graph_hopper_get_vrp_solution_by_jobidREAD

Collect a submitted route-optimization plan by the `jobId` that submission returned: the routes per vehicle with their stops in order, arrival times, the total distance, time and cost, and any `unassigned` services with the reason each was dropped. Answers with `status` `waiting_in_queue` or `processing` until the solver finishes, so a caller polls this via GET /vrp/solution/{jobId}

api
graph_hopper_post_clusterWRITE

Group customer addresses into clusters by travel cost rather than by straight-line distance -- the territory-planning service. `num_clusters` sets how many groups to make and `min_quantity` / `max_quantity` bound how much demand each may hold. This is the SYNCHRONOUS form; larger problems go through Submit a clustering problem. It computes an assignment and stores nothing via POST /cluster

api
graph_hopper_post_cluster_calculateWRITE

Queue a clustering problem and get back a `job_id` immediately; the assignment is collected with Get a clustering solution. This CREATES a job on GraphHopper's side, which is why it is a write via POST /cluster/calculate

api
graph_hopper_post_matchWRITE

Snap a recorded GPS track onto the road network and get the matched route back with distance, time and instructions -- the map-matching service. `gps_accuracy` (metres) tells the matcher how far a fix may have drifted and `vehicle` picks the profile whose network the track is matched against. NOTE: the sealed contract records no request body for this operation, so whatever JSON body is sent is forwarded verbatim; GraphHopper's own documentation is the reference for its shape via POST /match

api
graph_hopper_post_matrixWRITE

The same matrix calculation taking one JSON body, which is what a matrix of any size needs -- a few hundred points makes a query string no server will accept. Answers synchronously, so it is bounded by the request timeout; use Submit a large matrix for anything bigger via POST /matrix

api
graph_hopper_post_matrix_calculateWRITE

Queue a matrix too large to answer inside one request and get back a `job_id` immediately. The result is collected with Get a matrix result; until it is ready that call reports `waiting_in_queue` or `processing`. This CREATES a job on GraphHopper's side, which is why it is a write via POST /matrix/calculate

api
graph_hopper_post_routeWRITE

The same routing engine as the GET form, taking one JSON body instead of a long query string. This is the form to use for a custom model (`custom_model` with `priority`, `speed` and `areas` rules), for many points, or for anything that would overflow a URL. It computes a route and stores nothing via POST /route

api
graph_hopper_post_vrpWRITE

Route Optimization: given `vehicles`, `vehicle_types` and the `services` or `shipments` they must cover, work out which vehicle does what and in which order, honouring time windows, capacities, skills and driver breaks. This is the SYNCHRONOUS form and is bounded by the request timeout, so it suits small problems; anything larger goes through Submit a vehicle routing problem. It computes a plan and stores nothing via POST /vrp

api
graph_hopper_post_vrp_optimizeWRITE

Queue a route-optimization problem and get back a `job_id` immediately, which is the form real fleet problems use -- solving takes longer than a request may. The plan is collected with Get a route optimization solution. This CREATES a job on GraphHopper's side, which is why it is a write via POST /vrp/optimize

api

Put GraphHopper behind one governed endpoint.

Same permissions, same audit trail, whatever else you connect next.