Skip to main content

Booking Flow - Complete Guide

Hướng dẫn đầy đủ quy trình đặt vé từ A-Z.


📋 Overview

Complete booking flow từ tìm kiếm đến xuất vé, bao gồm thêm dịch vụ và chọn ghế.

Total Steps: 6 bước chính (+ Authentication module riêng)

Time Required: ~30-60 seconds (depending on selections)


🔄 Complete Flow Diagram


📚 Step-by-Step Guide

Prerequisites: Authentication

Module: ../authentication/

APIs:

  1. POST /oauth/token - Get access token
  2. GET /api/v1/credentials/me - Get user profile & agency info

See: ../authentication/README.md for complete authentication guide


Step 1: Get Airports

Doc: 01-GET-AIRPORTS.md

API: GET /api/v1/current/airports

Purpose: Get list of airports for departure/arrival selection

Output:

  • 6,073+ airports worldwide
  • Vietnam domestic: ~22 airports

Popular Routes:

  • SGN (Ho Chi Minh) ↔ HAN (Hanoi)
  • SGN ↔ DAD (Da Nang)
  • HAN ↔ DAD

Step 2: Search Flights

Doc: 02-SEARCH-FLIGHTS.md

API: POST /api/v1/services/booking/v1/tim-chuyen + Socket.IO


Step 2a: Create Booking Session

Doc: 02a-BOOKING-SESSION.md

API: POST /api/v1/services/booking/v1/booking-session

Purpose: Save selected flight, fare details, and passenger count to session

Input (Minimal):

  • Flight UUID from search
  • Passenger count (adults, children, infants)

Input (Recommended for Production):

  • Flight UUID from search
  • selected_fare_departure - Complete fare details for departure flight
  • selected_fare_return - Complete fare details for return flight (if round-trip)
  • Passenger count (adults, children, infants)

Why use selected_fare_departure/return?

  • ✅ Contains du_lieu_hang.key required for airline validation
  • ✅ Preserves exact pricing from search results
  • ✅ Prevents price mismatch errors during booking

Output:

  • Session ID (expires in 3600s)
  • Confirmed flight info

⚠️ Important:

  • Call after flight selection, before getting services
  • For round-trip: include both selected_fare_departure AND selected_fare_return
  • Each flight must have its own unique du_lieu_hang.key from search results

Step 3: Get Services & Seats

Doc: 03-GET-SERVICES.md

API: POST /api/v1/services/booking/v1/danh-sach-phu-tro-tim-ve

Purpose: Get available baggage, food, and seats for selected flight

Input:

{
"chang_bay": [
{
"index": 0,
"index_chuyen_bay": 0,
"ve_id": null
}
]
}

Output:

  • Baggage options (20kg, 30kg, 40kg)
  • Food/meal options
  • Available seats with prices

⚠️ Important: Save flight.uuid and fare.index for next step


Step 4: Select Services & Seats

Doc: 04-SELECT-SERVICES-SEATS.md

Purpose: Prepare data for booking request (no API call)

Actions:

  1. Filter services by type (baggage vs food)
  2. Select desired items
  3. Filter available seats
  4. Choose seat
  5. Build dich_vu and cho_ngoi arrays for booking request

Step 5: Hold Booking

Doc: 05-HOLD-BOOKING.md

API: POST /api/v1/services/booking/v1/dat-chuyen

Purpose: Reserve booking with payment deadline (~4 hours)

Request:

{
"api": "VJ",
"chuyen_bay": [{"uuid": "flight-uuid", "index_hang_cho": 0, ...}],
"hanh_khach": [{"ho": "NGUYEN VAN", "ten": "TEST", ...}],
"thong_tin_booker": {"ho": "TRAN THI", "ten": "BOOKER", ...},
"dich_vu": [...],
"cho_ngoi": [...],
"trang_thai": 0
}

Key Field: "trang_thai": 0 (HOLD)

Response:

{
"data": {
"ve": {
"id": 82,
"pnr": "AAMJ52",
"trang_thai": 0,
"ngay_het_han": "22-10-2025 06:03:00"
}
}
}

Save: ve_id, pnr, hanh_khach_id for later operations


Step 6: Issue Ticket

Doc: 06-ISSUE-TICKET.md

API: POST /api/v1/services/booking/v1/dat-chuyen (same as HOLD)

Purpose: Book and issue ticket immediately (pay now)

Difference from HOLD:

{
"trang_thai": 1
}

Key Field: "trang_thai": 1 (ISSUED)

Result:

  • Ticket issued immediately
  • F2 wallet charged
  • No payment deadline
  • Cannot cancel (only VOID/REFUND)

🔀 Decision Flow


💰 Pricing Calculation

Total Amount = Ticket + Services + Seats

Example:

Ticket (SGN-HAN, Economy):     1,086,300 VND
Baggage (30kg): 324,000 VND
Food (Combo 1): 60,000 VND
Seat (12C): 54,000 VND
----------------------------------------
TOTAL: 1,524,300 VND

⚠️ Important Rules

1. UUID Expiration

  • Flight UUIDs: Valid ~15-20 minutes after search
  • Service/Seat UUIDs: Valid ~5-10 minutes after fetch
  • Always get fresh UUIDs before booking

2. Indexing Convention

