---
updatedAt: 2025-11-18T06:37:34.000Z
---

# Pricing & Estimates

***

title: 'Pricing & Estimates'
description: 'Get price estimates and quotes before creating orders'
--------------------------------------------------------------------

`import \{ Callout } from 'nextra/components'`

# Pre-Order Information & Estimates

Before creating an order, you must use the aggregated preorder endpoint to gather all essential pre-order information. This single endpoint provides everything you need to present booking options to your customers and make informed decisions.

## Get Aggregated Pre-Order Information

The aggregated preorder endpoint is your one-stop solution for retrieving comprehensive pre-order data, including:

1. **Service Availability** - Which services are currently available for your route
2. **Service Capabilities** - Passenger and luggage capacity for each service tier
3. **Estimated Prices** - Real-time pricing with currency formatting
4. **Expected Arrival Time** - ETA ranges for driver pickup

This endpoint provides all the information needed to present complete booking options to your users.

### Endpoint

```
GET https://api.gett.com/v1/private/preorder/aggregated
```

### Headers

```
Content-Type: application/json
Authorization: Bearer {your_token}
```

### Query Parameters

| Parameter    | Type   | Required | Description                      |
| ------------ | ------ | -------- | -------------------------------- |
| `partner_id` | string | Yes      | Your partner ID provided by Gett |

### Request Body

| Parameter              | Type   | Required | Description                                                  |
| ---------------------- | ------ | -------- | ------------------------------------------------------------ |
| `stops`                | array  | Yes      | Array of stop objects defining the route                     |
| `stops[].type`         | string | Yes      | Type of stop: `origin`, `destination`, or `on_going`         |
| `stops[].location`     | object | Yes      | Location coordinates                                         |
| `stops[].location.lat` | float  | Yes      | Latitude coordinate                                          |
| `stops[].location.lng` | float  | Yes      | Longitude coordinate                                         |
| `scheduled_at`         | string | No       | Pickup time in ISO8601 format (e.g., `2025-09-28T13:35:00Z`) |
| `category`             | string | Yes      | Service category: `transportation` or `delivery`             |
| `locale`               | string | Yes      | Language code (e.g., `en`, `es`, `fr`)                       |
| `payment_type`         | string | Yes      | Payment method: `cash` (only option for partners)            |

### Example Request

```bash
curl --location 'https://api.gett.com/v1/private/preorder/aggregated?partner_id=1f4c281e-b3eb-4676-beb7-b3a61caba0e6' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer {token}' \
  --data '{
    "stops": [
      {
        "type": "origin",
        "location": {
          "lat": 51.473401, 
          "lng": -0.0221145
        }
      },
      {
        "type": "destination",
        "location": {
          "lat": 51.4712475, 
          "lng": 0.0357987
        }
      }
    ],
    "category": "transportation",
    "locale": "en",
    "payment_type": "cash"
  }'
```

### Example Response

