Booking Session
API Endpoint: POST /api/v1/services/booking/v1/booking-session
📋 Overview
Create or update booking session to save flight selection and booking progress.
Purpose:
- Save selected flight UUIDs
- Store passenger count
- Maintain booking state across page refreshes
- Get session_id for tracking
Session Expiry: 3600 seconds (1 hour)
🔌 API Specification
Endpoint
POST {{base_url}}/api/v1/services/booking/v1/booking-session
Headers
{
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {access_token}"
}
Request Body
Minimal Example (may work in some cases):
{
"flights": [
{
"uuid": "9de5bd3a-b951-11f0-a4ad-86d224031664",
"journey_type": "departure"
}
],
"passenger_number": {
"adult": 1,
"child": 0,
"infant": 0
}
}
Complete Example - One Way (recommended for production):
{
"flights": [
{
"uuid": "9de5bd3a-b951-11f0-a4ad-86d224031664",
"journey_type": "departure"
}
],
"selected_fare_departure": {
"index": 0,
"ma": "E1_ECO",
"ten": "Eco",
"so_ghe": 104,
"cabin": "ECONOMY",
"nguoi_lon": {
"gia_dai_ly": 1086300,
"gia_hien_thi": 1086300,
"gia_fare": 455800,
"gia_net": 1086300,
"phi_ve": 33800,
"phi_khuyen_mai": 0,
"phi_khuyen_mai_th": 0,
"phi_dai_ly": 0,
"thue": 630500,
"chi_tiet_thue": [
{
"ma": "AS",
"ten": "Airport Security Scan",
"gia_fare": 21700,
"gia_net": 21700,
"thue": 0
},
{
"ma": "AI",
"ten": "Airport Improvement Fund",
"gia_fare": 107000,
"gia_net": 107000,
"thue": 0
},
{
"ma": "AM",
"ten": "Admin Fee",
"gia_fare": 232300,
"gia_net": 250900,
"thue": 18600
},
{
"ma": "MF",
"ten": "Management Fee",
"gia_fare": 232300,
"gia_net": 250900,
"thue": 18600
}
],
"phi_xuat_ve": 0
},
"tre_em": {
"gia_dai_ly": 957600,
"gia_hien_thi": 957600,
"gia_fare": 455800,
"gia_net": 957600,
"phi_ve": 33800,
"phi_khuyen_mai": 0,
"phi_khuyen_mai_th": 0,
"phi_dai_ly": 0,
"thue": 501800,
"chi_tiet_thue": [
{
"ma": "AM",
"ten": "Admin Fee",
"gia_fare": 232300,
"gia_net": 250900,
"thue": 18600
},
{
"ma": "MF",
"ten": "Management Fee",
"gia_fare": 232300,
"gia_net": 250900,
"thue": 18600
}
],
"phi_xuat_ve": 0
},
"em_be": {
"gia_dai_ly": 0,
"gia_hien_thi": 0,
"gia_fare": 0,
"gia_net": 0,
"phi_ve": 0,
"phi_khuyen_mai": 0,
"phi_khuyen_mai_th": 0,
"phi_dai_ly": 0,
"thue": 0,
"chi_tiet_thue": [],
"phi_xuat_ve": 0
},
"du_lieu_hang": {
"key": "nlBxOkrƒeWPjoL8DOWVTrXCPjL¥pnaiavtzLƒ¥funlsrVo1je9VxvrADhtaskP3gNoYMALO5rƒQ4jmSfa1¥5n25FnYr1yc7CCbkaA6Tj2a9oCuPMmzKcYLNFq8ƒNodIh86n8Y549WU8XEK9JWEQDJcco1xnMpLdgZbFtL3SgB1RMxdƒqyv8hlR6uXorzRwx1I7aGy52JhbmGXCCnQgo6qAkdo1DBTGtfM01WJne8hdLkWv991Gj9ZCV75WokU7ƒeSxGH5yFYp6cQnZ4cjBWWywlqƒrGmve46thvBpFbhGu1Wy¥eC5TPy3wwcbrOJ8HxO1KceTj1vAdyVQva87rYuifqUnvLRJDMVlaxzJni8cJEij1K6LwE66JQS8veJdsin¥1pTKwq3RIsYD2fsSerb7jqc4atLa0zKZChg8yrlUFm5HBHQ1q4jCKsAPOYjjsUvJJfBrDw2K9QiJLyNi0m8W9o3GLo75mkRK2H1jLdEjP¥ƒMhWƒOJlbsZYIUznHB6znEgmvA8ƒGmmzLEVQSHxI4trAfiN0m9jhTlz¥A0fcx55Naovpm6A¥7IƒReXLKGSRƒG"
},
"ma_khuyen_mai": null
},
"passenger_number": {
"adult": 1,
"child": 0,
"infant": 0
}
}
Complete Example - Round Trip (recommended for round-trip bookings):
{
"flights": [
{
"uuid": "departure-flight-uuid",
"journey_type": "departure"
},
{
"uuid": "return-flight-uuid",
"journey_type": "return"
}
],
"selected_fare_departure": {
"index": 0,
"ma": "E1_ECO",
"ten": "Eco",
"cabin": "ECONOMY",
"nguoi_lon": { /* pricing details */ },
"tre_em": { /* pricing details */ },
"em_be": { /* pricing details */ },
"du_lieu_hang": {
"key": "EXAMPLE_KEY_FROM_DEPARTURE_FLIGHT"
},
"ma_khuyen_mai": null
},
"selected_fare_return": {
"index": 0,
"ma": "E1_ECO",
"ten": "Eco",
"cabin": "ECONOMY",
"nguoi_lon": { /* pricing details */ },
"tre_em": { /* pricing details */ },
"em_be": { /* pricing details */ },
"du_lieu_hang": {
"key": "EXAMPLE_KEY_FROM_RETURN_FLIGHT"
},
"ma_khuyen_mai": null
},
"passenger_number": {
"adult": 2,
"child": 1,
"infant": 0
}
}
Fields:
| Field | Type | Required | Description |
|---|---|---|---|
flights | array | ✅ Yes | Flight selections |
flights[].uuid | string | ✅ Yes | Flight UUID from search |
flights[].journey_type | string | ✅ Yes | Journey type: "departure" or "return" |
selected_fare_departure | object | ⚠️ Recommended | Complete fare details for departure flight |
selected_fare_departure.index | number | ⚠️ Recommended | Fare index (0-based) from search results |
selected_fare_departure.ma | string | ⚠️ Recommended | Fare code (e.g., "E1_ECO", "E2_SKYBOSS") |
selected_fare_departure.ten | string | ⚠️ Recommended | Fare name display |
selected_fare_departure.cabin | string | ⚠️ Recommended | Cabin class: "ECONOMY" or "BUSINESS" |
selected_fare_departure.nguoi_lon | object | ⚠️ Recommended | Adult pricing details |
selected_fare_departure.tre_em | object | ⚠️ Recommended | Child pricing details |
selected_fare_departure.em_be | object | ⚠️ Recommended | Infant pricing details |
selected_fare_departure.du_lieu_hang | object | ⚠️ Recommended | Airline validation data |
selected_fare_departure.du_lieu_hang.key | string | ⚠️ Recommended | Critical: Encoded key from airline API |
selected_fare_departure.ma_khuyen_mai | string/null | ⚠️ Recommended | Promotion code (if any) |
selected_fare_return | object | ⚠️ For Round-Trip | Complete fare details for return flight |
selected_fare_return.* | * | ⚠️ For Round-Trip | Same structure as selected_fare_departure |
passenger_number | object | ✅ Yes | Passenger count |
passenger_number.adult | number | ✅ Yes | Number of adults |
passenger_number.child | number | ✅ Yes | Number of children |
passenger_number.infant | number | ✅ Yes | Number of infants |
⚠️ Important Notes:
-
selected_fare_departureis HIGHLY RECOMMENDED for production use:- Contains
du_lieu_hang.keyrequired for airline validation - Preserves exact pricing from search results
- Prevents price mismatch errors
- Contains
-
For Round-Trip bookings:
- Include both
selected_fare_departureANDselected_fare_return - Each must have its own
du_lieu_hang.keyfrom respective flight search results - Both flights must be included in the
flightsarray
- Include both
-
du_lieu_hang.keyis critical:- Generated by airline API during search
- Cannot be manually created or modified
- Must be passed exactly as received from search results
- Used for fare validation and booking confirmation
-
Data Source:
- Get
selected_fare_departurefrom Socket.IO flight search results (departure) - Get
selected_fare_returnfrom Socket.IO flight search results (return) - Copy the entire fare object from the selected fare class
- Do NOT manually construct or modify these objects
- Get
✅ Success Response
Status: 200 OK
{
"message": "Booking session created successfully",
"data": {
"session_id": "b042ea16-da6a-4185-8723-6193b9e4effb",
"flights": [
{
"uuid": "9de5bd3a-b951-11f0-a4ad-86d224031664",
"journey_type": "departure",
"flight": "168",
"route": "SGN-HAN"
}
],
"expires_in_seconds": 3600
},
"status": "success",
"code": 200
}
Key Response Fields:
| Field | Type | Description |
|---|---|---|
data.session_id | string | Session ID for tracking |
data.flights[].uuid | string | Confirmed flight UUID |
data.flights[].flight | string | Flight number |
data.flights[].route | string | Route code (e.g., "SGN-HAN") |
data.expires_in_seconds | number | Session validity (3600s = 1 hour) |
🔄 Round-Trip Booking Details
For round-trip bookings, you must include:
- Both flight UUIDs in the
flightsarray selected_fare_departurewith fare details for the departure flightselected_fare_returnwith fare details for the return flight
Example: Minimal Round-Trip
{
"flights": [
{
"uuid": "departure-flight-uuid",
"journey_type": "departure"
},
{
"uuid": "return-flight-uuid",
"journey_type": "return"
}
],
"passenger_number": {
"adult": 2,
"child": 1,
"infant": 0
}
}
Example: Complete Round-Trip (Recommended)
{
"flights": [
{
"uuid": "departure-flight-uuid",
"journey_type": "departure"
},
{
"uuid": "return-flight-uuid",
"journey_type": "return"
}
],
"selected_fare_departure": {
"index": 0,
"ma": "E1_ECO",
"ten": "Eco",
"cabin": "ECONOMY",
"nguoi_lon": {
"gia_dai_ly": 1086300,
"gia_hien_thi": 1086300,
"gia_net": 1086300,
"thue": 630500
},
"tre_em": {
"gia_dai_ly": 957600,
"gia_hien_thi": 957600,
"gia_net": 957600,
"thue": 501800
},
"em_be": {
"gia_dai_ly": 0,
"gia_hien_thi": 0,
"gia_net": 0,
"thue": 0
},
"du_lieu_hang": {
"key": "DEPARTURE_KEY_FROM_SEARCH_RESULT"
},
"ma_khuyen_mai": null
},
"selected_fare_return": {
"index": 1,
"ma": "E2_DELUXE",
"ten": "Deluxe",
"cabin": "ECONOMY",
"nguoi_lon": {
"gia_dai_ly": 1425300,
"gia_hien_thi": 1425300,
"gia_net": 1425300,
"thue": 630500
},
"tre_em": {
"gia_dai_ly": 1296600,
"gia_hien_thi": 1296600,
"gia_net": 1296600,
"thue": 501800
},
"em_be": {
"gia_dai_ly": 0,
"gia_hien_thi": 0,
"gia_net": 0,
"thue": 0
},
"du_lieu_hang": {
"key": "RETURN_KEY_FROM_SEARCH_RESULT"
},
"ma_khuyen_mai": null
},
"passenger_number": {
"adult": 2,
"child": 1,
"infant": 0
}
}
⚠️ Critical for Round-Trip:
- Each flight (departure & return) has its own unique
du_lieu_hang.key - Keys must come from their respective search results
- Do NOT reuse the same key for both flights
💡 Usage Notes
When to Call
Call after flight selection:
1. Search flights (Socket.IO)
2. User selects flight + fare
3. → CREATE_BOOKING_SESSION ← Save selection
4. Proceed to services/booking
Session Benefits
- ✅ Persist flight selection across page refresh
- ✅ Track booking progress
- ✅ Prevent duplicate bookings
- ✅ Resume incomplete bookings
Session Expiry
After 3600 seconds:
- Session expires automatically
- Must create new session
- Flight UUIDs may also expire
🐛 Error Handling
Invalid Flight UUID
Response:
{
"status": "error",
"message": "Flight UUID không hợp lệ",
"code": 400
}
Solution: Search flights again to get fresh UUIDs
Missing Required Fields
Response:
{
"status": "error",
"message": "flights is required",
"code": 400
}
🔗 Related APIs
Before:
02-SEARCH-FLIGHTS.md- Search and select flight
After:
03-GET-SERVICES.md- Get baggage, food, seats05-HOLD-BOOKING.md- Complete booking (HOLD)06-ISSUE-TICKET.md- Complete booking (ISSUED)
📝 Example Flow
// 1. After flight selection
const selectedFlight = flights[0];
const fareIndex = 0;
// 2. Create booking session
const sessionResponse = await fetch('/api/v1/services/booking/v1/booking-session', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
flights: [{
uuid: selectedFlight.uuid,
journey_type: 'departure'
}],
passenger_number: {
adult: 1,
child: 0,
infant: 0
}
})
});
const session = await sessionResponse.json();
console.log('Session ID:', session.data.session_id);
console.log('Expires in:', session.data.expires_in_seconds, 'seconds');
// 3. Continue to services selection