Dynamic Travel Optimization in Booking with Quota and Capacity Management

Starting with the 25C update, the getBookingOptions and showBookingGrid API operations support the same enhanced dynamic travel optimization capabilities that were introduced in the findMatchingResources API operation in the 25A update. This enhancement significantly improves Orcle Fusion Field Service ability to dynamically optimize scheduling by balancing forecasted activity demand with travel minimization, leading to improved travel efficiency, operational cost savings, and higher customer satisfaction.

The travel-aware optimization is now extended beyond immediate resource matching to the earlier stages of the booking process. This allows the application to propose booking options that intelligently reduce unnecessary travel by aligning new appointments with existing schedules or expected demand patterns in nearby areas.

For example, consider a field service organization operating in a densely populated urban region. The updated API operations can now suggest appointment slots that coincide with other activities already planned nearby, or that are likely to attract clustered bookings based on historical trends and forecasted demand. For instance, if a field resource already has scheduled tasks in a particular neighborhood on a given day, the application may prioritize booking additional appointments in that area during the same timeframe, rather than spreading them across multiple days. This ensures better route consolidation, reduced travel fatigue for field resources, and timely service delivery.

During high-demand periods, such as seasonal maintenance cycles, the travel-aware capabilities of the showBookingGrid API operation help dispatchers identify time slots that are not only available in terms of capacity but are also optimal in terms of travel efficiency. This results in a more intelligent distribution of work and ensures that field teams can address more appointments per day within concentrated geographic zones.

Updated UI Parameters

On the Quota configuration  page, under the  Booking  section, you can now configure the following parameters regardless of the booking approach selected:

  • Optimization goal: Choose between Default (early scheduling) or Optimize Travel.
  • Use forecasted activities during booking: Option to consider forecasted activity flows during booking.
  • Forecast the activity flow within the days range: Defines the forecast range in days (Min and Max values between 0 and 31).
    • For dates before the range, only routes that already contain activities close to the booking are suggested.
    • For dates within the range, the activity flow forecast is applied in a way that additional travel in the proposed routes is close to the per-bucket average.
    • For dates after the range ends, all feasible route positions are returned.

When Use forecasted activities during booking is enabled using UI or API, the application adjusts its scheduling logic based on the booking date relative to the defined forecast range:

  • Before the forecast range: Only route options adjacent to existing activities or with minimal additional travel (less than 120% of average per-bucket travel) are returned.
  • Within the forecast range: Options are selected based on forecasted activity density, travel key proximity, and statistical travel estimations. If no forecast data is available, the application uses the same logic as for dates before the forecast range, that is, no forecasting is applied.
  • After the forecast range: All possible route options are returned, using the standard GetBookingOptions or showBookingGrid API behavior.

NOTE: For a detailed explanation and example of this logic, see Dynamic Travel Optimization in Booking for Direct Assignment in 25A What's New, where this behavior was originally introduced. The same logic is reused here for when Booking is done considering Quota and Capacity Management.

Get Booking Options API Operation Changes

Request Parameter Addition: A new object forecastDuringBooking was added to the request to enable the booking optimization option and the scheduling based on forecasted activity flow. The new object contains the following fields:

  • useForecastDuringBooking
  • optimizationGoal
  • minForecastRangeDay
  • maxForecastRangeDay

Example Request:

{
    "name": "useForecastDuringBooking",
    "in": "query",
    "type": "boolean",
    "description": "Turn on to sort and filter the results by means of forecasting the future activity flow to calculate the average additional travel per activity.",
    "required": false
},
{
    "name": "optimizationGoal",
    "in": "query",
    "type": "string",
    "enum": [
        "default",
        "minimizeAdditionalTravel"
    ],
    "description": "Choose minimizeAdditionalTravel to sort the results by increasing of additional travel added. Default option sorts the results by ETA from minimal to maximal.",
    "required": false
},
{
    "name": "minForecastRangeDay",
    "in": "query",
    "type": "integer",
    "minimum": 0,
    "maximum": 31,
    "description": "Number of days, counted from current day, where current day is 0, before which only results that has an existing activity within the close proximity are returned. No activity flow forecasting is done before Minimum Forecast Range Day.",
    "required": false
},
{
    "name": "maxForecastRangeDay",
    "in": "query",
    "type": "integer",
    "minimum": 0,
    "maximum": 31,
    "description": "Number of days, counted from current day, where current day is 0. Should be greater than Minimum Forecast Range Day. Application does the activity flow forecasting between Minimum Forecast Range Day and Maximum Forecast Range Day. During this period the average additional travel is calculated based on the number of the forecasted activities within the close proximity of the activity being booked and only results having the additional travel lesser than the average per-bucket travel are returned. After the Maximum Forecast Range Day all the available results are returned, despite the additional travel. No activity flow forecasting is done after Maximum Forecast Range Day.",
    "required": false
}

