Skip to main content
Glama
stays.py6.74 kB
"""Stays (accommodation) related models for Duffel API.""" from datetime import datetime from pydantic import BaseModel, Field, field_validator, ConfigDict from .common import ResponseFormat class GeographicLocation(BaseModel): """Geographic coordinates for accommodation search.""" model_config = ConfigDict(str_strip_whitespace=True, validate_assignment=True, extra='forbid') latitude: float = Field( ..., description="Latitude coordinate (-90 to 90)", ge=-90.0, le=90.0 ) longitude: float = Field( ..., description="Longitude coordinate (-180 to 180)", ge=-180.0, le=180.0 ) radius: int = Field( ..., description="Search radius in kilometers (1-100)", ge=1, le=100 ) class AccommodationGuest(BaseModel): """Guest information for accommodation search.""" model_config = ConfigDict(str_strip_whitespace=True, validate_assignment=True, extra='forbid') adult_count: int = Field( ..., description="Number of adult guests (18+)", ge=1, le=20 ) child_count: int | None = Field( default=0, description="Number of child guests (under 18)", ge=0, le=20 ) class SearchAccommodationInput(BaseModel): """Input for searching accommodations.""" model_config = ConfigDict(str_strip_whitespace=True, validate_assignment=True, extra='forbid') check_in_date: str = Field( ..., description="Check-in date in YYYY-MM-DD format (e.g., '2025-12-25')" ) check_out_date: str = Field( ..., description="Check-out date in YYYY-MM-DD format (e.g., '2025-12-27')" ) guests: AccommodationGuest = Field( ..., description="Guest count for the accommodation" ) rooms: int = Field( default=1, description="Number of rooms needed", ge=1, le=10 ) location: GeographicLocation | None = Field( default=None, description="Geographic location (latitude, longitude, radius) for search" ) accommodation_ids: list[str] | None = Field( default=None, description="Specific accommodation IDs to search (alternative to location)" ) response_format: ResponseFormat = Field( default=ResponseFormat.MARKDOWN, description="Output format: 'json' for raw data or 'markdown' for readable summary" ) @field_validator('check_in_date', 'check_out_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("Date cannot be in the past") return v except ValueError as e: raise ValueError(f"Invalid date format. Use YYYY-MM-DD: {e}") class GetAccommodationInput(BaseModel): """Input for retrieving accommodation details.""" model_config = ConfigDict(str_strip_whitespace=True, validate_assignment=True, extra='forbid') accommodation_id: str = Field( ..., description="Accommodation ID (e.g., 'acc_00009htYpSCXrwaB9DnUm0')", pattern="^acc_[a-zA-Z0-9]+$" ) response_format: ResponseFormat = Field( default=ResponseFormat.MARKDOWN, description="Output format: 'json' for raw data or 'markdown' for readable summary" ) class GetAccommodationRatesInput(BaseModel): """Input for getting rates for a search result.""" model_config = ConfigDict(str_strip_whitespace=True, validate_assignment=True, extra='forbid') search_result_id: str = Field( ..., description="Search result ID from accommodation search", pattern="^srs_[a-zA-Z0-9]+$" ) response_format: ResponseFormat = Field( default=ResponseFormat.MARKDOWN, description="Output format: 'json' for raw data or 'markdown' for readable summary" ) class CreateStaysQuoteInput(BaseModel): """Input for creating a stays quote.""" model_config = ConfigDict(str_strip_whitespace=True, validate_assignment=True, extra='forbid') rate_id: str = Field( ..., description="Rate ID from accommodation rates (e.g., 'rat_00009htYpSCXrwaB9DnUm0')", pattern="^rat_[a-zA-Z0-9]+$" ) response_format: ResponseFormat = Field( default=ResponseFormat.MARKDOWN, description="Output format: 'json' for raw data or 'markdown' for readable summary" ) class StaysGuestDetails(BaseModel): """Guest details for stays booking.""" model_config = ConfigDict(str_strip_whitespace=True, validate_assignment=True, extra='forbid') given_name: str = Field( ..., description="First/given name (e.g., 'John')", min_length=1, max_length=50 ) family_name: str = Field( ..., description="Last/family name (e.g., 'Smith')", min_length=1, max_length=50 ) email: str = Field( ..., description="Email address for booking confirmation" ) phone_number: str | None = Field( default=None, description="Phone number with country code (e.g., '+14155551234')" ) class CreateStaysBookingInput(BaseModel): """Input for creating a stays booking.""" model_config = ConfigDict(str_strip_whitespace=True, validate_assignment=True, extra='forbid') quote_id: str = Field( ..., description="Quote ID from stays quote (e.g., 'quo_00009htYpSCXrwaB9DnUm0')", pattern="^quo_[a-zA-Z0-9]+$" ) guests: list[StaysGuestDetails] = Field( ..., description="Guest details (at least one guest required)", min_length=1, max_length=20 ) special_requests: str | None = Field( default=None, description="Special requests for the accommodation", max_length=500 ) response_format: ResponseFormat = Field( default=ResponseFormat.MARKDOWN, description="Output format: 'json' for raw data or 'markdown' for readable summary" ) class GetStaysBookingInput(BaseModel): """Input for retrieving stays booking details.""" model_config = ConfigDict(str_strip_whitespace=True, validate_assignment=True, extra='forbid') booking_id: str = Field( ..., description="Stays booking ID (e.g., 'bok_00009htYpSCXrwaB9DnUm0')", pattern="^bok_[a-zA-Z0-9]+$" ) response_format: ResponseFormat = Field( default=ResponseFormat.MARKDOWN, description="Output format: 'json' for raw data or 'markdown' for readable summary" )

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