Searching and booking cars

Search car rentals, pick a fare, and create a car booking.

Cars follow the standard four-step flow: search → fares → build → book.
Search and fares stream results as Server-Sent Events (SSE); build and book
return JSON. Every request below carries the full consumer-HMAC and
traveler-bearer headers — see Authentication for how
$SIGNATURE is computed from $METHOD, the request path, $TIMESTAMP, and
the body.

1. Search

POST /v1/cars/search streams car-rental solutions as SSE.

curl -N -X POST "$TRAVELTECH_BASE_URL/v1/cars/search" \
  -H "TravelTech-Consumer: $CONSUMER" \
  -H "TravelTech-Timestamp: $TIMESTAMP" \
  -H "TravelTech-Signature: $SIGNATURE" \
  -H "Authorization: Bearer $TRAVELER_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "pickupLocation": {
      "id": "MXP",
      "type": "airport",
      "name": "Milan Malpensa",
      "country": "IT",
      "date": "2026-02-10",
      "time": "10:00"
    },
    "dropoffLocation": {
      "id": "MXP",
      "type": "airport",
      "date": "2026-02-14",
      "time": "10:00"
    },
    "driverAge": 30,
    "destinationTimezone": "Europe/Rome"
  }'

Request body (CarSearchRequest) — pickup and drop-off are CarLocation
objects identified by id and type (airport or place), each carrying its
own date (YYYY-MM-DD) and time (HH:MM, no timezone):

{
  "pickupLocation": {
    "id": "MXP",
    "type": "airport",
    "name": "Milan Malpensa",
    "country": "IT",
    "date": "2026-02-10",
    "time": "10:00"
  },
  "dropoffLocation": {
    "id": "MXP",
    "type": "airport",
    "date": "2026-02-14",
    "time": "10:00"
  },
  "driverAge": 30,
  "destinationTimezone": "Europe/Rome"
}

When dropoffLocation is omitted, the vehicle is returned to the pickup
location.

A full trace of the response stream — two solutions, then done:

event: solution
data: {"id":"018f2c3e-1234-7abc-8def-000000000121","companyName":"Example Rentals","category":"compact","pickupLocation":"Milan Malpensa","dropoffLocation":"Milan Malpensa","pickupAt":{"localAt":"2026-02-10T10:00:00","timezone":"Europe/Rome","source":"provider"},"dropoffAt":{"localAt":"2026-02-14T10:00:00","timezone":"Europe/Rome","source":"provider"},"totalPrice":{"amount":"186.40","currency":"EUR"},"carModel":"Fiat 500 or similar"}

event: solution
data: {"id":"018f2c3e-1234-7abc-8def-000000000122","companyName":"Another Rentals","category":"suv","pickupLocation":"Milan Malpensa","dropoffLocation":"Milan Malpensa","pickupAt":{"localAt":"2026-02-10T10:00:00","timezone":"Europe/Rome","source":"provider"},"dropoffAt":{"localAt":"2026-02-14T10:00:00","timezone":"Europe/Rome","source":"provider"},"totalPrice":{"amount":"312.00","currency":"EUR"},"carModel":"Jeep Compass or similar"}

event: done
data: {}

Each streamed solution's id is the searchSolutionId for the next step. A
provider failure ends the stream with a terminal event: error frame instead
of done:

event: error
data: {"code":"PROVIDER_ERROR","message":"Search temporarily unavailable."}

2. List fares

POST /v1/cars/fares streams the bookable fares for a chosen solution.

curl -N -X POST "$TRAVELTECH_BASE_URL/v1/cars/fares" \
  -H "TravelTech-Consumer: $CONSUMER" \
  -H "TravelTech-Timestamp: $TIMESTAMP" \
  -H "TravelTech-Signature: $SIGNATURE" \
  -H "Authorization: Bearer $TRAVELER_JWT" \
  -H "Content-Type: application/json" \
  -d '{ "searchSolutionId": "018f2c3e-1234-7abc-8def-000000000121", "solutionKey": null }'

Request body (CarFaresBody):

{ "searchSolutionId": "018f...", "solutionKey": null }

3. Build the fare

POST /v1/cars/fares/build locks a specific fare and returns it as JSON
(201).

curl -X POST "$TRAVELTECH_BASE_URL/v1/cars/fares/build" \
  -H "TravelTech-Consumer: $CONSUMER" \
  -H "TravelTech-Timestamp: $TIMESTAMP" \
  -H "TravelTech-Signature: $SIGNATURE" \
  -H "Authorization: Bearer $TRAVELER_JWT" \
  -H "Content-Type: application/json" \
  -d '{ "fareId": "018f2c3e-1234-7abc-8def-000000000221", "searchSolutionId": "018f2c3e-1234-7abc-8def-000000000121", "solutionKey": null }'