Example Response:

?dates=2025-02-14
&useForecastDuringBooking=true
&optimizationGoal=minimizeAdditionalTravel
&minForecastRangeDay=1
&maxForecastRangeDay=10
&determineAreaByWorkZone=true
&estimateTravelTime=true
&estimateDuration=true
&determineCategory=true
&string_text_activity_property=IN
&activityType=default_customer_activity_type
&WO_TYPE=4
&postalCode=32953
&city=Merrit%20Island&address=250%20Crockett%20Blvd
&state=FL
&latitude=28.3864047
&longitude=-80.7073004
&defaultDuration=40
&BookingStatisticProperty_1=PROP4
&BookingStatisticProperty_2=PROP5
&BookingStatisticProperty_3=PROP6
&BookingStatisticProperty_4=PROP7

Response changes: If the "Using forecasted activities flow" option is enabled (either through the GUI or API parameters), the scheduling options returned will be different from the default settings. A new object recommendationInfo is added.

The example of getBookingOptions response with new objects:

{
    "duration": 40,
    "travelTime": 31,
    "actualAtTime": "2025-02-07 14:47:33",
    "categories": [
        "API_category1"
    ],
    "workZone": "ChristmasBKFRD",
    "timeSlotsDictionary": [
        {
            "label": "08-10",
            "name": "08-10",
            "timeFrom": "00:01:00",
            "timeTo": "23:59:00"
        },
        {
            "label": "14-18",
            "name": "14-18",
            "timeFrom": "14:00:00",
            "timeTo": "18:00:00"
        },
        {
            "label": "12-14",
            "name": "12-14",
            "timeFrom": "12:00:00",
            "timeTo": "14:00:00"
        }
    ],
    "dates": [
        {
            "date": "2025-02-14",
            "areas": [
                {
                    "label": "AreaTF",
                    "name": "AreaTF",
                    "averageBucketTravel": 31,
                    "averageTravelKeyTravel": 15,
                    "hasNearbyActivities": true,
                    "hasForecastedActivities": false,
                    "duration": 40,
                    "travelTime": 30,
                    "bucket": "AreaTF",
                    "timeZone": "Europe/Athens",
                    "timeZoneDiff": 120,
                    "timeSlots": [
                        {
                            "label": "12-14",
                            "recommendationInfo": {
                                "additionalTravel": 23,
                                "travelKeyMatch": true
                            }
                        },
                        {
                            "label": "14-18",
                            "recommendationInfo": {
                                "additionalTravel": 23,
                                "travelKeyMatch": true
                            }
                        },
                        {
                            "label": "08-10",
                            "recommendationInfo": {
                                "additionalTravel": 23,
                                "travelKeyMatch": true
                            }
                        }
                    ]
                }
            ]
        }
    ]
}

Recommendation Info: New recommendationInfo object has been added to the getBookingOptions response structure:

"recommendationInfo": {
    "type": "object",
    "description": "This structure is provided for options that are recommended by the system.",
    "properties": {
        "additionalTravel": {
            "type": "integer",
            "title": "Additional Travel",
            "description": "The difference in minutes between total travel in the current route and travel in the proposed route where the booking activity added."
        },
        "travelKeyMatch": {
            "type": "boolean",
            "title": "Travel Key Match",
            "description": "Contains one of the following values: true or false. If true, either the previous or the following activity has the same travel travel key value as the activity specified in request. If false, then the previous or the following activity has the different travel key values as the activity specified in request."
        }
    }
}

Additional Travel field: New additionalTravel integer field has been added to the getBookingOptions (as a part of recommendationInfo object) response structure containing additional travel that is needed if the requested activity is booked at the proposed positions.

