diff --git a/.vs/CustomM.slnx/FileContentIndex/41c76a87-4087-444c-9287-789a1f92d389.vsidx b/.vs/CustomM.slnx/FileContentIndex/41c76a87-4087-444c-9287-789a1f92d389.vsidx new file mode 100644 index 0000000000..61efea9095 Binary files /dev/null and b/.vs/CustomM.slnx/FileContentIndex/41c76a87-4087-444c-9287-789a1f92d389.vsidx differ diff --git a/.vs/CustomM.slnx/FileContentIndex/66673d21-3398-42f9-bfed-dd49216651ce.vsidx b/.vs/CustomM.slnx/FileContentIndex/66673d21-3398-42f9-bfed-dd49216651ce.vsidx new file mode 100644 index 0000000000..a0a68ee66f Binary files /dev/null and b/.vs/CustomM.slnx/FileContentIndex/66673d21-3398-42f9-bfed-dd49216651ce.vsidx differ diff --git a/.vs/CustomM.slnx/FileContentIndex/85acd012-b787-4669-93f7-b74df3a90ef2.vsidx b/.vs/CustomM.slnx/FileContentIndex/85acd012-b787-4669-93f7-b74df3a90ef2.vsidx new file mode 100644 index 0000000000..4bb2946414 Binary files /dev/null and b/.vs/CustomM.slnx/FileContentIndex/85acd012-b787-4669-93f7-b74df3a90ef2.vsidx differ diff --git a/.vs/CustomM.slnx/FileContentIndex/8dd8556c-bb48-41a6-aaf6-4c78d630a1aa.vsidx b/.vs/CustomM.slnx/FileContentIndex/8dd8556c-bb48-41a6-aaf6-4c78d630a1aa.vsidx new file mode 100644 index 0000000000..f2dae07e44 Binary files /dev/null and b/.vs/CustomM.slnx/FileContentIndex/8dd8556c-bb48-41a6-aaf6-4c78d630a1aa.vsidx differ diff --git a/.vs/CustomM.slnx/FileContentIndex/8f03bb9e-f51a-4ad8-9a59-623bf57534e0.vsidx b/.vs/CustomM.slnx/FileContentIndex/8f03bb9e-f51a-4ad8-9a59-623bf57534e0.vsidx new file mode 100644 index 0000000000..706425f2b6 Binary files /dev/null and b/.vs/CustomM.slnx/FileContentIndex/8f03bb9e-f51a-4ad8-9a59-623bf57534e0.vsidx differ diff --git a/.vs/CustomM.slnx/v18/.wsuo b/.vs/CustomM.slnx/v18/.wsuo new file mode 100644 index 0000000000..8db4b5c616 Binary files /dev/null and b/.vs/CustomM.slnx/v18/.wsuo differ diff --git a/.vs/CustomM.slnx/v18/DocumentLayout.backup.json b/.vs/CustomM.slnx/v18/DocumentLayout.backup.json new file mode 100644 index 0000000000..9762a6da23 --- /dev/null +++ b/.vs/CustomM.slnx/v18/DocumentLayout.backup.json @@ -0,0 +1,12 @@ +{ + "Version": 1, + "WorkspaceRootPath": "C:\\Users\\PC\\Desktop\\CustomM\\", + "Documents": [], + "DocumentGroupContainers": [ + { + "Orientation": 0, + "VerticalTabListWidth": 256, + "DocumentGroups": [] + } + ] +} \ No newline at end of file diff --git a/.vs/CustomM.slnx/v18/DocumentLayout.json b/.vs/CustomM.slnx/v18/DocumentLayout.json new file mode 100644 index 0000000000..9762a6da23 --- /dev/null +++ b/.vs/CustomM.slnx/v18/DocumentLayout.json @@ -0,0 +1,12 @@ +{ + "Version": 1, + "WorkspaceRootPath": "C:\\Users\\PC\\Desktop\\CustomM\\", + "Documents": [], + "DocumentGroupContainers": [ + { + "Orientation": 0, + "VerticalTabListWidth": 256, + "DocumentGroups": [] + } + ] +} \ No newline at end of file diff --git a/.vs/VSWorkspaceState.json b/.vs/VSWorkspaceState.json new file mode 100644 index 0000000000..a57876ee7e --- /dev/null +++ b/.vs/VSWorkspaceState.json @@ -0,0 +1,9 @@ +{ + "ExpandedNodes": [ + "", + "\\independent-publisher-connectors", + "\\independent-publisher-connectors\\Google Maps Routes" + ], + "SelectedNode": "\\independent-publisher-connectors\\Google Maps Routes", + "PreviewInSolutionExplorer": false +} \ No newline at end of file diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite new file mode 100644 index 0000000000..1ea6e731d2 Binary files /dev/null and b/.vs/slnx.sqlite differ diff --git a/independent-publisher-connectors/Google Maps Routes/apiDefinition.json b/independent-publisher-connectors/Google Maps Routes/apiDefinition.json new file mode 100644 index 0000000000..aee3baccb4 --- /dev/null +++ b/independent-publisher-connectors/Google Maps Routes/apiDefinition.json @@ -0,0 +1,705 @@ +{ + "swagger": "2.0", + "info": { + "title": "Google Maps Routes", + "description": "Google Maps provides powerful location and routing services. This connector uses the Google Maps Routes API to calculate travel distance and estimated travel time between a single origin and destination.", + "version": "1.0", + "contact": { + "name": "Remsey Mailjard", + "url": "https://www.skills4-it.nl", + "email": "remsey@skills4-it.nl" + } + }, + "host": "routes.googleapis.com", + "basePath": "/", + "schemes": [ + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + { + "name": "Routes", + "description": "Google Maps Routes v2 operations (computeRoutes)." + } + ], + "paths": { + "/directions/v2:computeRoutes": { + "post": { + "tags": [ + "Routes" + ], + "summary": "Get distance and travel time", + "description": "Get travel distance and estimated travel time between an origin and a destination.", + "operationId": "GetDistanceAndTravelTime", + "x-ms-visibility": "important", + "parameters": [ + { + "name": "X-Goog-FieldMask", + "in": "header", + "required": true, + "type": "string", + "default": "*", + "x-ms-visibility": "advanced", + "x-ms-summary": "Define which route details should be returned.", + "description": "Comma-separated list of fields to include in the response (e.g. routes.duration,routes.distanceMeters). Use \"*\" to return all available fields.\n", + "enum": [ + "*", + "routes.distanceMeters", + "routes.duration", + "routes.staticDuration", + "routes.localizedValues.distance.text", + "routes.localizedValues.duration.text", + "routes.description", + "routes.warnings", + "routes.distanceMeters,routes.duration", + "routes.distanceMeters,routes.duration,routes.staticDuration", + "routes.duration,routes.staticDuration", + "routes.duration,routes.distanceMeters,routes.description", + "routes.duration,routes.distanceMeters,routes.warnings", + "routes.duration,routes.distanceMeters,routes.polyline", + "routes.duration,routes.distanceMeters,routes.legs", + "routes.duration,routes.distanceMeters,routes.localizedValues.distance.text,routes.localizedValues.duration.text", + "routes.duration,routes.distanceMeters,routes.localizedValues.distance.text,routes.localizedValues.duration.text,routes.polyline,routes.legs,routes.description,routes.warnings" + ], + "x-ms-enum-values": [ + { + "value": "*", + "displayName": "Everything (all fields)" + }, + { + "value": "routes.distanceMeters", + "displayName": "Distance only" + }, + { + "value": "routes.duration", + "displayName": "Duration (traffic-aware)" + }, + { + "value": "routes.staticDuration", + "displayName": "Duration (no traffic)" + }, + { + "value": "routes.localizedValues.distance.text", + "displayName": "Distance (localized text)" + }, + { + "value": "routes.localizedValues.duration.text", + "displayName": "Duration (localized text)" + }, + { + "value": "routes.description", + "displayName": "Route summary" + }, + { + "value": "routes.warnings", + "displayName": "Route warnings" + }, + { + "value": "routes.distanceMeters,routes.duration", + "displayName": "Minimal (fast)" + }, + { + "value": "routes.distanceMeters,routes.duration,routes.staticDuration", + "displayName": "Time + Distance (with/without traffic)" + }, + { + "value": "routes.duration,routes.staticDuration", + "displayName": "Compare traffic impact" + }, + { + "value": "routes.duration,routes.distanceMeters,routes.description", + "displayName": "Time + Distance + Summary" + }, + { + "value": "routes.duration,routes.distanceMeters,routes.warnings", + "displayName": "Time + Distance + Warnings" + }, + { + "value": "routes.duration,routes.distanceMeters,routes.polyline", + "displayName": "Time + Distance + Map path" + }, + { + "value": "routes.duration,routes.distanceMeters,routes.legs", + "displayName": "Time + Distance + Legs" + }, + { + "value": "routes.duration,routes.distanceMeters,routes.localizedValues.distance.text,routes.localizedValues.duration.text,routes.polyline,routes.legs,routes.description,routes.warnings", + "displayName": "Full (rich details)" + } + ] + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/ComputeRoutesRequest" + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/ComputeRoutesResponse" + } + }, + "400": { + "description": "Bad request" + }, + "403": { + "description": "Forbidden (invalid/expired API key or insufficient permissions)" + }, + "429": { + "description": "Too Many Requests (quota exceeded or rate-limited)" + }, + "default": { + "description": "Unexpected error (unhandled status code)." + } + }, + "x-ms-examples": { + "GetDistanceAndTravelTimeSample": { + "parameters": { + "X-Goog-FieldMask": "routes.distanceMeters,routes.duration,routes.staticDuration,routes.localizedValues.distance.text,routes.localizedValues.duration.text", + "body": { + "origin": { + "address": "Damrak 1, Amsterdam" + }, + "destination": { + "address": "Spoorlaan 5, Tilburg" + }, + "travelMode": "DRIVE", + "units": "METRIC", + "languageCode": "nl-NL", + "computeAlternativeRoutes": true + } + }, + "responses": { + "200": { + "body": { + "routes": [ + { + "distanceMeters": 115321, + "duration": "4980s", + "staticDuration": "4620s", + "localizedValues": { + "distance": { + "text": "115 km" + }, + "duration": { + "text": "1 uur 23 min" + } + }, + "description": "Fastest route via A2" + } + ] + } + } + } + } + } + } + } + }, + "definitions": { + "ComputeRoutesRequest": { + "type": "object", + "properties": { + "origin": { + "type": "object", + "description": "Origin waypoint. Provide either address OR location.latLng.", + "properties": { + "address": { + "type": "string", + "title": "Origin Address", + "description": "Full street address or place for the origin (e.g. Damrak 1, Amsterdam).\n", + "x-ms-summary": "e.g., Damrak 1, Amsterdam", + "example": "Damrak 1, 1012 LG Amsterdam, Netherlands", + "x-ms-visibility": "important" + }, + "location": { + "type": "object", + "description": "Latitude/Longitude coordinates for the origin.", + "properties": { + "latLng": { + "type": "object", + "description": "Geographic coordinates for the origin.", + "properties": { + "latitude": { + "type": "number", + "format": "double", + "title": "Origin Latitude", + "description": "Latitude in decimal degrees. Range between -90.0 (south) to +90.0 (north).", + "x-ms-summary": "e.g., 52.379189 (Origin)", + "example": 52.379189, + "x-ms-visibility": "advanced" + }, + "longitude": { + "type": "number", + "format": "double", + "title": "Origin Longitude", + "description": "Longitude in decimal degrees. Range between -180.0 (west) to +180.0 (east).", + "x-ms-summary": "e.g., 4.899431 (Origin)", + "example": 4.899431, + "x-ms-visibility": "advanced" + } + } + } + } + } + } + }, + "destination": { + "type": "object", + "description": "Destination waypoint. Provide either address OR location.latLng.", + "properties": { + "address": { + "type": "string", + "title": "Destination Address", + "description": "Full street address or place for the destination (e.g. Spui 70, Den Haag, Nederland).", + "x-ms-summary": "e.g., Spui 70, Den Haag", + "example": "Spui 70, 2511 BT Den Haag, Netherlands", + "x-ms-visibility": "important" + }, + "location": { + "type": "object", + "description": "Latitude/Longitude coordinates for the destination.", + "properties": { + "latLng": { + "type": "object", + "description": "Geographic coordinates for the destination.", + "properties": { + "latitude": { + "type": "number", + "format": "double", + "title": "Destination Latitude", + "description": "Latitude in decimal degrees. Range between -90.0 (south) to +90.0 (north).", + "x-ms-summary": "e.g., 52.070498 (Destination)", + "example": 52.070498, + "x-ms-visibility": "advanced" + }, + "longitude": { + "type": "number", + "format": "double", + "title": "Destination Longitude", + "description": "Longitude in decimal degrees. Range between -180.0 (west) to +180.0 (east).", + "x-ms-summary": "e.g., 4.313499 (Destination)", + "example": 4.313499, + "x-ms-visibility": "advanced" + } + } + } + } + } + } + }, + "travelMode": { + "type": "string", + "title": "Travel Mode", + "description": "Defines travel mode for route calculation. Default is driving.", + "x-ms-visibility": "important", + "default": "DRIVE", + "enum": [ + "DRIVE", + "BICYCLE", + "WALK", + "TWO_WHEELER", + "TRANSIT" + ], + "x-ms-enum-values": [ + { + "value": "DRIVE", + "displayName": "🚗 Driving" + }, + { + "value": "BICYCLE", + "displayName": "🚲 Bicycling" + }, + { + "value": "WALK", + "displayName": "🚶 Walking" + }, + { + "value": "TWO_WHEELER", + "displayName": "🛵 Two-Wheeler (Motorcycle/Scooter)" + }, + { + "value": "TRANSIT", + "displayName": "🚌 Public Transit" + } + ] + }, + "units": { + "type": "string", + "title": "Units", + "description": "Specifies units for display fields like distance text. Default is Metric (kilometers).", + "x-ms-visibility": "important", + "default": "METRIC", + "enum": [ + "METRIC", + "IMPERIAL" + ], + "x-ms-enum-values": [ + { + "value": "METRIC", + "displayName": "Metric (kilometers)" + }, + { + "value": "IMPERIAL", + "displayName": "Imperial (miles)" + } + ] + }, + "departureTime": { + "type": "string", + "description": "Planned departure time in UTC (e.g., 2025-09-20T14:00:00Z). Cannot be combined with arrivalTime.", + "title": "Departure Time", + "format": "date-time", + "x-ms-visibility": "advanced" + }, + "arrivalTime": { + "type": "string", + "description": "Desired arrival time in UTC (e.g., 2025-09-20T16:00:00Z). Cannot be combined with departureTime.", + "title": "Arrival Time", + "format": "date-time", + "x-ms-visibility": "advanced" + }, + "routingPreference": { + "type": "string", + "title": "Routing Preferences", + "description": "Determines how the route is calculated. This option can only be used when the travel mode is DRIVE or TWO_WHEELER.\n", + "x-ms-visibility": "advanced", + "default": "TRAFFIC_AWARE_OPTIMAL", + "x-ms-summary": "Traffic model (live vs. static)", + "enum": [ + "TRAFFIC_AWARE_OPTIMAL", + "TRAFFIC_AWARE", + "TRAFFIC_UNAWARE" + ], + "x-ms-enum-values": [ + { + "value": "TRAFFIC_AWARE_OPTIMAL", + "displayName": "🚦 Best Route (live traffic, default)" + }, + { + "value": "TRAFFIC_AWARE", + "displayName": "🚗 Balanced (considers traffic)" + }, + { + "value": "TRAFFIC_UNAWARE", + "displayName": "🛣️ Fastest Route (ignores traffic)" + } + ] + }, + "trafficModel": { + "type": "string", + "title": "Traffic Model", + "description": "Choose how live traffic is used to predict travel times. Applies only in Driving mode.", + "x-ms-visibility": "important", + "default": "BEST_GUESS", + "enum": [ + "BEST_GUESS", + "PESSIMISTIC", + "OPTIMISTIC" + ], + "x-ms-enum-values": [ + { + "value": "BEST_GUESS", + "displayName": "Best Guess (default, balanced prediction)" + }, + { + "value": "PESSIMISTIC", + "displayName": "Pessimistic (longer travel times)" + }, + { + "value": "OPTIMISTIC", + "displayName": "Optimistic (shorter travel times)" + } + ] + }, + "languageCode": { + "type": "string", + "title": "Language Code", + "description": "Language code for localized route output (e.g., en-US).", + "x-ms-visibility": "advanced", + "default": "en-US", + "enum": [ + "en-US", + "en-GB", + "nl-NL", + "fr-FR", + "de-DE", + "es-ES", + "it-IT" + ], + "x-ms-enum-values": [ + { + "value": "en-US", + "displayName": "English (United States)" + }, + { + "value": "en-GB", + "displayName": "English (United Kingdom)" + }, + { + "value": "nl-NL", + "displayName": "Dutch (Netherlands)" + }, + { + "value": "fr-FR", + "displayName": "French (France)" + }, + { + "value": "de-DE", + "displayName": "German (Germany)" + }, + { + "value": "es-ES", + "displayName": "Spanish (Spain)" + }, + { + "value": "it-IT", + "displayName": "Italian (Italy)" + } + ] + }, + "routeModifiers": { + "$ref": "#/definitions/RouteModifiers" + }, + "computeAlternativeRoutes": { + "type": "boolean", + "title": "Return Alternative Routes", + "description": "Return alternative routes to compare travel times.", + "x-ms-visibility": "advanced", + "x-ms-summary": "Return alternative routes" + }, + "extraComputations": { + "type": "array", + "title": "Extra Computations", + "description": "Request additional information like toll costs or fuel consumption. Select corresponding fields in the FieldMask to get results.", + "x-ms-visibility": "advanced", + "x-ms-summary": "e.g., Tolls, Fuel Consumption", + "items": { + "type": "string", + "enum": [ + "TOLLS", + "FUEL_CONSUMPTION", + "TRAFFIC_ON_POLYLINE" + ], + "x-ms-enum": { + "name": "ExtraComputations", + "values": [ + { + "value": "TOLLS", + "displayName": "Tolls" + }, + { + "value": "FUEL_CONSUMPTION", + "displayName": "Fuel Consumption" + }, + { + "value": "TRAFFIC_ON_POLYLINE", + "displayName": "Traffic on Polyline" + } + ] + } + } + } + }, + "required": [ + "origin", + "destination" + ] + }, + "ComputeRoutesResponse": { + "type": "object", + "description": "Contains the calculated route(s). By default, only the recommended route is returned. If `computeAlternativeRoutes=true`, the response may include multiple routes ordered by quality.\n", + "properties": { + "routes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "distanceMeters": { + "type": "integer", + "format": "int32", + "title": "Distance", + "description": "The total travel distance of the route in meters." + }, + "duration": { + "type": "string", + "title": "Duration with traffic (seconds)", + "description": "Estimated duration including traffic, as a string (e.g., '3461s')." + }, + "staticDuration": { + "type": "string", + "title": "Duration without traffic", + "description": "Travel time without traffic, in seconds (e.g., '3461s')." + }, + "description": { + "type": "string", + "title": "Route Summary", + "description": "A short summary of the route (e.g., \"Fastest route via A4 and A12\")." + }, + "travelAdvisory": { + "type": "object", + "description": "Contains additional information about the route, like toll costs if requested via Extra Computations.", + "properties": { + "tollInfo": { + "type": "object", + "properties": { + "estimatedPrice": { + "type": "array", + "items": { + "type": "object", + "properties": { + "currencyCode": { + "type": "string", + "title": "Currency Code" + }, + "units": { + "type": "string", + "title": "Units (e.g., Dollars, Euros)" + }, + "nanos": { + "type": "integer", + "title": "Nanos (cents)" + } + } + } + } + } + } + } + }, + "localizedValues": { + "type": "object", + "properties": { + "distance": { + "type": "object", + "properties": { + "text": { + "type": "string", + "title": "Readable Distance", + "description": "Formatted distance based on selected units (e.g., '75.4 km')." + } + } + }, + "duration": { + "type": "object", + "properties": { + "text": { + "type": "string", + "title": "Display Duration", + "description": "Human-readable travel time, including traffic (e.g., '58 mins' or '1 hour 5 mins')." + } + } + } + } + } + } + } + } + } + }, + "ErrorResponse": { + "type": "object", + "properties": { + "error": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "title": "Error Code", + "description": "The HTTP status code (e.g., 400, 403, 429, 500)." + }, + "message": { + "type": "string", + "title": "Error Message", + "description": "A developer-facing error message that provides details about the error." + }, + "status": { + "type": "string", + "title": "Error Status", + "description": "A status string that indicates the nature of the error (e.g., INVALID_ARGUMENT, PERMISSION_DENIED, RESOURCE_EXHAUSTED)." + } + } + } + } + }, + "RouteModifiers": { + "type": "object", + "description": "Preferences to avoid specific route features.", + "x-ms-visibility": "advanced", + "properties": { + "avoidTolls": { + "type": "boolean", + "title": "Avoid Tollroads", + "description": "Avoid toll roads in the calculated route.", + "enum": [ + true, + false + ] + }, + "avoidHighways": { + "type": "boolean", + "title": "Avoid Highways", + "description": "Avoid highways in the calculated route.", + "enum": [ + true, + false + ] + }, + "avoidFerries": { + "type": "boolean", + "title": "Avoid Ferries", + "description": "Avoid ferries in the calculated route.", + "enum": [ + true, + false + ] + } + } + } + }, + "securityDefinitions": { + "api_key": { + "type": "apiKey", + "in": "header", + "name": "X-Goog-Api-Key" + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-ms-connector-metadata": [ + { + "propertyName": "Website", + "propertyValue": "https://developers.google.com/maps/documentation/routes" + }, + { + "propertyName": "Privacy policy", + "propertyValue": "https://policies.google.com/privacy" + }, + { + "propertyName": "Terms of service", + "propertyValue": "https://cloud.google.com/maps-platform/terms" + }, + { + "propertyName": "Categories", + "propertyValue": "Data;Productivity" + }, + { + "propertyName": "Publisher", + "propertyValue": "Independent Publisher" + } + ] +} \ No newline at end of file diff --git a/independent-publisher-connectors/Google Maps Routes/apiProperties.json b/independent-publisher-connectors/Google Maps Routes/apiProperties.json new file mode 100644 index 0000000000..55217e1fd3 --- /dev/null +++ b/independent-publisher-connectors/Google Maps Routes/apiProperties.json @@ -0,0 +1,30 @@ +{ + "properties": { + "connectionParameters": { + "api_key": { + "type": "securestring", + "uiDefinition": { + "displayName": "API Key", + "description": "The Google Maps API Key for this api", + "tooltip": "Provide your API Key from: https://console.cloud.google.com/", + "constraints": { + "tabIndex": 2, + "clearText": false, + "required": "true" + } + } + } + }, + "iconBrandColor": "#da3b01", + "capabilities": [], + "publisher": "Remsey Mailjard", + "stackOwner": "Google", + "x-ms-connector-metadata": [ + { "propertyName": "Website", "propertyValue": "https://developers.google.com/maps/documentation/routes" }, + { "propertyName": "Privacy policy", "propertyValue": "https://policies.google.com/privacy" }, + { "propertyName": "Terms of service", "propertyValue": "https://cloud.google.com/maps-platform/terms" }, + { "propertyName": "Categories", "propertyValue": "Data;Productivity" }, + { "propertyName": "Publisher", "propertyValue": "Independent Publisher" } + ] + } +} \ No newline at end of file diff --git a/independent-publisher-connectors/Google Maps Routes/readme.md b/independent-publisher-connectors/Google Maps Routes/readme.md new file mode 100644 index 0000000000..d7f210454b --- /dev/null +++ b/independent-publisher-connectors/Google Maps Routes/readme.md @@ -0,0 +1,125 @@ +# Google Maps Routes (Independent Publisher) + +Google Maps provides powerful location and routing services. This connector uses the [Google Maps Routes API v2](https://developers.google.com/maps/documentation/routes) to calculate travel distance and estimated travel time between an origin and a destination. + +## Publisher: Remsey Mailjard +--- + +## Prerequisites + +To use this connector, you will need: +* A valid [Google Cloud](https://cloud.google.com/) project. +* An API key with the **Routes API** enabled. + +## Obtaining Credentials + +1. Go to the [Google Cloud Console](https://console.cloud.google.com/). +2. Create a new project or select an existing one. +3. Navigate to **APIs & Services > Library**. +4. Search for and select the **Routes API**, then click **Enable**. +5. Go to **APIs & Services > Credentials**. +6. Click **Create Credentials > API key**. +7. Copy the generated API key. It is strongly recommended to secure your API key by restricting its usage to the Routes API only. +8. Use this API key when creating the connection in the Power Platform. The connector uses an API key in the `X-Goog-Api-Key` header for authentication. + +--- + +## Supported Action + +### Get distance and travel time + +Calculates the travel distance and estimated travel time between an origin and a destination. The results can include distance in meters, duration in seconds (with and without traffic), and human-readable text values, among other details controlled by the FieldMask. + +#### Input Parameters + +| Parameter | Description | Required | +| --- | --- | :---: | +| **Origin Address** | The full street address for the origin (e.g., `Damrak 1, Amsterdam`). | Yes | +| **Destination Address** | The full street address for the destination (e.g., `Spoorlaan 5, Tilburg`). | Yes | +| **Travel Mode** | The desired mode of transportation. Defaults to `DRIVE`. | No | +| **Units** | The unit system to use for display text. Defaults to `METRIC`. | No | +| **Traffic Model** | Specifies how live traffic is used to predict travel times. Only applies in `Driving` mode. Defaults to `BEST_GUESS`. | No | +| **X-Goog-FieldMask** | A comma-separated list of fields to include in the response. Use `*` to return all fields. Defaults to `*`. | No | +| **Origin Latitude** | The latitude of the origin. Can be used instead of an address. | No | +| **Origin Longitude** | The longitude of the origin. Can be used instead of an address. | No | +| **Destination Latitude** | The latitude of the destination. Can be used instead of an address. | No | +| **Destination Longitude** | The longitude of the destination. Can be used instead of an address. | No | +| **Departure Time** | The planned departure time in UTC format (e.g., `2025-09-20T14:00:00Z`). Cannot be used with `Arrival Time`. | No | +| **Arrival Time** | The desired arrival time in UTC format (e.g., `2025-09-20T16:00:00Z`). Cannot be used with `Departure Time`. | No | +| **Routing Preferences** | Determines how the route is calculated (e.g., with or without live traffic). Defaults to `TRAFFIC_AWARE_OPTIMAL`. | No | +| **Language Code** | The language code for localized output (e.g., `nl-NL`). Defaults to `en-US`. | No | +| **Return Alternative Routes** | Set to `true` to receive alternative routes for comparison. | No | +| **Route Modifiers** | Specify whether to avoid tolls, highways, or ferries. | No | +| **Extra Computations** | Request additional information like toll costs. Requires a matching `X-Goog-FieldMask`. | No | + +#### Output Properties + +| Property | Description | Example | +| --- | --- | --- | +| **distanceMeters** | The total travel distance in meters. | `115321` | +| **duration** | The estimated travel time in seconds, including current traffic. | `"4980s"` | +| **staticDuration** | The travel time in seconds without considering traffic conditions. | `"4620s"` | +| **description** | A short summary of the route. | `"Fastest route via A2"` | +| **localizedValues.distance.text** | The distance in a human-readable format, based on the selected units. | `"115 km"` | +| **localizedValues.duration.text** | The travel time in a human-readable format. | `"1 hour 23 mins"` | + +--- + +## Usage Example in Power Automate + +This example shows how to calculate the travel time between Amsterdam and Tilburg. + +1. **Trigger:** Start with a manual trigger (`Manually trigger a flow`). +2. **Add Action:** Add the **Get distance and travel time** action from the Google Maps Routes connector. +3. **Fill Parameters:** + * **Origin Address:** `Damrak 1, Amsterdam` + * **Destination Address:** `Spoorlaan 5, Tilburg` + * **Language Code:** `en-US` +4. **Use Results:** Add a 'Compose' action to view the results. You can use dynamic content from the previous step. + * **Inputs:** `The estimated travel time is: @{body('Get_distance_and_travel_time')?['routes']?[0]?['localizedValues']?['duration']?['text']}` + +When you run the flow, the 'Compose' action will contain the text "The estimated travel time is: 1 hour 23 mins" (or a similar value depending on traffic). + +--- + +## Advanced Details + +### `X-Goog-FieldMask` Presets + +Use the `X-Goog-FieldMask` header to request only the data you need. This improves performance and reduces payload size. + +| Preset Label | Value | +| --- | --- | +| Everything (all fields) | `*` | +| Distance only | `routes.distanceMeters` | +| Duration (traffic-aware) | `routes.duration` | +| Duration (no traffic) | `routes.staticDuration` | +| Distance (localized text) | `routes.localizedValues.distance.text` | +| Duration (localized text) | `routes.localizedValues.duration.text` | +| Minimal (fast) | `routes.distanceMeters,routes.duration` | +| Compare traffic impact | `routes.duration,routes.staticDuration` | +| Time + Distance + Summary | `routes.duration,routes.distanceMeters,routes.description` | +| Full (rich details) | `routes.duration,routes.staticDuration,...,routes.description,routes.warnings` | + +> **Note:** If you use `Extra Computations` to request data like `TOLLS`, you must also add the corresponding fields (e.g., `routes.travelAdvisory.tollInfo`) to your FieldMask to receive the data. + +### Error Handling + +| HTTP Status | Meaning | Typical Causes | Recommended Handling | +| :---: | --- | --- | --- | +| `400` | Bad Request | Invalid/missing parameters, malformed FieldMask. | Validate inputs before calling the action, log error. | +| `403` | Forbidden | Invalid/expired API key, Routes API not enabled. | Check API key and ensure Routes API is enabled in your Google Cloud project. | +| `429` | Too Many Requests | Quota exceeded or rate limited by the API. | Use a retry policy in the action's settings (e.g., exponential backoff). | +| `5xx` | Server Error | Transient issues with the Google Maps Platform. | Use a retry policy in the action's settings. | + +### Best Practices + +* **Use a minimal FieldMask:** Start with `routes.distanceMeters,routes.duration,routes.localizedValues` and only add fields as needed. +* **Configure Retries:** In the action's settings in Power Automate, configure a retry policy for `429` and `5xx` errors. +* **Validate Inputs:** Ensure addresses or coordinates are valid before calling the connector to prevent `400` errors. + +### Known Issues and Limitations + +* The connector only supports a single origin and destination per call. Multi-stop itineraries require chaining multiple calls. +* While the underlying API supports Place IDs, this connector's schema is optimized for **address** and **latitude/longitude** inputs. +* Google Maps Platform quotas and billing apply. Ensure you monitor your usage in the Google Cloud Console. \ No newline at end of file