API: Multi-Seat Booking Workflow

Multi-Seat Booking

This guide shows how to book multiple seats (A1, A2, A3) using the seat request system. All seats will be grouped under one issue ID and expire simultaneously.

Scenario: User wants to book 3 seats (A1, A2, A3)

Step 1: First Seat

Creates new issue

seat_inventory_id: 123
Step 2: Second Seat

Add to existing issue

seat_inventory_id: 124
Step 3: Third Seat

Complete the group

seat_inventory_id: 125

1. First Seat Request (Creates New Issue)

Request:

POST /seat-requests

{
  "seat_inventory_id": 123,
  "notes": "Window seat preferred"
}

Response:


{
  "status": "success",
  "code": 201,
  "message": "Seat blocked successfully for 5 minutes",
  "data": {
    "seat_request_id": 456,
    "issue_id": "SR-20250821-143052-A1B2C3",
    "seat_inventory_id": 123,
    "status": "pending",
    "blocked_until": "2025-08-21T14:35:52.000000Z",
    "issue_summary": {
      "issue_id": "SR-20250821-143052-A1B2C3",
      "total_seats_in_issue": 1,
      "seats": [
        {
          "seat_request_id": 456,
          "seat_inventory_id": 123,
          "seat_id": 45,
          "status": "pending",
          "seat_number": "A1"
        }
      ]
    }
  }
}
                

2. Second Seat Request (Add to Existing Issue)

Request:

POST /seat-requests

{
  "seat_inventory_id": 124,
  "issue_id": "SR-20250821-143052-A1B2C3",
  "notes": "Adjacent to A1"
}

Response:


{
  "status": "success",
  "code": 201,
  "message": "Seat blocked successfully for 5 minutes",
  "data": {
    "seat_request_id": 457,
    "issue_id": "SR-20250821-143052-A1B2C3",
    "seat_inventory_id": 124,
    "status": "pending",
    "blocked_until": "2025-08-21T14:35:52.000000Z",
    "issue_summary": {
      "issue_id": "SR-20250821-143052-A1B2C3",
      "total_seats_in_issue": 2,
      "seats": [
        {
          "seat_request_id": 456,
          "seat_inventory_id": 123,
          "seat_id": 45,
          "status": "pending",
          "seat_number": "A1"
        },
        {
          "seat_request_id": 457,
          "seat_inventory_id": 124,
          "seat_id": 46,
          "status": "pending",
          "seat_number": "A2"
        }
      ]
    }
  }
}
                

3. Third Seat Request (Complete the Group)

Request:

POST /seat-requests

{
  "seat_inventory_id": 125,
  "issue_id": "SR-20250821-143052-A1B2C3",
  "notes": "Complete the row A1-A2-A3"
}

Response:


{
    "status": "success",
    "code": 201,
    "message": "Seat blocked successfully for 5 minutes",
    "data": {
        "seat_request_id": 124,
        "issue_id": "IE-20250115-143052-ABC123",
        "seat_inventory_id": 457,
        "status": "pending",
        "blocked_until": "2025-01-15T14:37:15",
        "blocked_for_minutes": 5,
        "remaining_time": {
            "minutes": 5,
            "seconds": 300,
            "expires_at": "2025-01-15T14:37:15"
        },
        "seat_info": {
            "seat": {
                "seat_number": "A2",
                "row_position": 1,
                "col_position": 2,
                "seat_type": "Business Class",
                "fare_amount": 1200
            },
            "trip": {
                "trip_date": "2025-01-20",
                "coach_no": "DH-AC-001",
                "coach_type": 1,
                "coach_type_name": "AC"
            },
            "route": {
                "start_district": "Dhaka",
                "end_district": "Chittagong",
                "route_display": "Dhaka → Chittagong",
                "distance": 250.5,
                "duration": "06:30:00"
            },
            "current_status": {
                "booking_status": 3,
                "status_name": "Blocked"
            }
        },
        "user_id": 25,
        "created_at": "2025-01-15T14:32:15.000Z",
        "issue_summary": {
            "issue_id": "IE-20250115-143052-ABC123",
            "total_seats_in_issue": 2,
            "seats": [
                {
                    "seat_request_id": 123,
                    "seat_inventory_id": 456,
                    "seat_id": 101,
                    "status": "pending",
                    "seat_number": "A1",
                    "row_position": 1,
                    "col_position": 1,
                    "seat_type": "Business Class",
                    "fare_amount": 1200
                },
                {
                    "seat_request_id": 124,
                    "seat_inventory_id": 457,
                    "seat_id": 102,
                    "status": "pending",
                    "seat_number": "A2",
                    "row_position": 1,
                    "col_position": 2,
                    "seat_type": "Business Class",
                    "fare_amount": 1200
                }
            ]
        }
    }
}
                