{
    "type":"object",
    "properties":{
...
        "additionalTravel":{
            "type":"integer",
            "title":"Additional Travel",
            "description":"The difference in minutes between total travel in the current route and travel in the proposed route where the booking activity added."
        },
...
    }
}

Travel Key Match field: New travelKeyMatch boolean field has been added to to the getBookingOptions response structure being true if the next or the previous of the activities in the route belongs to the same travel key.

{
    "type":"object",
    "properties":{
...
        "travelKeyMatch":{
            "type":"boolean",
            "title":"Travel Key Match",
            "description":"Contains one of the following values: true or false. If true, either the previous or the following activity has the same travel travel key value as the activity specified in request. If false, then the previous or the following activity has the different travel travel key values as the activity specified in request."
        }
    }
}

Average Bucket Travel: A new parameter averageBucketTravel was added. It is an average travel time for activities in the bucket.

"averageBucketTravel": {
    "type": "integer",
    "title": "Average Travel Time On The Technician Bucket",
    "description": "Contains the value of average travel time over the bucket."
}

Average TravelKey Travel: A new parameter averageTravelKeyTravel was added. It is an average travel time for activities within the same travel key.

"averageTravelKeyTravel": {
    "type": "integer",
    "title": "Average Travel Time On The FMR Activity Travel Key",
    "description": "Contains the value of average travel time for the traveling withing the same travel key as of FMR activity."
}

Has Nearby Activities: A new flag hasNearbyActivities was added. It indicating whether there are activities in the same travel key placed immediately before or after the bookable activity.

"hasNearbyActivities": {
    "type": "boolean",
    "title": "Contains Nearby Activities",
    "description": "Contains one of the following values: true or false. If true, either the previous or the following activity is in close proximity of the activity specified in request. If false, then the previous or the following activity is not in close proximity of the activity specified in request."
}

Has Forecasted Activities: A new flag has ForecastedActivities was added. It indicating whether forecasted activities were used during the calculation of the additionalTravel parameter.

"hasForecastedActivities": {
    "type": "boolean",
    "title": "Contains Forecasted Activities",
    "description": "Contains one of the following values: true or false. If true, the activity flow forecast was used to calculate the additional travel. If false, then only activities already present in the route were used to calculate the additional travel."
}

Too Long Travel Status: If the Using forecasted activities flow option is enabled either through the GUI or API parameters, the scheduling options returned could have a new status tooLongTravel. If additionalTravel exceeds averageBucketTravel by more than 20%, and there is no travelKeyMatch, the booking option gets the status tooLongTravel.

Show Booking Grid API Operation Changes

Request Parameter Addition: A new object 'forecastDuringBooking' was added to the request to enable the booking optimization option and the scheduling based on forecasted activity flow. The new object contains the following fields:

  • useForecastDuringBooking
  • optimizationGoal
  • minForecastRangeDay
  • maxForecastRangeDay

Example Request:

"forecastDuringBooking": {
    "type": "object",
    "title": "Forecast During Booking",
    "description": "The criteria used to sort and filter the results by means of forecasting the future activity flow to calculate the average additional travel per activity.<p>Results with travel more than an average per bucket are filtered out before the end of forecasting period. If a particular parameter is not present or not specified in request, then the default values are applied.</p>",
    "properties": {
        "useForecastDuringBooking": {
            "title": "Enable Forecast During Booking",
            "description": "Turn on to sort and filter the results by means of forecasting the future activity flow to calculate the average additional travel per activity.",
            "type": "boolean"
        },
        "optimizationGoal": {
            "title": "Optimization Goal",
            "description": "Choose minimizeAdditionalTravel to sort the results by increasing of additional travel added. Default option sorts the results by ETA from minimal to maximal.",
            "type": "string",
            "enum": [
                "default",
                "minimizeAdditionalTravel"
            ]
        },
        "minForecastRangeDay": {
            "title": "Minimum Forecast Range Day",
            "description": "Number of days, counted from current day, where current day is 0, before which only results that has an existing activity within the close proximity are returned. No activity flow forecasting is done before Minimum Forecast Range Day.",
            "type": "integer",
            "minimum": 0,
            "maximum": 31
        },
        "maxForecastRangeDay": {
            "title": "Maximum Forecast Range Day",
            "description": "Number of days, counted from current day, where current day is 0. Should be greater than Minimum Forecast Range Day. System does the activity flow forecasting between Minimum Forecast Range Day and Maximum Forecast Range Day. During this period the average additional travel is calculated based on the number of the forecasted activities within the close proximity of the activity being booked and only results having the additional travel lesser than the average per-bucket travel are returned. After the Maximum Forecast Range Day all the available results are returned, despite the additional travel. No activity flow forecasting is done after Maximum Forecast Range Day.",
            "type": "integer",
            "minimum": 0,
            "maximum": 31
        }
    }
}

