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:
- Service Availability - Which services are currently available for your route
- Service Capabilities - Passenger and luggage capacity for each service tier
- Estimated Prices - Real-time pricing with currency formatting
- 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
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
, orfixed_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 thisestimation_id
asquote_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 estimatesmin
&max
: Price range boundaries (for meter_range)amount
: Estimated or fixed price amount
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
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 asquote_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
asquote_id
locks in the displayed price - The customer pays exactly the amount shown, regardless of route changes
- Price is guaranteed at order creation time
Integration Workflow
Required Pre-Order Flow
- User selects route → Call aggregated endpoint
- Display options → Show available services with prices, capacity, and ETAs
- User selects service → Validate selection is still available
- Create order → Use the
product_id
andestimation_id
(asquote_id
) from the aggregated response
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
-
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
-
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
-
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'
};
}
}
Updated 7 days ago