FieldIndexingExample
Passenger (index_hanh_khach)1-based1, 2, 3
Segment (index_chang_bay)1-based1, 2
Flight (index_chuyen_bay)0-based0, 1

3. Name Format

// ✅ Correct
"ho": "NGUYEN VAN"
"ten": "TEST"

// ❌ Wrong
"ho": "Nguyen Van"
"ten": "test"

4. Date Format

DD-MM-YYYY (e.g., "01-11-2025")

🎯 Complete Example

Full Flow in One Request (Issue Direct)

curl -X POST "{{base_url}}/api/v1/services/booking/v1/dat-chuyen" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {access_token}" \
-d '{
"api": "VJ",
"nhieu_chang": 0,
"chuyen_bay": [{
"index": 1,
"uuid": "852ffde2-aeb0-11f0-8b81-86d224031662",
"phi_dai_ly": 0,
"index_hang_cho": 0,
"loai_phi_dai_ly": "Cơ bản"
}],
"hanh_khach": [{
"index": 1,
"ho": "NGUYEN VAN",
"ten": "TEST",
"email": "test@example.com",
"so_dien_thoai": "0987654321",
"ngay_sinh": "01-01-1990",
"the_thanh_vien": "",
"loai_hanh_khach": 1,
"danh_xung": 1,
"cha_me_id": null,
"ho_chieu": null
}],
"thong_tin_booker": {
"ho": "TRAN THI",
"ten": "BOOKER",
"email": "booker@example.com",
"so_dien_thoai": "0912345678"
},
"dich_vu": [
{
"uuid_dich_vu": "7a3251f4-aee4-11f0-bd8c-86d224031662",
"index_hanh_khach": 1,
"index_chang_bay": 1
}
],
"cho_ngoi": [
{
"ma_cho_ngoi": "nfRUyZla4RiDI5HExo49eN...",
"uuid_cho_ngoi": "7a5a7b02-aee4-11f0-bd8c-86d224031662",
"index_hanh_khach": 1,
"index_chang_bay": 1,
"index_chuyen_bay": 0
}
],
"ma_khuyen_mai": "",
"trang_thai": 1,
"xac_nhan_ve_dup": "",
"xac_nhan_thay_doi_gia": "",
"tong_gia_ve": 0,
"xac_nhan_cho_du_bi": ""
}'

Result:

{
"message": "Đặt chỗ thành công. ",
"data": {
"ve": {
"id": 85,
"pnr": "XYZ123",
"trang_thai": 1,
"gia_net": 1524300
}
},
"status": "success"
}

📊 Status Codes

trang_thaiStatusDescription
0HOLDGiữ chỗ - Cần thanh toán trong ~4 giờ
1ISSUEDĐã xuất vé - Đã thanh toán

Authentication (Prerequisites)

  • ../authentication/README.md - Complete auth guide
  • ../authentication/01-AUTHENTICATION.md - OAuth 2.0 login
  • ../authentication/02-GET-PROFILE.md - User & agency info

Booking Flows

  • 01-GET-AIRPORTS.md - Airport list
  • 02-SEARCH-FLIGHTS.md - Search with Socket.IO
  • 02a-BOOKING-SESSION.md - Create booking session (save flight selection)
  • 03-GET-SERVICES.md - Get baggage, food, seats
  • 04-SELECT-SERVICES-SEATS.md - Data preparation
  • 05-HOLD-BOOKING.md - Reserve booking
  • 06-ISSUE-TICKET.md - Book & issue immediately

Manage My Booking (MMB)

  • ../manage-booking/01-LIST-BOOKINGS.md - List all bookings
  • ../manage-booking/02-GET-DETAILS.md - Booking details
  • ../manage-booking/PAYMENT.md - Pay HOLD booking
  • ../manage-booking/UPDATE-SERVICES.md - Add services after booking
  • ../manage-booking/BUY-SEAT.md - Add seat after booking

🎓 Best Practices

1. Always Get Fresh Data

// ✅ Good
const airports = await getAirports();
const flights = await searchFlights(route);
const services = await getServices();
await bookWithServices(); // Immediate

// ❌ Bad
const services = await getServices();
await sleep(600000); // 10 minutes wait
await bookWithServices(); // UUIDs expired!

2. Handle Errors Gracefully

try {
const booking = await issueTicket(data);
} catch (error) {
if (error.message.includes("UUID không tồn tại")) {
// Re-fetch services with fresh UUIDs
const freshServices = await getServices();
const booking = await issueTicket(dataWithFreshUUIDs);
}
}

3. Validate Before Booking

// Check wallet balance first
const balance = await getWalletBalance();
const totalAmount = calculateTotal(ticket, services, seats);

if (balance < totalAmount) {
alert("Insufficient balance");
// Use HOLD instead of ISSUE
}

4. Save Important IDs

// After successful booking
const bookingData = {
ve_id: response.data.ve.id,
pnr: response.data.ve.pnr,
hanh_khach_id: response.data.hanh_khach[0].id,
key_chang_bay: response.data.chang_bay[0].key_chang_bay,
};
// Save to database/storage for MMB operations

📝 Summary

Complete Flow:

Auth Module → 1. Airports → 2. Search → 2a. Booking Session →
3. Get Services → 4. Select → 5. Hold/Issue → Done

Time: ~30-60 seconds

Result: Booking with PNR, ticket, services, and seats

Next: Manage booking via MMB APIs