Booking Details API
Authenticated endpoint for retrieving comprehensive booking details including offer, product, and passenger information.
Overview
Section titled “Overview”The Booking Details API provides an admin-only endpoint for accessing complete booking information scoped to specific markets and languages.
Authentication: Requires active admin session (web middleware + auth) and admin role.
Base URL Pattern: /api/{market}/{lang}/bookings/{bookingReference}
Endpoint
Section titled “Endpoint”GET /api/{market}/{lang}/bookings/{bookingReference}
Section titled “GET /api/{market}/{lang}/bookings/{bookingReference}”Get complete booking details by reference code.
Parameters:
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| market | path | string | Yes | Market code (case-insensitive) |
| lang | path | string | Yes | Language code (e.g., “en”, “es”, “ca”) |
| bookingReference | path | string | Yes | Booking reference code (e.g., “BK-ABC12345”) |
Response: 200 OK
{ "data": { "booking_reference": "BK-ABC12345", "status": "confirmed", "status_label": "Confirmed", "total_amount": "2500.00", "currency": "EUR", "currency_symbol": "€", "booked_at": "2024-12-15T10:30:00+00:00", "number_of_travelers": 2, "market_code": "es", "customer_service_phone": "+34 919 49 45 52", "footer_copyright": "© BY VOLARE SL. Todos los derechos reservados", "offer": { "id": 123, "sku": "ES-5CMB10-CA1-2024-01-15", "departure_date": "2024-01-15", "return_date": "2024-01-26", "trip_days": 12, "final_price": "1300.00", "marketing_price_per_pax": "650.00", "room_type": "double", "room_type_label": "Double Room", "departure_airport": { "iata_code": "BCN", "name": "Barcelona-El Prat Airport", "city": "Barcelona" } }, "product": { "id": 10, "sku": "ES-5CMB10-CA1", "title": "Tour de Sri Lanka", "subtitle": "Descobreix l'illa maragda", "short_description": "Una aventura increible...", "highlights": ["Sigiriya", "Kandy", "Yala"], "itinerary": [ { "day": 1, "date": "2024-01-15", "title": "Arrival in Colombo", "details": "Arrive, meet your host, private transfer to the hotel.", "image_url": "https://cdn.example.com/itineraries/day1.jpg" } ], "hero_image": "https://cdn.example.com/images/sri-lanka.jpg", "trip_duration_days": 10 }, "passengers": [ { "id": 1, "first_name": "John", "last_name": "Doe", "full_name": "John Doe", "age_category": "adult", "date_of_birth": "1985-03-15", "is_lead_passenger": true, "email": "john@example.com", "phone": "+34612345678" } ], "hotels": [ { "name": "Cinnamon Lodge Habarana", "city": "Habarana", "nights": 2, "check_in": "2024-01-15", "check_out": "2024-01-17", "image_urls": ["https://cdn.example.com/hotels/cinnamon.jpg"], "is_upgrade": false } ], "flights": { "cabin_class": "ECONOMY", "outbound": { "date": "2024-01-15", "departure_time": "10:30", "arrival_time": "23:45", "departure_airport": { "iata_code": "BCN", "city": "Barcelona" }, "arrival_airport": { "iata_code": "CMB", "city": "Colombo" }, "segments": [ { "flight_number": "EK186", "airline_code": "EK", "airline_name": "Emirates", "departure_airport": { "iata_code": "BCN", "city": "Barcelona" }, "arrival_airport": { "iata_code": "DXB", "city": "Dubai" }, "departure_time": "10:30", "arrival_time": "20:15" } ], "stopovers": [ { "airport": { "iata_code": "DXB", "city": "Dubai" }, "layover_minutes": 120 } ], "total_duration_minutes": 795 }, "inbound": { "date": "2024-01-25", "departure_time": "01:30", "arrival_time": "12:15", "departure_airport": { "iata_code": "CMB", "city": "Colombo" }, "arrival_airport": { "iata_code": "BCN", "city": "Barcelona" }, "segments": [], "stopovers": [], "total_duration_minutes": 780 } }, "experiences": [ { "name": "Visita guiada a la roca de Sigiriya", "city": "Sigiriya", "date": "2024-01-16", "image_url": "https://cdn.example.com/activities/sigiriya.jpg", "tier": "included" }, { "name": "Safari en jeep por el Parque Nacional de Yala", "city": "Yala", "date": "2024-01-17", "image_url": "https://cdn.example.com/activities/yala-safari.jpg", "tier": "extra" } ], "optional_services": [ { "name": "Traslado privado aeropuerto - hotel", "description": "Vehículo privado con conductor desde el aeropuerto de Colombo hasta el hotel." } ] }}Error Responses
Section titled “Error Responses”Not Authenticated (401)
Section titled “Not Authenticated (401)”{ "message": "Unauthenticated."}Not Admin (403)
Section titled “Not Admin (403)”{ "message": "Access denied. Admin role required."}Booking Not Found (404)
Section titled “Booking Not Found (404)”Returned when booking does not exist, or does not belong to requested market/locale.
{ "success": false, "error": "booking_not_found", "message": "Booking with reference 'XYZ' not found."}Language Not Supported (400)
Section titled “Language Not Supported (400)”{ "success": false, "error": "language_not_supported", "message": "Language 'de' is not supported by market 'ES'. Supported languages: es, ca"}Flight Data Sources
Section titled “Flight Data Sources”The flights field is populated from multiple sources in priority order:
| Priority | Source | Cabin Class | When Used |
|---|---|---|---|
| 1 | booking_upsells.flight_search_params | BUSINESS | Customer upgraded to business class |
| 2 | booking.flight_selection | ECONOMY | Customer selected economy flight during checkout |
| 3 | dynamic_flight_cache (itinerary_index=1) | ECONOMY | Legacy fallback for older bookings |
The resource handles both enriched format (with nested airport objects containing iata_code and city) and legacy format (plain IATA code strings) for backward compatibility.
Each segment carries both airline_code (IATA code, e.g. EK) and airline_name (full carrier name, e.g. Emirates). airline_name falls back to the code when the full name is unavailable — older economy selections stored before names were captured, or business-upgrade legs whose search params carry no names. Cached economy legs resolve the name from the dynamic_flight_cache_segments.airline_name column.
Trip Dates (Door-to-Door)
Section titled “Trip Dates (Door-to-Door)”offer.return_date (YYYY-MM-DD) and offer.trip_days (inclusive day count) are derived from the bound international flight via Offer::getTravelDates() — door-to-door, outbound departure day to return arrival-home day (same source as the booking emails). Both are null when no flight is bound (land-only / pre-flight); the frontend then falls back to the product.trip_duration_days land-tour estimate. product.trip_duration_days (itinerary nights + 1) remains unchanged and can under-report long-haul trips whose return leg spans an extra travel day.
Top-Level Fields
Section titled “Top-Level Fields”In addition to the booking core fields, the response includes market-aware metadata used by the frontend:
| Field | Type | Description |
|---|---|---|
market_code | string | Lowercased market code for frontend routing (defaults to es) |
customer_service_phone | string | null | Market customer-service phone number |
footer_copyright | string | null | Footer copyright text, resolved from CmsFooter via the market’s default locale |
Hotels
Section titled “Hotels”Each hotel stay groups consecutive nights at the same hotel.
| Field | Type | Description |
|---|---|---|
name | string | Hotel name |
city | string | null | POI city name |
nights | int | Number of nights |
check_in | string | Check-in date (YYYY-MM-DD) |
check_out | string | Check-out date (YYYY-MM-DD) |
image_urls | string[] | Full URLs for all hotel images (empty array when none) |
is_upgrade | bool | Whether the stay is a selected hotel upgrade (luxury or grand-luxury tier). The highest purchased tier wins: grand-luxury takes precedence over luxury, which takes precedence over the base selection hotel |
Itinerary
Section titled “Itinerary”product.itinerary is a flat, per-day list — one entry per calendar day, sequential from the offer’s departure date. Each item: { day, date, title, details, image_url }. The tour’s stops (which can span multiple nights) are flattened into individual days: per-day text (title/details) comes from the localized translation, and image_url is resolved from the tour template’s per-day image (day_image), or null when the tour has no image for that day.
Experiences and Optional Services
Section titled “Experiences and Optional Services”These arrays surface the activities and services for the booking:
experiences— the tour’s included activities plus the extra activity upsells the customer added at checkout. Each item:{ name, city, date, image_url, tier }wheretierisincludedorextra. Included activities are derived from the tour itinerary; extras come from activity upsells. Thedateis derived from the booking’s departure date plus the activity’s tour day (nullwhen no day is recorded). Entries are ordered chronologically. (A futuresubstitutiontier is not yet emitted.)optional_services— transfer upsells only (buildServicesDatafilters toBookingUpsellType::Transfer). Each item:{ name, description }. Travel insurance upsells are intentionally not surfaced here; see Travel Insurance (Intermundial).
Activity and transfer names/descriptions are localized to the market’s default locale.
Source Files
Section titled “Source Files”| Component | File |
|---|---|
| Controller | backend/app/Http/Controllers/Api/BookingController.php |
| Booking Resource | backend/app/Http/Resources/BookingDetailsResource.php |
| Offer Resource | backend/app/Http/Resources/OfferSummaryResource.php |
| Passenger Resource | backend/app/Http/Resources/PassengerSummaryResource.php |
| Route | backend/routes/api.php (market-scoped routes) |
Related
Section titled “Related”- Multi-Market API - Market and product endpoints
- Swagger: http://localhost/api/documentation