Request body (CarBuildFareBody):

{ "fareId": "018f...", "searchSolutionId": "018f...", "solutionKey": null }

Response (CarFareOut):

{
  "fareId": "018f2c3e-1234-7abc-8def-000000000221",
  "solutionKey": "5b7e91a3...",
  "providerName": "example-rentals",
  "totalPrice": { "amount": "186.40", "currency": "EUR" },
  "isRefundable": false,
  "conditions": ["Full-to-full fuel policy", "Unlimited mileage"],
  "ancillaries": [
    {
      "id": "018f2c3e-1234-7abc-8def-000000000321",
      "kind": "ancillary",
      "code": "gps",
      "name": "GPS navigation",
      "price": { "amount": "8.00", "currency": "EUR" },
      "priceUnit": "per_booking",
      "mode": "selectable",
      "isPerDay": true
    }
  ]
}

If the fare is no longer available (fare locks are time-limited), the build
call returns 410 with the standard
error envelope:

{
  "error": {
    "code": "OFFER_EXPIRED",
    "message": "This fare is no longer available. Search again to get a current price.",
    "details": [],
    "recoveryAction": "CHANGE_SELECTION",
    "retryAfterSeconds": null
  }
}

4. Book

POST /v1/cars/bookings creates the booking from the built fareId using the
shared CreateBookingRequest. Send a unique Idempotency-Key header
(required — see Bookings and trips):

curl -X POST "$TRAVELTECH_BASE_URL/v1/cars/bookings" \
  -H "TravelTech-Consumer: $CONSUMER" \
  -H "TravelTech-Timestamp: $TIMESTAMP" \
  -H "TravelTech-Signature: $SIGNATURE" \
  -H "Authorization: Bearer $TRAVELER_JWT" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 018f2c3e-1234-7abc-8def-000000000421" \
  -d '{
    "fareId": "018f2c3e-1234-7abc-8def-000000000221",
    "passengers": [
      { "firstName": "Ada", "lastName": "Lovelace", "type": "adult", "isHolder": true }
    ],
    "isPersonal": false,
    "tripId": null
  }'

Request body:

{
  "fareId": "018f...",
  "passengers": [
    {
      "firstName": "Ada",
      "lastName": "Lovelace",
      "type": "adult",
      "isHolder": true
    }
  ],
  "isPersonal": false,
  "tripId": null
}

Response (BookingDetailOut, 201):

{
  "bookingId": "018f2c3e-1234-7abc-8def-000000000421",
  "vertical": "car",
  "status": "pending",
  "providerName": null,
  "needsApproval": false,
  "totalPrice": { "amount": "186.40", "currency": "EUR" },
  "availableOperations": ["cancel_booking"],
  "providerData": {},
  "legs": [],
  "carDetail": {
    "pickupLocation": "Milan Malpensa",
    "dropoffLocation": "Milan Malpensa",
    "pickupAt": { "localAt": "2026-02-10T10:00:00", "timezone": "Europe/Rome", "source": "provider" },
    "dropoffAt": { "localAt": "2026-02-14T10:00:00", "timezone": "Europe/Rome", "source": "provider" },
    "rentalDays": 4,
    "vendorName": "Example Rentals",
    "vehicleCategory": "compact",
    "vehicleModel": "Fiat 500 or similar",
    "transmissionType": "manual",
    "isUnlimitedMileage": true
  },
  "travelers": [
    {
      "travelerId": "018f2c3e-1234-7abc-8def-000000000621",
      "displayName": "Ada Lovelace",
      "legAssignments": [],
      "isMainDriver": true
    }
  ],
  "bizAwayCode": "BA-671903",
  "providerConfirmationReferences": [],
  "tripId": null
}

Manage the booking lifecycle with the shared endpoints in
Bookings and trips. Car bookings don't carry the
disruption block — that's populated for flight and rail bookings only — but
other booking-level events still push a notification to the traveler; see
Notification severity tiers for how to
interpret and render the severity field on those notifications.

If the rental provider rejects the booking request outright (for example the
driver's age falls outside the vehicle's restriction, discovered only once the
request reaches the provider), the booking call returns 502 rather than
surfacing a raw upstream error:

{
  "error": {
    "code": "BAD_GATEWAY",
    "message": "Provider rejected the booking request.",
    "details": [],
    "recoveryAction": "RETRY_NOW",
    "retryAfterSeconds": null
  }
}

See the API Reference for the complete request and
response schemas.

Reporting issues

This page is maintained by the BizAway integration team. To request changes or
report an error, contact your BizAway integration contact. Edits made directly
in the ReadMe dashboard are overwritten on the next publish.


Did this page help you?