Pricing & Estimates

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

ParameterTypeRequiredDescription
partner_idstringYesYour partner ID provided by Gett

Request Body

ParameterTypeRequiredDescription
stopsarrayYesArray of stop objects defining the route
stops[].typestringYesType of stop: origin, destination, or on_going
stops[].locationobjectYesLocation coordinates
stops[].location.latfloatYesLatitude coordinate
stops[].location.lngfloatYesLongitude coordinate
scheduled_atstringNoPickup time in ISO8601 format (e.g., 2025-09-28T13:35:00Z)
categorystringYesService category: transportation or delivery
localestringYesLanguage code (e.g., en, es, fr)
payment_typestringYesPayment method: cash (only option for partners)

Example Request

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

{
  "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
**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.

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
**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.

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:

{
  "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):

{
  "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:

{
  "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
**Fixed Price Advantage**: When `fixed_price` is available, using the `quote_id` guarantees the exact fare to your customer, providing price certainty and transparency.

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
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.

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

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:

{
  "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

**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.

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

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'
    };
  }
}