openapi: 3.0.3 info: title: 'Laravel API Documentation' description: '' version: 1.0.0 servers: - url: 'https://apisun.trip.ro' tags: - name: 'Package Search' description: '' - name: 'Package Booking' description: '' - name: 'Hotel Booking' description: '' - name: 'Travel Data' description: '' - name: 'System Status' description: '' components: securitySchemes: default: type: http scheme: bearer description: '' security: - default: [] paths: /api/packages/search-options: post: summary: 'Get search options for travel form' operationId: getSearchOptionsForTravelForm description: "Provides dynamic options for travel search form based on user selections.\nReturns specific data based on the requested mode to optimize performance.\n\nThis endpoint supports 4 different modes, each optimized for specific use cases:\n\n**Mode: departure_locations**\n- Purpose: Get all available departure cities\n- Required: mode\n- Optional: departure_id (to mark active location)\n- Returns: Array of departure cities with airport codes and location hierarchy\n\n**Mode: destination_locations**\n- Purpose: Get destinations available from a specific departure city\n- Required: mode, departure_id\n- Returns: Array of destinations with transport type (bus/flight)\n\n**Mode: available_dates**\n- Purpose: Get available departure dates for a specific route\n- Required: mode, departure_id, destination_id\n- Returns: Array of available dates in Y-m-d format\n\n**Mode: available_nights**\n- Purpose: Get available night durations for a specific date and route\n- Required: mode, departure_id, destination_id, departure_date\n- Returns: Array of available night durations (integers)" parameters: - in: query name: lang description: 'Language code for localization.' example: ru required: false schema: type: string description: 'Language code for localization.' example: ru nullable: false responses: 200: description: '' content: application/json: schema: oneOf: - description: departure_locations type: object example: data: - id: 202553 airport_code: BUH active: true destination: Bucuresti country: Romania - id: 197276 airport_code: TSR destination: Timisoara region: 'Judetul Timis' country: Romania - id: 200366 airport_code: IAS destination: Iasi region: 'Judetul Iasi' country: Romania properties: data: type: array example: - id: 202553 airport_code: BUH active: true destination: Bucuresti country: Romania - id: 197276 airport_code: TSR destination: Timisoara region: 'Judetul Timis' country: Romania - id: 200366 airport_code: IAS destination: Iasi region: 'Judetul Iasi' country: Romania items: type: object properties: id: type: integer example: 202553 airport_code: type: string example: BUH active: type: boolean example: true destination: type: string example: Bucuresti country: type: string example: Romania - description: destination_locations type: object example: data: - id: 532 airport_code: VAR type: bus region: Varna country: Bulgaria - id: 269 airport_code: DXB type: flight region: Dubai country: 'Emiratele Arabe Unite' - id: 1364 airport_code: null type: flight region: Attica country: Grecia properties: data: type: array example: - id: 532 airport_code: VAR type: bus region: Varna country: Bulgaria - id: 269 airport_code: DXB type: flight region: Dubai country: 'Emiratele Arabe Unite' - id: 1364 airport_code: null type: flight region: Attica country: Grecia items: type: object properties: id: type: integer example: 532 airport_code: type: string example: VAR type: type: string example: bus region: type: string example: Varna country: type: string example: Bulgaria - description: available_dates type: object example: data: - '2025-09-03' - '2025-09-08' - '2025-09-10' - '2025-09-15' - '2025-09-20' properties: data: type: array example: - '2025-09-03' - '2025-09-08' - '2025-09-10' - '2025-09-15' - '2025-09-20' items: type: string - description: available_nights type: object example: data: - 3 - 5 - 7 - 10 - 14 properties: data: type: array example: - 3 - 5 - 7 - 10 - 14 items: type: integer 422: description: '' content: application/json: schema: oneOf: - description: missing_mode type: object example: error: 'Validation failed' messages: mode: - 'The mode field is required.' properties: error: type: string example: 'Validation failed' messages: type: object properties: mode: type: array example: - 'The mode field is required.' items: type: string - description: invalid_mode type: object example: error: 'Validation failed' messages: mode: - 'The selected mode is invalid.' properties: error: type: string example: 'Validation failed' messages: type: object properties: mode: type: array example: - 'The selected mode is invalid.' items: type: string - description: missing_departure_id_for_destinations type: object example: error: 'Validation failed' messages: departure_id: - 'The departure id field is required when mode is destination_locations.' properties: error: type: string example: 'Validation failed' messages: type: object properties: departure_id: type: array example: - 'The departure id field is required when mode is destination_locations.' items: type: string - description: missing_destination_id_for_dates type: object example: error: 'Validation failed' messages: destination_id: - 'The destination id field is required when mode is available_dates.' properties: error: type: string example: 'Validation failed' messages: type: object properties: destination_id: type: array example: - 'The destination id field is required when mode is available_dates.' items: type: string - description: missing_departure_date_for_nights type: object example: error: 'Validation failed' messages: departure_date: - 'The departure date field is required when mode is available_nights.' properties: error: type: string example: 'Validation failed' messages: type: object properties: departure_date: type: array example: - 'The departure date field is required when mode is available_nights.' items: type: string - description: invalid_date_format type: object example: error: 'Validation failed' messages: departure_date: - 'The departure date does not match the format Y-m-d.' properties: error: type: string example: 'Validation failed' messages: type: object properties: departure_date: type: array example: - 'The departure date does not match the format Y-m-d.' items: type: string 500: description: '' content: application/json: schema: type: object example: error: 'Internal server error' message: 'Failed to retrieve search options' properties: error: type: string example: 'Internal server error' message: type: string example: 'Failed to retrieve search options' tags: - 'Package Search' requestBody: required: true content: application/json: schema: type: object properties: mode: type: string description: 'Mode of operation. Must be one of: departure_locations, destination_locations, available_dates, available_nights.' example: departure_locations nullable: false departure_id: type: string description: 'ID of selected departure city. Required for destination_locations, available_dates, and available_nights modes. Optional for departure_locations mode (used to mark active location).' example: '"202553"' nullable: false destination_id: type: string description: 'ID of selected destination. Required for available_dates and available_nights modes.' example: '"123"' nullable: false departure_date: type: string description: 'Departure date in Y-m-d format. Required for available_nights mode.' example: '"2024-06-15"' nullable: false required: - mode /api/packages/search: post: summary: 'Initiate asynchronous package search' operationId: initiateAsynchronousPackageSearch description: "Initiates an asynchronous search across multiple travel providers.\nReturns a search_id that can be used to poll for results.\nSupports multiple providers (ChristianTour, OBS) with different execution types.\n\nPOST /api/packages/search" parameters: [] responses: 202: description: '' content: application/json: schema: type: object example: success: true search_id: 550e8400-e29b-41d4-a716-446655440000 providers: - christian_tour - obs estimated_completion_time: '30 seconds' status_url: 'http://localhost/api/packages/search/550e8400-e29b-41d4-a716-446655440000/results' cancel_url: 'http://localhost/api/packages/search/550e8400-e29b-41d4-a716-446655440000' properties: success: type: boolean example: true search_id: type: string example: 550e8400-e29b-41d4-a716-446655440000 providers: type: array example: - christian_tour - obs items: type: string estimated_completion_time: type: string example: '30 seconds' status_url: type: string example: 'http://localhost/api/packages/search/550e8400-e29b-41d4-a716-446655440000/results' cancel_url: type: string example: 'http://localhost/api/packages/search/550e8400-e29b-41d4-a716-446655440000' 400: description: '' content: application/json: schema: type: object example: success: false message: 'No providers available for async search' properties: success: type: boolean example: false message: type: string example: 'No providers available for async search' 422: description: '' content: application/json: schema: type: object example: success: false message: 'Validation failed' errors: departure_date: - 'The departure date must be a date after today.' occupancy: - 'The occupancy field is required.' properties: success: type: boolean example: false message: type: string example: 'Validation failed' errors: type: object properties: departure_date: type: array example: - 'The departure date must be a date after today.' items: type: string occupancy: type: array example: - 'The occupancy field is required.' items: type: string 500: description: '' content: application/json: schema: type: object example: success: false message: 'Failed to initiate search' error: 'Database connection failed' properties: success: type: boolean example: false message: type: string example: 'Failed to initiate search' error: type: string example: 'Database connection failed' tags: - 'Package Search' requestBody: required: true content: application/json: schema: type: object properties: departure_date: type: string description: 'Departure date. Must be after today.' example: '2025-11-28' nullable: false nights: type: integer description: 'Number of nights. Min: 1, Max: 30.' example: 7 nullable: false transport: type: array description: 'Array of transport types.' example: [] items: type: string departure_id: type: integer description: 'Departure location ID.' example: 202553 nullable: false destination_id: type: integer description: 'optional Destination location ID.' example: 269 nullable: false hotel_ids: type: array description: 'optional Array of hotel IDs to search.' example: [] items: type: string occupancy: type: array description: 'Room occupancy information. Min: 1 room.' example: - architecto items: type: string currency: type: string description: 'optional Currency code. Default: RON.' example: EUR nullable: false ignore_domains: type: array description: 'optional Domains to ignore.' example: [] items: type: string max_pages: type: integer description: 'optional Max pages to process. Min: 1, Max: 50.' example: 10 nullable: false providers: type: array description: 'optional Specific providers to use.' example: [] items: type: string required: - departure_date - nights - transport - departure_id - occupancy '/api/packages/search/{searchId}/results': get: summary: 'Get search results by session ID grouped by hotels' operationId: getSearchResultsBySessionIDGroupedByHotels description: "Retrieves the current status and results of an asynchronous search session.\nResults are grouped by hotels (provider + hotel_external_id) and paginated.\nOnly the cheapest offer per hotel is returned with site-specific pricing applied.\nHotel images are limited to first 4 images for performance optimization.\nResults can be filtered by provider, price range, or sorted by different criteria.\n\nResponse includes:\n- Enriched hotel data with images, facilities, and full destination hierarchy\n- Custom travel pricing based on site commissions\n- Complete flight and transfer information from provider\n- Occupancy details\n- Bus, flight, and tags data extracted from provider\n- Search progress and provider status information\n- Price range (min/max) calculated from the cheapest offer of each hotel\n\nGET /api/packages/search/{searchId}/results" parameters: - in: query name: page description: 'optional Page number for pagination.' example: 1 required: false schema: type: integer description: 'optional Page number for pagination.' example: 1 nullable: false - in: query name: per_page description: 'optional Hotels per page. Max: 100. Default: 20.' example: 20 required: false schema: type: integer description: 'optional Hotels per page. Max: 100. Default: 20.' example: 20 nullable: false - in: query name: sort_by description: 'optional Sort field. Values: id (offer database ID), min_price (cheapest offer), max_price (most expensive offer), found_at, destination_name, hotel_name, offers_count. Default: id.' example: id required: false schema: type: string description: 'optional Sort field. Values: id (offer database ID), min_price (cheapest offer), max_price (most expensive offer), found_at, destination_name, hotel_name, offers_count. Default: id.' example: id nullable: false - in: query name: sort_direction description: 'optional Sort direction. Values: asc (ascending), desc (descending). Default: asc.' example: asc required: false schema: type: string description: 'optional Sort direction. Values: asc (ascending), desc (descending). Default: asc.' example: asc nullable: false - in: query name: provider description: 'optional Filter by specific provider.' example: christian_tour required: false schema: type: string description: 'optional Filter by specific provider.' example: christian_tour nullable: false - in: query name: min_price description: 'optional Minimum price filter (applied to travel_price with commissions).' example: 100.0 required: false schema: type: number description: 'optional Minimum price filter (applied to travel_price with commissions).' example: 100.0 nullable: false - in: query name: max_price description: 'optional Maximum price filter (applied to travel_price with commissions).' example: 2000.0 required: false schema: type: number description: 'optional Maximum price filter (applied to travel_price with commissions).' example: 2000.0 nullable: false - in: query name: hotel_name description: 'optional Filter by hotel name. Searches for words that start with the input.' example: "'ho' will find 'Massa Hotel'\n\nNote: After optimization (OfferMinPriceTracker), the system saves only the cheapest offer per hotel.\n The 'total_offers' field shows ALL processed offers, while 'total_hotels' shows unique saved hotels." required: false schema: type: string description: 'optional Filter by hotel name. Searches for words that start with the input.' example: "'ho' will find 'Massa Hotel'\n\nNote: After optimization (OfferMinPriceTracker), the system saves only the cheapest offer per hotel.\n The 'total_offers' field shows ALL processed offers, while 'total_hotels' shows unique saved hotels." nullable: false responses: 200: description: '' content: application/json: schema: type: object example: success: true search_id: 019908a1-180e-7345-a654-855c90860cb1 status: completed results: - hotel_key: christian_tour_9910 provider: christian_tour hotel_external_id: '9910' hotel_name: 'Blend Club Aqua Resort' hotel_slug: blend-club-aqua-resort-9910 destination_name: Hurghada offers_with_min_price_count: 3 hotel: id: '9910' name: 'Blend Club Aqua Resort' classification: 4 latitude: '27.123456' longitude: '33.654321' address: city: Hurghada street: 'KM 21, Sahl Hashesh Road' country: Egypt email: info@resort.com phone: '+20 123 456 789' website: 'https://resort.com' images: - url: 'https://images.provider.com/hotel-9910/image1.jpg' - url: 'https://images.provider.com/hotel-9910/image2.jpg' facilities: - id: 8 name: Restaurant - id: 12 name: 'Swimming Pool' destination: name: Hurghada latitude: '27.123456' longitude: '33.654321' hierarchy_path: 'Egypt → Hurghada' offers: - id: 12345 offer_id: 7a86dd23-c4c8-499c-bff9-c2b05dd52767 room_type: 'DELUXE GARDEN VIEW' meal_plan: 'ALL INCLUSIVE' meal_plan_category_id: 5 check_in: '2025-09-27' check_out: '2025-10-04' nights: 7 travel_price: 3943.4 travel_discount_price: 2.0 currency: RON transfer: included: true type: airport-hotel occupancy: adults: 2 children: 0 children_ages: [] total: 2 bus: departure: city: Bucharest datetime: '2025-09-27T08:00:00' arrival: city: Hurghada datetime: '2025-09-27T14:00:00' flight: outbound: - flight_number: '4206' airline: code: A2 name: Animawings departure: code: OTP name: 'Henri Coanda International Airport' datetime: '2025-09-27T17:45:00' arrival: code: HRG name: 'Hurghada International Airport' datetime: '2025-09-27T20:55:00' duration: 190 baggage: checked: 20kg hand: 7kg inbound: - flight_number: '4207' airline: code: A2 name: Animawings departure: code: HRG name: 'Hurghada International Airport' datetime: '2025-10-04T23:55:00' arrival: code: OTP name: 'Henri Coanda International Airport' datetime: '2025-10-04T03:30:00' duration: 215 tags: - beach - family-friendly - all-inclusive - 5-star pagination: current_page: 1 per_page: 20 total: 42 last_page: 3 has_more_pages: true search_progress: completed_providers: 1 total_providers: 1 percentage: 100 is_completed: true provider_status: - provider: christian_tour status: completed results_count: 156 last_poll_at: null completed_at: '2025-10-03T07:13:44.000000Z' error_message: null meta: total_hotels: 42 total_offers: 90000 min_travel_price: 1250.5 max_travel_price: 8900.0 currency: RON expires_at: '2025-10-03T07:43:19.000000Z' created_at: '2025-10-03T07:13:19.000000Z' last_updated: '2025-10-03T07:13:44.000000Z' properties: success: type: boolean example: true search_id: type: string example: 019908a1-180e-7345-a654-855c90860cb1 status: type: string example: completed results: type: array example: - hotel_key: christian_tour_9910 provider: christian_tour hotel_external_id: '9910' hotel_name: 'Blend Club Aqua Resort' hotel_slug: blend-club-aqua-resort-9910 destination_name: Hurghada offers_with_min_price_count: 3 hotel: id: '9910' name: 'Blend Club Aqua Resort' classification: 4 latitude: '27.123456' longitude: '33.654321' address: city: Hurghada street: 'KM 21, Sahl Hashesh Road' country: Egypt email: info@resort.com phone: '+20 123 456 789' website: 'https://resort.com' images: - url: 'https://images.provider.com/hotel-9910/image1.jpg' - url: 'https://images.provider.com/hotel-9910/image2.jpg' facilities: - id: 8 name: Restaurant - id: 12 name: 'Swimming Pool' destination: name: Hurghada latitude: '27.123456' longitude: '33.654321' hierarchy_path: 'Egypt → Hurghada' offers: - id: 12345 offer_id: 7a86dd23-c4c8-499c-bff9-c2b05dd52767 room_type: 'DELUXE GARDEN VIEW' meal_plan: 'ALL INCLUSIVE' meal_plan_category_id: 5 check_in: '2025-09-27' check_out: '2025-10-04' nights: 7 travel_price: 3943.4 travel_discount_price: 2 currency: RON transfer: included: true type: airport-hotel occupancy: adults: 2 children: 0 children_ages: [] total: 2 bus: departure: city: Bucharest datetime: '2025-09-27T08:00:00' arrival: city: Hurghada datetime: '2025-09-27T14:00:00' flight: outbound: - flight_number: '4206' airline: code: A2 name: Animawings departure: code: OTP name: 'Henri Coanda International Airport' datetime: '2025-09-27T17:45:00' arrival: code: HRG name: 'Hurghada International Airport' datetime: '2025-09-27T20:55:00' duration: 190 baggage: checked: 20kg hand: 7kg inbound: - flight_number: '4207' airline: code: A2 name: Animawings departure: code: HRG name: 'Hurghada International Airport' datetime: '2025-10-04T23:55:00' arrival: code: OTP name: 'Henri Coanda International Airport' datetime: '2025-10-04T03:30:00' duration: 215 tags: - beach - family-friendly - all-inclusive - 5-star items: type: object properties: hotel_key: type: string example: christian_tour_9910 provider: type: string example: christian_tour hotel_external_id: type: string example: '9910' hotel_name: type: string example: 'Blend Club Aqua Resort' hotel_slug: type: string example: blend-club-aqua-resort-9910 destination_name: type: string example: Hurghada offers_with_min_price_count: type: integer example: 3 hotel: type: object properties: id: type: string example: '9910' name: type: string example: 'Blend Club Aqua Resort' classification: type: integer example: 4 latitude: type: string example: '27.123456' longitude: type: string example: '33.654321' address: type: object properties: city: type: string example: Hurghada street: type: string example: 'KM 21, Sahl Hashesh Road' country: type: string example: Egypt email: type: string example: info@resort.com phone: type: string example: '+20 123 456 789' website: type: string example: 'https://resort.com' images: type: array example: - url: 'https://images.provider.com/hotel-9910/image1.jpg' - url: 'https://images.provider.com/hotel-9910/image2.jpg' items: type: object properties: url: type: string example: 'https://images.provider.com/hotel-9910/image1.jpg' facilities: type: array example: - id: 8 name: Restaurant - id: 12 name: 'Swimming Pool' items: type: object properties: id: type: integer example: 8 name: type: string example: Restaurant destination: type: object properties: name: type: string example: Hurghada latitude: type: string example: '27.123456' longitude: type: string example: '33.654321' hierarchy_path: type: string example: 'Egypt → Hurghada' offers: type: array example: - id: 12345 offer_id: 7a86dd23-c4c8-499c-bff9-c2b05dd52767 room_type: 'DELUXE GARDEN VIEW' meal_plan: 'ALL INCLUSIVE' meal_plan_category_id: 5 check_in: '2025-09-27' check_out: '2025-10-04' nights: 7 travel_price: 3943.4 travel_discount_price: 2 currency: RON transfer: included: true type: airport-hotel occupancy: adults: 2 children: 0 children_ages: [] total: 2 bus: departure: city: Bucharest datetime: '2025-09-27T08:00:00' arrival: city: Hurghada datetime: '2025-09-27T14:00:00' flight: outbound: - flight_number: '4206' airline: code: A2 name: Animawings departure: code: OTP name: 'Henri Coanda International Airport' datetime: '2025-09-27T17:45:00' arrival: code: HRG name: 'Hurghada International Airport' datetime: '2025-09-27T20:55:00' duration: 190 baggage: checked: 20kg hand: 7kg inbound: - flight_number: '4207' airline: code: A2 name: Animawings departure: code: HRG name: 'Hurghada International Airport' datetime: '2025-10-04T23:55:00' arrival: code: OTP name: 'Henri Coanda International Airport' datetime: '2025-10-04T03:30:00' duration: 215 tags: - beach - family-friendly - all-inclusive - 5-star items: type: object properties: id: type: integer example: 12345 offer_id: type: string example: 7a86dd23-c4c8-499c-bff9-c2b05dd52767 room_type: type: string example: 'DELUXE GARDEN VIEW' meal_plan: type: string example: 'ALL INCLUSIVE' meal_plan_category_id: type: integer example: 5 check_in: type: string example: '2025-09-27' check_out: type: string example: '2025-10-04' nights: type: integer example: 7 travel_price: type: number example: 3943.4 travel_discount_price: type: number example: 2.0 currency: type: string example: RON transfer: type: object properties: included: type: boolean example: true type: type: string example: airport-hotel occupancy: type: object properties: adults: type: integer example: 2 children: type: integer example: 0 children_ages: type: array example: [] total: type: integer example: 2 bus: type: object properties: departure: type: object properties: city: { type: string, example: Bucharest } datetime: { type: string, example: '2025-09-27T08:00:00' } arrival: type: object properties: city: { type: string, example: Hurghada } datetime: { type: string, example: '2025-09-27T14:00:00' } flight: type: object properties: outbound: type: array example: - { flight_number: '4206', airline: { code: A2, name: Animawings }, departure: { code: OTP, name: 'Henri Coanda International Airport', datetime: '2025-09-27T17:45:00' }, arrival: { code: HRG, name: 'Hurghada International Airport', datetime: '2025-09-27T20:55:00' }, duration: 190, baggage: { checked: 20kg, hand: 7kg } } items: type: object properties: { flight_number: { type: string, example: '4206' }, airline: { type: object, properties: { code: { type: string, example: A2 }, name: { type: string, example: Animawings } } }, departure: { type: object, properties: { code: { type: string, example: OTP }, name: { type: string, example: 'Henri Coanda International Airport' }, datetime: { type: string, example: '2025-09-27T17:45:00' } } }, arrival: { type: object, properties: { code: { type: string, example: HRG }, name: { type: string, example: 'Hurghada International Airport' }, datetime: { type: string, example: '2025-09-27T20:55:00' } } }, duration: { type: integer, example: 190 }, baggage: { type: object, properties: { checked: { type: string, example: 20kg }, hand: { type: string, example: 7kg } } } } inbound: type: array example: - { flight_number: '4207', airline: { code: A2, name: Animawings }, departure: { code: HRG, name: 'Hurghada International Airport', datetime: '2025-10-04T23:55:00' }, arrival: { code: OTP, name: 'Henri Coanda International Airport', datetime: '2025-10-04T03:30:00' }, duration: 215 } items: type: object properties: { flight_number: { type: string, example: '4207' }, airline: { type: object, properties: { code: { type: string, example: A2 }, name: { type: string, example: Animawings } } }, departure: { type: object, properties: { code: { type: string, example: HRG }, name: { type: string, example: 'Hurghada International Airport' }, datetime: { type: string, example: '2025-10-04T23:55:00' } } }, arrival: { type: object, properties: { code: { type: string, example: OTP }, name: { type: string, example: 'Henri Coanda International Airport' }, datetime: { type: string, example: '2025-10-04T03:30:00' } } }, duration: { type: integer, example: 215 } } tags: type: array example: - beach - family-friendly - all-inclusive - 5-star items: type: string pagination: type: object properties: current_page: type: integer example: 1 per_page: type: integer example: 20 total: type: integer example: 42 last_page: type: integer example: 3 has_more_pages: type: boolean example: true search_progress: type: object properties: completed_providers: type: integer example: 1 total_providers: type: integer example: 1 percentage: type: integer example: 100 is_completed: type: boolean example: true provider_status: type: array example: - provider: christian_tour status: completed results_count: 156 last_poll_at: null completed_at: '2025-10-03T07:13:44.000000Z' error_message: null items: type: object properties: provider: type: string example: christian_tour status: type: string example: completed results_count: type: integer example: 156 last_poll_at: type: string example: null completed_at: type: string example: '2025-10-03T07:13:44.000000Z' error_message: type: string example: null meta: type: object properties: total_hotels: type: integer example: 42 total_offers: type: integer example: 90000 min_travel_price: type: number example: 1250.5 max_travel_price: type: number example: 8900.0 currency: type: string example: RON expires_at: type: string example: '2025-10-03T07:43:19.000000Z' created_at: type: string example: '2025-10-03T07:13:19.000000Z' last_updated: type: string example: '2025-10-03T07:13:44.000000Z' 401: description: '' content: application/json: schema: type: object example: success: false message: 'Unauthorized. Valid Site token required.' properties: success: type: boolean example: false message: type: string example: 'Unauthorized. Valid Site token required.' 404: description: '' content: application/json: schema: type: object example: success: false message: 'Search session not found' properties: success: type: boolean example: false message: type: string example: 'Search session not found' 410: description: '' content: application/json: schema: type: object example: success: false message: 'Search session has expired' properties: success: type: boolean example: false message: type: string example: 'Search session has expired' 500: description: '' content: application/json: schema: type: object example: success: false message: 'Failed to retrieve search results' error: 'Database error' properties: success: type: boolean example: false message: type: string example: 'Failed to retrieve search results' error: type: string example: 'Database error' tags: - 'Package Search' parameters: - in: path name: searchId description: 'The search session UUID.' example: '"550e8400-e29b-41d4-a716-446655440000"' required: true schema: type: string '/api/packages/search/{searchId}': delete: summary: 'Cancel search session' operationId: cancelSearchSession description: "Cancels an active search session and stops all running provider jobs.\nOnly sessions in 'pending' or 'in_progress' status can be cancelled.\n\nDELETE /api/packages/search/{searchId}" parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true message: 'Search session cancelled' search_id: 550e8400-e29b-41d4-a716-446655440000 properties: success: type: boolean example: true message: type: string example: 'Search session cancelled' search_id: type: string example: 550e8400-e29b-41d4-a716-446655440000 400: description: '' content: application/json: schema: type: object example: success: false message: 'Search session cannot be cancelled' current_status: completed properties: success: type: boolean example: false message: type: string example: 'Search session cannot be cancelled' current_status: type: string example: completed 404: description: '' content: application/json: schema: type: object example: success: false message: 'Search session not found' properties: success: type: boolean example: false message: type: string example: 'Search session not found' 500: description: '' content: application/json: schema: type: object example: success: false message: 'Failed to cancel search session' error: 'Database error' properties: success: type: boolean example: false message: type: string example: 'Failed to cancel search session' error: type: string example: 'Database error' tags: - 'Package Search' parameters: - in: path name: searchId description: 'The search session UUID to cancel.' example: '"550e8400-e29b-41d4-a716-446655440000"' required: true schema: type: string /api/packages/hotel-offers: post: summary: 'Get all offers for a specific hotel with available transport options' operationId: getAllOffersForASpecificHotelWithAvailableTransportOptions description: "Synchronously fetches all offers for the specified hotel(s) with grouping by flights and buses.\nResults are cached for a short period (configurable TTL) for fast repeated access.\nThis endpoint is typically used on hotel detail pages to show all available offers\nand transport options for filtering on the frontend.\n\nPOST /api/packages/hotel-offers" parameters: [] responses: 200: description: '' content: text/plain: schema: type: string example: "{\n \"success\": true,\n \"offers\": [...],\n \"transport_options\": {\"flights\": [...], \"buses\": [...]},\n \"hotel_info\": {...},\n \"meta\": {\"total_offers\": 42, \"providers\": [\"christian_tour\"], \"currency\": \"RON\", \"cache_ttl_seconds\": 600}\n}" 408: description: '' content: application/json: schema: type: object example: success: false message: 'Request timeout. Try with fewer details or larger timeout value.' properties: success: type: boolean example: false message: type: string example: 'Request timeout. Try with fewer details or larger timeout value.' 422: description: '' content: text/plain: schema: type: string example: "{\n \"success\": false,\n \"message\": \"Validation failed\",\n \"errors\": {...}\n}" 500: description: '' content: application/json: schema: type: object example: success: false message: 'Failed to fetch hotel offers' properties: success: type: boolean example: false message: type: string example: 'Failed to fetch hotel offers' tags: - 'Package Search' requestBody: required: true content: application/json: schema: type: object properties: departure_id: type: integer description: 'Departure location ID.' example: 202553 nullable: false destination_id: type: integer description: 'optional Destination location ID (optional when hotel_ids provided).' example: 269 nullable: false departure_date: type: string description: 'Departure date. Must be after today.' example: '2025-11-28' nullable: false nights: type: integer description: 'Number of nights. Min: 1, Max: 30.' example: 7 nullable: false transport: type: array description: 'optional Array of transport types. Default: ["flight", "bus"].' example: - flight - bus items: type: string hotel_ids: type: array description: 'Array of hotel IDs to get offers for.' example: - 12 - 34 items: type: string occupancy: type: array description: 'Room occupancy information. Min: 1 room.' example: - architecto items: type: string currency: type: string description: 'optional Currency code. Default: RON.' example: EUR nullable: false provider: type: string description: 'optional Specific provider to use. If not provided, uses provider from token abilities or first active.' example: christian_tour nullable: false timeout: type: integer description: 'optional Timeout in seconds (max 60). Default: 30.' example: 30 nullable: false required: - departure_id - departure_date - nights - hotel_ids - occupancy /api/booking/packages: post: summary: 'Book a package offer' operationId: bookAPackageOffer description: "Books a travel package offer through ChristianTour provider.\nHandles complete booking flow including guest validation, pricing verification,\nand booking confirmation with optional additional services.\n\nPOST /api/v1/booking/packages" parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: order_id: CT_PKG_ORD_789456 booking_confirmation_number: CT_PKG_BKG_123789 status: confirmed offer_id: christian_tour_pkg_456 package_name: '7 Days Rome & Florence' departure_date: '2024-06-15' return_date: '2024-06-22' nights: 7 total_price: 2150.75 currency: EUR travelers: - first_name: Maria last_name: Garcia type: adult room_assignment: 'Room 1' included_services: - 'Hotel accommodation' - 'Daily breakfast' - Transportation additional_services: - code: EXCURSION_ROME name: 'Rome City Tour' price: 85.0 currency: EUR booking_date: '2024-01-15T10:30:00Z' cancellation_policy: free_cancellation_until: '2024-05-15T23:59:59Z' penalty_schedule: - from_date: '2024-05-16T00:00:00Z' to_date: '2024-06-01T23:59:59Z' penalty_percentage: 25 meta: booking_type: packages provider: christian_tour total_travelers: 1 total_rooms: 1 processing_time: '2024-01-15T10:30:15Z' properties: success: type: boolean example: true data: type: object properties: order_id: type: string example: CT_PKG_ORD_789456 booking_confirmation_number: type: string example: CT_PKG_BKG_123789 status: type: string example: confirmed offer_id: type: string example: christian_tour_pkg_456 package_name: type: string example: '7 Days Rome & Florence' departure_date: type: string example: '2024-06-15' return_date: type: string example: '2024-06-22' nights: type: integer example: 7 total_price: type: number example: 2150.75 currency: type: string example: EUR travelers: type: array example: - first_name: Maria last_name: Garcia type: adult room_assignment: 'Room 1' items: type: object properties: first_name: type: string example: Maria last_name: type: string example: Garcia type: type: string example: adult room_assignment: type: string example: 'Room 1' included_services: type: array example: - 'Hotel accommodation' - 'Daily breakfast' - Transportation items: type: string additional_services: type: array example: - code: EXCURSION_ROME name: 'Rome City Tour' price: 85 currency: EUR items: type: object properties: code: type: string example: EXCURSION_ROME name: type: string example: 'Rome City Tour' price: type: number example: 85.0 currency: type: string example: EUR booking_date: type: string example: '2024-01-15T10:30:00Z' cancellation_policy: type: object properties: free_cancellation_until: type: string example: '2024-05-15T23:59:59Z' penalty_schedule: type: array example: - from_date: '2024-05-16T00:00:00Z' to_date: '2024-06-01T23:59:59Z' penalty_percentage: 25 items: type: object properties: from_date: type: string example: '2024-05-16T00:00:00Z' to_date: type: string example: '2024-06-01T23:59:59Z' penalty_percentage: type: integer example: 25 meta: type: object properties: booking_type: type: string example: packages provider: type: string example: christian_tour total_travelers: type: integer example: 1 total_rooms: type: integer example: 1 processing_time: type: string example: '2024-01-15T10:30:15Z' 400: description: '' content: application/json: schema: type: object example: success: false error: message: 'Package offer no longer available' code: OFFER_UNAVAILABLE provider: christian_tour offer_id: christian_tour_pkg_456 properties: success: type: boolean example: false error: type: object properties: message: type: string example: 'Package offer no longer available' code: type: string example: OFFER_UNAVAILABLE provider: type: string example: christian_tour offer_id: type: string example: christian_tour_pkg_456 422: description: '' content: application/json: schema: type: object example: success: false error: message: 'Validation failed' details: offer_id: - 'The offer id field is required.' occupancy.0.guests.0.birth_date: - 'The birth date does not match the format Y-m-d.' code: VALIDATION_ERROR properties: success: type: boolean example: false error: type: object properties: message: type: string example: 'Validation failed' details: type: object properties: offer_id: type: array example: - 'The offer id field is required.' items: type: string occupancy.0.guests.0.birth_date: type: array example: - 'The birth date does not match the format Y-m-d.' items: type: string code: type: string example: VALIDATION_ERROR 500: description: '' content: application/json: schema: type: object example: success: false error: message: 'An unexpected error occurred while processing the booking' code: INTERNAL_ERROR properties: success: type: boolean example: false error: type: object properties: message: type: string example: 'An unexpected error occurred while processing the booking' code: type: string example: INTERNAL_ERROR tags: - 'Package Booking' requestBody: required: true content: application/json: schema: type: object properties: offer_id: type: string description: 'The package offer identifier from search results.' example: '"christian_tour_pkg_456"' nullable: false reference_code: type: string description: 'optional Internal reference code for tracking.' example: '"REF789123"' nullable: false price: type: numeric description: 'Total package price. Min: 0.' example: '2150.75' nullable: false currency: type: string description: '3-letter currency code.' example: '"EUR"' nullable: false occupancy: type: array description: 'Room and traveler information. Min: 1 room.' example: - architecto items: type: string additional_services: type: array description: 'optional Array of additional service codes.' example: [] items: type: string required: - offer_id - price - currency - occupancy /api/booking/packages/verify: get: summary: 'Verify a package offer before booking' operationId: verifyAPackageOfferBeforeBooking description: "Verifies package offer availability and current pricing through ChristianTour.\nEnsures offer is still valid and price hasn't changed before booking.\n\nGET /api/v1/booking/packages/verify?offer_id=xxx" parameters: - in: query name: offer_id description: 'The package offer ID to verify.' example: '"christian_tour_pkg_456"' required: true schema: type: string description: 'The package offer ID to verify.' example: '"christian_tour_pkg_456"' nullable: false responses: 200: description: '' content: application/json: schema: type: object example: success: true data: available: true offer_id: christian_tour_pkg_456 package_name: '7 Days Rome & Florence' original_price: 2150.75 current_price: 2150.75 price_changed: false currency: EUR valid_until: '2024-01-15T23:59:59Z' departure_date: '2024-06-15' availability: seats_available: 8 rooms_available: 5 last_verified: '2024-01-15T10:30:00Z' meta: offer_type: packages provider: christian_tour verified_at: '2024-01-15T10:30:00Z' properties: success: type: boolean example: true data: type: object properties: available: type: boolean example: true offer_id: type: string example: christian_tour_pkg_456 package_name: type: string example: '7 Days Rome & Florence' original_price: type: number example: 2150.75 current_price: type: number example: 2150.75 price_changed: type: boolean example: false currency: type: string example: EUR valid_until: type: string example: '2024-01-15T23:59:59Z' departure_date: type: string example: '2024-06-15' availability: type: object properties: seats_available: type: integer example: 8 rooms_available: type: integer example: 5 last_verified: type: string example: '2024-01-15T10:30:00Z' meta: type: object properties: offer_type: type: string example: packages provider: type: string example: christian_tour verified_at: type: string example: '2024-01-15T10:30:00Z' 400: description: '' content: application/json: schema: type: object example: success: false error: message: 'Package offer no longer available' code: OFFER_VERIFICATION_ERROR offer_id: christian_tour_pkg_456 properties: success: type: boolean example: false error: type: object properties: message: type: string example: 'Package offer no longer available' code: type: string example: OFFER_VERIFICATION_ERROR offer_id: type: string example: christian_tour_pkg_456 422: description: '' content: application/json: schema: type: object example: success: false error: message: 'Validation failed' details: offer_id: - 'The offer id field is required.' code: VALIDATION_ERROR properties: success: type: boolean example: false error: type: object properties: message: type: string example: 'Validation failed' details: type: object properties: offer_id: type: array example: - 'The offer id field is required.' items: type: string code: type: string example: VALIDATION_ERROR 500: description: '' content: application/json: schema: type: object example: success: false error: message: 'Failed to verify package offer' details: 'Provider connection timeout' code: VERIFICATION_ERROR properties: success: type: boolean example: false error: type: object properties: message: type: string example: 'Failed to verify package offer' details: type: string example: 'Provider connection timeout' code: type: string example: VERIFICATION_ERROR tags: - 'Package Booking' /api/booking/packages/customize: post: summary: 'Customize a package offer by adding optional services' operationId: customizeAPackageOfferByAddingOptionalServices description: "Adds optional services to a package offer and returns updated pricing.\nServices can include excursions, transfers, insurance, and upgrades.\n\nPOST /api/v1/booking/packages/customize" parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: offer_id: christian_tour_pkg_456 package_name: '7 Days Rome & Florence' original_price: 2150.75 additional_services_price: 185.0 total_price: 2335.75 currency: EUR added_services: - code: EXCURSION_ROME name: 'Rome City Tour' description: "Full day guided tour of Rome's historic sites" price: 85.0 currency: EUR duration: '8 hours' included: true pricing: base_price: 2150.75 services_total: 185.0 selling_price: 2335.75 currency: EUR valid_until: '2024-01-15T23:59:59Z' meta: offer_type: packages provider: christian_tour customized_at: '2024-01-15T10:30:00Z' added_services_count: 1 properties: success: type: boolean example: true data: type: object properties: offer_id: type: string example: christian_tour_pkg_456 package_name: type: string example: '7 Days Rome & Florence' original_price: type: number example: 2150.75 additional_services_price: type: number example: 185.0 total_price: type: number example: 2335.75 currency: type: string example: EUR added_services: type: array example: - code: EXCURSION_ROME name: 'Rome City Tour' description: "Full day guided tour of Rome's historic sites" price: 85 currency: EUR duration: '8 hours' included: true items: type: object properties: code: type: string example: EXCURSION_ROME name: type: string example: 'Rome City Tour' description: type: string example: "Full day guided tour of Rome's historic sites" price: type: number example: 85.0 currency: type: string example: EUR duration: type: string example: '8 hours' included: type: boolean example: true pricing: type: object properties: base_price: type: number example: 2150.75 services_total: type: number example: 185.0 selling_price: type: number example: 2335.75 currency: type: string example: EUR valid_until: type: string example: '2024-01-15T23:59:59Z' meta: type: object properties: offer_type: type: string example: packages provider: type: string example: christian_tour customized_at: type: string example: '2024-01-15T10:30:00Z' added_services_count: type: integer example: 1 422: description: '' content: application/json: schema: type: object example: success: false error: message: 'Validation failed' details: offer_id: - 'The offer id field is required.' service_codes: - 'The service codes field is required.' code: VALIDATION_ERROR properties: success: type: boolean example: false error: type: object properties: message: type: string example: 'Validation failed' details: type: object properties: offer_id: type: array example: - 'The offer id field is required.' items: type: string service_codes: type: array example: - 'The service codes field is required.' items: type: string code: type: string example: VALIDATION_ERROR 500: description: '' content: application/json: schema: type: object example: success: false error: message: 'Failed to customize package offer' details: 'Service customization error' code: CUSTOMIZATION_ERROR properties: success: type: boolean example: false error: type: object properties: message: type: string example: 'Failed to customize package offer' details: type: string example: 'Service customization error' code: type: string example: CUSTOMIZATION_ERROR tags: - 'Package Booking' requestBody: required: true content: application/json: schema: type: object properties: offer_id: type: string description: 'The package offer ID to customize.' example: '"christian_tour_pkg_456"' nullable: false service_codes: type: array description: 'Array of service codes to add. Min: 1 service.' example: - architecto items: type: string required: - offer_id - service_codes /api/booking/packages/cancellation-policy: get: summary: 'Get cancellation policy for a package offer' operationId: getCancellationPolicyForAPackageOffer description: "Retrieves the cancellation policy for a specific package offer,\nincluding free cancellation periods and penalty schedules.\n\nGET /api/v1/booking/packages/cancellation-policy?offer_id=xxx" parameters: - in: query name: offer_id description: 'The package offer ID to get policy for.' example: '"christian_tour_pkg_456"' required: true schema: type: string description: 'The package offer ID to get policy for.' example: '"christian_tour_pkg_456"' nullable: false responses: 200: description: '' content: application/json: schema: type: object example: success: true data: offer_id: christian_tour_pkg_456 package_name: '7 Days Rome & Florence' cancellation_policy: free_cancellation_until: '2024-05-15T23:59:59Z' penalty_schedule: - from_date: '2024-05-16T00:00:00Z' to_date: '2024-06-01T23:59:59Z' penalty_percentage: 25 penalty_description: '25% of total booking value' - from_date: '2024-06-02T00:00:00Z' to_date: '2024-06-14T23:59:59Z' penalty_percentage: 50 penalty_description: '50% of total booking value' - from_date: '2024-06-15T00:00:00Z' penalty_percentage: 100 penalty_description: 'No refund' general_terms: - 'Cancellation must be requested in writing' - 'Refunds processed within 14 business days' - 'Force majeure exceptions may apply' contact_info: email: cancellations@christian-tour.com phone: '+40 21 123 4567' departure_date: '2024-06-15' current_date: '2024-01-15' meta: offer_type: packages provider: christian_tour retrieved_at: '2024-01-15T10:30:00Z' properties: success: type: boolean example: true data: type: object properties: offer_id: type: string example: christian_tour_pkg_456 package_name: type: string example: '7 Days Rome & Florence' cancellation_policy: type: object properties: free_cancellation_until: type: string example: '2024-05-15T23:59:59Z' penalty_schedule: type: array example: - from_date: '2024-05-16T00:00:00Z' to_date: '2024-06-01T23:59:59Z' penalty_percentage: 25 penalty_description: '25% of total booking value' - from_date: '2024-06-02T00:00:00Z' to_date: '2024-06-14T23:59:59Z' penalty_percentage: 50 penalty_description: '50% of total booking value' - from_date: '2024-06-15T00:00:00Z' penalty_percentage: 100 penalty_description: 'No refund' items: type: object properties: from_date: type: string example: '2024-05-16T00:00:00Z' to_date: type: string example: '2024-06-01T23:59:59Z' penalty_percentage: type: integer example: 25 penalty_description: type: string example: '25% of total booking value' general_terms: type: array example: - 'Cancellation must be requested in writing' - 'Refunds processed within 14 business days' - 'Force majeure exceptions may apply' items: type: string contact_info: type: object properties: email: type: string example: cancellations@christian-tour.com phone: type: string example: '+40 21 123 4567' departure_date: type: string example: '2024-06-15' current_date: type: string example: '2024-01-15' meta: type: object properties: offer_type: type: string example: packages provider: type: string example: christian_tour retrieved_at: type: string example: '2024-01-15T10:30:00Z' 404: description: '' content: application/json: schema: type: object example: success: false error: message: 'Package offer not found' code: OFFER_NOT_FOUND offer_id: christian_tour_pkg_456 properties: success: type: boolean example: false error: type: object properties: message: type: string example: 'Package offer not found' code: type: string example: OFFER_NOT_FOUND offer_id: type: string example: christian_tour_pkg_456 422: description: '' content: application/json: schema: type: object example: success: false error: message: 'Validation failed' details: offer_id: - 'The offer id field is required.' code: VALIDATION_ERROR properties: success: type: boolean example: false error: type: object properties: message: type: string example: 'Validation failed' details: type: object properties: offer_id: type: array example: - 'The offer id field is required.' items: type: string code: type: string example: VALIDATION_ERROR 500: description: '' content: application/json: schema: type: object example: success: false error: message: 'Failed to retrieve cancellation policy' details: 'Provider connection timeout' code: POLICY_ERROR properties: success: type: boolean example: false error: type: object properties: message: type: string example: 'Failed to retrieve cancellation policy' details: type: string example: 'Provider connection timeout' code: type: string example: POLICY_ERROR tags: - 'Package Booking' /api/booking/packages/stats: get: summary: 'Get package booking statistics' operationId: getPackageBookingStatistics description: "Retrieves comprehensive booking statistics for package bookings,\nincluding success rates, average values, and trends.\n\nGET /api/v1/booking/packages/stats" parameters: - in: query name: period description: 'optional Statistics period. Values: day, week, month, year. Default: month.' example: '"month"' required: false schema: type: string description: 'optional Statistics period. Values: day, week, month, year. Default: month.' example: '"month"' nullable: false - in: query name: from_date description: 'optional Start date for custom period. Format: Y-m-d.' example: '"2024-01-01"' required: false schema: type: string description: 'optional Start date for custom period. Format: Y-m-d.' example: '"2024-01-01"' nullable: false - in: query name: to_date description: 'optional End date for custom period. Format: Y-m-d.' example: '"2024-01-31"' required: false schema: type: string description: 'optional End date for custom period. Format: Y-m-d.' example: '"2024-01-31"' nullable: false responses: 200: description: '' content: application/json: schema: type: object example: success: true data: period: month from_date: '2024-01-01' to_date: '2024-01-31' summary: total_bookings: 156 successful_bookings: 142 failed_bookings: 14 success_rate: 91.03 total_value: 334250.75 average_booking_value: 2143.27 currency: EUR breakdown_by_status: confirmed: 135 on_request: 7 cancelled: 9 failed: 5 top_destinations: - destination: 'Rome & Florence' bookings: 45 total_value: 98450.25 - destination: 'Paris & Amsterdam' bookings: 32 total_value: 76240.5 booking_trends: - date: '2024-01-01' bookings: 5 value: 10725.5 - date: '2024-01-02' bookings: 8 value: 17440.25 error_analysis: most_common_errors: - error_type: OFFER_UNAVAILABLE count: 8 percentage: 57.14 - error_type: PAYMENT_FAILED count: 4 percentage: 28.57 meta: booking_type: packages provider: christian_tour generated_at: '2024-01-15T10:30:00Z' timezone: UTC properties: success: type: boolean example: true data: type: object properties: period: type: string example: month from_date: type: string example: '2024-01-01' to_date: type: string example: '2024-01-31' summary: type: object properties: total_bookings: type: integer example: 156 successful_bookings: type: integer example: 142 failed_bookings: type: integer example: 14 success_rate: type: number example: 91.03 total_value: type: number example: 334250.75 average_booking_value: type: number example: 2143.27 currency: type: string example: EUR breakdown_by_status: type: object properties: confirmed: type: integer example: 135 on_request: type: integer example: 7 cancelled: type: integer example: 9 failed: type: integer example: 5 top_destinations: type: array example: - destination: 'Rome & Florence' bookings: 45 total_value: 98450.25 - destination: 'Paris & Amsterdam' bookings: 32 total_value: 76240.5 items: type: object properties: destination: type: string example: 'Rome & Florence' bookings: type: integer example: 45 total_value: type: number example: 98450.25 booking_trends: type: array example: - date: '2024-01-01' bookings: 5 value: 10725.5 - date: '2024-01-02' bookings: 8 value: 17440.25 items: type: object properties: date: type: string example: '2024-01-01' bookings: type: integer example: 5 value: type: number example: 10725.5 error_analysis: type: object properties: most_common_errors: type: array example: - error_type: OFFER_UNAVAILABLE count: 8 percentage: 57.14 - error_type: PAYMENT_FAILED count: 4 percentage: 28.57 items: type: object properties: error_type: type: string example: OFFER_UNAVAILABLE count: type: integer example: 8 percentage: type: number example: 57.14 meta: type: object properties: booking_type: type: string example: packages provider: type: string example: christian_tour generated_at: type: string example: '2024-01-15T10:30:00Z' timezone: type: string example: UTC 422: description: '' content: application/json: schema: type: object example: success: false error: message: 'Validation failed' details: period: - 'The selected period is invalid.' from_date: - 'The from date does not match the format Y-m-d.' code: VALIDATION_ERROR properties: success: type: boolean example: false error: type: object properties: message: type: string example: 'Validation failed' details: type: object properties: period: type: array example: - 'The selected period is invalid.' items: type: string from_date: type: array example: - 'The from date does not match the format Y-m-d.' items: type: string code: type: string example: VALIDATION_ERROR 500: description: '' content: application/json: schema: type: object example: success: false error: message: 'Failed to retrieve booking statistics' details: 'Database query timeout' code: STATS_ERROR properties: success: type: boolean example: false error: type: object properties: message: type: string example: 'Failed to retrieve booking statistics' details: type: string example: 'Database query timeout' code: type: string example: STATS_ERROR tags: - 'Package Booking' /api/booking/hotels: post: summary: 'Book a hotel offer' operationId: bookAHotelOffer description: "Books a hotel offer through various travel providers (primarily ChristianTour).\nRequires guest information for all rooms and handles validation, pricing verification,\nand booking confirmation through the travel booking service." parameters: [] responses: 201: description: '' content: application/json: schema: type: object example: success: true data: order_id: CT_ORD_789123 booking_confirmation_number: CT_BKG_456789 status: confirmed offer_id: christian_tour_offer_123 hotel_name: 'Grand Hotel Milan' check_in: '2024-06-15' check_out: '2024-06-22' nights: 7 total_price: 1250.5 currency: EUR guests: - first_name: John last_name: Smith room_assignment: 'Room 1' booking_date: '2024-01-15T10:30:00Z' cancellation_policy: free_cancellation_until: '2024-06-08T23:59:59Z' penalty_after: '50% of total price' properties: success: type: boolean example: true data: type: object properties: order_id: type: string example: CT_ORD_789123 booking_confirmation_number: type: string example: CT_BKG_456789 status: type: string example: confirmed offer_id: type: string example: christian_tour_offer_123 hotel_name: type: string example: 'Grand Hotel Milan' check_in: type: string example: '2024-06-15' check_out: type: string example: '2024-06-22' nights: type: integer example: 7 total_price: type: number example: 1250.5 currency: type: string example: EUR guests: type: array example: - first_name: John last_name: Smith room_assignment: 'Room 1' items: type: object properties: first_name: type: string example: John last_name: type: string example: Smith room_assignment: type: string example: 'Room 1' booking_date: type: string example: '2024-01-15T10:30:00Z' cancellation_policy: type: object properties: free_cancellation_until: type: string example: '2024-06-08T23:59:59Z' penalty_after: type: string example: '50% of total price' 400: description: '' content: application/json: schema: type: object example: success: false error: message: 'Offer no longer available' code: OFFER_UNAVAILABLE provider: christian_tour offer_id: christian_tour_offer_123 properties: success: type: boolean example: false error: type: object properties: message: type: string example: 'Offer no longer available' code: type: string example: OFFER_UNAVAILABLE provider: type: string example: christian_tour offer_id: type: string example: christian_tour_offer_123 422: description: '' content: application/json: schema: type: object example: success: false error: validation_failed message: 'Validation failed' errors: offer_id: - 'The offer id field is required.' occupancy.0.guests.0.birth_date: - 'The birth date does not match the format Y-m-d.' properties: success: type: boolean example: false error: type: string example: validation_failed message: type: string example: 'Validation failed' errors: type: object properties: offer_id: type: array example: - 'The offer id field is required.' items: type: string occupancy.0.guests.0.birth_date: type: array example: - 'The birth date does not match the format Y-m-d.' items: type: string 500: description: '' content: application/json: schema: type: object example: success: false error: internal_error message: 'An unexpected error occurred' properties: success: type: boolean example: false error: type: string example: internal_error message: type: string example: 'An unexpected error occurred' tags: - 'Hotel Booking' requestBody: required: true content: application/json: schema: type: object properties: offer_id: type: string description: 'The unique offer identifier from search results.' example: '"christian_tour_offer_123"' nullable: false price: type: numeric description: 'The total offer price. Min: 0.' example: '1250.50' nullable: false currency: type: string description: '3-letter currency code.' example: '"EUR"' nullable: false occupancy: type: array description: 'Room and guest information. Min: 1 room.' example: - architecto items: type: string reference_code: type: string description: 'optional Internal reference code.' example: '"REF123456"' nullable: false booking_reference: type: string description: 'optional Booking reference in format provider:entity_type:external_id.' example: '"christian_tour:hotels:2"' nullable: false provider: type: string description: 'optional Provider name if booking_reference not provided.' example: '"christian_tour"' nullable: false required: - offer_id - price - currency - occupancy /api/booking/hotels/verify-offer: post: summary: 'Verify a hotel offer before booking' operationId: verifyAHotelOfferBeforeBooking description: "Verifies if a hotel offer is still available and at the same price\nbefore proceeding with booking. This ensures price accuracy and availability." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: available: true offer_id: christian_tour_offer_123 hotel_name: 'Grand Hotel Milan' original_price: 1250.5 current_price: 1250.5 price_changed: false currency: EUR valid_until: '2024-01-15T23:59:59Z' rooms_available: 3 last_verified: '2024-01-15T10:30:00Z' properties: success: type: boolean example: true data: type: object properties: available: type: boolean example: true offer_id: type: string example: christian_tour_offer_123 hotel_name: type: string example: 'Grand Hotel Milan' original_price: type: number example: 1250.5 current_price: type: number example: 1250.5 price_changed: type: boolean example: false currency: type: string example: EUR valid_until: type: string example: '2024-01-15T23:59:59Z' rooms_available: type: integer example: 3 last_verified: type: string example: '2024-01-15T10:30:00Z' 400: description: '' content: application/json: schema: type: object example: success: false error: message: 'Offer no longer available' code: OFFER_UNAVAILABLE provider: christian_tour offer_id: christian_tour_offer_123 reason: 'Sold out' properties: success: type: boolean example: false error: type: object properties: message: type: string example: 'Offer no longer available' code: type: string example: OFFER_UNAVAILABLE provider: type: string example: christian_tour offer_id: type: string example: christian_tour_offer_123 reason: type: string example: 'Sold out' 422: description: '' content: application/json: schema: type: object example: success: false error: validation_failed message: 'Validation failed' errors: provider: - 'The provider field is required.' offer_id: - 'The offer id field is required.' properties: success: type: boolean example: false error: type: string example: validation_failed message: type: string example: 'Validation failed' errors: type: object properties: provider: type: array example: - 'The provider field is required.' items: type: string offer_id: type: array example: - 'The offer id field is required.' items: type: string 500: description: '' content: application/json: schema: type: object example: success: false error: verification_failed message: 'Failed to verify offer: Provider connection timeout' properties: success: type: boolean example: false error: type: string example: verification_failed message: type: string example: 'Failed to verify offer: Provider connection timeout' tags: - 'Hotel Booking' requestBody: required: true content: application/json: schema: type: object properties: provider: type: string description: 'Provider name.' example: '"christian_tour"' nullable: false offer_id: type: string description: 'The offer ID to verify.' example: '"christian_tour_offer_123"' nullable: false search_params: type: array description: 'optional Original search parameters used.' example: [] items: type: string required: - provider - offer_id /api/booking/verify-offer: post: summary: 'Verify a hotel offer before booking' operationId: verifyAHotelOfferBeforeBooking description: "Verifies if a hotel offer is still available and at the same price\nbefore proceeding with booking. This ensures price accuracy and availability." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: available: true offer_id: christian_tour_offer_123 hotel_name: 'Grand Hotel Milan' original_price: 1250.5 current_price: 1250.5 price_changed: false currency: EUR valid_until: '2024-01-15T23:59:59Z' rooms_available: 3 last_verified: '2024-01-15T10:30:00Z' properties: success: type: boolean example: true data: type: object properties: available: type: boolean example: true offer_id: type: string example: christian_tour_offer_123 hotel_name: type: string example: 'Grand Hotel Milan' original_price: type: number example: 1250.5 current_price: type: number example: 1250.5 price_changed: type: boolean example: false currency: type: string example: EUR valid_until: type: string example: '2024-01-15T23:59:59Z' rooms_available: type: integer example: 3 last_verified: type: string example: '2024-01-15T10:30:00Z' 400: description: '' content: application/json: schema: type: object example: success: false error: message: 'Offer no longer available' code: OFFER_UNAVAILABLE provider: christian_tour offer_id: christian_tour_offer_123 reason: 'Sold out' properties: success: type: boolean example: false error: type: object properties: message: type: string example: 'Offer no longer available' code: type: string example: OFFER_UNAVAILABLE provider: type: string example: christian_tour offer_id: type: string example: christian_tour_offer_123 reason: type: string example: 'Sold out' 422: description: '' content: application/json: schema: type: object example: success: false error: validation_failed message: 'Validation failed' errors: provider: - 'The provider field is required.' offer_id: - 'The offer id field is required.' properties: success: type: boolean example: false error: type: string example: validation_failed message: type: string example: 'Validation failed' errors: type: object properties: provider: type: array example: - 'The provider field is required.' items: type: string offer_id: type: array example: - 'The offer id field is required.' items: type: string 500: description: '' content: application/json: schema: type: object example: success: false error: verification_failed message: 'Failed to verify offer: Provider connection timeout' properties: success: type: boolean example: false error: type: string example: verification_failed message: type: string example: 'Failed to verify offer: Provider connection timeout' tags: - 'Hotel Booking' requestBody: required: true content: application/json: schema: type: object properties: provider: type: string description: 'Provider name.' example: '"christian_tour"' nullable: false offer_id: type: string description: 'The offer ID to verify.' example: '"christian_tour_offer_123"' nullable: false search_params: type: array description: 'optional Original search parameters used.' example: [] items: type: string required: - provider - offer_id '/api/packages/hotels/{id}': get: summary: 'Get hotel details by external_id' operationId: getHotelDetailsByExternalId description: "Retrieves detailed information about a specific hotel by its external_id (christian_tour).\nIncludes related destination information, booking reference, and facilities.\n\nFacilities are loaded from the normalized travel_hotel_facilities table,\nproviding up-to-date amenity information from the provider." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: id: 2 destination_id: 234 name: 'Grand Hotel Milan' type: hotel classification: 5 latitude: 45.46427 longitude: 9.18951 description: 'Luxury hotel in Milan center' address: street: 'Via del Corso 123' city: Milan country: Italy postal_code: '20121' images: - url: 'https://example.com/hotel1.jpg' type: exterior - url: 'https://example.com/hotel2.jpg' type: room facilities: - id: 1 name: 'Meniu masă pentru copii' - id: 8 name: Restaurant - id: 11 name: Bar - id: 24 name: 'Servicii de înfrumusețare' - id: 39 name: Saună giata_id: '12345' provider: christian_tour external_id: '2' booking_reference: 'christian_tour:hotels:2' last_synced_at: '2025-10-20T09:30:00.000000Z' data_freshness: fresh destination: id: 234 name: Milan type: destination country_code: IT latitude: 45.46427 longitude: 9.18951 provider: christian_tour external_id: '234' booking_reference: 'christian_tour:destinations:234' last_synced_at: '2025-10-20T08:00:00.000000Z' data_freshness: fresh meta: cached: false cache_key: 'hotel_details:christian_tour:2' cache_ttl: 3600 properties: success: type: boolean example: true data: type: object properties: id: type: integer example: 2 destination_id: type: integer example: 234 name: type: string example: 'Grand Hotel Milan' type: type: string example: hotel classification: type: integer example: 5 latitude: type: number example: 45.46427 longitude: type: number example: 9.18951 description: type: string example: 'Luxury hotel in Milan center' address: type: object properties: street: type: string example: 'Via del Corso 123' city: type: string example: Milan country: type: string example: Italy postal_code: type: string example: '20121' images: type: array example: - url: 'https://example.com/hotel1.jpg' type: exterior - url: 'https://example.com/hotel2.jpg' type: room items: type: object properties: url: type: string example: 'https://example.com/hotel1.jpg' type: type: string example: exterior facilities: type: array example: - id: 1 name: 'Meniu masă pentru copii' - id: 8 name: Restaurant - id: 11 name: Bar - id: 24 name: 'Servicii de înfrumusețare' - id: 39 name: Saună items: type: object properties: id: type: integer example: 1 name: type: string example: 'Meniu masă pentru copii' giata_id: type: string example: '12345' provider: type: string example: christian_tour external_id: type: string example: '2' booking_reference: type: string example: 'christian_tour:hotels:2' last_synced_at: type: string example: '2025-10-20T09:30:00.000000Z' data_freshness: type: string example: fresh destination: type: object properties: id: type: integer example: 234 name: type: string example: Milan type: type: string example: destination country_code: type: string example: IT latitude: type: number example: 45.46427 longitude: type: number example: 9.18951 provider: type: string example: christian_tour external_id: type: string example: '234' booking_reference: type: string example: 'christian_tour:destinations:234' last_synced_at: type: string example: '2025-10-20T08:00:00.000000Z' data_freshness: type: string example: fresh meta: type: object properties: cached: type: boolean example: false cache_key: type: string example: 'hotel_details:christian_tour:2' cache_ttl: type: integer example: 3600 404: description: '' content: application/json: schema: type: object example: error: 'Hotel not found' message: "Hotel with external_id '2' not found" properties: error: type: string example: 'Hotel not found' message: type: string example: "Hotel with external_id '2' not found" tags: - 'Travel Data' parameters: - in: path name: id description: 'The hotel external_id from provider.' example: '"2"' required: true schema: type: string /api/travel/health: get: summary: 'Get detailed health check of Travel system' operationId: getDetailedHealthCheckOfTravelSystem description: "Provides comprehensive health check including database connectivity,\nprovider status, sync status, and cache health." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: overall_status: healthy database: status: healthy connection: active tables: travel_destinations: exists travel_hotels: exists providers: christian_tour: status: healthy response_time_ms: 245 sync_status: last_sync: '2024-01-15T10:30:00Z' status: healthy pending_syncs: 0 cache: status: healthy hit_ratio: 87 size_mb: 245 properties: success: type: boolean example: true data: type: object properties: overall_status: type: string example: healthy database: type: object properties: status: type: string example: healthy connection: type: string example: active tables: type: object properties: travel_destinations: type: string example: exists travel_hotels: type: string example: exists providers: type: object properties: christian_tour: type: object properties: status: type: string example: healthy response_time_ms: type: integer example: 245 sync_status: type: object properties: last_sync: type: string example: '2024-01-15T10:30:00Z' status: type: string example: healthy pending_syncs: type: integer example: 0 cache: type: object properties: status: type: string example: healthy hit_ratio: type: integer example: 87 size_mb: type: integer example: 245 503: description: '' content: application/json: schema: type: object example: success: true data: overall_status: unhealthy database: status: error error: 'Connection timeout' properties: success: type: boolean example: true data: type: object properties: overall_status: type: string example: unhealthy database: type: object properties: status: type: string example: error error: type: string example: 'Connection timeout' tags: - 'System Status' /api/travel/providers/stats: get: summary: 'Get provider statistics' operationId: getProviderStatistics description: "Retrieve comprehensive statistics about all travel data providers including their status,\ndata counts, sync information, and performance metrics.\n\nThis endpoint provides detailed insights into the health and performance of each provider\nin the travel API system, including:\n- Provider availability and connectivity status\n- Data volume statistics for each entity type\n- Last synchronization timestamps and success rates\n- Performance metrics and error counts\n- Cache hit ratios and response times" parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: - provider: christian_tour active: true status: healthy last_sync: '2024-01-15T10:30:00Z' sync_status: success data_counts: destinations: 1234 hotels: 5678 circuits: 234 experiences: 456 packages: 789 performance: avg_response_time_ms: 85 success_rate: 99.5 error_count: 2 cache_hit_ratio: 87.3 sync_info: last_full_sync: '2024-01-15T06:00:00Z' next_scheduled_sync: '2024-01-15T14:00:00Z' sync_frequency_hours: 8 - provider: obs active: true status: warning last_sync: '2024-01-15T08:45:00Z' sync_status: partial_error data_counts: destinations: 856 hotels: 2345 circuits: 123 experiences: 234 packages: 567 performance: avg_response_time_ms: 120 success_rate: 95.2 error_count: 15 cache_hit_ratio: 78.9 sync_info: last_full_sync: '2024-01-15T02:00:00Z' next_scheduled_sync: '2024-01-15T10:00:00Z' sync_frequency_hours: 8 meta: active_providers: 2 total_providers: 2 generated_at: '2024-01-15T12:00:00Z' properties: success: type: boolean example: true data: type: array example: - provider: christian_tour active: true status: healthy last_sync: '2024-01-15T10:30:00Z' sync_status: success data_counts: destinations: 1234 hotels: 5678 circuits: 234 experiences: 456 packages: 789 performance: avg_response_time_ms: 85 success_rate: 99.5 error_count: 2 cache_hit_ratio: 87.3 sync_info: last_full_sync: '2024-01-15T06:00:00Z' next_scheduled_sync: '2024-01-15T14:00:00Z' sync_frequency_hours: 8 - provider: obs active: true status: warning last_sync: '2024-01-15T08:45:00Z' sync_status: partial_error data_counts: destinations: 856 hotels: 2345 circuits: 123 experiences: 234 packages: 567 performance: avg_response_time_ms: 120 success_rate: 95.2 error_count: 15 cache_hit_ratio: 78.9 sync_info: last_full_sync: '2024-01-15T02:00:00Z' next_scheduled_sync: '2024-01-15T10:00:00Z' sync_frequency_hours: 8 items: type: object properties: provider: type: string example: christian_tour active: type: boolean example: true status: type: string example: healthy last_sync: type: string example: '2024-01-15T10:30:00Z' sync_status: type: string example: success data_counts: type: object properties: destinations: type: integer example: 1234 hotels: type: integer example: 5678 circuits: type: integer example: 234 experiences: type: integer example: 456 packages: type: integer example: 789 performance: type: object properties: avg_response_time_ms: type: integer example: 85 success_rate: type: number example: 99.5 error_count: type: integer example: 2 cache_hit_ratio: type: number example: 87.3 sync_info: type: object properties: last_full_sync: type: string example: '2024-01-15T06:00:00Z' next_scheduled_sync: type: string example: '2024-01-15T14:00:00Z' sync_frequency_hours: type: integer example: 8 meta: type: object properties: active_providers: type: integer example: 2 total_providers: type: integer example: 2 generated_at: type: string example: '2024-01-15T12:00:00Z' 500: description: '' content: application/json: schema: type: object example: error: 'Internal server error' message: 'Failed to retrieve provider statistics' properties: error: type: string example: 'Internal server error' message: type: string example: 'Failed to retrieve provider statistics' tags: - 'System Status' /api/health: get: summary: 'Get detailed health check of Travel system' operationId: getDetailedHealthCheckOfTravelSystem description: "Provides comprehensive health check including database connectivity,\nprovider status, sync status, and cache health." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: overall_status: healthy database: status: healthy connection: active tables: travel_destinations: exists travel_hotels: exists providers: christian_tour: status: healthy response_time_ms: 245 sync_status: last_sync: '2024-01-15T10:30:00Z' status: healthy pending_syncs: 0 cache: status: healthy hit_ratio: 87 size_mb: 245 properties: success: type: boolean example: true data: type: object properties: overall_status: type: string example: healthy database: type: object properties: status: type: string example: healthy connection: type: string example: active tables: type: object properties: travel_destinations: type: string example: exists travel_hotels: type: string example: exists providers: type: object properties: christian_tour: type: object properties: status: type: string example: healthy response_time_ms: type: integer example: 245 sync_status: type: object properties: last_sync: type: string example: '2024-01-15T10:30:00Z' status: type: string example: healthy pending_syncs: type: integer example: 0 cache: type: object properties: status: type: string example: healthy hit_ratio: type: integer example: 87 size_mb: type: integer example: 245 503: description: '' content: application/json: schema: type: object example: success: true data: overall_status: unhealthy database: status: error error: 'Connection timeout' properties: success: type: boolean example: true data: type: object properties: overall_status: type: string example: unhealthy database: type: object properties: status: type: string example: error error: type: string example: 'Connection timeout' tags: - 'System Status' /api/status: get: summary: 'Get Travel system status and sync information' operationId: getTravelSystemStatusAndSyncInformation description: "Provides detailed status information about providers, data types,\nand synchronization status." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: providers: christian_tour: name: christian_tour last_sync: '2024-01-15T10:30:00Z' sync_status: success total_records: 1234 freshness: fresh data_types: destinations: total_records: 2090 last_sync: '2024-01-15T10:30:00Z' freshness: fresh hotels: total_records: 5432 last_sync: '2024-01-15T09:45:00Z' freshness: acceptable database_stats: total_records: 7756 active_providers: 2 properties: success: type: boolean example: true data: type: object properties: providers: type: object properties: christian_tour: type: object properties: name: type: string example: christian_tour last_sync: type: string example: '2024-01-15T10:30:00Z' sync_status: type: string example: success total_records: type: integer example: 1234 freshness: type: string example: fresh data_types: type: object properties: destinations: type: object properties: total_records: type: integer example: 2090 last_sync: type: string example: '2024-01-15T10:30:00Z' freshness: type: string example: fresh hotels: type: object properties: total_records: type: integer example: 5432 last_sync: type: string example: '2024-01-15T09:45:00Z' freshness: type: string example: acceptable database_stats: type: object properties: total_records: type: integer example: 7756 active_providers: type: integer example: 2 tags: - 'System Status'