""" Kiwi.com / Tequila API adapter. """ import os import logging from datetime import date, datetime from typing import List, Dict, Any import requests from adapters.base import FlightAdapter logger = logging.getLogger(__name__) class KiwiAdapter(FlightAdapter): """ Adapter for Kiwi.com Tequila API. API docs: https://tequila.kiwi.com/docs/search/ """ API_BASE = "https://api.tequila.kiwi.com" def __init__(self): """Initialize the adapter. Requires KIWI_API_KEY environment variable.""" self.api_key = os.getenv("KIWI_API_KEY") if not self.api_key: raise ValueError( "KIWI_API_KEY environment variable not set. " "Get your API key from https://tequila.kiwi.com/portal/login" ) logger.info("Kiwi adapter initialized") def get_name(self) -> str: return "Kiwi/Tequila" def search_round_trip( self, origin: str, destination: str, departure_date: date, return_date: date, **kwargs ) -> List[Dict[str, Any]]: """ Search for round-trip flights via Kiwi API. Args: origin: IATA code (e.g., "BER") destination: IATA code (e.g., "EZE") departure_date: Departure date return_date: Return date Returns: List of normalized flight results. """ url = f"{self.API_BASE}/v2/search" params = { "fly_from": origin, "fly_to": destination, "date_from": departure_date.strftime("%d/%m/%Y"), "date_to": departure_date.strftime("%d/%m/%Y"), "return_from": return_date.strftime("%d/%m/%Y"), "return_to": return_date.strftime("%d/%m/%Y"), "flight_type": "round", "adults": 1, "curr": "EUR", "limit": 5, "sort": "price" } headers = { "apikey": self.api_key, "accept": "application/json" } try: logger.debug(f"Kiwi API request: {origin}→{destination} {departure_date} → {return_date}") response = requests.get(url, params=params, headers=headers, timeout=30) response.raise_for_status() data = response.json() results = [] for item in data.get("data", []): # Extract airline(s) - may be multiple for multi-leg flights airlines = set() for route in item.get("route", []): airline = route.get("airline") if airline: airlines.add(airline) airline_str = ", ".join(sorted(airlines)) if airlines else "Unknown" # Parse timestamps departure_time = datetime.fromtimestamp(item.get("dTime", 0)) return_time = datetime.fromtimestamp(item.get("aTime", 0)) # Build deep link deep_link = item.get("deep_link", "") results.append({ "price_eur": float(item.get("price", 0)), "airline": airline_str, "departure": departure_time, "return": return_time, "link": deep_link, "source": self.get_name() }) logger.debug(f"Kiwi API returned {len(results)} results") return results except requests.exceptions.RequestException as e: logger.error(f"Kiwi API request failed: {e}") return [] except Exception as e: logger.error(f"Error parsing Kiwi API response: {e}") return []