Example Response:

"forecastDuringBooking": {
    "useForecastDuringBooking": true,
    "optimizationGoal": "minimizeAdditionalTravel",
    "minForecastRangeDay": 1,
    "maxForecastRangeDay": 10
}

Response changes

If the "Using forecasted activities flow" option is enabled either through the GUI or API parameters, the scheduling options returned will be different from the default settings. The behavior for returned schedule options varies based on the date range and is the same as for findMatchingResources API.

The example of Items part of FMR response with new objects:

{
    "duration": 57,
    "travelTime": 31,
    "actualAtTime": "2025-02-07 14:54:36",
    "workZone": "ChristmasBKFRD",
    "areas": [
        {
            "label": "AreaTF",
            "name": "AreaTF",
            "bucket": "AreaTF",
            "averageBucketTravel": 31,
            "averageTravelKeyTravel": 15,
            "timeZone": "Europe/Athens",
            "areaTimeSlots": [
                "08-10",
                "14-18",
                "12-14"
            ],
            "dates": [
                {
                    "date": "2025-02-14",
                    "hasNearbyActivities": true,
                    "hasForecastedActivities": false,
                    "timeZoneDiff": 120,
                    "timeSlots": [
                        {
                            "label": "12-14",
                            "resourceId": "AreaTF",
                            "recommendationInfo": {
                                "additionalTravel": 23,
                                "travelKeyMatch": true
                            }
                        },
                        {
                            "label": "14-18",
                            "resourceId": "AreaTF",
                            "recommendationInfo": {
                                "additionalTravel": 31,
                                "travelKeyMatch": true
                            }
                        },
                        {
                            "label": "08-10",
                            "resourceId": "AreaTF",
                            "recommendationInfo": {
                                "additionalTravel": 23,
                                "travelKeyMatch": true,
                                "level": "best",
                                "nearbyDistance": 22.048
                            }
                        }
                    ]
                }
            ]
        }
    ]
}

Recommendation Info: The existing recommendationInfo object has been updated with two new fields:

