Skip to main content
Glama
flights.py7.57 kB
"""Flight-related models for Duffel API.""" from datetime import datetime from enum import Enum from typing import Literal from pydantic import BaseModel, Field, field_validator, ConfigDict from .common import ResponseFormat, PaymentType class PassengerType(str, Enum): """Passenger types supported by Duffel API.""" ADULT = "adult" CHILD = "child" INFANT_WITHOUT_SEAT = "infant_without_seat" class CabinClass(str, Enum): """Cabin class options for flights.""" ECONOMY = "economy" PREMIUM_ECONOMY = "premium_economy" BUSINESS = "business" FIRST = "first" class Slice(BaseModel): """A slice represents one leg of a journey (e.g., outbound or return).""" model_config = ConfigDict(str_strip_whitespace=True, validate_assignment=True, extra='forbid') origin: str = Field( ..., description="IATA airport or city code for departure (e.g., 'JFK', 'NYC', 'LON')", min_length=3, max_length=3 ) destination: str = Field( ..., description="IATA airport or city code for arrival (e.g., 'LAX', 'SFO', 'PAR')", min_length=3, max_length=3 ) departure_date: str = Field( ..., description="Departure date in YYYY-MM-DD format (e.g., '2025-12-25')" ) @field_validator('departure_date') @classmethod def validate_date_format(cls, v: str) -> str: """Validate date is in correct format and not in the past.""" try: date = datetime.strptime(v, "%Y-%m-%d").date() if date < datetime.now().date(): raise ValueError("Departure date cannot be in the past") return v except ValueError as e: raise ValueError(f"Invalid date format. Use YYYY-MM-DD: {e}") class Passenger(BaseModel): """Passenger information for flight search.""" model_config = ConfigDict(str_strip_whitespace=True, validate_assignment=True, extra='forbid') age: int | None = Field( default=None, description="Age of passenger. Recommended over 'type' for accuracy (e.g., 35, 12, 1)", ge=0, le=120 ) type: PassengerType | None = Field( default=None, description="Passenger type: 'adult', 'child', or 'infant_without_seat'. Use 'age' instead for better accuracy" ) @field_validator('type') @classmethod def check_age_or_type(cls, v, info): """Ensure either age or type is provided.""" if v is None and info.data.get('age') is None: raise ValueError("Either 'age' or 'type' must be provided") return v class FlightSearchInput(BaseModel): """Input for searching flights.""" model_config = ConfigDict(str_strip_whitespace=True, validate_assignment=True, extra='forbid') slices: list[Slice] = Field( ..., description="List of journey slices (legs). One-way = 1 slice, round-trip = 2 slices", min_length=1, max_length=4 ) passengers: list[Passenger] = Field( ..., description="List of passengers traveling. Include all travelers", min_length=1, max_length=9 ) cabin_class: CabinClass | None = Field( default=None, description="Preferred cabin class: 'economy', 'premium_economy', 'business', or 'first'" ) max_connections: int | None = Field( default=None, description="Maximum number of connections/stops per slice (e.g., 0 for direct flights, 1 for one stop)", ge=0, le=3 ) response_format: ResponseFormat = Field( default=ResponseFormat.MARKDOWN, description="Output format: 'json' for raw data or 'markdown' for readable summary" ) class GetOfferInput(BaseModel): """Input for retrieving a specific flight offer.""" model_config = ConfigDict(str_strip_whitespace=True, validate_assignment=True, extra='forbid') offer_id: str = Field( ..., description="Duffel offer ID (e.g., 'off_00009htYpSCXrwaB9DnUm0')", pattern="^off_[a-zA-Z0-9]+$" ) response_format: ResponseFormat = Field( default=ResponseFormat.MARKDOWN, description="Output format: 'json' for raw data or 'markdown' for readable summary" ) class PassengerDetails(BaseModel): """Detailed passenger information for booking.""" model_config = ConfigDict(str_strip_whitespace=True, validate_assignment=True, extra='forbid') id: str = Field( ..., description="Passenger ID from the offer (e.g., 'pas_00009hj8USM7Ncg31cBCL')" ) given_name: str = Field( ..., description="First/given name as shown on ID (e.g., 'John')", min_length=1, max_length=50 ) family_name: str = Field( ..., description="Last/family name as shown on ID (e.g., 'Smith')", min_length=1, max_length=50 ) born_on: str = Field( ..., description="Date of birth in YYYY-MM-DD format (e.g., '1985-03-15')" ) email: str = Field( ..., description="Email address for booking confirmation (e.g., 'john.smith@example.com')" ) phone_number: str = Field( ..., description="Phone number with country code (e.g., '+14155551234')" ) gender: Literal["m", "f"] = Field( ..., description="Gender: 'm' for male, 'f' for female" ) title: str | None = Field( default=None, description="Title (e.g., 'mr', 'mrs', 'ms', 'dr')" ) class Payment(BaseModel): """Payment information for booking.""" model_config = ConfigDict(str_strip_whitespace=True, validate_assignment=True, extra='forbid') type: PaymentType = Field( ..., description="Payment type: 'balance' (Duffel Balance), 'arc_bsp_cash' (IATA agent), or 'card' (credit card)" ) amount: str = Field( ..., description="Payment amount matching offer total_amount (e.g., '520.00')" ) currency: str = Field( ..., description="Payment currency matching offer total_currency (e.g., 'USD', 'EUR')", min_length=3, max_length=3 ) class CreateOrderInput(BaseModel): """Input for creating a flight order (booking).""" model_config = ConfigDict(str_strip_whitespace=True, validate_assignment=True, extra='forbid') offer_id: str = Field( ..., description="Offer ID to book (e.g., 'off_00009htYpSCXrwaB9DnUm0')", pattern="^off_[a-zA-Z0-9]+$" ) passengers: list[PassengerDetails] = Field( ..., description="Complete details for all passengers", min_length=1, max_length=9 ) payments: list[Payment] = Field( ..., description="Payment information (typically one payment object)", min_length=1, max_length=1 ) response_format: ResponseFormat = Field( default=ResponseFormat.MARKDOWN, description="Output format: 'json' for raw data or 'markdown' for readable summary" ) class GetOrderInput(BaseModel): """Input for retrieving order details.""" model_config = ConfigDict(str_strip_whitespace=True, validate_assignment=True, extra='forbid') order_id: str = Field( ..., description="Duffel order ID (e.g., 'ord_00009hthhsUZ8W4LxQgkjo')", pattern="^ord_[a-zA-Z0-9]+$" ) response_format: ResponseFormat = Field( default=ResponseFormat.MARKDOWN, description="Output format: 'json' for raw data or 'markdown' for readable summary" )

Implementation Reference

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/FortripEngineering/duffel-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server