openapi: 3.1.0
info:
  title: TourSniper Public API
  version: 1.0.0
  description: |
    Search and compare package tour prices from Russia.
    Aggregates real-time data from Travelata, OnlineTours, and Sletat.

    **Use cases for AI agents:**
    - Find cheapest tours to a destination
    - Compare prices across operators
    - Get hot deals and discounts
    - Check price ranges for trip planning

    **Rate limit:** 60 requests/minute per IP.
  contact:
    name: TourSniper Support
    url: https://t.me/ULIDEV_Official
  license:
    name: Proprietary
    url: https://toursniper.ru/terms

servers:
  - url: https://toursniper.ru
    description: Production

paths:
  /api/public/countries:
    get:
      operationId: listCountries
      summary: List supported destination countries
      description: Returns all countries available for tour search with their codes and metadata.
      responses:
        '200':
          description: List of countries
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/CountryInfo'

  /api/public/cities:
    get:
      operationId: listCities
      summary: List departure cities
      description: Returns all Russian cities available as departure points with their codes.
      responses:
        '200':
          description: List of cities
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/CityInfo'

  /api/public/search:
    get:
      operationId: searchTours
      summary: Search tours
      description: |
        Search for package tours by destination, dates, budget, and preferences.
        Aggregates results from Travelata, OnlineTours, and Sletat in real-time.
        Results sorted by price ascending.
      parameters:
        - name: country
          in: query
          required: true
          description: "Destination country code (e.g., 'turkey', 'egypt', 'thailand')"
          schema:
            type: string
            enum: [turkey, egypt, thailand, uae, maldives, srilanka, vietnam, indonesia, china]
        - name: departure_city
          in: query
          required: false
          description: "Departure city code (default: 'moscow')"
          schema:
            type: string
            default: moscow
        - name: date_from
          in: query
          required: false
          description: "Earliest departure date (YYYY-MM-DD). Defaults to tomorrow."
          schema:
            type: string
            format: date
        - name: date_to
          in: query
          required: false
          description: "Latest departure date (YYYY-MM-DD). Defaults to +30 days."
          schema:
            type: string
            format: date
        - name: nights_min
          in: query
          required: false
          description: Minimum number of nights
          schema:
            type: integer
            default: 7
            minimum: 1
            maximum: 28
        - name: nights_max
          in: query
          required: false
          description: Maximum number of nights
          schema:
            type: integer
            default: 14
            minimum: 1
            maximum: 28
        - name: adults
          in: query
          required: false
          description: Number of adults
          schema:
            type: integer
            default: 2
            minimum: 1
            maximum: 6
        - name: budget_max
          in: query
          required: false
          description: Maximum total budget in RUB
          schema:
            type: integer
        - name: stars_min
          in: query
          required: false
          description: Minimum hotel star rating
          schema:
            type: integer
            minimum: 1
            maximum: 5
        - name: meal_type
          in: query
          required: false
          description: "Meal plan filter: RO (room only), BB (breakfast), HB (half board), FB (full board), AI (all inclusive), UAI (ultra all inclusive)"
          schema:
            type: string
            enum: [RO, BB, HB, FB, AI, UAI]
        - name: limit
          in: query
          required: false
          description: Maximum results to return
          schema:
            type: integer
            default: 10
            minimum: 1
            maximum: 50
      responses:
        '200':
          description: Search results
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SearchResponse'
        '400':
          description: Invalid parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /api/public/hot:
    get:
      operationId: getHotDeals
      summary: Get hot tour deals
      description: |
        Returns current hot deals — tours with best prices or significant discounts.
        Updated every 5 minutes.
      parameters:
        - name: country
          in: query
          required: false
          description: Filter by country code (optional, returns all if omitted)
          schema:
            type: string
        - name: departure_city
          in: query
          required: false
          description: Departure city code
          schema:
            type: string
            default: moscow
        - name: limit
          in: query
          required: false
          description: Maximum results to return
          schema:
            type: integer
            default: 10
            minimum: 1
            maximum: 50
      responses:
        '200':
          description: Hot deals
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HotToursResponse'

  /api/public/price-range:
    get:
      operationId: getPriceRange
      summary: Get price range for a destination
      description: Returns min/max/average prices for tours to a given country. Useful for budget planning.
      parameters:
        - name: country
          in: query
          required: true
          description: Destination country code
          schema:
            type: string
        - name: departure_city
          in: query
          required: false
          description: Departure city code
          schema:
            type: string
            default: moscow
      responses:
        '200':
          description: Price range data
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PriceRangeResponse'

components:
  schemas:
    CountryInfo:
      type: object
      properties:
        code:
          type: string
          description: "Country code (e.g., 'turkey')"
        name_ru:
          type: string
          description: Country name in Russian
        flag:
          type: string
          description: Flag emoji
        long_haul:
          type: boolean
          description: True if long-haul destination
      required: [code, name_ru, flag, long_haul]

    CityInfo:
      type: object
      properties:
        code:
          type: string
          description: "City code (e.g., 'moscow')"
        name_ru:
          type: string
          description: City name in Russian
      required: [code, name_ru]

    TourOffer:
      type: object
      description: A single tour offer from a tour operator
      properties:
        hotel_name:
          type: string
        stars:
          type: integer
          description: "Hotel star rating (1-5)"
        country:
          type: string
        city:
          type: string
          description: Resort city/town
        price:
          type: integer
          description: Total price in RUB for all travelers
        price_per_person:
          type: integer
          description: Price per person in RUB
        nights:
          type: integer
        meal_type:
          type: string
          description: "RO, BB, HB, FB, AI, UAI"
        departure_date:
          type: string
          format: date
        operator:
          type: string
          description: Tour operator name
        booking_url:
          type: string
          format: uri
          description: Direct booking link
        photo_url:
          type: string
          format: uri
        rating:
          type: number
          description: "Hotel rating (0-10)"
        reviews_count:
          type: integer
        room_type:
          type: string
      required: [hotel_name, stars, country, city, price, price_per_person, nights, meal_type, departure_date, operator, booking_url]

    SearchResponse:
      type: object
      properties:
        query:
          type: object
          description: Echo of search parameters
        results:
          type: array
          items:
            $ref: '#/components/schemas/TourOffer'
        total:
          type: integer
        cached:
          type: boolean
      required: [query, results, total]

    HotToursResponse:
      type: object
      properties:
        tours:
          type: array
          items:
            $ref: '#/components/schemas/TourOffer'
        total:
          type: integer
        updated_at:
          type: string
          format: date-time
      required: [tours, total, updated_at]

    PriceRangeResponse:
      type: object
      properties:
        country:
          type: string
        departure_city:
          type: string
        min_price:
          type: integer
          nullable: true
          description: Minimum total price (RUB)
        max_price:
          type: integer
          nullable: true
        avg_price:
          type: integer
          nullable: true
        sample_size:
          type: integer
        period:
          type: string
      required: [country, departure_city, sample_size, period]

    ErrorResponse:
      type: object
      properties:
        detail:
          type: string
          description: Error message