"recommendationInfo": {
                                                        "type": "object",
                                                        "description": "This structure is provided for options that are recommended by the system.",
                                                        "properties": {
                                                            "level": {
                                                                "description": "This attribute may be used in user interfaces for booking to mark the options with two levels of recommendations.",
                                                                "type": "string",
                                                                "enum": [
                                                                    "good",
                                                                    "best"
                                                                ]
                                                            },
                                                            "nearbyDistance": {
                                                                "description": "The distance in kilometers to the nearby activity (e.g. 'nearbyDistance': 12.5). This value is provided for Capacity Areas with Quota based booking.",
                                                                "type": "number"
                                                            },
                                                            "nearbyTravel": {
                                                                "description": "The estimated travel time in minutes to or from the nearby activity. This value is provided for Capacity Areas with Direct Assignment based booking.",
                                                                "type": "integer"
                                                            },
                                                            "additionalTravel": {
                                                                "type": "integer",
                                                                "title": "Additional Travel",
                                                                "description": "The difference in minutes between total travel in the current route and travel in the proposed route where the booking activity added."
                                                            },
                                                            "travelKeyMatch": {
                                                                "type": "boolean",
                                                                "title": "Travel Key Match",
                                                                "description": "Contains one of the following values: true or false. If true, either the previous or the following activity has the same travel travel key value as the activity specified in request. If false, then the previous or the following activity has the different travel travel key values as the activity specified in request."
                                                            }
                                                        }

Additional Travel field: New additionalTravel integer field has been added to the showBookingGrid response structure containing additional travel that is needed if the requested activity is booked at the proposed positions.

{
    "type":"object",
    "properties":{
...
        "additionalTravel":{
            "type":"integer",
            "title":"Additional Travel",
            "description":"The difference in minutes between total travel in the current route and travel in the proposed route where the booking activity added."
        },
...
    }
}

Travel key match field: New travelKeyMatch boolean field has been added to to the showBookingGrid response structure being true if the next or the previous of the activities in the route belongs to the same travel key.

{
    "type":"object",
    "properties":{
...
        "travelKeyMatch":{
            "type":"boolean",
            "title":"Travel Key Match",
            "description":"Contains one of the following values: true or false. If true, either the previous or the following activity has the same travel travel key value as the activity specified in request. If false, then the previous or the following activity has the different travel travel key values as the activity specified in request."
        }
    }
}

Average TravelKey Travel: A new parameter averageTravelKeyTravel was added.  It is an average travel time for activities within the same travel key.

"averageTravelKeyTravel": {
    "type": "integer",
    "title": "Average Travel Time On The FMR Activity Travel Key",
    "description": "Contains the value of average travel time for the traveling withing the same travel key as of FMR activity."
}

Has Nearby Activities: A new flag hasNearbyActivities was added.  It indicating whether there are activities in the same travel key placed immediately before or after the bookable activity.

"hasNearbyActivities": {
    "type": "boolean",
    "title": "Contains Nearby Activities",
    "description": "Contains one of the following values: true or false. If true, either the previous or the following activity is in close proximity of the activity specified in request. If false, then the previous or the following activity is not in close proximity of the activity specified in request."
}

Has Forecasted Activities: A new flag hasForecastedActivities was added. It indicates whether forecasted activities were used during the calculation of the additionalTravel parameter.

"hasForecastedActivities": {
    "type": "boolean",
    "title": "Contains Forecasted Activities",
    "description": "Contains one of the following values: true or false. If true, the activity flow forecast was used to calculate the additional travel. If false, then only activities already present in the route were used to calculate the additional travel."
}

Too Long Travel Status: If the "Using forecasted activities flow" option is enabled (either through the GUI or API parameters), the scheduling options returned could have a new status tooLongTravel. If additionalTravel exceeds averageBucketTravel by more than 20%, and there is no travelKeyMatch, the booking option gets the status tooLongTravel.

Business Benefit

  • Reduce travel-related costs by introducing travel optimization into the early stages of the booking process, aligning booking decisions with the routing engine's travel efficiency goals.
  • Improve field resource efficiency by proactively grouping nearby appointments based on existing schedules or forecasted demand, minimizing unnecessary travel before routes are finalized.
  • Enhance service quality and responsiveness by enabling smarter booking options that support timely and efficient service delivery while maintaining alignment with real-time routing strategies.

Steps to Enable

There are two ways to enable the feature - through UI, as default values that are used for each and every API call, and on the per-request level.

Enabling through UI (Default for All API Calls)

  1. Access Quota Configuration:
    • Navigate to the Quota Configuration page from the Navigation menu.
    • Ensure the bucket(s) containing the technicians for the target activities are placed under one or more of the designated Capacity Areas.
  2. Enable Travel Optimization:
    • Under Optimization Goal, select "Minimize Travel" to order schedule options based on additional travel.
  3. Activate Forecasted Activities Flow:
    • Turn on the "Use forecasted activities flow during booking" option.
    • Adjust the forecast range using the slider to specify the number of days for which activity flow should be forecasted. Set the minimum and maximum days within the range (0–31 days). Note that 0 represents the current day, and the maximum range is 31 days.
  4. Save Configuration:
    • Save the changes to ensure the feature is enabled across all relevant API calls.

Enabling through API (Per-Request Level)

  1. Modify API Request:
    • In the API request, include the following fields under the  forecastDuringBooking object:
      • useForecastDuringBooking: true
      • optimizationGoal: minimizeAdditionalTravel
      • minForecastRangeDay and maxForecastRangeDay with values within the range of 0 to 31.
  2. Include Required Response Fields:
    • Ensure the schedulesToReturn collection includes the  forecastDuringBookingDetails object to retrieve the new fields in the response.
    • Verify the schedulesToReturn covers dates within the  minForecastRangeDay to maxForecastRangeDay range.

Tips And Considerations

  • Field Service subscription with Quota and Capacity Management functionality is required.
  • Choose the forecast range carefully based on operational needs. A broader range improves optimization but may increase processing time.
  • Balance flexibility for emergency bookings with travel minimization to maintain operational responsiveness.