This document describes how to create a multi-destination trip, set the correct
fields, and assign it to a vehicle to fulfill. It assumes you have set up Fleet
Engine, you have created vehicles, have a working driver app, and
optionally, a consumer app. You should also be familiar with the various trip
scenarios available for on-demand trips. See the following related guides for
that:

- [Set up Fleet Engine](https://developers.google.com/maps/documentation/mobility/fleet-engine/essentials/set-up-fleet.md.txt)
- [Create a vehicle](https://developers.google.com/maps/documentation/mobility/fleet-engine/essentials/vehicles/on-demand-create-vehicle.md.txt)
- [Trip scenarios](https://developers.google.com/maps/documentation/mobility/fleet-engine/essentials/trip-intro.md.txt#trip-scenarios) in the **On-demand trips** overview

## Trip creation basics

This section describes the request details necessary for creating a trip in
Fleet Engine. You issue a creation request using either gRPC and REST.

- `CreateTrip()` method: [gRPC](https://developers.google.com/maps/documentation/mobility/fleet-engine/reference/trips/rpc/maps.fleetengine.v1.md.txt#maps.fleetengine.v1.TripService) or [REST](https://developers.google.com/maps/documentation/mobility/fleet-engine/reference/trips/rest/v1/providers.trips/create.md.txt)
- `CreateTripRequest` message: [gRPC](https://developers.google.com/maps/documentation/mobility/fleet-engine/reference/trips/rpc/maps.fleetengine.v1.md.txt#maps.fleetengine.v1.CreateTripRequest) only

> [!NOTE]
> **Note:** Using `CreateTrip()` requires the credentials for the privileged account mentioned in [Fleet Engine: Service account roles](https://developers.google.com/maps/documentation/mobility/fleet-engine/essentials/set-up-fleet/service-accounts.md.txt).

## Trip Fields

Use the following fields to create a trip in Fleet Engine. You can use different
fields for the different kinds of trips: single- or multi-destination,
back-to-back, or shared pooling trips. You
can supply the optional fields when you create the trip, or you can set them
later when you update the trip.

| Name | Required? | Description |
|---|---|---|
| **[parent](https://developers.google.com/maps/documentation/mobility/fleet-engine/reference/trips/rpc/maps.fleetengine.v1.md.txt#maps.fleetengine.v1.CreateTripRequest.FIELDS.string.maps.fleetengine.v1.CreateTripRequest.parent)** | Yes | A string that includes the project ID. This ID must be the same ID used across your entire Fleet Engine integration, with the same service account roles. |
| **[trip_id](https://developers.google.com/maps/documentation/mobility/fleet-engine/reference/trips/rpc/maps.fleetengine.v1.md.txt#maps.fleetengine.v1.CreateTripRequest.FIELDS.string.maps.fleetengine.v1.CreateTripRequest.trip_id)** | Yes | A string that you create that uniquely identifies this trip. Trip IDs have certain restrictions, as indicated in the reference. |
| **[trip_type](https://developers.google.com/maps/documentation/mobility/fleet-engine/reference/trips/rpc/maps.fleetengine.v1.md.txt#maps.fleetengine.v1.Trip.FIELDS.maps.fleetengine.v1.TripType.maps.fleetengine.v1.Trip.trip_type)** | Yes | Set the [TripType](https://developers.google.com/maps/documentation/mobility/fleet-engine/reference/trips/rpc/maps.fleetengine.v1.md.txt#triptype) to the following values for the trip type you're creating: - **Single destination** : Set to `SHARED` or `EXCLUSIVE`. - **Multi-destination** : Set to `EXCLUSIVE`. - **Back-to-back** : Set to `EXCLUSIVE`. - **Shared pooling** : Set to `SHARED`. |
| **[pickup_point](https://developers.google.com/maps/documentation/mobility/fleet-engine/reference/trips/rpc/maps.fleetengine.v1.md.txt#maps.fleetengine.v1.Trip.FIELDS.maps.fleetengine.v1.TerminalLocation.maps.fleetengine.v1.Trip.pickup_point)** | Yes | The trip's point of origin. |
| **[Intermediate destinations](https://developers.google.com/maps/documentation/mobility/fleet-engine/reference/trips/rpc/maps.fleetengine.v1.md.txt#maps.fleetengine.v1.Trip.FIELDS.repeated.maps.fleetengine.v1.TerminalLocation.maps.fleetengine.v1.Trip.intermediate_destinations)** | Yes | **Multi-destination trips only** : The list of intermediate destinations that the driver visits in between pickup and drop-off. As with `dropoff_point`, this field can also be set later by calling `UpdateTrip`, but a multi-destination trip by definition contains intermediate destinations. |
| **[vehicle_waypoints](https://developers.google.com/maps/documentation/mobility/fleet-engine/reference/trips/rpc/maps.fleetengine.v1.md.txt#maps.fleetengine.v1.Trip.FIELDS.repeated.maps.fleetengine.v1.TripWaypoint.maps.fleetengine.v1.Trip.vehicle_waypoints)** | Yes | **Shared-pooling trips only** : This field supports interleaving the waypoints from multiple trips. It contains all of the remaining waypoints for the assigned vehicle, as well as the pickup and drop-off waypoints for this trip. You can set this field by calling `CreateTrip` or `UpdateTrip`. You can also update vehicle waypoints through the `waypoints` field with a call to `UpdateVehicle`. The service does not return this information on `GetTrip` calls due to privacy reasons. |
| **[number_of_passengers](https://developers.google.com/maps/documentation/mobility/fleet-engine/reference/trips/rpc/maps.fleetengine.v1.md.txt#maps.fleetengine.v1.Trip.FIELDS.int32.maps.fleetengine.v1.Trip.number_of_passengers)** | No | The number of passengers on the trip. |
| **[dropoff_point](https://developers.google.com/maps/documentation/mobility/fleet-engine/reference/trips/rpc/maps.fleetengine.v1.md.txt#maps.fleetengine.v1.Trip.FIELDS.maps.fleetengine.v1.TerminalLocation.maps.fleetengine.v1.Trip.dropoff_point)** | No | The trip's destination. |
| **[vehicle_id](https://developers.google.com/maps/documentation/mobility/fleet-engine/reference/trips/rpc/maps.fleetengine.v1.md.txt#maps.fleetengine.v1.Trip.FIELDS.string.maps.fleetengine.v1.Trip.vehicle_id)** | No | The ID of the vehicle assigned to the trip. |
[Trip fields]

## Example: create a multi-destination trip

The following demonstrates how to create an exclusive multi-destination trip
that has a pickup point, a drop-off point, and one intermediate destination.

```java
static final String PROJECT_ID = "my-rideshare-co-gcp-project";
static final String TRIP_ID = "multi-destination-trip-A";

TripServiceBlockingStub tripService = TripService.newBlockingStub(channel);

// Trip initial settings.
String parent = "providers/" + PROJECT_ID;

Trip trip = Trip.newBuilder()
    .setTripType(TripType.EXCLUSIVE)
    .setPickupPoint(
        TerminalLocation.newBuilder().setPoint(
            LatLng.newBuilder()
                .setLatitude(-6.195139).setLongitude(106.820826)))
    .setNumberOfPassengers(1)
    .setDropoffPoint(
        TerminalLocation.newBuilder().setPoint(
            LatLng.newBuilder()
                .setLatitude(-6.1275).setLongitude(106.6537)))
    // Add the list of intermediate destinations.
    .addAllIntermediateDestinations(
        ImmutableList.of(
            TerminalLocation.newBuilder().setPoint(
                LatLng.newBuilder()
                    .setLatitude(-6.195139).setLongitude(106.820826)).build()))
    .build();

// Create the Trip request.
CreateTripRequest createTripRequest = CreateTripRequest.newBuilder()
    .setParent(parent)
    .setTripId(TRIP_ID)  // Trip ID assigned by the Provider server.
    .setTrip(trip)       // Initial state is NEW.
    .build();

// Error handling.
try {
  Trip createdTrip =
      tripService.createTrip(createTripRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
    case ALREADY_EXISTS:  // Trip already exists.
      break;
    case PERMISSION_DENIED:
      break;
  }
  return;
}
```

> [!WARNING]
> **Experimental:** As an experimental feature, the `TerminalLocation` ([gRPC](https://developers.google.com/maps/documentation/mobility/fleet-engine/reference/trips/rpc/maps.fleetengine.v1.md.txt#terminallocation) or [REST](https://developers.google.com/maps/documentation/mobility/fleet-engine/reference/trips/rest/v1/TerminalLocation.md.txt)) field now supports using `place` ([gRPC](https://developers.google.com/maps/documentation/mobility/fleet-engine/reference/trips/rpc/maps.fleetengine.v1.md.txt#maps.fleetengine.v1.TerminalLocation.FIELDS.string.maps.fleetengine.v1.TerminalLocation.place) or [REST](https://developers.google.com/maps/documentation/mobility/fleet-engine/reference/trips/rest/v1/TerminalLocation.md.txt#FIELDS.place)), either alongside or instead of `LatLng`.

## Update a multi-destination trip

You must configure the trip with a vehicle ID so that the Fleet Engine can track
the vehicle along its route. For details on updating a trip, see
[Update trips and manage their state](https://developers.google.com/maps/documentation/mobility/fleet-engine/journeys/trips/update-trip.md.txt).

If you don't specify a drop-off or intermediate destinations when you
create the trip, you can always do it at this point.

> [!NOTE]
> **Note:** Whenever you set or update `intermediate_destinations` on a trip, Fleet Engine populates the `intermediate_destinations_version` in the created trip entity. You must cache this field in your system and pass in the `UpdateTripRequest` when you later update the `intermediate_destination_index`. This keeps the intermediate destinations in sync between your driver client and Fleet Engine.

### Example trip update

The following demonstrates how to update a trip to add a list of intermediate
destinations and set a vehicle ID.

```java
static final String PROJECT_ID = "my-rideshare-co-gcp-project";
static final String TRIP_ID = "multi-destination-trip-A";

String tripName = "providers/" + PROJECT_ID + "/trips/" + TRIP_ID;

TripServiceBlockingStub tripService = TripService.newBlockingStub(channel);

// The trip settings to be updated.
Trip trip = Trip.newBuilder()
    // Add the list of intermediate destinations.
    .addAllIntermediateDestinations(
        ImmutableList.of(
            TerminalLocation.newBuilder().setPoint(
                LatLng.newBuilder()
                    .setLatitude(-6.195139).setLongitude(106.820826)).build()))
    .setVehicleId("8241890")
    .build();

// The trip update request.
UpdateTripRequest updateTripRequest = UpdateTripRequest.newBuilder()
    .setName(tripName)
    .setTrip(trip)
    .setUpdateMask(
        FieldMask.newBuilder()
            .addPaths("intermediate_destinations")
            .addPaths("vehicle_id")
            .build())
    .build();

// Error handling.
try {
  Trip updatedTrip =
      tripService.updateTrip(updateTripRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
    case NOT_FOUND:            // The trip doesn't exist.
      break;
    case PERMISSION_DENIED:
      break;
  }
  return;
}
```

> [!WARNING]
> **Experimental:** As an experimental feature, the `TerminalLocation` ([gRPC](https://developers.google.com/maps/documentation/mobility/fleet-engine/reference/trips/rpc/maps.fleetengine.v1.md.txt#terminallocation) or [REST](https://developers.google.com/maps/documentation/mobility/fleet-engine/reference/trips/rest/v1/TerminalLocation.md.txt)) field now supports using `place` ([gRPC](https://developers.google.com/maps/documentation/mobility/fleet-engine/reference/trips/rpc/maps.fleetengine.v1.md.txt#maps.fleetengine.v1.TerminalLocation.FIELDS.string.maps.fleetengine.v1.TerminalLocation.place) or [REST](https://developers.google.com/maps/documentation/mobility/fleet-engine/reference/trips/rest/v1/TerminalLocation.md.txt#FIELDS.place)), either alongside or instead of `LatLng`.

## Manage trip state for multi-destination trips

You specify the state of a trip using one of the [`TripStatus`](https://developers.google.com/maps/documentation/mobility/fleet-engine/reference/trips/rpc/maps.fleetengine.v1.md.txt#tripstatus) enumeration
values. When a trip's state changes, for example from `ENROUTE_TO_PICKUP` to
`ARRIVED_AT_PICKUP`, you must update the trip state in Fleet Engine. Trip
state always begins with a value of `NEW`, and ends with a value of either
`COMPLETE` or `CANCELED`.

For a multi-destination trip, in addition to updating the trip state as you
would for a single destination trip, you must also update the following
every time your vehicle reaches an intermediate destination:

- `intermediateDestinationIndex`
- `intermediateDestinationsVersion`

To do this, use the following values from the [`TripStatus`](https://developers.google.com/maps/documentation/mobility/fleet-engine/reference/trips/rpc/maps.fleetengine.v1.md.txt#tripstatus) enumeration.

- `ENROUTE_TO_PICKUP`
- `ARRIVED_AT_PICKUP`
- `ENROUTE_TO_INTERMEDIATE_DESTINATION`
- `ARRIVED_AT_INTERMEDIATE_DESTINATION`
- `ENROUTE_TO_DROPOFF`
- `COMPLETE`

> [!NOTE]
> **Note:** The trip should transition through both `ENROUTE_TO_INTERMEDIATE_DESTINATION` and `ARRIVED_AT_INTERMEDIATE_DESTINATION` once for every intermediate destination.

### Example trip with intermediate destinations

The following shows how to create a multi-destination trip that has passed its
pickup point, and is now en route to its first intermediate destination.

```java
static final String PROJECT_ID = "my-rideshare-co-gcp-project";
static final String TRIP_ID = "multi-destination-trip-A";

String tripName = "providers/" + PROJECT_ID + "/trips/" + TRIP_ID;

// Get the trip object from either the Fleet Engine or storage.
Trip trip = ...;

TripServiceBlockingStub tripService = TripService.newBlockingStub(channel);

// The trip settings to be updated.
Trip trip = Trip.newBuilder()
    // Trip status cannot return to a previous state once it has passed.
    .setTripStatus(TripStatus.ENROUTE_TO_INTERMEDIATE_DESTINATION)

    // Enroute to the first intermediate destination.
    .setIntermediateDestinationIndex(0)

    // You must provide an intermediate_destinations_version to ensure that you
    // have the same intermediate destinations list as the Fleet Engine.
    .setIntermediateDestinationsVersion(
         trip.getIntermediateDestinationsVersion())
    .build();

// The trip update request.
UpdateTripRequest updateTripRequest = UpdateTripRequest.newBuilder()
    .setName(tripName)
    .setTrip(trip)
    .setUpdateMask(
        FieldMask.newBuilder()
            .addPaths("trip_status")
            .addPaths("intermediate_destination_index")
            // intermediate_destinations_version must not be in the update mask.
            .build())
    .build();

// Error handling.
try {
  Trip updatedTrip =
      tripService.updateTrip(updateTripRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
    case NOT_FOUND:            // The trip doesn't exist.
      break;
    case FAILED_PRECONDITION:  // Either the trip status is invalid, or the
                               // intermediate_destinations_version doesn't
                               // match Fleet Engine's.
      break;
    case PERMISSION_DENIED:
      break;
  }
  return;
}
```

## What's next

- [Create back-to-back trips](https://developers.google.com/maps/documentation/mobility/fleet-engine/journeys/trips/back-to-back.md.txt)
- [Set up the Driver SDK](https://developers.google.com/maps/documentation/mobility/driver-sdk)