Get Services - Lấy Danh Sách Dịch Vụ
API Endpoint: POST /api/v1/services/booking/v1/danh-sach-phu-tro-tim-ve
📋 Overview
Lấy danh sách dịch vụ & ghế khả dụng cho chuyến bay đã chọn.
Services Available:
- Baggage (Hành lý ký gửi): 20kg, 30kg, 40kg, Oversize
- Food (Suất ăn): Combo meals, drinks
- Seats (Chỗ ngồi): Standard, Extra legroom, Exit row
When to call: After search flights, before hold/issue booking.
🔌 API Specification
Endpoint
POST {{base_url}}/api/v1/services/booking/v1/danh-sach-phu-tro-tim-ve
Headers
{
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {access_token}"
}
Request Body
For New Booking (Before HOLD):
{
"chang_bay": [
{
"index": 0,
"uuid": "1f4a8f90-ba1a-11f0-a743-e69416960d28",
"index_hang_cho": 0
}
],
"hanh_khach": [
{
"index": 1,
"hanh_khach_id": 1,
"ho": "NGUYEN VAN",
"ten": "TEST",
"email": "app@example.com",
"so_dien_thoai": "0702349398",
"ngay_sinh": "01-02-1993",
"the_thanh_vien": "",
"loai_hanh_khach": 1,
"danh_xung": 1,
"cha_me_id": null
}
]
}
For Existing Booking (MMB):
{
"chang_bay": [
{
"index": 0,
"index_chuyen_bay": 0,
"ve_id": 123
}
]
}
Fields:
| Field | Type | Required | Description |
|---|---|---|---|
chang_bay | array | ✅ Yes | Flight segments |
chang_bay[].index | number | ✅ Yes | Segment index (0-based) |
chang_bay[].uuid | string | ⚠️ For New | Flight UUID from search (for new booking) |
chang_bay[].index_hang_cho | number | ⚠️ For New | Selected fare index (0-based, for new booking) |
chang_bay[].index_chuyen_bay | number | ⚠️ For MMB | Flight index (0-based, for existing booking) |
chang_bay[].ve_id | number/null | ⚠️ For MMB | Booking ID (for existing booking only) |
hanh_khach | array | ⚠️ For New | Passenger information (for new booking) |
hanh_khach[].index | number | ⚠️ For New | Passenger index (1-based) |
hanh_khach[].hanh_khach_id | number | ⚠️ For New | Set to 1 for new booking (temp ID) |
hanh_khach[].ho | string | ⚠️ For New | Last name (UPPERCASE) |
hanh_khach[].ten | string | ⚠️ For New | First name (UPPERCASE) |
hanh_khach[].email | string | ⚠️ For New | Email address |
hanh_khach[].so_dien_thoai | string | ⚠️ For New | Phone number |
hanh_khach[].ngay_sinh | string | ⚠️ For New | Date of birth (DD-MM-YYYY) |
hanh_khach[].loai_hanh_khach | number | ⚠️ For New | Passenger type: 1=Adult, 2=Child, 3=Infant |
hanh_khach[].danh_xung | number | ⚠️ For New | Title: 1=Mr, 2=Mrs, 3=Ms |
Important:
- For new booking (before HOLD): Use
uuid,index_hang_cho, andhanh_khacharray - For existing booking (MMB): Use
index_chuyen_bayandve_idonly hanh_khach_idcan be set to 1 for new bookings (temporary, will be replaced after booking)- Passenger info is needed to calculate age-specific pricing (child/infant discounts)
✅ Success Response
Status: 200 OK
{
"message": "Lấy danh sách phụ trợ thành công",
"data": {
"0": {
"dich_vu": {
"0": [
{
"uuid": "7a3251f4-aee4-11f0-bd8c-86d224031662",
"ma": "encoded-service-code",
"ten": "Bag 30kgs",
"ten_hien_thi": "Gói 30kg",
"nhom": "Hành lý ký gửi",
"mo_ta_nhom": "Baggage",
"mo_ta": "Baggage 30kgs",
"loai_dich_vu": 2,
"so_kg": "30",
"gia_fare": 300000,
"thue_phi": 24000,
"gia_net": 324000,
"hang_bay": "VJ",
"hinh_anh": "http://..."
},
{
"uuid": "7a35fd6e-aee4-11f0-bd8c-86d224031662",
"ten": "Combo 1",
"ten_hien_thi": "Combo ZALO1",
"nhom": "Suất ăn",
"mo_ta_nhom": "Food",
"loai_dich_vu": 1,
"gia_net": 60000,
"hang_bay": "VJ"
}
]
},
"cho_ngoi": {
"1": {
"A": {
"ma_ghe": "1A",
"ma_cho_ngoi": "encoded-seat-code",
"uuid": "7a5a0c96-aee4-11f0-bd8c-86d224031662",
"gia_net": 64800,
"gia_fare": 60000,
"thue_phi": 4800,
"hop_le": true,
"trang_thai": false,
"loi_thoat": true,
"hang_bay": "VJ",
"index_chuyen_bay": 0
}
}
}
}
},
"status": "success",
"code": 200
}
📦 Response Structure
Services (dich_vu)
data["0"].dich_vu["0"]; // Array of services
Service Object:
| Field | Type | Description |
|---|---|---|
uuid | string | Service UUID (for booking) |
ma | string | Encoded service code |
ten | string | Service name |
ten_hien_thi | string | Display name |
nhom | string | Category: "Hành lý ký gửi", "Suất ăn" |
loai_dich_vu | number | Type: 1 = Food, 2 = Baggage |
gia_net | number | Total price (VND) |
gia_fare | number | Base fare |
thue_phi | number | Tax/fee |
so_kg | string | Weight (baggage only) |
Seats (cho_ngoi)
data["0"].cho_ngoi; // Object keyed by row number
Seat Map Structure:
{
"1": { // Row number
"A": { seat_object }, // Column A
"B": { seat_object }, // Column B
...
},
"2": { ... }
}
Seat Object:
| Field | Type | Description |
|---|---|---|
uuid | string | Seat UUID (for booking) |
ma_ghe | string | Seat number (e.g., "1A", "12F") |
ma_cho_ngoi | string | Encoded seat code |
gia_net | number | Seat price (VND) |
hop_le | boolean | Available: true = can book |
trang_thai | boolean | Occupied: true = already booked |
loi_thoat | boolean | Exit row: true = yes |
index_chuyen_bay | number | Flight index (0-based) |
💡 Example: cURL
curl -X POST "{{base_url}}/api/v1/services/booking/v1/danh-sach-phu-tro-tim-ve" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {access_token}" \
-d '{
"chang_bay": [{
"index": 0,
"uuid": "1f4a8f90-ba1a-11f0-a743-e69416960d28",
"index_hang_cho": 0
}],
"hanh_khach": [{
"index": 1,
"hanh_khach_id": 1,
"ho": "NGUYEN VAN",
"ten": "TEST",
"email": "app@example.com",
"so_dien_thoai": "0702349398",
"ngay_sinh": "01-02-1993",
"the_thanh_vien": "",
"loai_hanh_khach": 1,
"danh_xung": 1,
"cha_me_id": null
}]
}'
🔍 Filtering Services
Baggage Only
const baggage = services.filter((s) => s.loai_dich_vu === 2);
Food Only
const food = services.filter((s) => s.loai_dich_vu === 1);
Non-Free Services
const paidServices = services.filter((s) => s.gia_net > 0);
🔍 Filtering Seats
Available Seats Only
// Flatten seat map
const allSeats = [];
Object.keys(seatMap).forEach((row) => {
Object.keys(seatMap[row]).forEach((col) => {
const seat = seatMap[row][col];
if (seat) allSeats.push(seat);
});
});
// Filter available
const availableSeats = allSeats.filter(
(s) => s.hop_le === true && s.trang_thai === false,
);
Exit Row Seats
const exitSeats = availableSeats.filter((s) => s.loi_thoat === true);
By Price Range
// Standard seats (cheapest)
const standardSeats = availableSeats.filter((s) => s.gia_net < 50000);
// Premium seats
const premiumSeats = availableSeats.filter((s) => s.gia_net >= 50000);
⚠️ Important Notes
1. Service Types
| loai_dich_vu | Category | Examples |
|---|---|---|
1 | Food (Suất ăn) | Combo meals, snacks, drinks |
2 | Baggage (Hành lý) | 20kg, 30kg, 40kg, Oversize |
2. Seat Availability
// Check if seat can be booked
if (seat.hop_le === true && seat.trang_thai === false) {
// Available to book
}
hop_le: true= Valid seat (not blocked)trang_thai: false= Not occupied yet
3. UUID Expiration
Important: UUIDs expire quickly (~5-10 minutes)
- Get fresh services/seats before booking
- Don't cache UUIDs for long periods
- If booking fails with "UUID không tồn tại", re-fetch
4. Free vs Paid
Some services/seats may be free (gia_net: 0):
- Free baggage in DELUXE/SKYBOSS fare
- Free seat selection in premium cabins
- Promotional items
5. New Booking vs MMB (Existing Booking)
New Booking (Before HOLD):
{
"chang_bay": [{
"index": 0,
"uuid": "flight-uuid-from-search",
"index_hang_cho": 0
}],
"hanh_khach": [{ /* passenger info */ }]
}
Existing Booking (MMB - Add Services):
{
"chang_bay": [{
"index": 0,
"index_chuyen_bay": 0,
"ve_id": 104
}]
}
Key Differences:
- New booking: Use
uuid+index_hang_cho+hanh_khach - MMB: Use
index_chuyen_bay+ve_id(nohanh_khachneeded)
🔗 Next Steps
After getting services/seats:
- Select items → Save UUIDs
- Add to booking → See next doc:
04-SELECT-SERVICES-SEATS.md- Choose baggage/food/seats
- Hold/Issue → Include in booking request:
05-HOLD-BOOKING.md06-ISSUE-TICKET.md
📝 Notes
- Returns both services (baggage, food) and seats in one API call
- UUIDs expire quickly - fetch fresh before booking
- New booking: Requires
uuid,index_hang_cho, andhanh_khacharray - MMB (existing): Requires
index_chuyen_bayandve_idonly loai_dich_vu: 1= Food,2= Baggage- Check
hop_le: trueandtrang_thai: falsefor available seats - Seat prices vary by position (exit row more expensive)
- Some items may be free (
gia_net: 0) depending on fare class - Passenger info needed for age-based pricing (child/infant discounts)