```json
{
  "routes": [
    {
      "uuid": "c41116f6-697c-4799-80e6-af0953a61b00",
      "provider": "google",
      "polyline": "mldyHdgCa@PK?_@Mw@iAG?U[Da@HUN_@Xs@p@yBf@eBj@iCXiBRwCJmBDk@@i@?aBA_ACaAB{@H_ANSh@eBb@qAPw@Fm@F{@?yAIaCWeFe@uHEoBFeCLcBPmCAM@_@D_@D{@VgDd@wGN}@^{FPmCDkBCwBMmE_Cmb@k@mKIqAG_@YmAO[IUASBUFMHi@J_AC]u@mMe@iIKoBEKCGSoCGw@@m@@OIcAa@_IWcFIoAK}AKYK_AKkAg@eFi@cGO{@EGKCWUKWIi@?a@Fg@LY@k@@q@SgBWmDYqEI{EAsDHmBTEtB]jAORFJNP^DNbBoAdBiAtBwAnA{@jBiAz@_@`Ac@EYm@qE]gDEq@O_E",
      "scheduled_at": "2025-10-06T10:34:43Z",
      "distance": 4624,
      "duration": 703,
      "duration_unit": "s",
      "distance_unit": "m",
      "selected_route": true,
      "label": ["manual"]
    }
  ],
  "product_with_prices": [
    {
      "product": {
        "product_id": "74352801-2d3d-4235-966e-11e07b0e076a",
        "name": "Guest Booking",
        "icon": "https://static.gett.com/services/media/media_files/28207/uk_black-cab__1.png",
        "description": "Iconic, spacious black cabs with 5 or 6 seats that can cut through traffic using the bus lanes to get you to your destination faster",
        "eta_sec": 206,
        "eta_description": "Under 4 min",
        "booking_settings": {
          "on_demand": {
            "allowed": true
          },
          "pre_book": {
            "allowed": true,
            "pre_book_in_advance_min": 30,
            "edit_enabled": true,
            "edit_before_scheduled_at_min": 30,
            "destination_mandatory": false
          },
          "stops": {
            "mandatory_origin": true,
            "mandatory_destination": false,
            "ongoing_stops": {
              "allowed": true,
              "max_ongoing_stops": 3
            }
          },
          "multi_riders": {
            "allowed": true,
            "max_tracked_riders": 5
          },
          "max_available_seats": 5,
          "note_to_driver": {
            "allowed": true,
            "mandatory": false
          }
        }
      },
      "price": {
        "pricing_options": [
          {
            "estimation_id": "6f1caae3-d3fa-4b18-992f-ae0a374acfab",
            "price_concept": "meter_range",
            "calculated_as": "meter",
            "include_vat": true,
            "currency": "£",
            "currency_iso": "GBP",
            "tech_fee": {
              "applicable": false,
              "value": 0
            },
            "additional_fee": [
              {
                "name": "driving",
                "value": "18.6",
                "min": 17,
                "max": 20
              }
            ],
            "properties": [
              {
                "name": "meter_total",
                "min": 17,
                "max": 20,
                "is_range": true,
                "amount": "18.6",
                "percentage": null
              }
            ]
          }
        ]
      },
      "eta_to_destination": "0001-01-01T00:00:00Z"
    }
  ]
}
```

## Understanding the Pre-Order Response

The aggregated response provides four critical pieces of information through two main sections:

### Routes Section

Contains route and journey information:

* **Route Details**: Distance (in meters), duration (in seconds), and route polyline
* **Scheduling**: Confirmation of scheduled pickup time
* **Provider**: Route calculation provider (e.g., Google)

### Product with Prices Section

Contains available services and their details:

### 1. Service Availability

Each product includes booking settings that indicate availability:

* **On Demand**: Whether immediate booking is `allowed`
* **Pre-book**: Whether advance booking is `allowed` with minimum advance time
* **Stops Configuration**: Maximum ongoing stops and destination requirements

### 2. Service Capabilities

Detailed service capabilities in `booking_settings`:

* **max\_available\_seats**: Maximum passenger capacity
* **max\_ongoing\_stops**: Maximum intermediate stops allowed
* **max\_tracked\_riders**: Maximum riders that can be tracked
* **note\_to\_driver**: Whether driver notes are supported

### 3. Estimated Prices

Pricing information in the `price.pricing_options` array:

* **estimation\_id**: Unique quote identifier used as `quote_id` when creating orders
* **price\_concept**: Pricing model - `meter`, `meter_range`, or `fixed_price`
  * `meter`: Final price calculated by taxi meter (estimate may be 0 or minimal)
  * `meter_range`: Final price calculated by meter, with estimated range provided (min/max values)
  * `fixed_price`: Price is committed when you create the order using this `estimation_id` as `quote_id`
* **calculated\_as**: Method used to calculate the price (e.g., "meter", "distance")
* **currency** & **currency\_iso**: Currency symbol and ISO code
* **include\_vat**: Whether VAT is included in pricing
* **tech\_fee**: Technology fee details and applicability
* **additional\_fee**: Additional fees with min/max ranges (for meter\_range pricing)
* **properties**: Pricing breakdown with amounts and ranges
  * `is_range`: Indicates if the price includes min/max estimates
  * `min` & `max`: Price range boundaries (for meter\_range)
  * `amount`: Estimated or fixed price amount

<Callout type="info">
  **Price Commitment**: When `price_concept` is `fixed_price`, providing the `estimation_id` as `quote_id` in your order creation request commits the displayed price. For `meter` or `meter_range` pricing, the `quote_id` is still required but the final price will be determined by the taxi meter.
</Callout>

### 4. Expected Arrival Time (ETA)

Driver pickup time estimates:

* **eta\_sec**: ETA in seconds from booking
* **eta\_description**: Human-readable ETA description
* **eta\_to\_destination**: Estimated arrival time at destination

### Service Details

Additional service information:

* **product\_id**: Unique identifier for booking
* **name** & **description**: Service display information
* **icon**: Service icon URL for UI display

<Callout type="warning">
  **Always call the aggregated endpoint before creating orders.** Prices, availability, and ETAs can change rapidly. Never attempt to create an order without first getting current pre-order information.
</Callout>

## Pricing Types

The aggregated response includes pricing information with different pricing models:

### Meter Pricing

When `price_concept` is `"meter"` or `"meter_range"`, the price shown is an **estimate only**:

**Simple Meter Pricing:**

```json
{
  "estimation_id": "4f3cc8ba-b24e-42d9-aef8-3ce528f603fd",
  "price_concept": "meter",
  "calculated_as": "meter",
  "properties": [
    {
      "name": "meter_total",
      "amount": "0",
      "is_range": false
    }
  ]
}
```

**Meter Range Pricing (with estimated range):**

```json
{
  "estimation_id": "6f1caae3-d3fa-4b18-992f-ae0a374acfab",
  "price_concept": "meter_range",
  "calculated_as": "meter",
  "additional_fee": [
    {
      "name": "driving",
      "value": "18.6",
      "min": 17,
      "max": 20
    }
  ],
  "properties": [
    {
      "name": "meter_total",
      "min": 17,
      "max": 20,
      "is_range": true,
      "amount": "18.6"
    }
  ]
}
```

* The `estimation_id` must be provided as `quote_id` when creating the order
* The **final price will be calculated by the taxi meter** during the ride
* For `meter_range`, the displayed range (min/max) and estimated amount are for reference only
* The actual fare may differ from the estimate

### Fixed Price

When `price_concept` is `"fixed_price"`, the price is **committed** when you create the order:

```json
{
  "estimation_id": "1a22584a-9685-4153-a629-271ebc34dcda",
  "price_concept": "fixed_price",
  "calculated_as": "distance",
  "properties": [
    {
      "name": "fixed_total",
      "amount": "25.50",
      "is_range": false
    }
  ]
}
```

* Providing the `estimation_id` as `quote_id` **locks in the displayed price**
* The customer pays exactly the amount shown, regardless of route changes
* Price is guaranteed at order creation time

<Callout type="success">
  **Fixed Price Advantage**: When `fixed_price` is available, using the `quote_id` guarantees the exact fare to your customer, providing price certainty and transparency.
</Callout>

## Integration Workflow

### Required Pre-Order Flow

1. **User selects route** → Call aggregated endpoint
2. **Display options** → Show available services with prices, capacity, and ETAs
3. **User selects service** → Validate selection is still available
4. **Create order** → Use the `product_id` and `estimation_id` (as `quote_id`) from the aggregated response

<Callout type="info">
  When creating an order, you must provide the `quote_id` parameter with the value of `estimation_id` from the selected product's `pricing_options` array. For services with `price_concept: "fixed_price"`, this commits the displayed price. For `price_concept: "meter"`, the quote is required but the final price is determined by the taxi meter.
</Callout>

### Best Practices

#### Real-time Updates

* Cache pre-order data for maximum 2-3 minutes to balance performance and accuracy
* Refresh automatically when route parameters change
* Show users when information was last updated
* Re-fetch before order creation if data is older than 2 minutes

#### Handling Availability Changes

```javascript
async function getPreOrderInfo(routeData) {
  try {
    const response = await fetch(`/v1/private/preorder/aggregated?partner_id=${partnerId}`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(routeData)
    });

    if (!response.ok) {
      if (response.status === 400) {
        throw new Error('Invalid route parameters');
      } else if (response.status === 404) {
        throw new Error('No services available for this route');
      }
      throw new Error('Failed to get pre-order information');
    }

    const data = await response.json();
    
    // Check if we have products and routes
    if (!data.product_with_prices || data.product_with_prices.length === 0) {
      throw new Error('No services currently available for this route');
    }

    if (!data.routes || data.routes.length === 0) {
      throw new Error('No valid routes found for this request');
    }

    // Filter products that allow the requested booking type
    const availableServices = data.product_with_prices.filter(item => {
      const isOnDemand = !routeData.scheduled_at;
      if (isOnDemand) {
        return item.product.booking_settings.on_demand?.allowed;
      } else {
        return item.product.booking_settings.pre_book?.allowed;
      }
    });
    
    if (availableServices.length === 0) {
      throw new Error('No services available for the requested booking type');
    }

    return {
      ...data,
      product_with_prices: availableServices
    };
  } catch (error) {
    console.error('Pre-order info request failed:', error);
    throw error;
  }
}
```

### Multiple Stops

For routes with multiple stops, include all stops in the request:

```json
{
  "stops": [
    {
      "type": "origin",
      "location": {
        "lat": 51.4988787,
        "lng": -0.020746
      }
    },
    {
      "type": "on_going",
      "location": {
        "lat": 51.4899,
        "lng": -0.0125
      }
    },
    {
      "type": "destination",
      "location": {
        "lat": 51.4712475,
        "lng": 0.0357987
      }
    }
  ]
}
```

## Essential Integration Requirements

<Callout type="error">
  **Mandatory Pre-Order Check**: You must call the aggregated endpoint for every booking attempt. This is not optional - it's required to ensure service availability and get current pricing.
</Callout>

### Critical Implementation Points

1. **Always Check All Four Aspects**:
   * ✅ Service availability before showing options
   * ✅ Service capabilities to match user needs
   * ✅ Current prices for accurate billing
   * ✅ Real ETAs for user expectations

2. **User Experience Guidelines**:
   * Display all available service tiers with clear capability differences
   * Show real-time ETAs to set proper expectations
   * Update information when route changes
   * Handle "no services available" scenarios gracefully

3. **Technical Requirements**:
   * Never cache pre-order data longer than 2-3 minutes
   * Always validate selected service is still available before order creation
   * Implement proper loading states during API calls
   * Handle network failures and API errors appropriately

### Complete Integration Example

```javascript
class BookingFlow {
  async displayBookingOptions(origin, destination, scheduledTime) {
    // Step 1: Get all pre-order information
    const preOrderData = await this.getPreOrderInfo({
      stops: [
        { type: 'origin', location: origin },
        { type: 'destination', location: destination }
      ],
      scheduled_at: scheduledTime,
      category: 'transportation',
      locale: 'en',
      payment_type: 'cash'
    });

    // Step 2: Extract route information
    const selectedRoute = preOrderData.routes.find(route => route.selected_route) || preOrderData.routes[0];
    const routeInfo = {
      distance: `${(selectedRoute.distance / 1000).toFixed(1)} km`,
      duration: `${Math.round(selectedRoute.duration / 60)} min`,
      scheduledAt: selectedRoute.scheduled_at
    };

    // Step 3: Process available services
    const availableServices = preOrderData.product_with_prices.filter(item => {
      const isOnDemand = !scheduledTime;
      return isOnDemand 
        ? item.product.booking_settings.on_demand?.allowed
        : item.product.booking_settings.pre_book?.allowed;
    });

    if (availableServices.length === 0) {
      throw new Error('No services available for this route at this time');
    }

    // Step 4: Format service options for display
    return availableServices.map(item => {
      const product = item.product;
      const pricing = item.price.pricing_options[0];
      
      return {
        id: product.product_id,
        name: product.name,
        description: product.description,
        icon: product.icon,
        eta: product.eta_description,
        etaSeconds: product.eta_sec,
        maxSeats: product.booking_settings.max_available_seats,
        maxOngoingStops: product.booking_settings.stops.ongoing_stops.max_ongoing_stops,
        pricing: {
          concept: pricing.price_concept,
          currency: pricing.currency,
          currencyIso: pricing.currency_iso,
          includeVat: pricing.include_vat,
          techFee: pricing.tech_fee
        },
        bookingSettings: product.booking_settings,
        routeInfo: routeInfo
      };
    });
  }

