Skip to content
Home » GraphHopper

GraphHopper

GraphHopper Directions API Integration Guide

Integrate the GraphHopper Directions API to calculate road distance between pickup and delivery locations, and store the result on the Load record in FTM.

Overview

This integration connects FTM with the GraphHopper Directions API to calculate the point-to-point distance between pickup and delivery facilities. The result is stored in the FreightTM__Distance__c field on the FreightTM__Load__c object. The integration runs asynchronously, ensuring that the UI remains responsive.

Key Components

  • Apex Class: GraphHopperQueueable (Queueable + callout)
  • External Service: GraphHopper Directions API /route
  • Data: FreightTM__Load__c + related FreightTM__Facility__c (with coordinates)

What This Integration Does

  • Takes two coordinates (Pickup & Delivery).
  • Calls GraphHopper Routing API with a chosen profile (default is car).
  • Extracts paths[0].distance (in meters) from the response.
  • Converts meters to kilometers and stores it in FreightTM__Distance__c.
  • Runs asynchronously to ensure the UI remains responsive; it is safe to enqueue from Flow/Apex.

Setup Requirements

  1. GraphHopper API Key
    – Create/get an API key in your GraphHopper account.
    Do not hard-code the API key; store it securely (use step 3 below).
  2. Salesforce Callout Allowlist
    – Add Remote Site Settings for https://graphhopper.com (or use Named Credential).
  3. Recommended: Named Credential + Protected Storage
    – Use Named Credentials (URL: https://graphhopper.com/api/1/).
    – Store the API key in Protected Custom Metadata/Setting (org-wide) and append &key=… at runtime.

    Note: GraphHopper expects the key as a query parameter. Named Credentials don’t add it automatically.
  4. Permissions
    – Ensure Apex Class access to GraphHopperQueueable.
    – CRUD/FLS to FreightTM__Load__c.FreightTM__Distance__c.
    – Read access to related Facility coordinates (Coordinates__c).
  5. Facility Coordinates Present
    – Ensure both Pickup and Delivery Facilities have valid Geolocation values in Coordinates__c (latitude and longitude).
  6. Attribution
    – GraphHopper uses OpenStreetMap data. If you display maps or route results, include appropriate attribution within your UI per licensing.

How It Works

  1. A process (Flow, Apex, button, or Scheduler) enqueues GraphHopperQueueable with a list of Load Ids.
  2. The job queries Loads and related Pickup/Delivery Coordinates__c.
  3. For each Load with both coordinates present:
    – Build a GET /route request with two point parameters (lat, lon), profile=car (or other), and key=<API_KEY>.
    – Send the callout and parse the JSON response.
    – Read paths[0].distance (in meters) and convert to kilometers.
    – Update FreightTM__Distance__c on the Load.
  4. Loads missing coordinates are skipped with a debug note.

Field Mapping

Inputs (from Salesforce)

ObjectFieldPurpose
FreightTM__Facility__cCoordinates__cStart latitude/longitude
FreightTM__Facility__cCoordinates__cEnd latitude/longitude

Output (to Salesforce)

ObjectFieldValue
FreightTM__Load__cFreightTM__Distance__cRoute distance in kilometers (rounded)

API Response → Fields

GraphHopper JSON FieldMeaningFTM Use
paths[0].distanceTotal route distance in metersYes (convert to kilometers)
paths[0].timeTotal travel time in millisecondsNot used (optional future)

Implementation

  1. Secure the API key:
    – Create Protected Custom Metadata/Setting GraphHopper_Config__mdt with a field API_Key__c.
    – Reference it in Apex instead of hard-coding.
  2. Switch Endpoint to Named Credential:
    – Use the following code to set the endpoint and pass the API key from Protected Metadata.

    String base = 'callout:GraphHopper/route';
    String params = '?point=' + startPoint.getLatitude() + ',' + startPoint.getLongitude() +
                    '&point=' + endPoint.getLatitude() + ',' + endPoint.getLongitude() +
                    '&profile=' + 'car' +
                    '&key=' + GraphHopper_Config__mdt.getInstance('Default').API_Key__c;
    request.setEndpoint(base + params);
  3.  Avoid Duplicate Calls:
    – Only enqueue when either facility coordinate changed or FreightTM__Distance__c is blank/stale.
    – Use a before/after save Flow or Apex trigger with change detection.
  4. Rounding & Units:
    – Store distance as routeMeters / 1000.0. Optionally round to 1–2 decimals for UI.
  5. Bulk Patterns:
    execute already handles multiple Loads. Keep per-transaction API calls within GraphHopper rate limits. Add Limits.getCallouts() checks as guard rails.
  6. Error Handling:
    – Log status codes and response body on non-200 responses.
    – Consider a small retry/backoff for transient 5xx errors.
    – For persistent failures, add a platform event or a custom error object for ops visibility.
  7. Matrix API for Many Pairs:
    – For bulk origin-destination distances (e.g., computing a lane matrix), use the Matrices API and update your persistence model accordingly.
  8. Optional Custom Profiles:
    – For truck constraints (heights, weights), use small_truck or truck profiles (paid) or define custom profiles (premium) and reference them via the profile parameter.

Common Issues

  1. 401/403 Unauthorized:
    – Invalid or missing API key. Ensure &key= is appended correctly.
  2. 429 Rate Limit:
    – Exceeded your plan’s QPS/credits. Reduce concurrency, add jittered retries, and cache distances.
  3. Empty paths Array:
    – Points too close, off-network, or in the ocean; or profile not available on your plan.
  4. Null Coordinates:
    – Ensure both Facilities have coordinates populated. Skip gracefully when missing.
  5. Hard-coded Key in Code:
    -Security risk. Move to protected storage and audit your repo.
  6. URL Too Long:
    – When adding more parameters, switch to POST /route and set JSON body.

Limitations

  • The free plan supports only car, bike, and foot profiles. Heavy vehicle profiles require paid plans.
  • No live traffic in standard OSM routing; TomTom add-on currently applies to Route Optimization, not base Routing.
  • Rate limits/credits apply. Bursts may be throttled.
  • Data coverage/accuracy depends on OSM and your package region.
  • Single-pair focus: For N×M distances, use Matrices API.

FAQs

  1. What profile should I use?
     car by default. For fleets, consider small_truck or truck (paid). You can also build a Custom Profile (premium) to reflect restrictions.
  2. Does GraphHopper return time as well?
     Yes. paths[0].time in milliseconds. You can store this in a custom field if needed.
  3. Can I use POST instead of GET?
     Yes, and it’s recommended for complex requests (custom models, many params) and to avoid URL limits.
  4. How do I stay within rate limits?
     Batch Loads, respect QPS, add backoff on 429/5xx errors, and cache distances when inputs haven’t changed.
  5. Can I compute many distances at once?
     Use the Matrices API for efficient N×M travel times/distances.
  6. Do I need to show attribution?
     If you display maps or route data publicly, include attribution for OpenStreetMap/GraphHopper per licensing.
  7. How do I trigger the queueable flow?
    Create an Invocable Apex that accepts a list of Load IDs and enqueues GraphHopperQueueable. Call it from an After-Save Record-Triggered Flow when coordinates change.
  8. Can I add via points?
     Yes. Add more point= parameters (GET) or an array in POST. Distance will reflect the full route.

GraphHopper Route Optimization (VRP) Integration Guide

Integrate the GraphHopper Route Optimization (VRP) API with FTM to sequence trip stops, optimize routes, and calculate accurate distance and time for trips.

Overview

This integration connects your FTM environment to the GraphHopper VRP API, enabling per-trip optimization and the calculation of accurate distance and time values for routes.

What It Does

  • Sequences trip stops optimally for one vehicle (closed-loop routing)
  • Handles business rules for load prioritization (e.g., high-priority loads first)
  • Calculates and updates distance and time metrics for Trips and Loads
  • Works asynchronously, triggered by Flow, Apex, or manual button clicks

Key Components

  • Apex Class: GraphHopperOptimizer (Queueable Apex)
  • External Services: GraphHopper Route Optimization (/vrp, /route)
  • Data: FreightTM__Trip__c, FreightTM__Load__c, coordinates (pickup/delivery)

Setup Requirements

1. GraphHopper API Key

  • Create a GraphHopper API key from the GraphHopper Developer Portal.
  • Store the API key securely in Protected Custom Metadata (e.g., GraphHopper_Config__mdt.API_Key__c).

2. Salesforce Callout Allowlist

  • Add Remote Site Settings or a Named Credential for https://graphhopper.com/api/1/.
  • Recommended: Use Named Credentials to handle the base URL and append the API key dynamically.

3. Named Credential + Secure Key Handling

  • For best security practice, use Named Credentials for API communication and Custom Metadata for API key storage.
  • Construct requests like:
     callout:GraphHopper/vrp?key=<API_KEY>

4. Permissions

  • Apex Class: Access to GraphHopperOptimizer (Queueable)
  • Field Permissions: CRUD/FLS on Trip and Load fields (Total_Distance__c, Estimated_Driving_Time__c, Route_Sequence__c)
  • Coordinates: Access to Coordinates__Latitude__s, Coordinates__Longitude__s on Warehouse and Load records.

5. Facility Coordinates

  • Ensure that Warehouse facilities have valid latitude/longitude coordinates (Coordinates__Latitude__s and Coordinates__Longitude__s).
  • Ensure Loads have proper pickup/delivery coordinates.

How It Works

1. Query Depot & Stops

  • Depot Coordinates are pulled from the Warehouse record linked to the Trip.
  • Service Stops are fetched from the Load records (delivery coordinates).

2. Build VRP Payload

The VRP payload is constructed with:

  • One vehicle starting at the depot
  • Return-to-depot set to true
  • Each stop (from Load) becomes a service with id = Load.Id and coordinates.

Optional parameters like completion_time and configuration flags (e.g., routing.calc_points) can be added.

3. VRP Request

  • A synchronous call is made to the /vrp endpoint:
     POST /vrp?key=...
     This is ideal for small problems (solvable within ~10 seconds).
  • For large problems, use /vrp/optimize?key=... and poll the solution via /vrp/solution/{jobId}?key=....

4. Extract Initial Sequence

The response from GraphHopper provides a sequence of stops (by id).

  • Extract routes[0].activities and reorder based on the id (matching Load Ids).
  • Assign a Route Sequence to each Load.

5. Handle Business Rules

If any high-priority Loads exist, re-order them before finalizing the sequence.

6. Routing

The final sequence is sent to the /route endpoint to compute the closed-loop route (from depot → stops → depot):

  • Points are structured as:
     [depotLon, depotLat], [lon, lat], [depotLon, depotLat]
  • Call /route with the required vehicle profile and snap_preventions (e.g., motorway, ferry, tunnel).

7. Write Back Results

  • Trip:
    • Total_Distance__c (distance in kilometers)
    • Estimated_Driving_Time__c (formatted time)
  • Load:
    • Update the Route_Sequence__c field according to the final order.

8. Fallback

If the /route call fails or returns no paths, fallback to the VRP solution’s distance/time (solution.distance, solution.transport_time).

Field Mapping

FTM FieldGraphHopper API FieldPurpose
Warehouse Coordinatesvehicle start/endUsed as depot coordinates
Load Coordinatesservice coordinatesUsed as stop coordinates
VRP Solutionroutes[0].activities[].idOrder of loads/services
Route Distancepaths[0].distanceTotal distance (meters) → km
Route Timepaths[0].timeTotal travel time (ms) → formatted
Fallback VRP Solutionsolution.distanceDistance (m) → km
Fallback VRP Solutionsolution.transport_timeTime (s) → formatted

Error Handling & Observability

  • Log status codes and response bodies for non-200 responses.
  • Add retry logic for rate-limited (429) or server errors (5xx).
  • Optionally, create a Platform Event or custom Integration_Log__c for error tracking.

FAQs

  1. When should I use /vrp vs /vrp/optimize?

    Use /vrp for small, fast problems (< 10 stops).
    Use /vrp/optimize for large problems, then poll with /vrp/solution/{jobId}.
  1. Can I pass shipments instead of services?
     Yes, if a stop has both pickup and delivery, use shipments to ensure proper sequencing (pickup before delivery).
  2. How do I respect truck restrictions?
     Use the small_truck or truck profile, or set up a custom profile if your plan supports it.
  3. How do I track API credit usage?
     Monitor the X-RateLimit-* headers in the response for credits/usage. You can log these per request.
  4. Can I avoid specific roads (e.g., ferries, motorways)?
     Yes, use the snap_preventions parameter to avoid certain road types.

Need Help?
For questions, changes, or to activate your GraphHopper integration, email [email protected]

Leave a Reply

Your email address will not be published. Required fields are marked *


Let's Talk!

Thanks for stopping by! We're here to help, please don't hesitate to reach out.

Watch a Demo