JavaScript Implementation Example


class SeatRequestManager {
  constructor(authToken) {
    this.authToken = authToken;
    this.baseURL = '/api/seat-requests';
    this.currentIssueId = null;
  }

  async requestSeat(seatInventoryId, notes = '') {
    const payload = {
      seat_inventory_id: seatInventoryId,
      notes: notes
    };

    // If we have an existing issue, add to it
    if (this.currentIssueId) {
      payload.issue_id = this.currentIssueId;
    }

    const response = await fetch(this.baseURL, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${this.authToken}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(payload)
    });

    const data = await response.json();

    if (response.ok) {
      // Store issue ID for subsequent requests
      this.currentIssueId = data.data.issue_id;
      return data;
    } else {
      throw new Error(data.message);
    }
  }

  async getAllSeatsInIssue() {
    if (!this.currentIssueId) {
      throw new Error('No active issue');
    }

    const response = await fetch(`${this.baseURL}/${this.currentIssueId}`, {
      headers: {
        'Authorization': `Bearer ${this.authToken}`
      }
    });

    return await response.json();
  }

  async cancelEntireIssue() {
    if (!this.currentIssueId) {
      throw new Error('No active issue');
    }

    const response = await fetch(`${this.baseURL}/${this.currentIssueId}`, {
      method: 'DELETE',
      headers: {
        'Authorization': `Bearer ${this.authToken}`
      }
    });

    const data = await response.json();

    if (response.ok) {
      this.currentIssueId = null; // Reset issue ID
    }

    return data;
  }
}

// Usage Example
async function bookThreeSeats() {
  const manager = new SeatRequestManager('your_auth_token');

  try {
    // Request first seat (creates new issue)
    console.log('Requesting seat A1...');
    const seat1 = await manager.requestSeat(123, 'Window seat preferred');
    console.log('Seat A1 blocked:', seat1.data.issue_id);

    // Request second seat (adds to existing issue)
    console.log('Requesting seat A2...');
    const seat2 = await manager.requestSeat(124, 'Adjacent to A1');
    console.log('Seat A2 blocked, total seats:', seat2.data.issue_summary.total_seats_in_issue);

    // Request third seat (adds to existing issue)
    console.log('Requesting seat A3...');
    const seat3 = await manager.requestSeat(125, 'Complete the row A1-A2-A3');
    console.log('Seat A3 blocked, total seats:', seat3.data.issue_summary.total_seats_in_issue);

    // Check all seats status
    console.log('Checking all seats status...');
    const status = await manager.getAllSeatsInIssue();
    console.log('All seats:', status.data.seats.map(s => s.seat_info.seat.seat_number));

    return status;
  } catch (error) {
    console.error('Error booking seats:', error.message);
    throw error;
  }
}

// Execute the booking
bookThreeSeats()
  .then(result => console.log('Successfully blocked all seats!', result))
  .catch(error => console.error('Failed to block seats:', error));
                

Key Points

Timing
  • All seats have same 5-minute expiry
  • Timer resets with each new seat added
  • Synchronized expiration for all seats
  • Automatic release after timeout
Management
  • First request creates new issue
  • Subsequent requests add to issue
  • Independent seat blocking
  • Flexible cancellation options

Best Practices

  • Store Issue ID: Keep the issue_id from the first request to add more seats
  • Monitor Timer: Check remaining time before it expires
  • Error Handling: Handle seat unavailability gracefully
  • User Feedback: Show users which seats are selected and time remaining
  • Cleanup: Cancel unused requests to free seats for others

Common Use Cases

  • Family Booking: Parents booking seats for family members
  • Group Travel: Booking adjacent seats for friends
  • Corporate Travel: Reserving seats for business team
  • Event Booking: Securing multiple seats for special occasions