  async createOrderWithValidation(selectedProductId, orderData) {
    // Re-validate availability before creating order
    const currentInfo = await this.getPreOrderInfo(orderData.routeInfo);
    const selectedProduct = currentInfo.product_with_prices.find(
      item => item.product.product_id === selectedProductId
    );

    if (!selectedProduct) {
      throw new Error('Selected service is no longer available');
    }

    // Check booking type availability
    const isOnDemand = !orderData.scheduled_at;
    const bookingAllowed = isOnDemand 
      ? selectedProduct.product.booking_settings.on_demand?.allowed
      : selectedProduct.product.booking_settings.pre_book?.allowed;

    if (!bookingAllowed) {
      throw new Error('Selected booking type is not available for this service');
    }

    // Get the estimation_id (quote_id) from the pricing options
    const quoteId = selectedProduct.price.pricing_options[0].estimation_id;

    // Proceed with order creation using validated product_id and quote_id
    return await this.createOrder({
      ...orderData,
      product_id: selectedProductId,
      quote_id: quoteId
    });
  }

  formatPriceDisplay(pricingOptions) {
    const pricing = pricingOptions[0];
    
    // Handle meter pricing - show as estimate
    if (pricing.price_concept === 'meter') {
      return {
        displayText: `${pricing.currency} Metered pricing`,
        type: 'meter',
        isEstimate: true,
        note: 'Final price determined by taxi meter'
      };
    }
    
    // Handle meter range pricing - show range estimate
    if (pricing.price_concept === 'meter_range') {
      const mainProperty = pricing.properties.find(p => p.name.includes('total'));
      if (mainProperty && mainProperty.is_range) {
        return {
          displayText: `${pricing.currency}${mainProperty.min}-${mainProperty.max}`,
          estimatedAmount: `${pricing.currency}${mainProperty.amount}`,
          type: 'meter_range',
          isEstimate: true,
          note: 'Estimated range - final price determined by taxi meter'
        };
      }
    }
    
    // Handle fixed pricing - show exact amount
    if (pricing.price_concept === 'fixed_price') {
      const mainProperty = pricing.properties.find(p => p.name.includes('total'));
      if (mainProperty && mainProperty.amount !== "0") {
        return {
          displayText: `${pricing.currency}${mainProperty.amount}`,
          type: 'fixed_price',
          isEstimate: false,
          note: 'Price guaranteed at booking'
        };
      }
    }
    
    // Fallback for other pricing types
    return {
      displayText: `${pricing.currency} Variable pricing`,
      type: 'variable',
      isEstimate: true,
      note: 'Contact support for pricing details'
    };
  }
}
```