{
 "openapi": "3.1.0",
 "info": {
  "title": "ScraperCompany Hotel Rate API",
  "version": "1.0.0",
  "description": "Live hotel rates from Google Hotels, the major OTAs (Booking.com, Hotels.com, Expedia, Agoda, Tripadvisor, Hostelworld), vacation rentals (Airbnb, Vrbo), Google Flights and hotels' own official booking engines, normalized into consistent JSON with per-rate provenance. The same data is available to AI agents through the MCP server at `https://api.scrapercompany.com/mcp`.\n\n## Base URL\n\nAll requests go to `https://api.scrapercompany.com`. Every path in this reference is relative to it, for example `POST https://api.scrapercompany.com/v1/calendar`.\n\n## Authentication\n\nSend your API key in the `x-api-key` header:\n\n```bash\ncurl https://api.scrapercompany.com/v1/markets \\\n  -H \"x-api-key: sk_your_key\"\n```\n\nThe API also accepts `Authorization: Bearer <key>` and an `api_key` query parameter (handy for SearchAPI-style GET integrations). Prefer the header: query strings tend to end up in logs and browser history.\n\nKeys look like `sk_` followed by random characters. There is a single key type, with no separate live and test keys. During the beta, keys are issued by the ScraperCompany team: [contact sales or support](https://scrapercompany.com/contact) to get one. Keys cannot yet be created or rotated from the dashboard.\n\n## Errors\n\nErrors return a non-2xx status and a JSON body with a `detail` field:\n\n```json\n{\"detail\": \"missing or invalid API key\"}\n```\n\nRequest-validation failures (`422`) usually return `detail` as a list of problems, each with `loc`, `msg` and `type`; a few semantic checks return a plain string instead. Status codes used: `400` bad request, `401` missing or invalid key, `402` insufficient credits (only once credit enforcement is on), `404` not found, `409` conflict, `422` validation error, `429` rate or concurrency limit exceeded, `502` the upstream source failed or blocked the request, `503` temporarily unavailable. Responses carry an `x-request-id` header (`req_...`); for calls recorded in your request history it is also the `id` used by `GET /v1/requests/{request_id}`, so quote it when contacting support.\n\n## Rate limits\n\nEach key has a requests-per-minute limit, enforced over a sliding 60-second window. The default is 60 requests per minute; your key's limit is returned as `key.rate_limit_per_min` by `GET /v1/usage`. Going over it returns `429` with `{\"detail\": \"rate limit 60/min exceeded\"}`. No rate-limit or `Retry-After` headers are sent, so back off (for example exponentially) and retry. Once credit enforcement is switched on, a `429` can also mean the plan's concurrent-request limit was reached (`concurrency limit N reached for the <plan> plan`).\n\n## Credits\n\nCredit metering is in beta and paid plans are not on sale yet. Metering runs in *shadow* mode: every request is metered and recorded, and nothing is blocked. Each operation states its cost in its description (\"Credits: N\") and in the `x-credits` extension. Failed, blocked and empty results are free.\n\nMetered responses carry `x-credits-charged` (credits charged for the request) and `x-credits-remaining` (credits left on the account). `GET /v1/billing` returns your plan, balance and period, `GET /v1/billing/ledger` every credit movement, and `GET /v1/billing/plans` the plan catalogue and full cost table. Once enforcement is on, a request that needs more credits than are available gets `402`.\n\n| Operation | Credits |\n|---|---|\n| Property search / resolve: `POST /v1/search`, `POST /v1/ota/{booking,hotels,agoda,expedia,vrbo}/search` | 1 |\n| Google Hotels destination search: `POST /v1/hotels/search`, `POST /v1/serp/google_hotels` | 3 per page (an empty page is free) |\n| Google Hotels calendar: `POST /v1/calendar`, `POST /v1/serp/google_hotels_calendar` (calendar adds 3 per night with `basis: mainstream` and 3 per `verify_sources` spot-check) | 5 |\n| Calendar batch: `POST /v1/jobs` | each succeeded item priced like `POST /v1/calendar` (5 by default) |\n| Google property, offers, rooms and stay: `POST /v1/offers`, `POST /v1/rooms`, `POST /v1/stay`, `POST /v1/serp/google_hotels_property` | 3 |\n| Single OTA source: Booking.com, Hotels.com, Expedia, Vrbo, Agoda, Tripadvisor, Hostelworld, Airbnb (`POST /v1/serp/airbnb`, `GET /api/v1/search`) | 8 |\n| Airbnb priced calendar: `POST /v1/airbnb/calendar`, `POST /v1/serp/airbnb_property_availability_calendar` | 8, plus 1 per night actually priced (at most 92) |\n| Official hotel site: `POST /v1/official` | 4 |\n| OTA compare: `POST /v1/ota/compare` | 20 |\n| Google Flights search, return leg and booking options: `POST /v1/serp/google_flights`, `POST /v1/serp/google_flights_return`, `POST /v1/serp/google_flights_booking` | 3 |\n| Google Flights location search: `POST /v1/serp/google_flights_location_search` | 1 |\n| Google Flights calendar: `POST /v1/serp/google_flights_calendar` | 5 |\n| Metadata, billing and stored reads: usage, request history, billing, markets, OTA sources, official engines, storage status, stored rates, job submission and polling | 0 |\n\n## Coverage\n\n- **Google Hotels calendar**: `POST /v1/calendar` returns up to 330 nights per call (90 by default).\n- **Official hotel sites**: `POST /v1/official` covers 31 official booking engines, detected automatically from the hotel's website.\n- **SearchAPI compatibility**: `/v1/serp/*` and `GET /api/v1/search` accept SearchAPI's parameter names and return its response shapes, so existing integrations only change their base URL.\n- **MCP server**: `POST /mcp` exposes 18 read-only tools (hotel rates, flights, vacation rentals, credit balance) to Model Context Protocol clients, authenticated with the same API key and metered like the REST call each tool wraps.\n",
  "contact": {
   "name": "ScraperCompany Support",
   "url": "https://scrapercompany.com/contact"
  },
  "termsOfService": "https://scrapercompany.com/terms"
 },
 "servers": [
  {
   "url": "https://api.scrapercompany.com",
   "description": "Production"
  }
 ],
 "security": [
  {
   "ApiKeyAuth": []
  },
  {
   "BearerAuth": []
  },
  {
   "ApiKeyQuery": []
  }
 ],
 "tags": [
  {
   "name": "Discovery",
   "description": "Start here. Turn a hotel name into the property token every Google endpoint keys off."
  },
  {
   "name": "Google News",
   "description": "Google's own RSS wire: keyword search and section headlines, newest first, one page of up to 100 stories per call."
  },
  {
   "name": "Indeed",
   "description": "Indeed job search over plain HTTP: the embedded job-cards model with salary, posting age, company ratings and Indeed's own redirect links."
  },
  {
   "name": "Walmart",
   "description": "Walmart product search and reviews over plain HTTP: the store's own __NEXT_DATA__ JSON, no browser."
  },
  {
   "name": "Amazon",
   "description": "Amazon product search (without a browser; prices follow the local point-of-sale) and a product's ratings histogram with featured reviews."
  },
  {
   "name": "Google Shopping",
   "description": "Google Shopping cards rendered in a real browser: title, price, merchant, condition, and Google's data-pid per product."
  },
  {
   "name": "Google Jobs",
   "description": "Google Jobs listings rendered in a real browser: title, company, location, publisher, posting age, employment type and apply links per card."
  },
  {
   "name": "Google Maps",
   "description": "Places search and place detail from the maps RPC: name, address, coordinates, rating, phone, website, category, and the review count on detail."
  },
  {
   "name": "Google Trends",
   "description": "Interest over time and related queries from Google's explore API: 0-100 relative values and rising queries with growth percentages."
  },
  {
   "name": "Google Search",
   "description": "Google's web results with People Also Ask and the AI Overview, rendered in a real browser (Google serves a JS shell to plain HTTP)."
  },
  {
   "name": "Bing",
   "description": "Bing organic web search over plain HTTP: title, destination URL, display URL and snippet per result, with Bing's related-search suggestions."
  },
  {
   "name": "Google Hotels",
   "description": "Google Hotels' destination search, property page and price calendar. `/v1/hotels/search` lists a destination's hotels with prices; `/v1/calendar` is the cheap one — a whole horizon in a single ~30 KB call; `/v1/offers` is per-OTA detail for one night."
  },
  {
   "name": "Jobs",
   "description": "Durable asynchronous calendar batches. Submit up to 50 properties with an Idempotency-Key, poll per-item status, and optionally receive a signed completion webhook."
  },
  {
   "name": "Booking.com",
   "description": "Resolve a hotel name to its Booking.com URL slug, then query Booking.com's own inventory. The calendar returns 61 priced dates for ~5.5 KB; rooms come from the property page's room grid."
  },
  {
   "name": "Hotels.com",
   "description": "Resolve a hotel name to its numeric Hotels.com property id, then query Expedia Group inventory. No calendar exists here, so it is one call per date. Prices are NOT comparable across points-of-sale."
  },
  {
   "name": "Expedia",
   "description": "Resolve a hotel name to its numeric Expedia property id, then query Expedia's own rooms and rate plans for one stay. The point-of-sale (`market`, US or CA) decides the currency."
  },
  {
   "name": "Vrbo",
   "description": "Search vacation rentals by destination and dates, then quote one rental's stay: nightly price, total, whether fees are included and the payment model."
  },
  {
   "name": "Agoda",
   "description": "Resolve a hotel name to its Agoda property id, then query Agoda's own rooms and rate plans. Its 23 currencies are genuine conversions of one rate."
  },
  {
   "name": "Tripadvisor",
   "description": "Metasearch prices from Booking.com, Hotels.com, Expedia and others for one stay window, by Tripadvisor locationId. Name search is not available yet: take the locationId from the hotel's Tripadvisor URL."
  },
  {
   "name": "Hostelworld",
   "description": "Query Hostelworld's own rooms and rate plans using numeric property ids. Returns per-bed pricing for dorms and per-room pricing for privates. Currency is property-specific (not selectable)."
  },
  {
   "name": "Airbnb",
   "description": "Destination and map-area vacation-rental search in SearchAPI's `engine=airbnb` parameter and response shape. One guest page returns listing ids, prices, breakdowns, ratings, coordinates, images and cursor pagination. `/v1/airbnb/calendar` adds a day-by-day availability calendar with Airbnb's own quoted nightly prices."
  },
  {
   "name": "Cross-source",
   "description": "Queries that span providers — rate parity, and the capability matrix describing what each source can do."
  },
  {
   "name": "Official site",
   "description": "The rate the hotel sells at itself, through whichever of 31 booking engines it runs, detected automatically."
  },
  {
   "name": "SearchAPI compatibility",
   "description": "Drop-in shapes for callers already written against SearchAPI's Google Hotels and Google Flights engines (Google Flights follows SerpApi's `departure_token` / `booking_token` flow) — repointing is a base-URL change."
  },
  {
   "name": "Stored rates",
   "description": "Fast reads over the latest stored, normalized rates. These endpoints never collect live from an upstream source."
  },
  {
   "name": "Usage",
   "description": "Customer-scoped request history and aggregate usage. Every result is isolated to the authenticated API key; credentials and response bodies are never stored."
  },
  {
   "name": "Billing",
   "description": "Your plan, credit balance and credit ledger, and the plan catalogue with the cost of every operation. Metered responses carry `x-credits-charged` and `x-credits-remaining`; failed or empty results are free."
  }
 ],
 "paths": {
  "/v1/markets": {
   "get": {
    "tags": [
     "Discovery"
    ],
    "summary": "List configured markets",
    "description": "Credits: 0 (failed requests are free)",
    "operationId": "list_markets",
    "x-credits": 0,
    "responses": {
     "200": {
      "description": "Configured markets, each with its verified currency, gl and default tax basis",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/MarketsResponse"
        },
        "example": {
         "markets": [
          {
           "code": "US",
           "currency": "USD",
           "label": "United States",
           "rates_include_tax": false
          },
          {
           "code": "CA",
           "currency": "CAD",
           "label": "Canada",
           "rates_include_tax": false
          },
          {
           "code": "MX",
           "currency": "MXN",
           "label": "Mexico",
           "rates_include_tax": false
          }
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     }
    }
   }
  },
  "/v1/search": {
   "post": {
    "tags": [
     "Discovery"
    ],
    "summary": "Find a property token by name",
    "description": "Resolve a hotel name to candidate property tokens.\n\nVerification is on by default: each candidate is checked with a calendar lookup (slower, but no extra credits; a search costs 1 credit).\nThat is the right default for onboarding: a wrong token yields rates that\nare entirely plausible and belong to a different hotel. Turn it off only\nwhen a human is going to confirm the choice anyway.\n\nNot a hot path — tokens are stable, so resolve once and store the result.\nGoogle rate-limits search more aggressively than the calendar.\n\nCredits: 1 (failed requests are free)",
    "operationId": "search_properties",
    "x-credits": 1,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/SearchRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Candidate properties, best match first",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/SearchResponse"
        },
        "example": {
         "query": "Blue Horizons Garden Resort St George's",
         "gl": "us",
         "requested_market": "GD",
         "attempted_markets": [
          "GD",
          "US"
         ],
         "matched_market": "US",
         "market_fallback_used": true,
         "search_status": "matched",
         "external_fallback_recommended": false,
         "matches": [
          {
           "token": "ChcI7LnnsZLasKYOGgsvZy8xdHJzejFiORAB",
           "rank": 0,
           "verified": true,
           "name": "Blue Horizons Garden Resort",
           "name_score": 1.0
          }
         ]
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/rates/stored": {
   "get": {
    "tags": [
     "Stored rates"
    ],
    "summary": "Read current stored rates without scraping",
    "description": "Stored-rate lookup with explicit freshness metadata.\n\nCredits: 0 (failed requests are free)",
    "operationId": "stored_rates",
    "x-credits": 0,
    "parameters": [
     {
      "name": "token",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string",
       "minLength": 8,
       "description": "Google property token whose rates have already been collected into stored rates (for example by a `POST /v1/jobs` batch).",
       "title": "Token"
      },
      "description": "Google property token whose rates have already been collected into stored rates (for example by a `POST /v1/jobs` batch)."
     },
     {
      "name": "start",
      "in": "query",
      "required": false,
      "schema": {
       "anyOf": [
        {
         "type": "string",
         "format": "date"
        },
        {
         "type": "null"
        }
       ],
       "description": "Inclusive first stay date.",
       "title": "Start"
      },
      "description": "Inclusive first stay date."
     },
     {
      "name": "end",
      "in": "query",
      "required": false,
      "schema": {
       "anyOf": [
        {
         "type": "string",
         "format": "date"
        },
        {
         "type": "null"
        }
       ],
       "description": "Inclusive last stay date.",
       "title": "End"
      },
      "description": "Inclusive last stay date."
     },
     {
      "name": "limit",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "maximum": 2000,
       "minimum": 1,
       "default": 500,
       "title": "Limit"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Latest stored rates; this endpoint performs no live collection",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/StoredRatesResponse"
        },
        "example": {
         "source": "google_hotels",
         "source_property_id": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
         "count": 1,
         "last_observed_at": "2026-08-07 03:08:24.123+00",
         "last_success_at": "2026-08-07 03:08:25.456+00",
         "age_seconds": 42,
         "freshness": "fresh",
         "rates": [
          {
           "property_name": "Hilton Chicago",
           "stay_date": "2028-12-30",
           "occupancy_key": "adults=2",
           "los": 1,
           "rate": 332.01,
           "rate_base": 307.01,
           "rate_before_taxes_with_fees": 332.01,
           "rate_total": 399.48,
           "tax": 67.47,
           "fees": 25.0,
           "currency": "USD",
           "market": "US",
           "rates_include_tax": false,
           "observed_at": "2026-08-07 03:08:24.123+00",
           "last_changed_at": "2026-08-07 03:08:24.123+00",
           "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
           "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
           "provenance": {
            "schema_version": 1,
            "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
            "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
            "observed_at": "2026-08-07T01:23:45.678Z",
            "source": "google_hotels_calendar",
            "source_kind": "calendar",
            "collector": "scrapingme.google_calendar",
            "source_property_id": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
            "requested_market": "US",
            "requested_currency": "USD",
            "returned_currency": "USD",
            "egress_mode": "direct",
            "price_basis": "room_base_before_taxes_and_fees",
            "derivation": "normalized_upstream"
           }
          }
         ]
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "422": {
      "$ref": "#/components/responses/ValidationError"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/storage/status": {
   "get": {
    "tags": [
     "Stored rates"
    ],
    "summary": "Inspect stored-rates service status",
    "description": "Operational status and record counts for the stored-rates service.\n\nCredits: 0 (failed requests are free)",
    "operationId": "storage_status",
    "x-credits": 0,
    "responses": {
     "200": {
      "description": "Stored-rates service status and record counts",
      "content": {
       "application/json": {
        "schema": {},
        "example": {
         "database": {
          "tables": {
           "properties": 4,
           "property_source_identifiers": 4,
           "scrape_runs": 3,
           "rate_current": 51,
           "rate_history": 76,
           "refresh_jobs": 8,
           "refresh_job_items": 12,
           "request_history": 1842
          },
          "latest_run": {
           "run_id": "scraperun_0123456789abcdef0123456789abcdef",
           "status": "succeeded",
           "rows_written": 51,
           "rows_changed": 6,
           "rows_removed": 1,
           "finished_at": "2026-08-07 03:08:25.456+00"
          }
         },
         "r2_configured": true,
         "shared_cache_configured": true,
         "worker_archiving_enabled": true,
         "worker_persistence_enabled": true
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/usage": {
   "get": {
    "tags": [
     "Usage"
    ],
    "summary": "Read this API key's usage",
    "description": "Request counts, errors, bytes, and latency for the calling key only.\n\nCredits: 0 (failed requests are free)",
    "operationId": "customer_usage",
    "x-credits": 0,
    "parameters": [
     {
      "name": "period",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "pattern": "^(24h|7d|30d|90d)$",
       "description": "Aggregation window: 24 hours, 7, 30, or 90 days.",
       "default": "30d",
       "title": "Period"
      },
      "description": "Aggregation window: 24 hours, 7, 30, or 90 days."
     }
    ],
    "responses": {
     "200": {
      "description": "Customer-scoped request volume, error rate, bytes, and latency",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/UsageResponse"
        },
        "example": {
         "key": {
          "name": "example-production",
          "prefix": "sk_example1",
          "rate_limit_per_min": 600,
          "role": "customer"
         },
         "period": {
          "name": "30d",
          "start": "2026-07-11T19:00:00+00:00",
          "end": "2026-08-10T19:00:00+00:00"
         },
         "totals": {
          "requests": 1842,
          "successful": 1804,
          "errors": 38,
          "rate_limited": 2,
          "response_bytes": 18742311,
          "avg_duration_ms": 482,
          "p95_duration_ms": 2210
         },
         "by_status": [
          {
           "status": 200,
           "requests": 1804
          },
          {
           "status": 422,
           "requests": 36
          },
          {
           "status": 429,
           "requests": 2
          }
         ],
         "by_endpoint": [
          {
           "method": "POST",
           "path": "/v1/calendar",
           "requests": 1290,
           "errors": 12,
           "avg_duration_ms": 391,
           "p95_duration_ms": 884
          }
         ],
         "by_day": [
          {
           "date": "2029-01-01",
           "requests": 74,
           "errors": 1,
           "response_bytes": 812204
          }
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "422": {
      "$ref": "#/components/responses/ValidationError"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/requests": {
   "get": {
    "tags": [
     "Usage"
    ],
    "summary": "List this API key's request history",
    "description": "Newest-first metadata with keyset pagination and optional filters.\n\nCredits: 0 (failed requests are free)",
    "operationId": "customer_request_history",
    "x-credits": 0,
    "parameters": [
     {
      "name": "limit",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "maximum": 200,
       "minimum": 1,
       "default": 50,
       "title": "Limit"
      }
     },
     {
      "name": "cursor",
      "in": "query",
      "required": false,
      "schema": {
       "anyOf": [
        {
         "type": "string"
        },
        {
         "type": "null"
        }
       ],
       "description": "Opaque `next_cursor` from the previous page.",
       "title": "Cursor"
      },
      "description": "Opaque `next_cursor` from the previous page."
     },
     {
      "name": "status",
      "in": "query",
      "required": false,
      "schema": {
       "anyOf": [
        {
         "type": "integer",
         "maximum": 599,
         "minimum": 100
        },
        {
         "type": "null"
        }
       ],
       "title": "Status"
      }
     },
     {
      "name": "method",
      "in": "query",
      "required": false,
      "schema": {
       "anyOf": [
        {
         "type": "string",
         "pattern": "^(GET|POST|PUT|PATCH|DELETE)$"
        },
        {
         "type": "null"
        }
       ],
       "title": "Method"
      }
     },
     {
      "name": "path",
      "in": "query",
      "required": false,
      "schema": {
       "anyOf": [
        {
         "type": "string",
         "maxLength": 300
        },
        {
         "type": "null"
        }
       ],
       "description": "Exact normalized route path, such as `/v1/calendar`.",
       "title": "Path"
      },
      "description": "Exact normalized route path, such as `/v1/calendar`."
     }
    ],
    "responses": {
     "200": {
      "description": "Newest-first request metadata for the authenticated API key",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/RequestHistoryResponse"
        },
        "example": {
         "requests": [
          {
           "id": "req_0123456789abcdef0123456789abcdef",
           "method": "POST",
           "path": "/v1/calendar",
           "status": 200,
           "duration_ms": 391,
           "response_bytes": 18342,
           "request": {
            "body": {
             "token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
             "market": "US",
             "currency": "USD",
             "days": 90
            }
           },
           "created_at": "2026-08-10 18:51:06.724001+00"
          }
         ],
         "count": 1,
         "has_more": true,
         "next_cursor": "WyIyMDI2LTA4LTEwIDE4OjUxOjA2LjcyNDAwMSswMCIsInJlcV8wMTIzIl0"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "422": {
      "$ref": "#/components/responses/ValidationError"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/requests/{request_id}": {
   "get": {
    "tags": [
     "Usage"
    ],
    "summary": "Read one request-history record",
    "description": "Return 404 for missing records and records owned by another key.\n\nCredits: 0 (failed requests are free)",
    "operationId": "customer_request_detail",
    "x-credits": 0,
    "parameters": [
     {
      "name": "request_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string",
       "title": "Request Id"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "One request record; records belonging to another API key return 404",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/RequestRecord"
        },
        "example": {
         "id": "req_0123456789abcdef0123456789abcdef",
         "method": "GET",
         "path": "/v1/rates/stored",
         "status": 200,
         "duration_ms": 46,
         "response_bytes": 9271,
         "request": {
          "query": {
           "token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
           "start": "2029-01-02",
           "end": "2029-02-01"
          }
         },
         "created_at": "2026-08-10 18:52:11.104922+00"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/ValidationError"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/jobs": {
   "post": {
    "tags": [
     "Jobs"
    ],
    "summary": "Submit a durable calendar batch",
    "description": "Persist before returning 202; execution can survive API restarts.\n\nCredits: each succeeded item is priced like POST /v1/calendar, surcharges included (5 for a default item); failed items are free",
    "operationId": "submit_calendar_job",
    "x-credits": 5,
    "x-credits-variable": true,
    "parameters": [
     {
      "name": "Idempotency-Key",
      "in": "header",
      "required": true,
      "schema": {
       "type": "string",
       "minLength": 1,
       "maxLength": 200,
       "description": "Unique per logical submission. Reusing it with the same body returns the original job; a different body is 409.",
       "title": "Idempotency-Key"
      },
      "description": "Unique per logical submission. Reusing it with the same body returns the original job; a different body is 409."
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CalendarJobRequest"
       }
      }
     }
    },
    "responses": {
     "202": {
      "description": "Durably queued; poll the returned URL for progress",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/CalendarJob"
        },
        "example": {
         "id": "refreshjob_0123456789abcdef0123456789abcdef",
         "job_id": "refreshjob_0123456789abcdef0123456789abcdef",
         "poll_url": "/v1/jobs/refreshjob_0123456789abcdef0123456789abcdef",
         "status": "queued",
         "priority": 5,
         "callback_url": "https://example.com/webhooks/scrapercompany",
         "callback_status": "pending",
         "callback_attempts": 0,
         "result_summary": {},
         "items_total": 1,
         "items_succeeded": 0,
         "items_failed": 0,
         "created_at": "2026-08-10T14:05:00Z",
         "updated_at": "2026-08-10T14:05:00Z",
         "items": [
          {
           "id": "refreshitem_0123456789abcdef0123456789abcdef",
           "item_index": 0,
           "token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
           "label": "Boston Marriott Copley Place",
           "status": "queued",
           "request": {
            "token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
            "label": "Boston Marriott Copley Place",
            "market": "US",
            "currency": "USD",
            "days": 90,
            "adults": 2,
            "los": 1,
            "basis": "cheapest",
            "is_hostel": false,
            "probe_min_stay": true,
            "verify_sources": 0
           },
           "attempts": 0,
           "updated_at": "2026-08-10T14:05:00Z"
          }
         ]
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     },
     "422": {
      "$ref": "#/components/responses/ValidationError"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/jobs/{job_id}": {
   "get": {
    "tags": [
     "Jobs"
    ],
    "summary": "Poll a calendar batch and its per-item status",
    "description": "Credits: 0 (failed requests are free)",
    "operationId": "get_calendar_job",
    "x-credits": 0,
    "parameters": [
     {
      "name": "job_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string",
       "title": "Job Id"
      }
     },
     {
      "name": "include_results",
      "in": "query",
      "required": false,
      "schema": {
       "type": "boolean",
       "description": "Include each completed calendar payload. Leave false for a small status-only response.",
       "default": false,
       "title": "Include Results"
      },
      "description": "Include each completed calendar payload. Leave false for a small status-only response."
     }
    ],
    "responses": {
     "200": {
      "description": "Current job and per-property progress",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/CalendarJob"
        },
        "example": {
         "id": "refreshjob_0123456789abcdef0123456789abcdef",
         "job_id": "refreshjob_0123456789abcdef0123456789abcdef",
         "poll_url": "/v1/jobs/refreshjob_0123456789abcdef0123456789abcdef",
         "status": "succeeded",
         "priority": 5,
         "callback_url": "https://example.com/webhooks/scrapercompany",
         "callback_status": "delivered",
         "callback_attempts": 1,
         "artifact_uri": "r2://example-bucket/jobs/example.json.gz",
         "artifact_sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
         "result_summary": {
          "rates": 90,
          "wire_bytes": 29804,
          "database": {
           "run_id": "scraperun_0123456789abcdef",
           "rows_written": 90,
           "rows_changed": 82,
           "rows_removed": 1
          }
         },
         "items_total": 1,
         "items_succeeded": 1,
         "items_failed": 0,
         "created_at": "2026-08-10T14:05:00Z",
         "started_at": "2026-08-10T14:05:01Z",
         "finished_at": "2026-08-10T14:05:02Z",
         "updated_at": "2026-08-10T14:05:02Z",
         "items": [
          {
           "id": "refreshitem_0123456789abcdef0123456789abcdef",
           "item_index": 0,
           "token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
           "label": "Boston Marriott Copley Place",
           "status": "succeeded",
           "request": {
            "token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
            "label": "Boston Marriott Copley Place",
            "market": "US",
            "currency": "USD",
            "days": 90,
            "adults": 2,
            "los": 1,
            "basis": "cheapest",
            "is_hostel": false,
            "probe_min_stay": true,
            "verify_sources": 0
           },
           "attempts": 1,
           "started_at": "2026-08-10T14:05:01Z",
           "finished_at": "2026-08-10T14:05:02Z",
           "updated_at": "2026-08-10T14:05:02Z"
          }
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/ValidationError"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/calendar": {
   "post": {
    "tags": [
     "Google Hotels"
    ],
    "summary": "Price a forward horizon in one call",
    "description": "Forward horizon of nightly rates — the cheap bulk path.\n\nCredits: 5, plus 3 per night with `basis: mainstream` and 3 per `verify_sources` spot-check (failed requests are free)",
    "operationId": "google_calendar",
    "x-credits": 5,
    "x-credits-variable": true,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CalendarRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "One row per stay date. ~30 KB for a 90-night window",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/CalendarResponse"
        },
        "example": {
         "token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
         "market": "US",
         "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
         "observed_at": "2026-08-07T01:23:45.678Z",
         "requested_days": 90,
         "coverage": 0.9333,
         "wire_bytes": 29804,
         "elapsed_s": 0.31,
         "calendar_elapsed_s": 0.14,
         "unpriced_dates": [
          "2029-01-10"
         ],
         "validation": {
          "ok": true,
          "errors": [],
          "warnings": []
         },
         "tax_profile": {
          "rate": 0.2032,
          "confidence": "high",
          "itemised": 84,
          "derived": 0
         },
         "rates": [
          {
           "stay_date": "2028-12-26",
           "rate": 332.01,
           "rate_base": 332.01,
           "rate_total": 424.48,
           "tax": 67.47,
           "fees": 25.0,
           "currency": "USD",
           "market": "US",
           "rates_include_tax": false,
           "adults": 2,
           "los": 1,
           "implied_tax_rate": 0.203217,
           "provenance": {
            "schema_version": 1,
            "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
            "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
            "observed_at": "2026-08-07T01:23:45.678Z",
            "source": "google_hotels_calendar",
            "source_kind": "calendar",
            "collector": "scrapingme.google_calendar",
            "source_property_id": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
            "requested_market": "US",
            "requested_currency": "USD",
            "returned_currency": "USD",
            "egress_mode": "direct",
            "price_basis": "room_base_before_taxes_and_fees",
            "derivation": "normalized_upstream"
           }
          }
         ]
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/ValidationError"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/stay": {
   "post": {
    "tags": [
     "Google Hotels"
    ],
    "summary": "Price one explicit stay window",
    "description": "One explicit stay window. `rate` is the WHOLE-STAY figure — length of\nstay moves the nightly price, so dividing it out would misrepresent it.\n\nCredits: 3 (failed requests are free)",
    "operationId": "google_stay",
    "x-credits": 3,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/StayRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "One priced stay window, tax split out",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/StayResponse"
        },
        "example": {
         "nights": 3,
         "token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
         "rate": 2492.73,
         "rate_base": 2492.73,
         "rate_before_taxes_with_fees": 2567.73,
         "rate_total": 3053.03,
         "tax": 485.3,
         "fees": 75,
         "currency": "USD",
         "market": "US",
         "rates_include_tax": false,
         "adults": 2,
         "los": 3,
         "stay_date": "2029-02-05",
         "implied_tax_rate": 0.1947,
         "provenance": {
          "schema_version": 1,
          "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
          "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
          "observed_at": "2026-08-07T01:23:45.678Z",
          "source": "google_hotels_calendar",
          "source_kind": "calendar",
          "collector": "scrapingme.google_calendar",
          "source_property_id": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
          "requested_market": "US",
          "requested_currency": "USD",
          "returned_currency": "USD",
          "egress_mode": "direct",
          "price_basis": "room_base_before_taxes_and_fees",
          "derivation": "normalized_upstream"
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/ValidationError"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/offers": {
   "post": {
    "tags": [
     "Google Hotels"
    ],
    "summary": "Per-OTA offers for one night",
    "description": "Per-OTA breakdown for one night. Heavier than /v1/calendar (~365 KB on\nthe wire vs ~30 KB), so use it for the dates that matter, not all of them.\n\nCredits: 3 (failed requests are free)",
    "operationId": "google_offers",
    "x-credits": 3,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/OffersRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Every OTA on the property for one night, with per-room detail",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/OffersResponse"
        },
        "example": {
         "token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
         "check_in": "2029-02-05",
         "check_out": "2029-02-06",
         "nights": 1,
         "adults": 2,
         "device": "iphone",
         "coverage": 2,
         "currency": "USD",
         "currency_matches_request": true,
         "rates_include_tax": false,
         "requested_market": "US",
         "egress_market": "US",
         "egress_geo_locked_ok": true,
         "price_insights_market_verified": true,
         "lowest_price_per_night": 303.67,
         "rooms_total": 173,
         "name": "Hilton Chicago",
         "hotel_class": "4-star hotel",
         "hotel_class_stars": 4,
         "rating": 4.3,
         "reviews": 10686,
         "deal": "25% less than usual",
         "has_deal": true,
         "deal_description": "Great Deal",
         "price_insights": {
          "lowest_price": "$304",
          "price_level": "typical",
          "typical_price_range": {
           "low_price": "$304",
           "high_price": "$521"
          }
         },
         "sources": [
          "Official site",
          "Booking.com",
          "Expedia",
          "Hotels.com"
         ],
         "missing_sources": [],
         "refundable_offers": 2,
         "wire_bytes": 4381263,
         "elapsed_s": 1.14,
         "warnings": [],
         "offers": [
          {
           "source": "Official site",
           "raw_source": "Hilton Chicago",
           "is_official": true,
           "nights": 1,
           "currency": "USD",
           "price_per_night": 499.44,
           "price_per_night_before_taxes": 420.05,
           "tax": 79.39,
           "total": 499.44,
           "has_free_cancellation": true,
           "free_cancellation_until": "2029-02-01",
           "free_cancellation_time": "23:59",
           "room_id": "rate-plan-42",
           "provenance": {
            "schema_version": 1,
            "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
            "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
            "observed_at": "2026-08-07T01:23:45.678Z",
            "source": "google_hotels_property_offers",
            "source_kind": "offer",
            "collector": "scrapingme.google_property",
            "source_property_id": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
            "requested_market": "US",
            "requested_currency": "USD",
            "returned_currency": "USD",
            "egress_mode": "market_proxy",
            "price_basis": "room_base_before_taxes_and_fees",
            "derivation": "normalized_upstream"
           },
           "rooms": [
            {
             "name": "1 KING BED",
             "description": "1 bed",
             "beds": 1,
             "is_suite": false,
             "price_before_taxes": 420.06,
             "price_total": 499.45,
             "has_free_cancellation": true,
             "free_cancellation_until": "2029-02-01",
             "free_cancellation_time": "23:59",
             "link": "https://www.google.com/aclk?...",
             "thumbnail": "https://lh3.googleusercontent.com/..."
            }
           ]
          }
         ]
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/ValidationError"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/rooms": {
   "post": {
    "tags": [
     "Google Hotels"
    ],
    "summary": "Room types by OTA, aligned on one signature",
    "description": "Room types by OTA, aligned onto a comparable signature.\n\nEach OTA names the same room its own way — on one property the official\nsite and Expedia shared **zero** names verbatim — so a pivot on the raw\nname shows every row filled by one source. Rows here are keyed on a\nnormalised signature and every cell keeps the source's own wording.\n\nRoom detail rides on Google's featured-offer blocks, which the thin\nvariant of the page omits entirely. A source with `rooms: 0` means this\nrender carried none for it, NOT that the OTA has no inventory.\n\nCredits: 3 (failed requests are free)",
    "operationId": "google_room_matrix",
    "x-credits": 3,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/RoomMatrixRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Room signature x source. An empty cell means the render carried no detail for that source, NOT that the room is unavailable",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/RoomMatrixResponse"
        },
        "example": {
         "search_parameters": {
          "engine": "google_hotels_rooms",
          "token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
          "check_in_date": "2029-02-05",
          "check_out_date": "2029-02-06",
          "adults": 2,
          "currency": "USD",
          "sources": [
           "Official site",
           "Booking.com",
           "Hotels.com",
           "Expedia"
          ]
         },
         "property": {
          "name": "Hilton Chicago",
          "currency": "USD",
          "currency_matches_request": true,
          "requested_market": "US",
          "egress_market": "US",
          "egress_geo_locked_ok": true
         },
         "render": {
          "wire_bytes": 4416000,
          "carried_room_detail": true
         },
         "sources": [
          {
           "source": "Official site",
           "rooms": 23,
           "cheapest": 420.06,
           "dearest": 527.98,
           "currency": "USD",
           "is_official": true
          },
          {
           "source": "Hotels.com",
           "rooms": 28,
           "cheapest": 419.51,
           "dearest": 1974.23,
           "currency": "USD",
           "is_official": false,
           "duplicate_of": "Expedia"
          }
         ],
         "rows": [
          {
           "signature": "1 king",
           "cells": {
            "Official site": {
             "name": "1 KING BED",
             "price": 420.06,
             "total": 499.45
            },
            "Expedia": {
             "name": "Room, 1 King Bed",
             "price": 419.51,
             "total": 498.79
            }
           }
          }
         ],
         "totals": {
          "sources_present": 4,
          "sources_with_rooms": 3,
          "distinct_signatures": 32
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/ValidationError"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/news": {
   "post": {
    "tags": [
     "Google News"
    ],
    "summary": "Google News results or section headlines",
    "description": "One page (up to 100) of Google News results.\n\nThis is Google's own published RSS wire — the same feed reader apps\nconsume — so it carries the feed's semantics: newest first, one page per\nrequest, a `when:` freshness operator instead of a date range, and\n`link` values that are Google's canonical redirects to the publisher.\n`q` searches; `topic` reads a section feed; with neither the edition's\ntop stories answer.\n\nCredits: 1 (failed requests are free)",
    "operationId": "google_news",
    "x-credits": 1,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/GoogleNewsRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "One page of Google News results with the publisher of each story",
      "content": {
       "application/json": {
        "schema": {},
        "example": {
         "search_parameters": {
          "engine": "google_news",
          "q": "Hilton Chicago",
          "gl": "US",
          "hl": "en"
         },
         "news_results": [
          {
           "position": 1,
           "title": "Sleep in history: Inside Hilton Chicago, the city's grandest hotel",
           "link": "https://news.google.com/rss/articles/CBMigAFBVV95cUxOTFVQSS1SaXdVWjNMdUR6WWk1SUk5LTdFSm44bW1xOEtTMko3bDJ0ZlBfaEY0eUlSWGZUV2tOTUZxWmU5Rzg2RVRRQ2RzR243UnJ4UEwwMFR5MzRiSEtnOEFWa2I0M0ZoU1lzYlpBNVhWRHl2d2JqanZrM2xsRkNxag?oc=5",
           "story_token": "CBMigAFBVV95cUxOTFVQSS1SaXdVWjNMdUR6WWk1SUk5LTdFSm44bW1xOEtTMko3bDJ0ZlBfaEY0eUlSWGZUV2tOTUZxWmU5Rzg2RVRRQ2RzR243UnJ4UEwwMFR5MzRiSEtnOEFWa2I0M0ZoU1lzYlpBNVhWRHl2d2JqanZrM2xsRkNxag",
           "published": "2025-10-31T07:00:00Z",
           "source": {
            "name": "Time Out Worldwide",
            "url": "https://www.timeout.com"
           }
          },
          {
           "position": 2,
           "title": "Second story title from the same feed",
           "link": "https://news.google.com/rss/articles/CBMiWhFDQUlRQUNvZENodHljRjlvT25SZmJHOVBVMHh0VTJkSlNsa3lMVmMxZVMxMWVtYxAB?oc=5",
           "story_token": "CBMiWhFDQUlRQUNvZENodHljRjlvT25SZmJHOVBVMHh0VTJkSlNsa3lMVmMxZVMxMWVtYxAB",
           "published": "2026-09-28T22:45:10Z",
           "source": {
            "name": "Chicago Tribune",
            "url": "https://www.chicagotribune.com"
           }
          }
         ],
         "total": 2,
         "meta": {
          "source": "google_news",
          "wire_bytes": 8678,
          "elapsed_s": 0.412,
          "egress_mode": "direct"
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/bing/search": {
   "post": {
    "tags": [
     "Bing"
    ],
    "summary": "Bing organic web search over plain HTTP",
    "description": "One page of Bing organic results, up to 35 per request.\n\nBing answers plain HTTP with no JS and no tokens. Each result keeps the\ntitle, the destination URL (Bing's click tracker is decoded back to the\ndestination; an undecodable tracker is returned as-is rather than\ndropped), the display URL and the snippet. `related_searches` carries\nBing's own refinement suggestions when the page shows them.\n\nCredits: 1 (failed requests are free)",
    "operationId": "bing_search",
    "x-credits": 1,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/BingSearchRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "One page of Bing organic results with the trackers decoded",
      "content": {
       "application/json": {
        "schema": {},
        "example": {
         "search_parameters": {
          "engine": "bing_search",
          "q": "Hilton Chicago",
          "first": 1
         },
         "organic_results": [
          {
           "position": 1,
           "title": "Hotels by Hilton - Book the Best Rates Across All Brands",
           "url": "https://www.hilton.com/en/",
           "snippet": "Explore Hilton's portfolio of hotels and distinct brands across the globe. Book directly for the best rates during your next stay. Expect …",
           "display_url": "https://www.hilton.com"
          },
          {
           "position": 2,
           "title": "Hilton Chicago, IL - Hotel Overview, Reviews & Rates",
           "url": "https://www.hilton.com/en/hotels/chichhx-hilton-chicago/",
           "snippet": "Stay at Hilton Chicago, a landmark hotel on Michigan Avenue with direct access to McCormick Place…",
           "display_url": "https://www.hilton.com › en › hotels"
          }
         ],
         "related_searches": [
          {
           "query": "hilton chicago magnificent mile",
           "link": "/search?q=hilton+chicago+magnificent+mile"
          }
         ],
         "total": 2,
         "meta": {
          "source": "bing_search",
          "wire_bytes": 19420,
          "elapsed_s": 0.388,
          "egress_mode": "direct"
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/google/search": {
   "post": {
    "tags": [
     "Google Search"
    ],
    "summary": "Google organic results with PAA and AI overview",
    "description": "One rendered page of Google web results.\n\nGoogle serves a JavaScript shell to plain HTTP, so this renders the page\nin a real browser — seconds per call, the honest cost of the flagship.\nThe answer carries the organic list, the People Also Ask questions (the\nquestions only: answers load on expansion and are not in the DOM), the\nAI Overview text when Google generates one, and related searches.\n`link` is Google's `/goto` redirect unless `resolve=true`, which follows\neach one (one HTTP request per result).\n\nCredits: 5 (failed requests are free)",
    "operationId": "google_search",
    "x-credits": 5,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/GoogleSearchRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "One rendered page of Google organic results with PAA and AI overview",
      "content": {
       "application/json": {
        "schema": {},
        "example": {
         "search_parameters": {
          "engine": "google_search",
          "q": "best time to visit japan",
          "page": 1
         },
         "organic_results": [
          {
           "position": 1,
           "title": "Best Time to Visit Japan: Seasons, Months, Weather & Events",
           "link": "https://www.google.com/goto?url=CAESeQHrOzAVJE8lGsYKYT",
           "display_url": "https://en.japantravel.com › Culture",
           "snippet": "Mar 25, 2026 — If we're going by popular opinion, spring (March to May) is the best time to visit Japan…"
          },
          {
           "position": 2,
           "title": "The Best Time to Visit Japan",
           "link": "https://www.google.com/goto?url=CAESdAHrOzAVksx1otYJyS",
           "display_url": "https://www.japan-guide.com › travel-essentials",
           "snippet": "The best time to visit Japan is in spring (March to May) for cherry blossoms, or autumn (October to November) for foliage…"
          }
         ],
         "people_also_ask": [
          "Is $5000 enough for a week in Japan?",
          "What is the cheapest month to go to Japan?",
          "What month is best for cherry blossoms in Japan?",
          "What is Japan's rainy season?"
         ],
         "related_searches": [],
         "ai_overview": "Spring: Cherry Blossoms (March – May)\nHighlights: Mild temperatures (45–70°F) and famous cherry blossoms (sakura) peaking in late March to early April.\nDrawbacks: Extremely crowded and expensive.",
         "ai_overview_sources": [],
         "total": 2,
         "meta": {
          "source": "google_search",
          "wire_bytes": 662725,
          "elapsed_s": 8.2,
          "rendered": true
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/trends/interest": {
   "post": {
    "tags": [
     "Google Trends"
    ],
    "summary": "Interest over time for a keyword",
    "description": "Google Trends interest over time, one 0-100 timeline.\n\nValues are relative to the keyword's own peak in the window (100 =\nbusiest point) — not absolute volume, exactly as Google's charts state.\n`time_range` uses Google's own grammar.\n\nCredits: 1 (failed requests are free)",
    "operationId": "google_trends_interest",
    "x-credits": 1,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/TrendsInterestRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Interest over time: 0-100 relative to the keyword's own peak",
      "content": {
       "application/json": {
        "schema": {},
        "example": {
         "search_parameters": {
          "engine": "google_trends_interest",
          "keyword": "Hilton",
          "geo": "US",
          "time_range": "today 1-m"
         },
         "series": [
          {
           "points": [
            {
             "date": "2029-01-23",
             "value": 41
            },
            {
             "date": "2029-01-24",
             "value": 38
            },
            {
             "date": "2029-01-25",
             "value": 47
            },
            {
             "date": "2029-01-26",
             "value": 52
            }
           ]
          }
         ],
         "total": 4,
         "meta": {
          "source": "google_trends",
          "wire_bytes": 8456,
          "elapsed_s": 0.612
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/trends/related": {
   "post": {
    "tags": [
     "Google Trends"
    ],
    "summary": "Related queries: top and rising",
    "description": "Google Trends related queries, split top and rising.\n\nTop values are 0-100 relative to the top query; rising values are\ngrowth percentages, and above 5000% Google answers \"Breakout\", carried\nas `breakout: true` with a null value.\n\nCredits: 1 (failed requests are free)",
    "operationId": "google_trends_related",
    "x-credits": 1,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/TrendsRelatedRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Related queries: top (0-100) and rising (growth %, or Breakout)",
      "content": {
       "application/json": {
        "schema": {},
        "example": {
         "search_parameters": {
          "engine": "google_trends_related",
          "keyword": "Hilton",
          "geo": "US",
          "time_range": "today 1-m"
         },
         "top": [
          {
           "query": "hilton honors",
           "kind": "top",
           "value": 100,
           "breakout": false
          },
          {
           "query": "hilton head",
           "kind": "top",
           "value": 87,
           "breakout": false
          }
         ],
         "rising": [
          {
           "query": "hilton giveaway 2026",
           "kind": "rising",
           "value": 300,
           "breakout": false
          },
          {
           "query": "hilton points exploit",
           "kind": "rising",
           "breakout": true
          }
         ],
         "meta": {
          "source": "google_trends",
          "wire_bytes": 6421,
          "elapsed_s": 0.538
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/maps/search": {
   "post": {
    "tags": [
     "Google Maps"
    ],
    "summary": "Places matching a Maps query",
    "description": "One page of Google Maps place cards.\n\n`q` is whatever the Maps search box takes — a business name, a\ncategory in a place, a landmark. Each card carries name, address,\ncoordinates, rating, phone, website, category and the `place_token`\nthe detail call keys off. The review count is only on the detail\nrecord.\n\nCredits: 3 (failed requests are free)",
    "operationId": "google_maps_search",
    "x-credits": 3,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/MapsSearchRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Places matching a Maps query, with tokens for the detail call",
      "content": {
       "application/json": {
        "schema": {},
        "example": {
         "search_parameters": {
          "engine": "google_maps_search",
          "q": "Hilton Chicago",
          "gl": "us",
          "hl": "en"
         },
         "places": [
          {
           "place_token": "0x880e2c99242c7a2f:0x4de3d4bb09dba1",
           "name": "Hilton Chicago",
           "address": "720 S Michigan Ave, Chicago, IL 60605",
           "gps_coordinates": {
            "latitude": 41.872259199999995,
            "longitude": -87.624696
           },
           "rating": 4.3,
           "phone": "(312) 922-4400",
           "website": "https://www.hilton.com/en/hotels/chichhh-hilton-chicago/",
           "category": "Hotel"
          },
          {
           "place_token": "0x880e2c99242c7a2f:0x31660dda0c86665",
           "name": "The Chicago Hotel Collection Wrigleyville",
           "address": "844 W Addison St, Chicago, IL 60613",
           "gps_coordinates": {
            "latitude": 41.945531,
            "longitude": -87.654866
           },
           "rating": 4.1,
           "phone": "(773) 525-4700",
           "website": "https://www.chicago-hotel-collection.com/",
           "category": "Hotel"
          }
         ],
         "total": 2,
         "meta": {
          "source": "google_maps",
          "wire_bytes": 270014,
          "elapsed_s": 0.712
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/maps/detail": {
   "post": {
    "tags": [
     "Google Maps"
    ],
    "summary": "One place's detail record",
    "description": "One place's detail card: the search fields plus the review count.\n\nToken and name come from the same `POST /v1/maps/search` row — the\ntoken pin answers only when the query names the same place.\n\nCredits: 3 (failed requests are free)",
    "operationId": "google_maps_detail",
    "x-credits": 3,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/MapsDetailRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "One place's detail record: the search fields plus the review count",
      "content": {
       "application/json": {
        "schema": {},
        "example": {
         "search_parameters": {
          "engine": "google_maps_detail",
          "place_token": "0x880e2c99242c7a2f:0x4de3d4bb09dba1",
          "name": "Hilton Chicago",
          "gl": "us",
          "hl": "en"
         },
         "place": {
          "place_token": "0x880e2c99242c7a2f:0x4de3d4bb09dba1",
          "name": "Hilton Chicago",
          "address": "720 S Michigan Ave, Chicago, IL 60605",
          "gps_coordinates": {
           "latitude": 41.872259199999995,
           "longitude": -87.624696
          },
          "rating": 4.3,
          "reviews": 10999,
          "phone": "(312) 922-4400",
          "website": "https://www.hilton.com/en/hotels/chichhh-hilton-chicago/",
          "category": "Hotel"
         },
         "meta": {
          "source": "google_maps",
          "wire_bytes": 310583,
          "elapsed_s": 0.664
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/jobs/search": {
   "post": {
    "tags": [
     "Google Jobs"
    ],
    "summary": "Google Jobs listings for a query",
    "description": "One rendered page of Google Jobs cards.\n\nGoogle serves a JavaScript shell to plain HTTP, so this renders the\njobs panel in a real browser — seconds per call. Each card carries the\ntitle, company, location, the upstream publisher (`via`), the relative\nposting age (Google publishes no absolute dates here), the employment\ntype, and the apply links with their sources.\n\nCredits: 3 (failed requests are free)",
    "operationId": "google_jobs_search",
    "x-credits": 3,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/GoogleJobsRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "One rendered page of Google Jobs cards with apply sources",
      "content": {
       "application/json": {
        "schema": {},
        "example": {
         "search_parameters": {
          "engine": "google_jobs",
          "q": "hotel jobs chicago"
         },
         "jobs_results": [
          {
           "title": "Housekeeping Supervisor - Part Time",
           "company": "Sonesta International Hotels",
           "location": "Chicago, IL, United States",
           "via": "LinkedIn",
           "posted": "1 day ago",
           "employment_type": "Part-time",
           "apply_options": [
            {
             "source": "LinkedIn",
             "link": "https://www.google.com/goto?url=CAES9wEB6zswFTBT"
            },
            {
             "source": "Indeed",
             "link": "https://www.google.com/goto?url=CAESugEB6zswFdeT"
            }
           ]
          },
          {
           "title": "Assistant Room Operations Manager- Housekeeping",
           "company": "Marriott",
           "location": "Chicago, IL, United States",
           "via": "Marriott Careers",
           "posted": "6 days ago",
           "employment_type": "Full-time",
           "apply_options": [
            {
             "source": "Marriott Careers",
             "link": "https://www.google.com/goto?url=CAESugEB6zswFxyz"
            }
           ]
          }
         ],
         "total": 2,
         "meta": {
          "source": "google_jobs",
          "wire_bytes": 474558,
          "elapsed_s": 9.8
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/shopping/search": {
   "post": {
    "tags": [
     "Google Shopping"
    ],
    "summary": "Google Shopping products for a query",
    "description": "One rendered page of Google Shopping cards (~10 per page).\n\nGoogle serves a JavaScript shell to plain HTTP, so this renders the\nshopping SERP in a real browser — seconds per call. Each card carries\nthe title, price, merchant and condition chips (\"Pre-owned\"), plus\nGoogle's `data-pid`. Google renders the same product more than once;\nthe answer dedupes by `data-pid`.\n\nCredits: 3 (failed requests are free)",
    "operationId": "google_shopping_search",
    "x-credits": 3,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/GoogleShoppingRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "One rendered page of Google Shopping cards",
      "content": {
       "application/json": {
        "schema": {},
        "example": {
         "search_parameters": {
          "engine": "google_shopping",
          "q": "hilton bathrobe"
         },
         "shopping_results": [
          {
           "title": "Paris Hilton Women Robe Blue Size S/m $92",
           "price": 39.0,
           "merchant": "eBay",
           "product_id": "15138752771170097272",
           "item_id": "1792340598104035252"
          },
          {
           "title": "Paris Hilton lounge robe",
           "price": 25.0,
           "merchant": "Whatnot",
           "product_id": "15138752771170097273",
           "item_id": "1792340598104035253"
          },
          {
           "title": "Paris Hilton One Size Fits Most White Polyester Bathrobe",
           "price": 15.0,
           "merchant": "eBay",
           "condition": "Pre-owned",
           "product_id": "15138752771170097274",
           "item_id": "1792340598104035254"
          }
         ],
         "total": 3,
         "meta": {
          "source": "google_shopping",
          "wire_bytes": 854947,
          "elapsed_s": 10.4
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/amazon/search": {
   "post": {
    "tags": [
     "Amazon"
    ],
    "summary": "Amazon product search over plain HTTP",
    "description": "One page (~48) of Amazon search results.\n\nOver plain HTTP. Prices follow the local point-of-sale — a\nCanadian exit answers CAD — so `price_text` keeps the display string\nverbatim and `currency` carries the best-effort guess from its symbol.\nSponsored rows come labelled in `sponsored` rather than dropped.\n\nCredits: 1 (failed requests are free)",
    "operationId": "amazon_search",
    "x-credits": 1,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/AmazonSearchRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "One page of Amazon search results (prices in the local point-of-sale)",
      "content": {
       "application/json": {
        "schema": {},
        "example": {
         "search_parameters": {
          "engine": "amazon_search",
          "q": "bathrobe"
         },
         "products": [
          {
           "asin": "B084PBWBJR",
           "title": "PAVILIA Premium Womens Plush Soft Robe, Fluffy Warm Fleece Sherpa Bathrobe",
           "price": 42.52,
           "price_text": "CAD 42.52",
           "currency": "CAD",
           "rating": 4.6,
           "ratings_count": 13206,
           "url": "https://www.amazon.com/dp/B084PBWBJR",
           "image": "https://m.media-amazon.com/images/I/61VOJmplqeL._AC_UL320_.jpg",
           "sponsored": false
          },
          {
           "asin": "B07FZSP1BR",
           "title": "Alexander Del Rossa Womens Robe, Long Fleece Bathrobe",
           "price": 55.0,
           "price_text": "CAD 55.00",
           "currency": "CAD",
           "rating": 4.7,
           "ratings_count": 8941,
           "url": "https://www.amazon.com/dp/B07FZSP1BR",
           "sponsored": true
          }
         ],
         "total": 2,
         "meta": {
          "source": "amazon_search",
          "wire_bytes": 110467,
          "elapsed_s": 1.212
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/amazon/reviews": {
   "post": {
    "tags": [
     "Amazon"
    ],
    "summary": "A product's histogram and featured reviews",
    "description": "A product's ratings histogram and featured reviews.\n\nThe `/product-reviews` list requires sign-in (measured: redirected to\nsign-in over plain HTTP and in a fresh browser), so the answer is the\nproduct page's own reviews widget, rendered in a real browser: the\n5→1 histogram, the global ratings count, and the featured reviews\n(title, rating, date, author, body, \"Verified Purchase\", helpful\nvotes).\n\nCredits: 2 (failed requests are free)",
    "operationId": "amazon_reviews",
    "x-credits": 2,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/AmazonReviewsRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "A product's ratings histogram and featured reviews",
      "content": {
       "application/json": {
        "schema": {},
        "example": {
         "search_parameters": {
          "engine": "amazon_reviews",
          "asin": "B084PBWBJR"
         },
         "total_ratings": 13206,
         "histogram": {
          "5": 78,
          "4": 11,
          "3": 6,
          "2": 2,
          "1": 3
         },
         "reviews": [
          {
           "source": "amazon",
           "rating": 5.0,
           "title": "Soft and comfy!!",
           "text": "Thick, soft, cozy, comfy, warm, good length, good quality, absorbent. Would purchase again.",
           "date": "2028-11-12",
           "author": "Ms. G.",
           "helpful_votes": 3,
           "labels": [
            "Verified Purchase"
           ]
          }
         ],
         "meta": {
          "source": "amazon",
          "wire_bytes": 54488,
          "elapsed_s": 8.9
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/walmart/search": {
   "post": {
    "tags": [
     "Walmart"
    ],
    "summary": "Walmart product search over plain HTTP",
    "description": "One page (~40) of Walmart search results.\n\nWalmart's own `__NEXT_DATA__` store over plain HTTP — no browser. Each\nitem carries name, brand, price with currency, rating, review count,\nand the item id the reviews call keys off. Sponsored items come\nlabelled in `sponsored` rather than dropped.\n\nCredits: 1 (failed requests are free)",
    "operationId": "walmart_search",
    "x-credits": 1,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/WalmartSearchRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "One page of Walmart search results from the store's own JSON",
      "content": {
       "application/json": {
        "schema": {},
        "example": {
         "search_parameters": {
          "engine": "walmart_search",
          "q": "bathrobe"
         },
         "products": [
          {
           "item_id": "5255687930",
           "name": "Black Womens Robe, Fleece Plush Soft Fluffy Bathrobe, S/M",
           "brand": "Pavilia",
           "price": 19.99,
           "currency": "USD",
           "rating": 4.4,
           "ratings_count": 2484,
           "url": "https://www.walmart.com/ip/PAVILIA-Black-Women-Robe-5255687930",
           "image": "https://i5.walmartimages.com/seo/PAVILIA-Black-Women-Robe_482875EB",
           "sponsored": false
          },
          {
           "item_id": "17299362344",
           "name": "Mainstays Fleece Bathrobe, Unisex, Adult",
           "brand": "Mainstays",
           "price": 16.98,
           "currency": "USD",
           "rating": 4.5,
           "ratings_count": 1290,
           "url": "https://www.walmart.com/ip/Mainstays-Fleece-Bathrobe-17299362344",
           "sponsored": true
          }
         ],
         "aggregated_count": 387,
         "total": 2,
         "meta": {
          "source": "walmart_search",
          "wire_bytes": 181760,
          "elapsed_s": 1.344
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/walmart/reviews": {
   "post": {
    "tags": [
     "Walmart"
    ],
    "summary": "One page of Walmart reviews with the summary",
    "description": "One page (10) of Walmart reviews for an item.\n\nPlain HTTP — no browser, no tokens. The answer carries the review\nlist (rating, title, text, date normalized from Walmart's M/D/YYYY,\nthe \"Verified Purchase\" badge) plus the summary: average, total,\nper-star counts and percentages, recommended percentage, and\nWalmart's own `next_page` url.\n\nCredits: 2 (failed requests are free)",
    "operationId": "walmart_reviews",
    "x-credits": 2,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/WalmartReviewsRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "One page of Walmart reviews with the ratings summary",
      "content": {
       "application/json": {
        "schema": {},
        "example": {
         "search_parameters": {
          "engine": "walmart_reviews",
          "item_id": "5255687930",
          "page": 1,
          "sort": "relevancy"
         },
         "total": 2484,
         "summary": {
          "average": 4.4,
          "total": 2484,
          "counts": {
           "1": 180,
           "2": 74,
           "3": 148,
           "4": 296,
           "5": 1786
          },
          "percentages": {
           "1": 8,
           "2": 3,
           "3": 6,
           "4": 11,
           "5": 72
          },
          "recommended_pct": 81
         },
         "reviews": [
          {
           "source": "walmart",
           "review_id": "20669430",
           "rating": 5.0,
           "title": "Comfortable Robe",
           "text": "This robe is absolutely beautiful and so comfortable.",
           "date": "2027-08-07",
           "author": "Rhoda",
           "labels": [
            "Verified Purchase"
           ]
          }
         ],
         "next_page": "sort=relevancy&page=2",
         "meta": {
          "source": "walmart",
          "wire_bytes": 27192,
          "elapsed_s": 1.102
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/indeed/jobs": {
   "post": {
    "tags": [
     "Indeed"
    ],
    "summary": "Indeed job search over plain HTTP",
    "description": "One page (~45) of Indeed job records.\n\nIndeed answers plain HTTP with its own embedded job-cards model — no\nbrowser, no tokens. Each record carries the jobkey, title, company,\nlocation, salary (verbatim text plus Indeed's extracted min/max and\nperiod), the relative posting age, the creation date from Indeed's\nepoch, the company's rating, and Indeed's own redirect link.\nSponsored rows come labelled, not dropped.\n\nCredits: 1 (failed requests are free)",
    "operationId": "indeed_jobs",
    "x-credits": 1,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/IndeedJobsRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "One page of Indeed job records over plain HTTP",
      "content": {
       "application/json": {
        "schema": {},
        "example": {
         "search_parameters": {
          "engine": "indeed_jobs",
          "q": "hotel jobs",
          "location": "Chicago, IL",
          "page": 1
         },
         "jobs_results": [
          {
           "jobkey": "8f0ec6e87b6ba389",
           "title": "Front Desk Agent",
           "company": "Marriott International, Inc",
           "location": "Chicago, IL 60616",
           "salary": {
            "text": "$27.87 an hour",
            "min": 27.87,
            "max": 27.87,
            "period": "HOURLY"
           },
           "posted": "6 days ago",
           "created": "2029-02-16",
           "company_rating": 4.0,
           "company_review_count": 26245,
           "job_types": [],
           "remote": false,
           "sponsored": false,
           "link": "https://www.indeed.com/rc/clk?jk=8f0ec6e87b6ba389",
           "snippet": "Process all guest check-ins by confirming reservations, assigning room…"
          },
          {
           "jobkey": "e3479bc018d43229",
           "title": "Housekeeping Attendant",
           "company": "Sonesta International Hotels",
           "location": "Chicago, IL",
           "salary": {
            "text": "$21.00 an hour",
            "min": 21.0,
            "max": 21.0,
            "period": "HOURLY"
           },
           "posted": "1 day ago",
           "created": "2029-02-21",
           "company_rating": 4.1,
           "company_review_count": 402,
           "job_types": [
            "PART_TIME"
           ],
           "remote": false,
           "sponsored": false,
           "link": "https://www.indeed.com/rc/clk?jk=e3479bc018d43229",
           "snippet": "Clean guest rooms and public areas."
          }
         ],
         "total": 2,
         "meta": {
          "source": "indeed",
          "wire_bytes": 1759431,
          "elapsed_s": 1.488
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/hotels/search": {
   "post": {
    "tags": [
     "Google Hotels"
    ],
    "summary": "Search a destination for hotels and prices",
    "description": "One page (~20) of the properties Google Hotels lists for a destination.\n\nEach property carries its `property_token` (feed it to `/v1/calendar` or\n`/v1/offers`), rating, class, amenities, images, coordinates, deal signal\nand the lowest price for the stay, itemised into base, taxes, fees and\ntotal with provenance. Vacation rentals add their seller rows. Page on with\n`pagination.next_page_token`, resending the same body.\n\nOne upstream call per page. Prices follow the market Google sees the\nrequest from; `warnings` says when that market could not be verified.\n\nCredits: 3 per page of results; an empty page and failed requests are free",
    "operationId": "google_hotels_search",
    "x-credits": 3,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/GoogleHotelsSearchRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "One page of destination results; stay totals keep base, taxes and fees apart",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/GoogleHotelsSearchResponse"
        },
        "example": {
         "search_parameters": {
          "engine": "google_hotels_search",
          "q": "hotels in Montreal",
          "check_in_date": "2029-03-14",
          "check_out_date": "2029-03-16",
          "adults": 2,
          "currency": "CAD",
          "gl": "ca",
          "hl": "en",
          "sort_by": "relevance"
         },
         "search_information": {
          "total_results": 5778,
          "location": "Montreal",
          "location_data_id": "0x4cc91a541c64b70d:0x654e3138211fefef",
          "nights": 2,
          "returned": 7,
          "priced": 7,
          "requested_currency": "CAD",
          "returned_currency": "CAD",
          "currency_matches_request": true,
          "requested_market": "CA",
          "available_property_types": [
           {
            "id": 19,
            "name": "Bed and breakfasts"
           },
           {
            "id": 18,
            "name": "Spa hotels"
           },
           {
            "id": 14,
            "name": "Hostels"
           }
          ]
         },
         "properties": [
          {
           "type": "hotel",
           "property_token": "ChgImtDg_rW5k8iWARoLL2cvMXRzamQ4NncQAQ",
           "name": "Radisson Hotel Montreal Airport",
           "data_id": "0x4cc9178df6e67b8d:0x96904dcb5fd8281a",
           "description": "Modern lodging with a restaurant & an indoor pool, plus free WiFi & an airport shuttle.",
           "link": "https://www.choicehotels.com/quebec/montreal/radisson-hotels/cnc37?mc=llgoxxpx",
           "gps_coordinates": {
            "latitude": 45.4851544,
            "longitude": -73.6909316
           },
           "country": "CA",
           "check_in_time": "3:00 PM",
           "check_out_time": "11:00 AM",
           "hotel_class": "4-star hotel",
           "extracted_hotel_class": 4,
           "rating": 3.5,
           "reviews": 2535,
           "reviews_histogram": {
            "1": 443,
            "2": 220,
            "3": 396,
            "4": 674,
            "5": 802
           },
           "location_rating": 3.1,
           "proximity_to_things_to_do_rating": 3.2,
           "proximity_to_restaurants_rating": 2.8,
           "proximity_to_transit_rating": 2.5,
           "airport_access_rating": 4.6,
           "reviews_breakdown": [
            {
             "name": "Fitness",
             "description": "Fitness",
             "total": 199,
             "positive": 119,
             "neutral": 13,
             "negative": 67
            },
            {
             "name": "Pool",
             "description": "Pool",
             "total": 107,
             "positive": 78,
             "neutral": 7,
             "negative": 22
            }
           ],
           "amenities": [
            "Breakfast ($)",
            "Free Wi-Fi",
            "Parking ($)",
            "Pools",
            "Hot tub",
            "Air conditioning"
           ],
           "amenity_codes": [
            [
             1,
             165
            ],
            [
             1,
             29
            ],
            [
             1,
             17
            ],
            [
             1,
             21
            ],
            [
             1,
             10
            ],
            [
             1,
             2
            ]
           ],
           "thumbnail": "https://lh3.googleusercontent.com/gps-cs-s/AHRPTWk0lycQOr7G_2oWSLSEpBlBBfN0wY5jwgISonycKD0xeg__AHXxCEpS3XqlR9IcD1alML-r6P2EvsCMBx_Lt3KN8sOYNRZU4Jouiz7gc8JcjOskWyeb7HyYDCnqD1bR4L-24cbbvm9TvXHm=s150-w92-h150-n-k-no",
           "images": [
            {
             "thumbnail": "https://lh3.googleusercontent.com/gps-cs-s/AHRPTWk0lycQOr7G_2oWSLSEpBlBBfN0wY5jwgISonycKD0xeg__AHXxCEpS3XqlR9IcD1alML-r6P2EvsCMBx_Lt3KN8sOYNRZU4Jouiz7gc8JcjOskWyeb7HyYDCnqD1bR4L-24cbbvm9TvXHm=s287-w287-h192-n-k-no-v1",
             "original": "https://lh3.googleusercontent.com/gps-cs-s/AHRPTWk0lycQOr7G_2oWSLSEpBlBBfN0wY5jwgISonycKD0xeg__AHXxCEpS3XqlR9IcD1alML-r6P2EvsCMBx_Lt3KN8sOYNRZU4Jouiz7gc8JcjOskWyeb7HyYDCnqD1bR4L-24cbbvm9TvXHm=s10000"
            }
           ],
           "nearby_places": [
            {
             "name": "Côte-de-Liesse / No 6400",
             "category_code": 2,
             "transportations": [
              {
               "type": "Walking",
               "type_code": 2,
               "duration": "2 min"
              }
             ]
            }
           ],
           "deal": "27% less than usual",
           "deal_description": "Great Deal",
           "deal_kind": "below_usual_price",
           "rate": {
            "currency": "CAD",
            "check_in": "2029-03-14",
            "check_out": "2029-03-16",
            "nights": 2,
            "price_per_night": "$121",
            "price_per_night_before_taxes": "$102",
            "extracted_price_per_night": 121.0,
            "extracted_price_per_night_before_taxes": 101.67969,
            "total_price": "$242",
            "total_price_before_taxes": "$203",
            "base": 203.35938,
            "taxes": 38.640625,
            "fees": 0.0,
            "total": 242.0,
            "before_taxes": 203.36,
            "from_display_text": false
           },
           "provenance": {
            "schema_version": 1,
            "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
            "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
            "observed_at": "2026-09-30T22:46:08.123Z",
            "source": "google_hotels_search",
            "source_kind": "search_listing",
            "collector": "scrapingme.google_hotels_search",
            "source_property_id": "ChgImtDg_rW5k8iWARoLL2cvMXRzamQ4NncQAQ",
            "requested_market": "CA",
            "requested_currency": "CAD",
            "returned_currency": "CAD",
            "egress_mode": "direct",
            "price_basis": "stay_total_including_taxes_and_fees",
            "derivation": "normalized_upstream"
           }
          },
          {
           "type": "vacation_rental",
           "property_token": "ChkQzZioqLvP4IUiGg0vZy8xMXpjZmhoMzJwEAI",
           "name": "HoMa Loft 206 – Bright, Modern & Easy Parking",
           "link": "https://www.host-me.ca/properties/69e924482b031c00122c840e",
           "gps_coordinates": {
            "latitude": 45.54264831542969,
            "longitude": -73.53958129882812
           },
           "country": "CA",
           "check_in_time": "4:00 PM",
           "check_out_time": "10:00 AM",
           "location_rating": 2.9,
           "proximity_to_restaurants_rating": 2.5,
           "airport_access_rating": 3.9,
           "amenities": [
            "Air conditioning",
            "Kid-friendly",
            "Heating",
            "Ironing board",
            "Kitchen",
            "Microwave"
           ],
           "excluded_amenities": [
            "No balcony",
            "No crib",
            "No elevator"
           ],
           "essential_info": [
            "Entire apartment",
            "Sleeps 2",
            "1 bedroom",
            "1 bathroom"
           ],
           "thumbnail": "https://lh3.googleusercontent.com/grass-proxy/AIM7gW39AJ5sNUqWYbyQkdBH2YHq7dV63MGIYm0DnOBPevzdmKuKVhPt19sLNF1TWMEzHBW2kN-KopL4tXsF2coEPixiQxcAV6aM2SWxYoWA73riNVMyRVNI3QHt-96hRHLb5couboHdgW6G-tN6pu_pOwPJZdNGqL_RGKM9UOM7G9cUNeoBDdsqXM6hNg=s150-w92-h150-n-k-no",
           "images": [
            {
             "thumbnail": "https://lh3.googleusercontent.com/grass-proxy/AIM7gW39AJ5sNUqWYbyQkdBH2YHq7dV63MGIYm0DnOBPevzdmKuKVhPt19sLNF1TWMEzHBW2kN-KopL4tXsF2coEPixiQxcAV6aM2SWxYoWA73riNVMyRVNI3QHt-96hRHLb5couboHdgW6G-tN6pu_pOwPJZdNGqL_RGKM9UOM7G9cUNeoBDdsqXM6hNg=s287-w287-h192-n-k-no-v1",
             "original": "https://lh3.googleusercontent.com/grass-proxy/AIM7gW39AJ5sNUqWYbyQkdBH2YHq7dV63MGIYm0DnOBPevzdmKuKVhPt19sLNF1TWMEzHBW2kN-KopL4tXsF2coEPixiQxcAV6aM2SWxYoWA73riNVMyRVNI3QHt-96hRHLb5couboHdgW6G-tN6pu_pOwPJZdNGqL_RGKM9UOM7G9cUNeoBDdsqXM6hNg=s10000"
            }
           ],
           "nearby_places": [
            {
             "name": "Montréal-Pierre Elliott Trudeau International Airport",
             "category_code": 3,
             "transportations": [
              {
               "type": "Taxi",
               "type_code": 0,
               "duration": "35 min"
              },
              {
               "type": "Public transport",
               "type_code": 3,
               "duration": "1 hr 30 min"
              }
             ]
            }
           ],
           "rate": {
            "currency": "CAD",
            "check_in": "2029-03-14",
            "check_out": "2029-03-16",
            "nights": 2,
            "price_per_night": "$152",
            "price_per_night_before_taxes": "$138",
            "extracted_price_per_night": 152.34,
            "extracted_price_per_night_before_taxes": 138.49,
            "total_price": "$305",
            "total_price_before_taxes": "$277",
            "base": 185.0,
            "taxes": 27.70375,
            "fees": 91.98,
            "total": 304.68378,
            "before_taxes": 276.98,
            "from_display_text": false
           },
           "sources": [
            {
             "source": "host-me",
             "raw_source": "host-me",
             "displayed_prices": [
              "$138",
              "$152"
             ],
             "partner_id": "420480647",
             "logo": "//www.gstatic.com/travel-hotels/branding/icon_default.png",
             "price_per_night": "$152",
             "price_per_night_before_taxes": "$138",
             "extracted_price_per_night": 152.0,
             "extracted_price_per_night_before_taxes": 138.0,
             "has_free_cancellation": true,
             "free_cancellation_until": "Oct 16",
             "free_cancellation_time": "4:00 PM",
             "is_featured": true
            }
           ],
           "provenance": {
            "schema_version": 1,
            "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
            "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
            "observed_at": "2026-09-30T22:46:08.123Z",
            "source": "google_hotels_search",
            "source_kind": "search_listing",
            "collector": "scrapingme.google_hotels_search",
            "source_property_id": "ChkQzZioqLvP4IUiGg0vZy8xMXpjZmhoMzJwEAI",
            "requested_market": "CA",
            "requested_currency": "CAD",
            "returned_currency": "CAD",
            "egress_mode": "direct",
            "price_basis": "stay_total_including_taxes_and_fees",
            "derivation": "normalized_upstream"
           }
          }
         ],
         "brands": [
          {
           "id": 33,
           "title": "Accor Live Limitless",
           "children": [
            {
             "id": 8,
             "title": "Fairmont Hotels and Resorts"
            },
            {
             "id": 47,
             "title": "Novotel"
            },
            {
             "id": 84,
             "title": "Sofitel"
            }
           ]
          },
          {
           "id": 18,
           "title": "Best Western International",
           "children": [
            {
             "id": 155,
             "title": "Best Western"
            },
            {
             "id": 104,
             "title": "Best Western Plus"
            }
           ]
          }
         ],
         "pagination": {
          "records_from": 1,
          "records_to": 20,
          "next_page_token": "CBI="
         },
         "warnings": [
          "prices reflect this server's egress, not a verified CA exit; configure a market proxy for market-matched results"
         ],
         "meta": {
          "wire_bytes": 214986,
          "elapsed_s": 1.89,
          "egress": {
           "mode": "direct",
           "class": "direct",
           "pool": "direct",
           "attempts": 1,
           "path": [
            "direct/direct:ok"
           ]
          },
          "skipped_records": 0
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/serp/google_hotels": {
   "post": {
    "tags": [
     "SearchAPI compatibility"
    ],
    "summary": "google_hotels destination search, drop-in",
    "description": "Drop-in for SearchAPI's `engine=google_hotels`.\n\nSame request names and response hierarchy (`search_parameters`,\n`search_information`, `properties[]`, `brands[]`, `pagination`).\nExtracted prices are exact floats rather than rounded integers, and each\nproperty adds `prices[]` where Google attached seller rows. Filters this\nsource cannot honour are refused with 422 instead of being ignored.\n\nCredits: 3 per page of results; an empty page and failed requests are free",
    "operationId": "serp_google_hotels",
    "x-credits": 3,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/SerpGoogleHotelsRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "SearchAPI google_hotels shape; extracted prices are exact floats",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/SerpGoogleHotelsResponse"
        },
        "example": {
         "search_metadata": {
          "status": "Success",
          "created_at": "2026-09-30T22:46:08Z",
          "request_time_taken": 1.89,
          "total_time_taken": 1.89
         },
         "search_parameters": {
          "engine": "google_hotels",
          "q": "hotels in Montreal",
          "check_in_date": "2029-03-14",
          "check_out_date": "2029-03-16",
          "adults": 2,
          "currency": "CAD",
          "gl": "ca",
          "hl": "en",
          "sort_by": "relevance"
         },
         "search_information": {
          "total_results": 5778,
          "location": "Montreal",
          "currency_matches_request": true
         },
         "properties": [
          {
           "type": "hotel",
           "property_token": "ChgImtDg_rW5k8iWARoLL2cvMXRzamQ4NncQAQ",
           "data_id": "0x4cc9178df6e67b8d:0x96904dcb5fd8281a",
           "name": "Radisson Hotel Montreal Airport",
           "link": "https://www.choicehotels.com/quebec/montreal/radisson-hotels/cnc37?mc=llgoxxpx",
           "description": "Modern lodging with a restaurant & an indoor pool, plus free WiFi & an airport shuttle.",
           "gps_coordinates": {
            "latitude": 45.4851544,
            "longitude": -73.6909316
           },
           "city": "Montreal",
           "country": "CA",
           "check_in_time": "3:00 PM",
           "check_out_time": "11:00 AM",
           "price_per_night": {
            "price": "$121",
            "extracted_price": 121.0,
            "price_before_taxes": "$102",
            "extracted_price_before_taxes": 101.67969
           },
           "total_price": {
            "price": "$242",
            "extracted_price": 242.0,
            "price_before_taxes": "$203",
            "extracted_price_before_taxes": 203.36
           },
           "deal": "27% less than usual",
           "deal_description": "Great Deal",
           "nearby_places": [
            {
             "name": "Côte-de-Liesse / No 6400",
             "transportations": [
              {
               "type": "Walking",
               "duration": "2 min"
              }
             ]
            }
           ],
           "hotel_class": "4-star hotel",
           "extracted_hotel_class": 4,
           "rating": 3.5,
           "reviews": 2535,
           "reviews_histogram": {
            "1": 443,
            "2": 220,
            "3": 396,
            "4": 674,
            "5": 802
           },
           "location_rating": 3.1,
           "proximity_to_things_to_do_rating": 3.2,
           "proximity_to_restaurants_rating": 2.8,
           "proximity_to_transit_rating": 2.5,
           "airport_access_rating": 4.6,
           "reviews_breakdown": [
            {
             "name": "Fitness",
             "description": "Fitness",
             "total": 199,
             "positive": 119,
             "neutral": 13,
             "negative": 67
            },
            {
             "name": "Pool",
             "description": "Pool",
             "total": 107,
             "positive": 78,
             "neutral": 7,
             "negative": 22
            }
           ],
           "amenities": [
            "Breakfast ($)",
            "Free Wi-Fi",
            "Parking ($)",
            "Pools",
            "Hot tub",
            "Air conditioning"
           ],
           "images": [
            {
             "thumbnail": "https://lh3.googleusercontent.com/gps-cs-s/AHRPTWk0lycQOr7G_2oWSLSEpBlBBfN0wY5jwgISonycKD0xeg__AHXxCEpS3XqlR9IcD1alML-r6P2EvsCMBx_Lt3KN8sOYNRZU4Jouiz7gc8JcjOskWyeb7HyYDCnqD1bR4L-24cbbvm9TvXHm=s287-w287-h192-n-k-no-v1",
             "original": "https://lh3.googleusercontent.com/gps-cs-s/AHRPTWk0lycQOr7G_2oWSLSEpBlBBfN0wY5jwgISonycKD0xeg__AHXxCEpS3XqlR9IcD1alML-r6P2EvsCMBx_Lt3KN8sOYNRZU4Jouiz7gc8JcjOskWyeb7HyYDCnqD1bR4L-24cbbvm9TvXHm=s10000"
            }
           ],
           "thumbnail": "https://lh3.googleusercontent.com/gps-cs-s/AHRPTWk0lycQOr7G_2oWSLSEpBlBBfN0wY5jwgISonycKD0xeg__AHXxCEpS3XqlR9IcD1alML-r6P2EvsCMBx_Lt3KN8sOYNRZU4Jouiz7gc8JcjOskWyeb7HyYDCnqD1bR4L-24cbbvm9TvXHm=s150-w92-h150-n-k-no",
           "currency": "CAD"
          },
          {
           "type": "vacation_rental",
           "property_token": "ChkQzZioqLvP4IUiGg0vZy8xMXpjZmhoMzJwEAI",
           "name": "HoMa Loft 206 – Bright, Modern & Easy Parking",
           "link": "https://www.host-me.ca/properties/69e924482b031c00122c840e",
           "gps_coordinates": {
            "latitude": 45.54264831542969,
            "longitude": -73.53958129882812
           },
           "city": "Montreal",
           "country": "CA",
           "check_in_time": "4:00 PM",
           "check_out_time": "10:00 AM",
           "price_per_night": {
            "price": "$152",
            "extracted_price": 152.34,
            "price_before_taxes": "$138",
            "extracted_price_before_taxes": 138.49
           },
           "total_price": {
            "price": "$305",
            "extracted_price": 304.68,
            "price_before_taxes": "$277",
            "extracted_price_before_taxes": 276.98
           },
           "nearby_places": [
            {
             "name": "Montréal-Pierre Elliott Trudeau International Airport",
             "transportations": [
              {
               "type": "Taxi",
               "duration": "35 min"
              },
              {
               "type": "Public transport",
               "duration": "1 hr 30 min"
              }
             ]
            }
           ],
           "location_rating": 2.9,
           "proximity_to_restaurants_rating": 2.5,
           "airport_access_rating": 3.9,
           "amenities": [
            "Air conditioning",
            "Kid-friendly",
            "Heating",
            "Ironing board",
            "Kitchen",
            "Microwave"
           ],
           "excluded_amenities": [
            "No balcony",
            "No crib",
            "No elevator"
           ],
           "essential_info": [
            "Entire apartment",
            "Sleeps 2",
            "1 bedroom",
            "1 bathroom"
           ],
           "images": [
            {
             "thumbnail": "https://lh3.googleusercontent.com/grass-proxy/AIM7gW39AJ5sNUqWYbyQkdBH2YHq7dV63MGIYm0DnOBPevzdmKuKVhPt19sLNF1TWMEzHBW2kN-KopL4tXsF2coEPixiQxcAV6aM2SWxYoWA73riNVMyRVNI3QHt-96hRHLb5couboHdgW6G-tN6pu_pOwPJZdNGqL_RGKM9UOM7G9cUNeoBDdsqXM6hNg=s287-w287-h192-n-k-no-v1",
             "original": "https://lh3.googleusercontent.com/grass-proxy/AIM7gW39AJ5sNUqWYbyQkdBH2YHq7dV63MGIYm0DnOBPevzdmKuKVhPt19sLNF1TWMEzHBW2kN-KopL4tXsF2coEPixiQxcAV6aM2SWxYoWA73riNVMyRVNI3QHt-96hRHLb5couboHdgW6G-tN6pu_pOwPJZdNGqL_RGKM9UOM7G9cUNeoBDdsqXM6hNg=s10000"
            }
           ],
           "thumbnail": "https://lh3.googleusercontent.com/grass-proxy/AIM7gW39AJ5sNUqWYbyQkdBH2YHq7dV63MGIYm0DnOBPevzdmKuKVhPt19sLNF1TWMEzHBW2kN-KopL4tXsF2coEPixiQxcAV6aM2SWxYoWA73riNVMyRVNI3QHt-96hRHLb5couboHdgW6G-tN6pu_pOwPJZdNGqL_RGKM9UOM7G9cUNeoBDdsqXM6hNg=s150-w92-h150-n-k-no",
           "prices": [
            {
             "source": "host-me",
             "raw_source": "host-me",
             "displayed_prices": [
              "$138",
              "$152"
             ],
             "partner_id": "420480647",
             "logo": "//www.gstatic.com/travel-hotels/branding/icon_default.png",
             "price_per_night": "$152",
             "price_per_night_before_taxes": "$138",
             "extracted_price_per_night": 152.0,
             "extracted_price_per_night_before_taxes": 138.0,
             "has_free_cancellation": true,
             "free_cancellation_until": "Oct 16",
             "free_cancellation_time": "4:00 PM",
             "is_featured": true
            }
           ],
           "currency": "CAD"
          }
         ],
         "brands": [
          {
           "id": 33,
           "title": "Accor Live Limitless",
           "children": [
            {
             "id": 8,
             "title": "Fairmont Hotels and Resorts"
            },
            {
             "id": 47,
             "title": "Novotel"
            },
            {
             "id": 84,
             "title": "Sofitel"
            }
           ]
          },
          {
           "id": 18,
           "title": "Best Western International",
           "children": [
            {
             "id": 155,
             "title": "Best Western"
            },
            {
             "id": 104,
             "title": "Best Western Plus"
            }
           ]
          }
         ],
         "pagination": {
          "records_from": 1,
          "records_to": 20,
          "next_page_token": "CBI="
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/hotels/property": {
   "post": {
    "tags": [
     "Google Hotels"
    ],
    "summary": "One property's details record: name, address, phone",
    "description": "The address-bearing render for one property token.\n\nThe search card omits the mailing address; pinning the token answers\nwith the details widget, parsed like any property card: name, mailing\naddress, phone, rating, review count, class, times. Use it to confirm a\n`/v1/hotels/search` result is the property you meant before targeting it\nwith rate or review calls. The stay dates it prices are transport for\nthis call and not its answer.\n\nCredits: 3 (failed requests are free)",
    "operationId": "google_hotels_property_details",
    "x-credits": 3,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/GoogleHotelsPropertyRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "One property's details record: name, mailing address, phone",
      "content": {
       "application/json": {
        "schema": {},
        "example": {
         "type": "hotel",
         "property_token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
         "name": "Hilton Chicago",
         "data_id": "0x880e2c99242c7a2f:0x4de3d4bb09dba1",
         "description": "Modern lodging with a restaurant & an indoor pool.",
         "gps_coordinates": {
          "latitude": 41.8722592,
          "longitude": -87.624696
         },
         "country": "US",
         "address": "720 S Michigan Ave, Chicago, IL 60605, United States",
         "phone": "+1 312-922-4400",
         "check_in_time": "3:00 PM",
         "check_out_time": "11:00 AM",
         "hotel_class": "3-star hotel",
         "extracted_hotel_class": 3,
         "rating": 4.3,
         "reviews": 10999,
         "reviews_histogram": {
          "1": 596,
          "2": 428,
          "3": 880,
          "4": 2607,
          "5": 6488
         },
         "reviews_breakdown": [],
         "amenities": [
          "Free Wi-Fi",
          "Indoor pool"
         ],
         "amenity_codes": [
          [
           1,
           165
          ]
         ],
         "excluded_amenities": [],
         "essential_info": [],
         "thumbnail": "https://lh3.googleusercontent.com/gps-cs-s/REDACTED",
         "images": [],
         "nearby_places": [],
         "rate": {
          "currency": "USD",
          "check_in": "2029-03-19",
          "check_out": "2029-03-20",
          "nights": 1,
          "from_display_text": false
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/hotels/resolve": {
   "post": {
    "tags": [
     "Google Hotels"
    ],
    "summary": "Find properties by name and place, with addresses",
    "description": "Look up a hotel by name and place, identify it by address.\n\nRuns the destination search for `q` (name plus city, region or country;\n`gl` biases the market), then fetches each of the top `limit`\ncandidates' details record to attach the mailing address and phone. The\nanswer lists the properties with their `property_token`, ready for\n`/v1/calendar`, `/v1/offers` and `/v1/hotels/reviews`, so the lookup\nhappens once and the token is stored.\n\nCredits: 12 (failed requests are free)",
    "operationId": "google_hotels_resolve",
    "x-credits": 12,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/GoogleHotelsResolveRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Properties matching a name and place, each with its property token and mailing address",
      "content": {
       "application/json": {
        "schema": {},
        "example": {
         "search_parameters": {
          "q": "Hilton Chicago",
          "gl": "us",
          "hl": "en",
          "currency": "USD",
          "limit": 3
         },
         "location": "Chicago",
         "properties": [
          {
           "property_token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
           "name": "Hilton Chicago",
           "rating": 4.3,
           "reviews": 10999,
           "type": "hotel",
           "address": "720 S Michigan Ave, Chicago, IL 60605, United States",
           "phone": "+1 312-922-4400"
          },
          {
           "property_token": "ChgImtDg_rW5k8iWARoLL2cvMXRzamQ4NncQAQ",
           "name": "Hilton Chicago/Magnificent Mile Suites",
           "rating": 4.2,
           "reviews": 2808,
           "type": "hotel",
           "address": "540 N Michigan Ave, Chicago, IL 60611, United States",
           "phone": "+1 312-661-0640"
          }
         ]
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/hotels/reviews": {
   "post": {
    "tags": [
     "Google Hotels"
    ],
    "summary": "Guest reviews, aggregated by provider",
    "description": "Google Hotels guest reviews for one property token.\n\nGoogle mixes its own reviews with Tripadvisor's, Priceline's and\nothers'; each row names its `provider` and keeps that provider's rating\nscale (5 for Google/Tripadvisor, 10 for Priceline) rather than a silently\nrenormalised one. Ten reviews per page; `pages` follows Google's\ncontinuation token, and `next_page_token` continues past that.\n\nCredits: 2 (failed requests are free)",
    "operationId": "google_hotels_reviews",
    "x-credits": 2,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/GoogleHotelsReviewsRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Google Hotels guest reviews, aggregated by provider with each row's own rating scale",
      "content": {
       "application/json": {
        "schema": {},
        "example": {
         "source": "google",
         "property_id": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
         "offset": 0,
         "limit": 10,
         "next_page_token": "CjEIARIpCgoAP7_LACnN____EhAgaDet6skqGaNbIqMAAAAAGgn92PwCYGHGd2UYACIA:10",
         "count": 3,
         "reviews": [
          {
           "source": "google",
           "review_id": "Ci9DQUlRQUNvZENodHljRjlvT25SZmJHOVBVMHh0VTJkSlNsa3lMVmMxZVMxMWVtYxAB",
           "rating": 3.0,
           "text": "We stayed here for one night during a trip to Chicago, and overall, the hotel served its purpose, but I don't think we'd book here again.",
           "date": "a month ago",
           "author": "Amber S",
           "management_reply": "Dear Amber, thank you for choosing us for your stay.",
           "provider": "Google"
          },
          {
           "source": "google",
           "review_id": "ChdDSUhNMG9nS0VQLXBpdUc4aE5peXZ3RRAB",
           "rating": 4.0,
           "text": "It is a magnificent old building with spacious rooms.",
           "date": "4 weeks ago",
           "author": "adflanagan13",
           "url": "https://www.tripadvisor.com/ShowUserReviews-g35805-d87590-r1075812531",
           "provider": "Tripadvisor"
          },
          {
           "source": "google",
           "review_id": "ChdDSUhNMG9nS0VJYVBqUG1LMGJmZzBnRRAB",
           "rating": 9.0,
           "text": "The location, having access to the pool and fitness center, was just lovely.",
           "date": "5 months ago",
           "author": "Ronald",
           "provider": "Priceline"
          }
         ],
         "provenance": {
          "schema_version": 1,
          "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
          "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
          "observed_at": "2026-08-07T01:23:45.678Z",
          "source": "google_hotels_calendar",
          "source_kind": "calendar",
          "collector": "scrapingme.google_calendar",
          "source_property_id": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
          "requested_market": "US",
          "requested_currency": "USD",
          "returned_currency": "USD",
          "egress_mode": "direct",
          "price_basis": "room_base_before_taxes_and_fees",
          "derivation": "normalized_upstream"
         },
         "wire_bytes": 40175,
         "elapsed_s": 0.388,
         "egress_mode": "direct",
         "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
         "observed_at": "2026-08-07T01:23:45.678Z",
         "warnings": []
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/ota/sources": {
   "get": {
    "tags": [
     "Cross-source"
    ],
    "summary": "What each source supports, and what it costs",
    "description": "What each OTA can actually answer.\n\nPublished because the three are not interchangeable — one returns a whole\nhorizon, the others one date; only Agoda breaks out rooms — and a caller\nshould pick on capability rather than by trial and error.\n\nCredits: 0 (failed requests are free)",
    "operationId": "ota_source_matrix",
    "x-credits": 0,
    "responses": {
     "200": {
      "description": "Per-source capability matrix — granularity, identifier type, and whether a browser token is needed",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/OtaSourcesResponse"
        },
        "example": {
         "sources": {
          "booking": {
           "engine": "booking_calendar",
           "primary_operation": "calendar",
           "identifier": "pagename (URL slug) + country",
           "granularity": "daily lowest rate",
           "multi_date": true,
           "max_dates_per_call": 61,
           "per_room": false,
           "currency_selectable": true,
           "needs_browser_token": true,
           "operations": {
            "search": {
             "supported": true,
             "needs_browser_token": true,
             "available": true
            },
            "rates": {
             "supported": true,
             "needs_browser_token": true,
             "available": true
            },
            "rooms": {
             "supported": true,
             "needs_browser_token": true,
             "available": true
            },
            "calendar": {
             "supported": true,
             "needs_browser_token": true,
             "available": true
            }
           },
           "notes": "Cheapest horizon sweep. A year costs 6 calls / ~33 KB.",
           "available": true
          },
          "hotels": {
           "engine": "hotels_property",
           "primary_operation": "rates",
           "identifier": "numeric property id",
           "granularity": "headline price for one stay window",
           "multi_date": false,
           "max_dates_per_call": 1,
           "per_room": false,
           "currency_selectable": true,
           "currency_mechanism": "point-of-sale",
           "markets": [
            "AU"
           ],
           "needs_browser_token": true,
           "operations": {
            "search": {
             "supported": true,
             "needs_browser_token": false,
             "available": true
            },
            "rates": {
             "supported": true,
             "needs_browser_token": true,
             "available": true
            },
            "rooms": {
             "supported": true,
             "needs_browser_token": true,
             "available": true
            },
            "calendar": {
             "supported": false,
             "needs_browser_token": false,
             "available": false,
             "unavailable_reason": "not supported"
            }
           },
           "notes": "No calendar exists; one call per date. Prices are NOT comparable across markets …",
           "available": true
          },
          "agoda": {
           "engine": "agoda_property",
           "primary_operation": "rates",
           "identifier": "numeric property id",
           "granularity": "every room type and rate plan",
           "multi_date": false,
           "max_dates_per_call": 1,
           "per_room": true,
           "currency_selectable": true,
           "currencies": [
            "AED"
           ],
           "needs_browser_token": false,
           "operations": {
            "search": {
             "supported": true,
             "needs_browser_token": false,
             "available": true
            },
            "rates": {
             "supported": true,
             "needs_browser_token": false,
             "available": true
            },
            "rooms": {
             "supported": true,
             "needs_browser_token": false,
             "available": true
            },
            "calendar": {
             "supported": false,
             "needs_browser_token": false,
             "available": false,
             "unavailable_reason": "not supported"
            }
           },
           "notes": "No anti-bot gate. Richest per-date answer, and its currencies are genuine FX con…",
           "available": true
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     }
    }
   }
  },
  "/v1/ota/booking/search": {
   "post": {
    "tags": [
     "Booking.com"
    ],
    "summary": "Find a Booking.com slug by hotel name",
    "description": "Resolve a hotel name to Booking.com's country/slug identifier.\n\nAdd `city` whenever possible. A slug is stable, so search once during\nonboarding and store `recommended_match` for calendar and room calls.\nIt is null when only weak or ambiguous candidates were found; `matches`\nremains available for manual review.\n\nCredits: 1 (failed requests are free)",
    "operationId": "booking_search",
    "x-credits": 1,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/BookingSearchRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Candidate Booking.com URL slugs, ranked against the requested hotel name",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/BookingSearchResponse"
        },
        "example": {
         "search_parameters": {
          "engine": "booking_search",
          "name": "Moxy Boston Downtown",
          "city": "Boston",
          "limit": 5
         },
         "search_status": "matched",
         "recommended_match": {
          "pagename": "moxy-boston-downtown",
          "country": "us",
          "name": "Moxy Boston Downtown",
          "url": "https://www.booking.com/hotel/us/moxy-boston-downtown.html",
          "rank": 0,
          "name_score": 1.0,
          "identity_score": 1.0,
          "match_score": 1.0,
          "confidence": "high"
         },
         "warnings": [],
         "matches": [
          {
           "pagename": "moxy-boston-downtown",
           "country": "us",
           "name": "Moxy Boston Downtown",
           "url": "https://www.booking.com/hotel/us/moxy-boston-downtown.html",
           "rank": 0,
           "name_score": 1.0,
           "identity_score": 1.0,
           "match_score": 1.0,
           "confidence": "high"
          }
         ],
         "meta": {
          "source": "booking",
          "matches": 1,
          "selection_method": "name_city_confidence",
          "match_threshold": 0.8,
          "match_margin": 0.12,
          "wire_bytes": 1384521,
          "elapsed_s": 1.214
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/ota/booking": {
   "post": {
    "tags": [
     "Booking.com"
    ],
    "summary": "Price calendar — 61 dates per call",
    "description": "Booking.com forward horizon — 61 dates per call.\n\nCredits: 8 (failed requests are free)",
    "operationId": "booking_calendar",
    "x-credits": 8,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/BookingRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Booking's own calendar. Paged past its 61-day cap automatically",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/BookingCalendarResponse"
        },
        "example": {
         "search_parameters": {
          "engine": "booking_calendar",
          "pagename": "moxy-boston-downtown",
          "country": "us",
          "start_date": "2029-02-05",
          "days": 3,
          "currency": "USD",
          "adults": 2,
          "rooms": 1
         },
         "property": {
          "pagename": "moxy-boston-downtown",
          "hotel_id": 5375786
         },
         "calendar": [
          {
           "stay_date": "2029-02-05",
           "available": true,
           "price": 453.0,
           "currency": "USD",
           "min_length_of_stay": 1,
           "provenance": {
            "schema_version": 1,
            "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
            "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
            "observed_at": "2026-08-07T01:23:45.678Z",
            "source": "booking_com",
            "source_kind": "ota_calendar",
            "collector": "scrapingme.ota.booking",
            "source_property_id": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
            "requested_market": "US",
            "requested_currency": "USD",
            "returned_currency": "USD",
            "egress_mode": "direct",
            "price_basis": "room_base_before_taxes_and_fees",
            "derivation": "normalized_upstream"
           }
          },
          {
           "stay_date": "2029-02-06",
           "available": false,
           "price": null,
           "currency": "USD",
           "min_length_of_stay": 1
          }
         ],
         "unavailable_dates": [
          "2029-02-06",
          "2029-02-07"
         ],
         "meta": {
          "source": "booking",
          "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
          "observed_at": "2026-08-07T01:23:45.678Z",
          "calls": 1,
          "wire_bytes": 454,
          "elapsed_s": 2.147,
          "dates": 3,
          "priced": 1
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/ota/hotels/search": {
   "post": {
    "tags": [
     "Hotels.com"
    ],
    "summary": "Find a Hotels.com property id by hotel name",
    "description": "Resolve a hotel name to Hotels.com's numeric property identifier.\n\nThis uses Hotels.com's lightweight typeahead response. Add `city` to disambiguate common brands,\nthen store `recommended_match.property_id` for headline-price and room\ncalls. It is null when only weak or ambiguous candidates were found.\n\nCredits: 1 (failed requests are free)",
    "operationId": "hotels_search",
    "x-credits": 1,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/HotelsSearchRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Candidate Hotels.com numeric property ids, with city-aware ranking",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/HotelsSearchResponse"
        },
        "example": {
         "search_parameters": {
          "engine": "hotels_search",
          "name": "Moxy Boston Downtown",
          "city": "Boston",
          "market": "US",
          "limit": 5
         },
         "search_status": "matched",
         "recommended_match": {
          "property_id": "38766175",
          "name": "Moxy Boston Downtown",
          "city": "Boston",
          "address": "240 TREMONT STREET, Boston, MA",
          "country": "USA",
          "url": "https://www.hotels.com/ho38766175",
          "rank": 0,
          "score": 1.0,
          "name_score": 1.0,
          "identity_score": 1.0,
          "match_score": 1.0,
          "confidence": "high",
          "city_score": 1.0,
          "winner_reason": "EXACT_MATCH",
          "coordinates": {
           "latitude": 42.350952,
           "longitude": -71.064804
          }
         },
         "warnings": [],
         "matches": [
          {
           "property_id": "38766175",
           "name": "Moxy Boston Downtown",
           "city": "Boston",
           "address": "240 TREMONT STREET, Boston, MA",
           "country": "USA",
           "url": "https://www.hotels.com/ho38766175",
           "rank": 0,
           "score": 1.0,
           "name_score": 1.0,
           "identity_score": 1.0,
           "match_score": 1.0,
           "confidence": "high",
           "city_score": 1.0,
           "winner_reason": "EXACT_MATCH",
           "coordinates": {
            "latitude": 42.350952,
            "longitude": -71.064804
           }
          }
         ],
         "meta": {
          "source": "hotels",
          "matches": 1,
          "selection_method": "name_city_confidence",
          "match_threshold": 0.8,
          "match_margin": 0.12,
          "wire_bytes": 921,
          "elapsed_s": 0.184
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/ota/hotels": {
   "post": {
    "tags": [
     "Hotels.com"
    ],
    "summary": "Headline price for one stay window",
    "description": "Hotels.com headline price for one stay window.\n\nOne small request.\n`price_per_night` is the sticky bar's lead price, as it always was; on\nthe US and DE points-of-sale that is the stay total including taxes and\nfees, so `price_per_night_is` says which it is and `total`/`nightly`\ncarry the labelled figures. An unbookable stay is `available: false`\nwith Hotels.com's own `unavailable_reason`, billed like any other\nanswer; only a reply with nothing in it is free.\n\nCredits: 8 (failed requests are free)",
    "operationId": "hotels_price",
    "x-credits": 8,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/HotelsRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Headline price for one window, measured on www.hotels.com. `price_per_night` is the sticky bar's lead price as before; here (`price_per_night_is: stay_total`) that is the stay total, and `nightly` is Hotels.com's own nightly figure before taxes and fees. `currency` is what the point-of-sale actually priced in",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/HotelsPriceResponse"
        },
        "example": {
         "search_parameters": {
          "engine": "hotels_property",
          "property_id": "12570",
          "check_in_date": "2029-04-10",
          "check_out_date": "2029-04-11",
          "adults": 2,
          "market": "US",
          "currency": "USD"
         },
         "property": {
          "property_id": "12570",
          "price_per_night": 475.0,
          "price_per_night_is": "stay_total",
          "total": 475.0,
          "nightly": 374.0,
          "lead_text": "$475",
          "total_text": "$475",
          "nightly_text": "$374 nightly",
          "currency": "USD",
          "currency_verified": true,
          "available": true,
          "provenance": {
           "schema_version": 1,
           "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
           "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
           "observed_at": "2026-08-07T01:23:45.678Z",
           "source": "hotels_com",
           "source_kind": "ota_offer",
           "collector": "scrapingme.ota.hotels",
           "source_property_id": "12570",
           "requested_market": "US",
           "requested_currency": "USD",
           "returned_currency": "USD",
           "egress_mode": "direct",
           "price_basis": "stay_headline",
           "derivation": "parsed_display_price"
          }
         },
         "meta": {
          "source": "hotels",
          "nights": 1,
          "wire_bytes": 6066,
          "egress_mode": "direct",
          "elapsed_s": 2.35,
          "comparable_across_markets": false
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/ota/expedia/search": {
   "post": {
    "tags": [
     "Expedia"
    ],
    "summary": "Find an Expedia property id by hotel name",
    "description": "Resolve a hotel name to Expedia's numeric property identifier.\n\nUses Expedia's own typeahead (one small request). Add `city`\nto disambiguate brands, then store `recommended_match.property_id` for\n`POST /v1/ota/expedia`. It is null when only weak or ambiguous candidates\nwere found. Expedia ids match Hotels.com's for newer properties only.\n\nCredits: 1 (failed requests are free)",
    "operationId": "expedia_search",
    "x-credits": 1,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/ExpediaSearchRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Candidate Expedia numeric property ids, with city-aware ranking",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ExpediaSearchResponse"
        },
        "example": {
         "search_parameters": {
          "engine": "expedia_search",
          "name": "Hilton Chicago",
          "city": "Chicago",
          "market": "US",
          "limit": 5
         },
         "search_status": "matched",
         "recommended_match": {
          "property_id": "12570",
          "name": "Hilton Chicago",
          "city": "Chicago",
          "address": "720 S Michigan Ave, Chicago, IL",
          "country": "USA",
          "url": "https://www.expedia.com/h12570.Hotel-Information",
          "rank": 0,
          "score": 1.0,
          "name_score": 1.0,
          "identity_score": 1.0,
          "match_score": 1.0,
          "confidence": "high",
          "city_score": 1.0,
          "winner_reason": "",
          "coordinates": {
           "latitude": 41.872505,
           "longitude": -87.62482
          }
         },
         "warnings": [],
         "matches": [
          {
           "property_id": "12570",
           "name": "Hilton Chicago",
           "city": "Chicago",
           "address": "720 S Michigan Ave, Chicago, IL",
           "country": "USA",
           "url": "https://www.expedia.com/h12570.Hotel-Information",
           "rank": 0,
           "match_score": 1.0,
           "confidence": "high"
          }
         ],
         "meta": {
          "source": "expedia",
          "matches": 1,
          "selection_method": "name_city_confidence",
          "match_threshold": 0.8,
          "match_margin": 0.12,
          "wire_bytes": 4008,
          "elapsed_s": 0.31,
          "egress_mode": "direct"
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/ota/expedia": {
   "post": {
    "tags": [
     "Expedia"
    ],
    "summary": "Rooms, rate plans and headline for one stay window",
    "description": "Expedia's own rooms and rate plans.\n\nOne request per stay. Each offer has the upstream\nstay `total` (Expedia labels it \"Total with taxes and fees\"), the upstream\n`nightly` price before taxes, `taxes_and_fees` derived from the two (see\nits provenance), cancellation terms read from the policy selector, and\nthe payment model. `available` is false with Expedia's own\n`unavailable_reason` when the stay cannot be booked as asked - a minimum\nstay, for instance. That answer is billed like any other: only a reply\nwith nothing in it is free.\n\nCredits: 8 (failed requests are free)",
    "operationId": "expedia_rates",
    "x-credits": 8,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/ExpediaRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Headline plus rooms and rate plans. `total` is upstream (taxes and fees included); `taxes_and_fees` is derived and says so in its provenance",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ExpediaRatesResponse"
        },
        "example": {
         "search_parameters": {
          "engine": "expedia_property",
          "property_id": "12570",
          "check_in_date": "2029-04-10",
          "check_out_date": "2029-04-11",
          "adults": 2,
          "market": "US",
          "currency": "USD",
          "rooms": true
         },
         "property": {
          "property_id": "12570",
          "total": 475.0,
          "price_per_night": 374.0,
          "basis": "sticky_bar",
          "total_text": "$475",
          "nightly_text": "$374 nightly",
          "currency": "USD",
          "currency_verified": true,
          "available": true,
          "cheapest_total": 475.0,
          "provenance": {
           "schema_version": 1,
           "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
           "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
           "observed_at": "2026-08-07T01:23:45.678Z",
           "source": "expedia_com",
           "source_kind": "ota_offer",
           "collector": "scrapingme.ota.expedia",
           "source_property_id": "12570",
           "requested_market": "US",
           "requested_currency": "USD",
           "returned_currency": "USD",
           "egress_mode": "direct",
           "price_basis": "stay_headline",
           "derivation": "upstream"
          }
         },
         "rooms": [
          {
           "unit_id": "403873",
           "name": "Room, 1 King Bed",
           "cheapest_total": 635.0,
           "offers": [
            {
             "plan_id": "266071241",
             "room_type_id": "403873",
             "total": 635.0,
             "nightly": 509.0,
             "taxes_and_fees": 126.0,
             "currency": "USD",
             "total_text": "$635 total",
             "nightly_text": "$509 nightly",
             "taxes_and_fees_included": true,
             "payment_model": "PAY_NOW",
             "hotel_collect": false,
             "member_only": false,
             "refundable": false,
             "cancellation_text": "Non-Refundable",
             "extras_text": "No extras",
             "strikeout_text": "",
             "inventory_type": "MERCHANT",
             "business_model": "EXPEDIA_COLLECT",
             "messages": [],
             "provenance": {
              "schema_version": 1,
              "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
              "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
              "observed_at": "2026-08-07T01:23:45.678Z",
              "source": "expedia_com",
              "source_kind": "ota_rate_plan",
              "collector": "scrapingme.ota.expedia",
              "source_property_id": "12570",
              "requested_market": "US",
              "requested_currency": "USD",
              "returned_currency": "USD",
              "egress_mode": "direct",
              "price_basis": "stay_total_including_taxes_and_fees",
              "derivation": "upstream",
              "upstream_rate_id": "266071241"
             },
             "taxes_and_fees_provenance": {
              "schema_version": 1,
              "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
              "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
              "observed_at": "2026-08-07T01:23:45.678Z",
              "source": "expedia_com",
              "source_kind": "ota_rate_plan",
              "collector": "scrapingme.ota.expedia",
              "source_property_id": "12570",
              "requested_market": "US",
              "requested_currency": "USD",
              "returned_currency": "USD",
              "egress_mode": "direct",
              "price_basis": "taxes_and_fees_combined",
              "derivation": "total_minus_nightly_times_nights",
              "upstream_rate_id": "266071241"
             }
            },
            {
             "plan_id": "266071239",
             "room_type_id": "403873",
             "total": 742.0,
             "nightly": 599.0,
             "taxes_and_fees": 143.0,
             "currency": "USD",
             "total_text": "$742 total",
             "nightly_text": "$599 nightly",
             "taxes_and_fees_included": true,
             "payment_model": "PAY_LATER",
             "hotel_collect": true,
             "member_only": false,
             "refundable": true,
             "cancellation_text": "Fully refundable before Nov 14",
             "extras_text": "No extras",
             "strikeout_text": "",
             "inventory_type": "DIRECT_AGENCY",
             "business_model": "HOTEL_COLLECT",
             "messages": [],
             "provenance": {
              "schema_version": 1,
              "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
              "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
              "observed_at": "2026-08-07T01:23:45.678Z",
              "source": "expedia_com",
              "source_kind": "ota_rate_plan",
              "collector": "scrapingme.ota.expedia",
              "source_property_id": "12570",
              "requested_market": "US",
              "requested_currency": "USD",
              "returned_currency": "USD",
              "egress_mode": "direct",
              "price_basis": "stay_total_including_taxes_and_fees",
              "derivation": "upstream",
              "upstream_rate_id": "266071239"
             }
            }
           ]
          }
         ],
         "meta": {
          "source": "expedia",
          "nights": 1,
          "wire_bytes": 181597,
          "elapsed_s": 0.62,
          "room_types": 37,
          "offers": 149,
          "egress_mode": "direct",
          "comparable_across_markets": false,
          "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
          "observed_at": "2026-08-07T01:23:45.678Z"
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/ota/vrbo/search": {
   "post": {
    "tags": [
     "Vrbo"
    ],
    "summary": "Vacation-rental listings with stay prices",
    "description": "Search Vrbo by destination and dates.\n\nReturns Vrbo's recommended listings with the numeric `property_id` that\n`POST /v1/ota/vrbo` quotes, the listing id and URL, and Vrbo's own nightly\nand stay prices. One request returns up to 50 listings.\n\nCredits: 1 (failed requests are free)",
    "operationId": "vrbo_search",
    "x-credits": 1,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/VrboSearchRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Vrbo listings with the property id that the quote endpoint takes",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/VrboSearchResponse"
        },
        "example": {
         "search_parameters": {
          "engine": "vrbo_search",
          "destination": "South Lake Tahoe, California",
          "check_in_date": "2029-04-10",
          "check_out_date": "2029-04-13",
          "adults": 2,
          "market": "US",
          "currency": "USD",
          "limit": 10
         },
         "summary": {
          "matched_properties": 359,
          "results_heading": "Search results showing 359 properties in South Lake Tahoe, California"
         },
         "listings": [
          {
           "property_id": "122942416",
           "listing_id": "20218736ha",
           "name": "Tahoe Keys Sunset Reflections",
           "summary": "House · 4 bedrooms · 4 Queen Beds",
           "url": "https://www.vrbo.com/20218736ha",
           "nightly": 462.0,
           "total": 1386.0,
           "currency": "USD",
           "nightly_text": "$462",
           "total_text": "$1,386 for 3 nights",
           "fees_included": true,
           "rank": 0,
           "provenance": {
            "schema_version": 1,
            "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
            "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
            "observed_at": "2026-08-07T01:23:45.678Z",
            "source": "vrbo",
            "source_kind": "ota_search_listing",
            "collector": "scrapingme.ota.vrbo",
            "source_property_id": "122942416",
            "requested_market": "US",
            "requested_currency": "USD",
            "returned_currency": "USD",
            "egress_mode": "direct",
            "price_basis": "stay_total_fees_included",
            "derivation": "upstream"
           }
          }
         ],
         "meta": {
          "source": "vrbo",
          "listings": 1,
          "wire_bytes": 107695,
          "elapsed_s": 0.58,
          "egress_mode": "direct",
          "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
          "observed_at": "2026-08-07T01:23:45.678Z"
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/ota/vrbo": {
   "post": {
    "tags": [
     "Vrbo"
    ],
    "summary": "Stay quote for one vacation rental",
    "description": "A Vrbo stay quote: nightly and total price, fees and payment model.\n\nThe total is Vrbo's own figure and `fees_included` repeats its \"All fees\nincluded\" label; cleaning and service fees and taxes are not itemised by\nVrbo for this request, so they are not invented here. A stay Vrbo\nwill not sell as asked (minimum stay, dates taken) returns\n`available: false` with Vrbo's reason, billed like any other answer.\n\nCredits: 8 (failed requests are free)",
    "operationId": "vrbo_quote",
    "x-credits": 8,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/VrboRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "A Vrbo stay quote. `fees_included` repeats Vrbo's own label; fees and taxes are not itemised",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/VrboQuoteResponse"
        },
        "example": {
         "search_parameters": {
          "engine": "vrbo_property",
          "property_id": "122942416",
          "check_in_date": "2029-04-10",
          "check_out_date": "2029-04-13",
          "adults": 2,
          "market": "US",
          "currency": "USD"
         },
         "property": {
          "property_id": "122942416",
          "total": 1386.0,
          "price_per_night": 462.0,
          "basis": "cheapest_offer",
          "total_text": "$1,386 for 3 nights",
          "nightly_text": "$462",
          "fees_included": true,
          "currency": "USD",
          "currency_verified": true,
          "available": true,
          "payment_model": "PAY_LATER_WITH_DEPOSIT",
          "provenance": {
           "schema_version": 1,
           "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
           "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
           "observed_at": "2026-08-07T01:23:45.678Z",
           "source": "vrbo",
           "source_kind": "ota_offer",
           "collector": "scrapingme.ota.vrbo",
           "source_property_id": "122942416",
           "requested_market": "US",
           "requested_currency": "USD",
           "returned_currency": "USD",
           "egress_mode": "direct",
           "price_basis": "stay_headline",
           "derivation": "upstream"
          }
         },
         "offers": [
          {
           "plan_id": "0000f7528ddb0787463c9be9506a3b5eceb0",
           "room_type_id": "122942416",
           "total": 1386.0,
           "nightly": 462.0,
           "currency": "USD",
           "total_text": "$1,386 for 3 nights",
           "nightly_text": "$462",
           "fees_included": true,
           "payment_model": "PAY_LATER_WITH_DEPOSIT",
           "hotel_collect": true,
           "member_only": false,
           "inventory_type": "VRBO",
           "business_model": "HOTEL_COLLECT",
           "messages": [
            "Reserve now, pay deposit",
            "Your dates are available"
           ],
           "provenance": {
            "schema_version": 1,
            "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
            "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
            "observed_at": "2026-08-07T01:23:45.678Z",
            "source": "vrbo",
            "source_kind": "ota_rate_plan",
            "collector": "scrapingme.ota.vrbo",
            "source_property_id": "122942416",
            "requested_market": "US",
            "requested_currency": "USD",
            "returned_currency": "USD",
            "egress_mode": "direct",
            "price_basis": "stay_total_fees_included",
            "derivation": "upstream",
            "upstream_rate_id": "0000f7528ddb0787463c9be9506a3b5eceb0"
           }
          }
         ],
         "meta": {
          "source": "vrbo",
          "nights": 3,
          "wire_bytes": 8065,
          "listing_resolved": false,
          "elapsed_s": 0.44,
          "egress_mode": "direct",
          "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
          "observed_at": "2026-08-07T01:23:45.678Z"
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/ota/agoda/search": {
   "post": {
    "tags": [
     "Agoda"
    ],
    "summary": "Find an Agoda property id by hotel name",
    "description": "Resolve a hotel name to Agoda's numeric property identifier.\n\nThis uses Agoda's lightweight guest-facing suggestion endpoint. Add `city` to disambiguate common brands,\nthen store `recommended_match.property_id` for room and rate-plan calls.\nIt is null when only weak or ambiguous candidates were found.\n\nCredits: 1 (failed requests are free)",
    "operationId": "agoda_search",
    "x-credits": 1,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/AgodaSearchRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Candidate Agoda numeric property ids, with city-aware ranking",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/AgodaSearchResponse"
        },
        "example": {
         "search_parameters": {
          "engine": "agoda_search",
          "name": "Moxy Boston Downtown",
          "city": "Boston",
          "origin": "US",
          "limit": 5
         },
         "search_status": "matched",
         "recommended_match": {
          "property_id": "8795952",
          "name": "Moxy Boston Downtown",
          "city": "Boston (MA)",
          "country": "US",
          "location": "Boston (MA), United States",
          "rank": 0,
          "score": 1.0,
          "name_score": 1.0,
          "identity_score": 1.0,
          "match_score": 1.0,
          "confidence": "high",
          "city_score": 1.0
         },
         "warnings": [],
         "matches": [
          {
           "property_id": "8795952",
           "name": "Moxy Boston Downtown",
           "city": "Boston (MA)",
           "country": "US",
           "location": "Boston (MA), United States",
           "rank": 0,
           "score": 1.0,
           "name_score": 1.0,
           "identity_score": 1.0,
           "match_score": 1.0,
           "confidence": "high",
           "city_score": 1.0
          }
         ],
         "meta": {
          "source": "agoda",
          "matches": 1,
          "selection_method": "name_city_confidence",
          "match_threshold": 0.8,
          "match_margin": 0.12,
          "wire_bytes": 8144,
          "elapsed_s": 0.221
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/ota/agoda": {
   "post": {
    "tags": [
     "Agoda"
    ],
    "summary": "Rooms and rate plans for one night",
    "description": "Agoda: every room type and rate plan for one stay window.\n\nCredits: 8 (failed requests are free)",
    "operationId": "agoda_rooms",
    "x-credits": 8,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/AgodaRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Agoda rooms and rate plans",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/AgodaRoomsResponse"
        },
        "example": {
         "search_parameters": {
          "engine": "agoda_property",
          "property_id": "8795952",
          "check_in_date": "2029-02-05",
          "check_out_date": "2029-02-06",
          "adults": 2,
          "rooms": 1,
          "currency": "USD"
         },
         "property": {
          "property_id": "8795952",
          "name": "Moxy Boston Downtown",
          "price_per_night": 527.0,
          "currency": "USD",
          "tax_inclusive": true,
          "sold_out": false,
          "rooms": [
           {
            "name": "Center Stage, Guest room, 1 Queen, City view",
            "offers": [
             {
              "price": 527.0,
              "currency": "USD",
              "currency_code": "USD",
              "price_text": "USD 527",
              "tax_inclusive": true,
              "discount": "-29%",
              "free_cancellation": false,
              "provenance": {
               "schema_version": 1,
               "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
               "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
               "observed_at": "2026-08-07T01:23:45.678Z",
               "source": "agoda",
               "source_kind": "ota_rate_plan",
               "collector": "scrapingme.ota.agoda",
               "source_property_id": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
               "requested_market": "US",
               "requested_currency": "USD",
               "returned_currency": "USD",
               "egress_mode": "direct",
               "price_basis": "room_base_before_taxes_and_fees",
               "derivation": "normalized_upstream"
              }
             }
            ]
           }
          ]
         },
         "meta": {
          "source": "agoda",
          "nights": 1,
          "wire_bytes": 117723,
          "elapsed_s": 0.361,
          "room_types": 5,
          "offers": 9,
          "comparable_across_markets": true
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/ota/tripadvisor/search": {
   "post": {
    "tags": [
     "Tripadvisor"
    ],
    "summary": "Find a Tripadvisor locationId by hotel name",
    "description": "**Not available yet.** Tripadvisor name search is not implemented in the current release: this operation always returns `502` with `{\"detail\": \"TripadvisorError\"}` (not charged). Take the `locationId` from the hotel's Tripadvisor URL instead — the digits after `-d` in `/Hotel_Review-g{geoId}-d{locationId}-...` — and pass it to `POST /v1/ota/tripadvisor`. The 200 example below shows the planned response shape.\n\nResolve a hotel name to Tripadvisor's locationId.\n\nTripadvisor uses locationId for both search and availability queries.\nStore `recommended_match.location_id` for pricing calls. It is null when\nonly weak or ambiguous candidates were found.\n\nCredits: 1 (failed requests are free)",
    "operationId": "tripadvisor_search",
    "x-credits": 1,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/TripadvisorSearchRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Tripadvisor location search results with locationId",
      "content": {
       "application/json": {
        "schema": {},
        "example": {
         "query": "Moxy Boston Downtown",
         "matches": [
          {
           "location_id": "97679",
           "title": "Moxy Boston Downtown",
           "secondary_text": "Boston, MA",
           "place_type": "HOTEL",
           "hierarchy": "Massachusetts > Boston"
          }
         ],
         "recommended_match": {
          "location_id": "97679",
          "title": "Moxy Boston Downtown",
          "secondary_text": "Boston, MA",
          "place_type": "HOTEL",
          "hierarchy": "Massachusetts > Boston"
         },
         "wire_bytes": 3245
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/ValidationError"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/ota/tripadvisor": {
   "post": {
    "tags": [
     "Tripadvisor"
    ],
    "summary": "Metasearch prices for one stay window",
    "description": "Tripadvisor metasearch: aggregated offers from multiple providers.\n\nReturns prices from Booking, Hotels.com, Expedia, and other providers as\naggregated by Tripadvisor.\n\nCredits: 8 (failed requests are free)",
    "operationId": "tripadvisor_prices",
    "x-credits": 8,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/TripadvisorRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Metasearch aggregation of provider offers for one stay window",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/TripadvisorPricesResponse"
        },
        "example": {
         "search_parameters": {
          "engine": "tripadvisor_property",
          "location_id": "97679",
          "check_in_date": "2029-02-22",
          "check_out_date": "2029-02-23",
          "nights": 1,
          "adults": 2,
          "rooms": 1,
          "currency": "USD"
         },
         "property": {
          "location_id": "97679",
          "hotel_id": "97679",
          "price_per_night": 150.0,
          "currency": "USD",
          "provenance": {
           "schema_version": 1,
           "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
           "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
           "observed_at": "2026-08-07T01:23:45.678Z",
           "source": "tripadvisor",
           "source_kind": "metasearch",
           "collector": "scrapingme.ota.tripadvisor",
           "source_property_id": "97679",
           "requested_market": null,
           "requested_currency": "USD",
           "returned_currency": "USD",
           "egress_mode": "direct",
           "price_basis": "unknown",
           "derivation": "normalized_upstream"
          }
         },
         "offers": [
          {
           "price": 150.0,
           "currency": "USD",
           "provider_name": "booking.com",
           "provenance": {
            "schema_version": 1,
            "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
            "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
            "observed_at": "2026-08-07T01:23:45.678Z",
            "source": "tripadvisor",
            "source_kind": "metasearch",
            "collector": "scrapingme.ota.tripadvisor",
            "source_property_id": "97679",
            "requested_market": null,
            "requested_currency": "USD",
            "returned_currency": "USD",
            "egress_mode": "direct",
            "price_basis": "unknown",
            "derivation": "normalized_upstream"
           }
          },
          {
           "price": 155.0,
           "currency": "USD",
           "provider_name": "hotels.com",
           "provenance": {
            "schema_version": 1,
            "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
            "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
            "observed_at": "2026-08-07T01:23:45.678Z",
            "source": "tripadvisor",
            "source_kind": "metasearch",
            "collector": "scrapingme.ota.tripadvisor",
            "source_property_id": "97679",
            "requested_market": null,
            "requested_currency": "USD",
            "returned_currency": "USD",
            "egress_mode": "direct",
            "price_basis": "unknown",
            "derivation": "normalized_upstream"
           }
          }
         ],
         "meta": {
          "source": "tripadvisor",
          "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
          "observed_at": "2026-08-07T01:23:45.678Z",
          "nights": 1,
          "wire_bytes": 8456,
          "elapsed_s": 0.342,
          "offers": 2
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/ota/expedia/reviews": {
   "post": {
    "tags": [
     "Expedia"
    ],
    "summary": "Guest reviews for one property, newest first",
    "description": "Expedia guest reviews for one property.\n\nOne POST, no cookies, no browser. Ratings are 0-10 parsed from the\nupstream score label; the \"Verified review\" disclaimer and \"Liked: …\"\nthemes ride in `labels`, exactly as Expedia publishes them. Page by\n`start_index += size`.\n\nCredits: 2 (failed requests are free)",
    "operationId": "expedia_reviews",
    "x-credits": 2,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/ExpediaReviewsRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "One page of Expedia guest reviews with the property's replies",
      "content": {
       "application/json": {
        "schema": {},
        "example": {
         "source": "expedia",
         "property_id": "12570",
         "total": 3324,
         "offset": 0,
         "limit": 10,
         "rating_scale": 10.0,
         "count": 2,
         "reviews": [
          {
           "source": "expedia",
           "review_id": "6aa5f679b71e666498336ee6",
           "rating": 10.0,
           "text": "Great hotel and location!",
           "date": "2029-02-04",
           "author": "Rebecca",
           "management_reply": "Dear Valued Guest, it's wonderful to receive your outstanding rating of Hilton Chicago!",
           "language": "en_CA",
           "helpful_votes": 0,
           "labels": [
            "Liked: Cleanliness, staff & service, amenities, property conditions & facilities",
            "Verified review"
           ],
           "stay_info": "Stayed 4 nights in Sep 2026"
          },
          {
           "source": "expedia",
           "review_id": "f2b3a1d0c5e266498336ee7",
           "rating": 10.0,
           "text": "Beautiful historic property, comfortable beds.",
           "date": "2029-01-11",
           "author": "Jazmin",
           "language": "en_US",
           "labels": [
            "Liked: Cleanliness",
            "Verified review"
           ],
           "stay_info": "Stayed 3 nights in Aug 2026"
          }
         ],
         "provenance": {
          "schema_version": 1,
          "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
          "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
          "observed_at": "2026-08-07T01:23:45.678Z",
          "source": "google_hotels_calendar",
          "source_kind": "calendar",
          "collector": "scrapingme.google_calendar",
          "source_property_id": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
          "requested_market": "US",
          "requested_currency": "USD",
          "returned_currency": "USD",
          "egress_mode": "direct",
          "price_basis": "room_base_before_taxes_and_fees",
          "derivation": "normalized_upstream"
         },
         "wire_bytes": 19859,
         "elapsed_s": 0.471,
         "egress_mode": "direct",
         "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
         "observed_at": "2026-08-07T01:23:45.678Z",
         "warnings": []
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/ota/hotels/reviews": {
   "post": {
    "tags": [
     "Hotels.com"
    ],
    "summary": "Guest reviews for one property, newest first",
    "description": "Hotels.com guest reviews via the site's own registered reviews query.\n\nThe same registered query Expedia answers, POSTed to the Hotels.com\nhost with the Hotels.com point-of-sale. One POST, no browser; page by\n`start_index += size`.\n\nCredits: 2 (failed requests are free)",
    "operationId": "hotels_reviews",
    "x-credits": 2,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/HotelsReviewsRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Google Hotels guest reviews, aggregated by provider with each row's own rating scale",
      "content": {
       "application/json": {
        "schema": {},
        "example": {
         "source": "google",
         "property_id": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
         "offset": 0,
         "limit": 10,
         "next_page_token": "CjEIARIpCgoAP7_LACnN____EhAgaDet6skqGaNbIqMAAAAAGgn92PwCYGHGd2UYACIA:10",
         "count": 3,
         "reviews": [
          {
           "source": "google",
           "review_id": "Ci9DQUlRQUNvZENodHljRjlvT25SZmJHOVBVMHh0VTJkSlNsa3lMVmMxZVMxMWVtYxAB",
           "rating": 3.0,
           "text": "We stayed here for one night during a trip to Chicago, and overall, the hotel served its purpose, but I don't think we'd book here again.",
           "date": "a month ago",
           "author": "Amber S",
           "management_reply": "Dear Amber, thank you for choosing us for your stay.",
           "provider": "Google"
          },
          {
           "source": "google",
           "review_id": "ChdDSUhNMG9nS0VQLXBpdUc4aE5peXZ3RRAB",
           "rating": 4.0,
           "text": "It is a magnificent old building with spacious rooms.",
           "date": "4 weeks ago",
           "author": "adflanagan13",
           "url": "https://www.tripadvisor.com/ShowUserReviews-g35805-d87590-r1075812531",
           "provider": "Tripadvisor"
          },
          {
           "source": "google",
           "review_id": "ChdDSUhNMG9nS0VJYVBqUG1LMGJmZzBnRRAB",
           "rating": 9.0,
           "text": "The location, having access to the pool and fitness center, was just lovely.",
           "date": "5 months ago",
           "author": "Ronald",
           "provider": "Priceline"
          }
         ],
         "provenance": {
          "schema_version": 1,
          "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
          "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
          "observed_at": "2026-08-07T01:23:45.678Z",
          "source": "google_hotels_calendar",
          "source_kind": "calendar",
          "collector": "scrapingme.google_calendar",
          "source_property_id": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
          "requested_market": "US",
          "requested_currency": "USD",
          "returned_currency": "USD",
          "egress_mode": "direct",
          "price_basis": "room_base_before_taxes_and_fees",
          "derivation": "normalized_upstream"
         },
         "wire_bytes": 40175,
         "elapsed_s": 0.388,
         "egress_mode": "direct",
         "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
         "observed_at": "2026-08-07T01:23:45.678Z",
         "warnings": []
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/ota/tripadvisor/reviews": {
   "post": {
    "tags": [
     "Tripadvisor"
    ],
    "summary": "Guest reviews, newest first as the site orders them",
    "description": "Tripadvisor guest reviews for one locationId.\n\nOne persisted-query request through the same session warmup pricing\nuses. Ratings are 0-5; each review keeps the author, stay type, stay\ndate, management reply and language the site publishes. Page by\n`offset += limit`.\n\nCredits: 2 (failed requests are free)",
    "operationId": "tripadvisor_reviews",
    "x-credits": 2,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/TripadvisorReviewsRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "One page of Tripadvisor guest reviews, newest first",
      "content": {
       "application/json": {
        "schema": {},
        "example": {
         "source": "tripadvisor",
         "property_id": "208453",
         "total": 9023,
         "offset": 0,
         "limit": 10,
         "rating_scale": 5.0,
         "count": 2,
         "reviews": [
          {
           "source": "tripadvisor",
           "review_id": "1079997723",
           "rating": 5.0,
           "title": "Hilton times square fab hotel",
           "text": "if you are coming to New York hilton times square is the best for location . large spacious rooms great service , friendly staff , highly recommend",
           "date": "2029-02-21",
           "author": "Sue B",
           "trip_type": "FAMILY",
           "stay_date": "2029-02-21",
           "management_reply": "Dear Gayatri, it's a privilege to learn about your memorable stay with us!",
           "language": "en",
           "helpful_votes": 0,
           "url": "/ShowUserReviews-g60763-d208453-r1079997723-Hilton_New_York_Times_Square-New_York_City_New_York.html"
          },
          {
           "source": "tripadvisor",
           "review_id": "1076579565",
           "rating": 4.0,
           "title": "Good location",
           "text": "Rooms were comfortable, staff friendly.",
           "date": "2029-02-19",
           "author": "Nina",
           "trip_type": "BUSINESS",
           "stay_date": "2029-02-19",
           "language": "en",
           "helpful_votes": 2,
           "url": "/ShowUserReviews-g60763-d208453-r1076579565-Hilton_New_York_Times_Square-New_York_City_New_York.html"
          }
         ],
         "provenance": {
          "schema_version": 1,
          "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
          "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
          "observed_at": "2026-08-07T01:23:45.678Z",
          "source": "google_hotels_calendar",
          "source_kind": "calendar",
          "collector": "scrapingme.google_calendar",
          "source_property_id": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
          "requested_market": "US",
          "requested_currency": "USD",
          "returned_currency": "USD",
          "egress_mode": "direct",
          "price_basis": "room_base_before_taxes_and_fees",
          "derivation": "normalized_upstream"
         },
         "wire_bytes": 15619,
         "elapsed_s": 0.412,
         "egress_mode": "direct",
         "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
         "observed_at": "2026-08-07T01:23:45.678Z",
         "warnings": []
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/ota/booking/reviews": {
   "post": {
    "tags": [
     "Booking.com"
    ],
    "summary": "Guest reviews from the property page's own query document",
    "description": "Booking.com guest reviews for one property slug.\n\nThe bootstrap is the same WAF-cleared page fetch the calendar uses; it\nyields the CSRF token plus the numeric ids the reviews query needs.\nRatings are 0-10; each review keeps the guest, their country, the room\ntype, the stay dates, and the property's reply. `text` filters by\nkeyword server-side. That answer is billed like any other: only a reply\nwith nothing in it is free.\n\nCredits: 2 (failed requests are free)",
    "operationId": "booking_reviews",
    "x-credits": 2,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/BookingReviewsRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "One page of Booking.com guest reviews with the property's replies",
      "content": {
       "application/json": {
        "schema": {},
        "example": {
         "source": "booking",
         "pagename": "newbury-guest-house",
         "hotel_id": 236725,
         "ufi": 20061717,
         "country": "us",
         "total": 523,
         "skip": 0,
         "limit": 10,
         "sort": "MOST_RELEVANT",
         "rating_scale": 10.0,
         "count": 2,
         "reviews": [
          {
           "source": "booking",
           "review_id": "48b4dc6c098c149e",
           "rating": 8.0,
           "title": "Good value, warm and inviting staff and very neat and clean rooms.",
           "text": "No breakfast but coffee/tea in lobby, location very good-on fanciest street in Boston and room was clean neat and comfortable.",
           "date": "2026-10-15",
           "author": "Anna",
           "author_country": "United States",
           "stay_date": "2026-10-15",
           "room_type": "Deluxe Room",
           "management_reply": "Hello Anna, we are pleased that you enjoyed your stay. We value your kind words and feedback.",
           "language": "xu",
           "helpful_votes": 0,
           "url": "48b4dc6c098c149e"
          },
          {
           "source": "booking",
           "review_id": "23d02bc7e442bfa9",
           "rating": 10.0,
           "title": "I will be returning to this hotel",
           "text": "This location was excellent. close to food and shops.",
           "date": "2027-04-02",
           "author": "Deborah",
           "author_country": "United States",
           "stay_date": "2027-03-31",
           "room_type": "Luxury Double",
           "language": "xu",
           "helpful_votes": 0,
           "url": "23d02bc7e442bfa9"
          }
         ],
         "rating_scores": [
          {
           "name": "Staff",
           "value": 9.3,
           "count": 258
          }
         ],
         "sorters": [
          {
           "value": "MOST_RELEVANT",
           "name": "Most relevant"
          },
          {
           "value": "NEWEST_FIRST",
           "name": "Newest first"
          },
          {
           "value": "OLDEST_FIRST",
           "name": "Oldest first"
          }
         ],
         "provenance": {
          "schema_version": 1,
          "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
          "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
          "observed_at": "2026-08-07T01:23:45.678Z",
          "source": "google_hotels_calendar",
          "source_kind": "calendar",
          "collector": "scrapingme.google_calendar",
          "source_property_id": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
          "requested_market": "US",
          "requested_currency": "USD",
          "returned_currency": "USD",
          "egress_mode": "direct",
          "price_basis": "room_base_before_taxes_and_fees",
          "derivation": "normalized_upstream"
         },
         "wire_bytes": 14973,
         "elapsed_s": 0.521,
         "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
         "observed_at": "2026-08-07T01:23:45.678Z"
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/ota/hostelworld": {
   "post": {
    "tags": [
     "Hostelworld"
    ],
    "summary": "Rooms and rate plans for one stay window",
    "description": "Hostelworld: every dorm bed and private room with rate plans.\n\nCurrency is NOT selectable — Hostelworld returns the property's native\ncurrency (typically GBP for UK hostels). Per-bed pricing for dorms,\nper-room pricing for privates.\n\nCredits: 8 (failed requests are free)",
    "operationId": "hostelworld_rooms",
    "x-credits": 8,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/HostelworldRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Hostelworld rooms and rate plans",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/HostelworldResponse"
        },
        "example": {
         "search_parameters": {
          "engine": "hostelworld_property",
          "property_id": "88047",
          "check_in_date": "2029-03-03",
          "check_out_date": "2029-03-04",
          "guests": 1
         },
         "property": {
          "property_id": "88047",
          "price_per_night": 52.9,
          "currency": "GBP",
          "sold_out": false,
          "deposit_percentage": 15,
          "free_cancellation_available": true,
          "provenance": {
           "schema_version": 1,
           "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
           "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
           "observed_at": "2026-08-07T01:23:45.678Z",
           "source": "hostelworld",
           "source_kind": "ota_rate_plan",
           "collector": "scrapingme.ota.hostelworld",
           "source_property_id": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
           "requested_market": "US",
           "requested_currency": "USD",
           "returned_currency": "USD",
           "egress_mode": "direct",
           "price_basis": "room_base_before_taxes_and_fees",
           "derivation": "normalized_upstream"
          },
          "rooms": [
           {
            "room_id": 383266,
            "name": "8 Bed Mixed Dorm Ensuite",
            "room_type": "dorm",
            "basic_type": "Mixed Dorm",
            "capacity": 8,
            "ensuite": true,
            "beds_available": 42,
            "rate_plans": [
             {
              "rate_plan_id": 151291,
              "rate_plan_type": "STANDARD",
              "payment_procedure": "depositPayable",
              "payment_label": "Deposit only",
              "is_default": true,
              "price": 52.9,
              "original_price": 66.13,
              "currency": "GBP",
              "min_nights": 1,
              "restrictions": [],
              "promotions": {
               "discount": "20.00"
              },
              "provenance": {
               "schema_version": 1,
               "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
               "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
               "observed_at": "2026-08-07T01:23:45.678Z",
               "source": "hostelworld",
               "source_kind": "ota_rate_plan",
               "collector": "scrapingme.ota.hostelworld",
               "source_property_id": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
               "requested_market": "US",
               "requested_currency": "USD",
               "returned_currency": "USD",
               "egress_mode": "direct",
               "price_basis": "room_base_before_taxes_and_fees",
               "derivation": "normalized_upstream"
              }
             }
            ]
           }
          ]
         },
         "meta": {
          "source": "hostelworld",
          "nights": 1,
          "wire_bytes": 49946,
          "elapsed_s": 0.284,
          "dorms_count": 8,
          "privates_count": 4,
          "comparable_across_markets": false
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/ota/booking/rooms": {
   "post": {
    "tags": [
     "Booking.com"
    ],
    "summary": "Room types and rate plans",
    "description": "Booking.com room types and rate plans for one stay window.\n\nFills the gap left by `/v1/rooms`: Google's entity page frequently carries\nno room detail for the Booking.com row, so this goes to Booking directly.\n\nPrices come from the property page's room grid, enriched with room\nsize and occupancy when Booking.com provides them.\n\nCredits: 8 (failed requests are free)",
    "operationId": "booking_rooms",
    "x-credits": 8,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/BookingRoomsRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Room types with both rate plans — the cheap non-refundable one and the dearer free-cancellation one",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/BookingRoomsResponse"
        },
        "example": {
         "pagename": "moxy-boston-downtown",
         "hotel_id": "5375786",
         "property_name": "Moxy Boston Downtown",
         "check_in": "2029-02-05",
         "check_out": "2029-02-06",
         "nights": 1,
         "currency": "USD",
         "sold_out": false,
         "rendered": true,
         "catalogue_from_graphql": false,
         "cheapest_rate": 250.0,
         "wire_bytes": 2136057,
         "rooms": [
          {
           "name": "Center Stage, Guest room, 1 Queen, City view",
           "room_id": "537578602",
           "beds": "1 queen bed",
           "room_size": 22.0,
           "max_persons": 2,
           "cheapest_rate": 250.0,
           "rate_plans": [
            {
             "block_id": "537578602_191393531_0_42_0",
             "price": 250.0,
             "currency": "USD",
             "guests": 2,
             "free_cancellation": false,
             "no_prepayment": false,
             "breakfast_included": false
            },
            {
             "block_id": "537578602_246436396_0_42_0",
             "price": 269.0,
             "currency": "USD",
             "guests": 2,
             "free_cancellation": true,
             "no_prepayment": true,
             "breakfast_included": false
            }
           ]
          }
         ]
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/ValidationError"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/ota/hotels/rooms": {
   "post": {
    "tags": [
     "Hotels.com"
    ],
    "summary": "Room types and rate plans",
    "description": "Hotels.com room types and rate plans for one stay window.\n\nOne request: the same document as\n`/v1/ota/hotels` with the room grid included. Each rate plan keeps its\n`price` (the card's lead price; on the US and DE points-of-sale the stay\ntotal including taxes and fees) and adds the labelled `total` and\n`nightly`, a derived `taxes_and_fees`, the payment model and the\ninventory source.\n\n~100-200 KB against ~6 KB for the headline price, so use it on the dates\nthat matter rather than sweeping a horizon.\n\nCredits: 8 (failed requests are free)",
    "operationId": "hotels_rooms",
    "x-credits": 8,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/HotelsRoomsRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Room types with rate plans, measured on www.hotels.com (Hilton Chicago, one night). `price` is the card's lead price - here the stay total including taxes and fees - and `total`/`nightly` are the labelled figures. A plan sold pay-now and pay-at-property is two rows",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/HotelsRoomsResponse"
        },
        "example": {
         "property_id": "12570",
         "market": "US",
         "check_in": "2029-04-10",
         "check_out": "2029-04-11",
         "nights": 1,
         "currency": "USD",
         "requested_currency": "USD",
         "currency_verified": true,
         "available": true,
         "sold_out": false,
         "cheapest_rate": 475.0,
         "wire_bytes": 181614,
         "egress_mode": "direct",
         "rooms": [
          {
           "name": "Room, 2 Double Beds",
           "unit_id": "16572",
           "cheapest_rate": 635.0,
           "rate_plans": [
            {
             "plan_id": "266071193",
             "price": 635.0,
             "price_text": "$635 total",
             "currency": "USD",
             "refundable": false,
             "refundable_until": "",
             "pay_now": true,
             "provenance": {
              "schema_version": 1,
              "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
              "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
              "observed_at": "2026-08-07T01:23:45.678Z",
              "source": "hotels_com",
              "source_kind": "ota_rate_plan",
              "collector": "scrapingme.ota.hotels_rooms",
              "source_property_id": "12570",
              "requested_market": "US",
              "requested_currency": "USD",
              "returned_currency": "USD",
              "egress_mode": "direct",
              "price_basis": "stay_rate_plan",
              "derivation": "upstream",
              "upstream_rate_id": "266071193"
             },
             "room_type_id": "16572",
             "payment_model": "PAY_NOW",
             "hotel_collect": false,
             "total": 635.0,
             "nightly": 509.0,
             "taxes_and_fees": 126.0,
             "taxes_and_fees_provenance": {
              "schema_version": 1,
              "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
              "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
              "observed_at": "2026-08-07T01:23:45.678Z",
              "source": "hotels_com",
              "source_kind": "ota_rate_plan",
              "collector": "scrapingme.ota.hotels_rooms",
              "source_property_id": "12570",
              "requested_market": "US",
              "requested_currency": "USD",
              "returned_currency": "USD",
              "egress_mode": "direct",
              "price_basis": "taxes_and_fees_combined",
              "derivation": "total_minus_nightly_times_nights",
              "upstream_rate_id": "266071193"
             },
             "total_text": "$635 total",
             "nightly_text": "$509 nightly",
             "taxes_and_fees_included": true,
             "cancellation_text": "Non-Refundable",
             "extras_text": "No extras",
             "member_only": false,
             "inventory_type": "MERCHANT",
             "business_model": "EXPEDIA_COLLECT"
            },
            {
             "plan_id": "266071191",
             "price": 742.0,
             "price_text": "$742 total",
             "currency": "USD",
             "refundable": true,
             "refundable_until": "Nov 14",
             "pay_now": false,
             "room_type_id": "16572",
             "payment_model": "PAY_LATER",
             "hotel_collect": true,
             "total": 742.0,
             "nightly": 599.0,
             "taxes_and_fees": 143.0,
             "total_text": "$742 total",
             "nightly_text": "$599 nightly",
             "taxes_and_fees_included": true,
             "cancellation_text": "Fully refundable before Nov 14",
             "extras_text": "No extras",
             "member_only": false,
             "inventory_type": "DIRECT_AGENCY",
             "business_model": "HOTEL_COLLECT"
            }
           ]
          },
          {
           "name": "Suite, Multiple Beds, Non Smoking",
           "unit_id": "325392434",
           "rate_plans": []
          }
         ]
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/ValidationError"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/ota/compare": {
   "post": {
    "tags": [
     "Cross-source"
    ],
    "summary": "Rate parity across Booking, Hotels.com, Agoda and Expedia",
    "description": "Fan out across every source given an identifier.\n\nFail-soft per source: this returns 200 with per-source status even when one\nOTA is blocked, because losing three good answers to one bad one is worse\nthan a partial result the caller can see. `comparison.comparable` is false\nfor a single priced source or mixed currencies; mixed-currency minima and\nspreads are not calculated.\n\nCredits: 20 (failed requests are free)",
    "operationId": "ota_compare",
    "x-credits": 20,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CompareRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "One night per source. Fail-soft: a blocked OTA is a row with a status",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/CompareResponse"
        },
        "example": {
         "search_parameters": {
          "engine": "ota_compare",
          "check_in_date": "2029-02-05",
          "check_out_date": "2029-02-06",
          "adults": 2,
          "currency": "USD",
          "booking_pagename": "moxy-boston-downtown",
          "agoda_property_id": "8795952"
         },
         "comparison": {
          "status": "comparable",
          "comparable": true,
          "identifiers": {
           "booking": "moxy-boston-downtown",
           "agoda": "8795952"
          },
          "lowest_price": 285.0,
          "lowest_source": "booking",
          "spread": 47.0,
          "prices": {
           "booking": 285.0,
           "agoda": 332.0
          },
          "currencies": {
           "booking": "USD",
           "agoda": "USD"
          },
          "price_provenance": {},
          "reason": "Sources price on different bases (booking_display_average, total_including_taxes_and_fees); the headline minimum mixes them. Compare within `by_price_basis`.",
          "price_basis_consistent": false,
          "by_price_basis": {
           "booking_display_average": {
            "sources": [
             "booking"
            ],
            "currencies": [
             "USD"
            ],
            "lowest_source": "booking",
            "lowest_price_per_night": 285.0
           },
           "total_including_taxes_and_fees": {
            "sources": [
             "agoda"
            ],
            "currencies": [
             "USD"
            ],
            "lowest_source": "agoda",
            "lowest_price_per_night": 332.0
           }
          }
         },
         "sources": {
          "booking": {
           "status": "ok",
           "price_per_night": 285.0,
           "currency": "USD",
           "price_basis": "booking_display_average"
          },
          "agoda": {
           "status": "ok",
           "price_per_night": 332.0,
           "currency": "USD",
           "price_basis": "total_including_taxes_and_fees"
          }
         },
         "meta": {
          "requested": 2,
          "ok": 2,
          "elapsed_s": 15.89
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/official/engines": {
   "get": {
    "tags": [
     "Official site"
    ],
    "summary": "Supported booking engines and their cost",
    "description": "Which booking engines can be scraped, and what each costs.\n\nPublished because the spread is large — 0.2 s and no browser for\nSiteMinder against ~7 s and a browser per query for DerbySoft — and a\ncaller batching a sweep should be able to plan around it.\n\nCredits: 0 (failed requests are free)",
    "operationId": "official_engines",
    "x-credits": 0,
    "responses": {
     "200": {
      "description": "Booking engines the detector can route to, with browser cost. `identified_only` are active gaps; `retired` are historical products with no live flow",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/OfficialEnginesResponse"
        },
        "example": {
         "extractable": {
          "accor": {
           "browser": null,
           "cost_s": 0.5
          },
          "bookcore": {
           "browser": null,
           "cost_s": 1.0
          },
          "channex": {
           "browser": null,
           "cost_s": 0.5
          },
          "brand_choice": {
           "browser": "every query",
           "cost_s": 9.0
          },
          "derbysoft": {
           "browser": "every query",
           "cost_s": 7.0
          },
          "evt": {
           "browser": "every query",
           "cost_s": 8.0
          },
          "guestline": {
           "browser": null,
           "cost_s": 0.5
          },
          "brand_hilton": {
           "browser": "every query",
           "cost_s": 8.0
          },
          "brand_ihg": {
           "browser": null,
           "cost_s": 1.0
          },
          "ireshotels": {
           "browser": null,
           "cost_s": 1.0
          },
          "cloudbeds": {
           "browser": null,
           "cost_s": 1.5
          },
          "d_edge": {
           "browser": "every query",
           "cost_s": 8.0
          },
          "siteminder": {
           "browser": null,
           "cost_s": 0.2
          },
          "seekda": {
           "browser": null,
           "cost_s": 1.0
          },
          "minor": {
           "browser": null,
           "cost_s": 1.0
          },
          "newbook": {
           "browser": null,
           "cost_s": 5.0
          },
          "pointa": {
           "browser": null,
           "cost_s": 1.0
          },
          "profitroom": {
           "browser": null,
           "cost_s": 2.5
          },
          "mirai": {
           "browser": null,
           "cost_s": 1.0
          },
          "simplebooking": {
           "browser": null,
           "cost_s": 1.0
          },
          "resnexus": {
           "browser": "every query",
           "cost_s": 7.0
          },
          "ihotelier": {
           "browser": "once per token (hours)",
           "cost_s": 0.3
          },
          "innroad": {
           "browser": "once per session",
           "cost_s": 1.5
          },
          "langham": {
           "browser": null,
           "cost_s": 1.0
          },
          "marriott": {
           "browser": "once per session",
           "cost_s": 0.5
          },
          "mews": {
           "browser": null,
           "cost_s": 1.5
          },
          "rmscloud": {
           "browser": null,
           "cost_s": 1.0
          },
          "thinkreservations": {
           "browser": null,
           "cost_s": 0.5
          },
          "synxis": {
           "browser": "once per session",
           "cost_s": 0.7
          },
          "webrezpro": {
           "browser": "once per session",
           "cost_s": 1.0
          },
          "brand_wyndham": {
           "browser": "every query",
           "cost_s": 7.0
          }
         },
         "identified_only": [],
         "retired": [
          "bookingcom_bs"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     }
    }
   }
  },
  "/v1/official": {
   "post": {
    "tags": [
     "Official site"
    ],
    "summary": "Rates from the hotel's own booking engine",
    "description": "Rates from the hotel's own booking engine.\n\nThe hotel website is resolved to its booking page, then its booking engine is\ndetected automatically. The caller never chooses a vendor.\n\nCredits: 4 (failed requests are free)",
    "operationId": "official_rates",
    "x-credits": 4,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/OfficialRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Normalised public and member rates from the detected booking engine",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/OfficialResponse"
        },
        "example": {
         "search_parameters": {
          "engine": "official_marriott",
          "source_url": "https://www.marriott.com/en-us/hotels/yyzrz-the-ritz-carlton-toronto/overview/",
          "booking_url": "https://www.marriott.com/en-us/hotels/yyzrz-the-ritz-carlton-toronto/overview/",
          "check_in_date": "2029-02-05",
          "check_out_date": "2029-02-06",
          "adults": 2,
          "currency": "CAD"
         },
         "engine": "marriott",
         "source_url": "https://www.marriott.com/en-us/hotels/yyzrz-the-ritz-carlton-toronto/overview/",
         "booking_url": "https://www.marriott.com/en-us/hotels/yyzrz-the-ritz-carlton-toronto/overview/",
         "detected_by": "url",
         "discovery_pages": 0,
         "wrapper_resolutions": 0,
         "discovery_cache_hit": false,
         "discovery_elapsed_s": 0.001,
         "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
         "observed_at": "2026-08-07T01:23:45.678Z",
         "property_ref": "YYZRZ",
         "check_in": "2029-02-05",
         "check_out": "2029-02-06",
         "nights": 1,
         "currency": "CAD",
         "sold_out": false,
         "cheapest_rate": 690.0,
         "cheapest_member_rate": 655.5,
         "member_rates_returned": 1,
         "rooms_returned": 1,
         "used_browser": false,
         "elapsed_s": 0.71,
         "rooms": [
          {
           "name": "Deluxe King",
           "code": "GENR",
           "max_occupancy": 2,
           "quantity": 3,
           "available": true,
           "cheapest_rate": 690.0,
           "rates": [
            {
             "price": 690.0,
             "price_total": 779.7,
             "currency": "CAD",
             "rate_plan": "Flexible",
             "tax_inclusive": true,
             "access_type": "public",
             "is_discounted": false,
             "provenance": {
              "schema_version": 1,
              "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
              "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
              "observed_at": "2026-08-07T01:23:45.678Z",
              "source": "official_marriott",
              "source_kind": "official",
              "collector": "scrapingme.official.marriott",
              "source_property_id": "YYZRZ",
              "requested_market": "US",
              "requested_currency": "USD",
              "returned_currency": "USD",
              "egress_mode": "direct",
              "price_basis": "room_base_before_taxes_and_fees",
              "derivation": "normalized_upstream"
             }
            },
            {
             "price": 655.5,
             "price_total": 740.72,
             "original_price": 690.0,
             "currency": "CAD",
             "rate_plan": "Marriott Bonvoy Member",
             "tax_inclusive": false,
             "access_type": "member",
             "is_discounted": true
            }
           ]
          }
         ]
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/serp/airbnb": {
   "post": {
    "tags": [
     "Airbnb"
    ],
    "summary": "Airbnb search, SearchAPI-compatible",
    "description": "Search Airbnb with SearchAPI's request names and response hierarchy.\n\nEach call runs one live Airbnb search. Use\n`next_page_token` from the response for the next page. The same engine is\nalso available at SearchAPI's GET-style `/api/v1/search?engine=airbnb`.\n\nCredits: 8 (failed requests are free)",
    "operationId": "serp_airbnb",
    "x-credits": 8,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/AirbnbSearchRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "SearchAPI-compatible Airbnb destination results with live prices",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/AirbnbSearchResponse"
        },
        "example": {
         "search_metadata": {
          "id": "search_2af4914e869a4a36958659ef",
          "status": "Success",
          "created_at": "2026-08-06T18:46:11+00:00",
          "request_time_taken": 1.3,
          "parsing_time_taken": 0.02,
          "total_time_taken": 1.32,
          "request_url": "https://www.airbnb.ca/s/Toronto/homes?...",
          "wire_bytes": 918246
         },
         "search_parameters": {
          "engine": "airbnb",
          "airbnb_domain": "airbnb.ca",
          "currency": "CAD",
          "q": "Toronto",
          "check_in_date": "2029-02-01",
          "check_out_date": "2029-02-03",
          "adults": "2",
          "include_taxes": "true"
         },
         "search_information": {
          "query_displayed": "Homes in Toronto, Canada",
          "results": "Over 1,000 homes in Toronto",
          "check_in_date": "2029-02-01",
          "check_out_date": "2029-02-03",
          "adults": 2,
          "guests": "2 guests"
         },
         "properties": [
          {
           "position": 1,
           "id": "734254017349424949",
           "title": "Chic Studio w Balcony Fast WiFi by Yonge-Dundas",
           "description": "Condo in Toronto",
           "link": "https://www.airbnb.ca/rooms/734254017349424949",
           "booking_link": "https://www.airbnb.ca/rooms/734254017349424949?check_in=2026-09-10&check_out=2026-09-12&adults=2&children=0&infants=0&pets=0",
           "booking_token": "eyJjaGVja19pbiI6IjIwMjYtMDktMTAiLCJwcm9wZXJ0eV9pZCI6IjczNDI1NDAxNzM0OTQyNDk0OSJ9",
           "rating": 4.96,
           "reviews": 166,
           "price": {
            "total_price": "$737 CAD",
            "extracted_total_price": 737,
            "total_with_taxes": "$737 CAD",
            "extracted_total_with_taxes": 737,
            "qualifier": "for 2 nights",
            "extracted_qualifier": 2,
            "price_per_qualifier": "2 nights x $310.00 CAD",
            "extracted_price_per_qualifier": 310,
            "breakdown": [
             {
              "description": "2 nights x $310.00 CAD",
              "price": "$620.00 CAD",
              "extracted_price": 620
             },
             {
              "description": "Taxes",
              "price": "$117.00 CAD",
              "extracted_price": 117
             }
            ]
           },
           "check_in_date": "2029-02-01",
           "check_out_date": "2029-02-03",
           "time_period": "Sep 10 – 12",
           "accommodations": [
            "1 bedroom",
            "1 queen bed",
            "1 bath"
           ],
           "gps_coordinates": {
            "latitude": 43.654,
            "longitude": -79.38
           },
           "has_free_cancellation": true,
           "badges": [
            "Guest favourite"
           ],
           "images": [
            "https://a0.muscache.com/im/pictures/example.jpeg"
           ]
          }
         ],
         "pagination": {
          "next_page_token": "eyJzZWN0aW9uX29mZnNldCI6MH0="
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/api/v1/search": {
   "get": {
    "tags": [
     "Airbnb"
    ],
    "summary": "SearchAPI GET alias for engine=airbnb",
    "description": "Drop-in GET endpoint for existing SearchAPI Airbnb integrations.\n\nKeep ``engine=airbnb``, every existing query parameter and either the\n``api_key`` query credential or Bearer token; only replace the origin.\n\nCredits: 8 (failed requests are free)",
    "operationId": "searchapi_airbnb_get",
    "x-credits": 8,
    "parameters": [
     {
      "name": "engine",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "description": "Must be `airbnb`.",
       "enum": [
        "airbnb"
       ],
       "default": "airbnb",
       "title": "Engine"
      },
      "description": "Must be `airbnb`."
     },
     {
      "name": "q",
      "in": "query",
      "required": false,
      "schema": {
       "anyOf": [
        {
         "type": "string"
        },
        {
         "type": "null"
        }
       ],
       "description": "Destination text. Required unless `bounding_box` is supplied.",
       "examples": [
        "Toronto"
       ],
       "title": "Q"
      },
      "description": "Destination text. Required unless `bounding_box` is supplied."
     },
     {
      "name": "bounding_box",
      "in": "query",
      "required": false,
      "schema": {
       "anyOf": [
        {
         "type": "string"
        },
        {
         "type": "null"
        }
       ],
       "description": "Map bounds as `[[ne_lat,ne_lng],[sw_lat,sw_lng]]`; takes precedence over `q`.",
       "examples": [
        "[[43.72,-79.27],[43.62,-79.49]]"
       ],
       "title": "Bounding Box"
      },
      "description": "Map bounds as `[[ne_lat,ne_lng],[sw_lat,sw_lng]]`; takes precedence over `q`."
     },
     {
      "name": "airbnb_domain",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "description": "Country/language Airbnb host.",
       "examples": [
        "airbnb.ca"
       ],
       "enum": [
        "airbnb.ae",
        "airbnb.am",
        "airbnb.at",
        "airbnb.az",
        "airbnb.ba",
        "airbnb.be",
        "airbnb.ca",
        "airbnb.cat",
        "airbnb.ch",
        "airbnb.cl",
        "airbnb.cn",
        "airbnb.co.cr",
        "airbnb.co.id",
        "airbnb.co.in",
        "airbnb.co.kr",
        "airbnb.co.nz",
        "airbnb.co.uk",
        "airbnb.co.ve",
        "airbnb.com",
        "airbnb.com.ar",
        "airbnb.com.au",
        "airbnb.com.bo",
        "airbnb.com.br",
        "airbnb.com.bz",
        "airbnb.com.co",
        "airbnb.com.ec",
        "airbnb.com.ee",
        "airbnb.com.gt",
        "airbnb.com.hk",
        "airbnb.com.hn",
        "airbnb.com.my",
        "airbnb.com.ni",
        "airbnb.com.pa",
        "airbnb.com.pe",
        "airbnb.com.ph",
        "airbnb.com.py",
        "airbnb.com.ro",
        "airbnb.com.sg",
        "airbnb.com.sv",
        "airbnb.com.tr",
        "airbnb.com.tw",
        "airbnb.com.ua",
        "airbnb.com.vn",
        "airbnb.cz",
        "airbnb.de",
        "airbnb.dk",
        "airbnb.es",
        "airbnb.fi",
        "airbnb.fr",
        "airbnb.gr",
        "airbnb.gy",
        "airbnb.hu",
        "airbnb.ie",
        "airbnb.is",
        "airbnb.it",
        "airbnb.jp",
        "airbnb.lt",
        "airbnb.lu",
        "airbnb.lv",
        "airbnb.me",
        "airbnb.mx",
        "airbnb.nl",
        "airbnb.no",
        "airbnb.pl",
        "airbnb.pt",
        "airbnb.rs",
        "airbnb.ru",
        "airbnb.se",
        "airbnb.si",
        "ar.airbnb.com",
        "bg.airbnb.com",
        "de.airbnb.lu",
        "es.airbnb.com",
        "fr.airbnb.be",
        "fr.airbnb.ca",
        "fr.airbnb.ch",
        "ga.airbnb.ie",
        "he.airbnb.com",
        "hi.airbnb.co.in",
        "hr.airbnb.com",
        "it.airbnb.ch",
        "ka.airbnb.com",
        "kn.airbnb.co.in",
        "mk.airbnb.com",
        "mr.airbnb.co.in",
        "mt.airbnb.com.mt",
        "sk.airbnb.com",
        "sq.airbnb.com",
        "sw.airbnb.com",
        "th.airbnb.com",
        "xh.airbnb.co.za",
        "zh-t.airbnb.com",
        "zh.airbnb.com",
        "zu.airbnb.co.za"
       ],
       "default": "airbnb.com",
       "title": "Airbnb Domain"
      },
      "description": "Country/language Airbnb host."
     },
     {
      "name": "currency",
      "in": "query",
      "required": false,
      "schema": {
       "anyOf": [
        {
         "type": "string"
        },
        {
         "type": "null"
        }
       ],
       "description": "Airbnb-supported ISO 4217 display currency.",
       "examples": [
        "CAD"
       ],
       "enum": [
        "AED",
        "AUD",
        "BAM",
        "BGN",
        "BRL",
        "CAD",
        "CHF",
        "CLP",
        "CNY",
        "COP",
        "CRC",
        "CZK",
        "DKK",
        "EGP",
        "EUR",
        "GBP",
        "GHS",
        "GTQ",
        "HKD",
        "HNL",
        "HUF",
        "IDR",
        "ILS",
        "INR",
        "JPY",
        "KES",
        "KRW",
        "KZT",
        "MAD",
        "MXN",
        "MYR",
        "NOK",
        "NZD",
        "PEN",
        "PHP",
        "PLN",
        "QAR",
        "RON",
        "RUB",
        "SAR",
        "SEK",
        "SGD",
        "THB",
        "TRY",
        "TWD",
        "UAH",
        "UGX",
        "USD",
        "UYU",
        "VND",
        "ZAR"
       ],
       "title": "Currency"
      },
      "description": "Airbnb-supported ISO 4217 display currency."
     },
     {
      "name": "include_taxes",
      "in": "query",
      "required": false,
      "schema": {
       "type": "boolean",
       "description": "Include tax-inclusive totals when Airbnb exposes a tax line.",
       "default": false,
       "title": "Include Taxes"
      },
      "description": "Include tax-inclusive totals when Airbnb exposes a tax line."
     },
     {
      "name": "check_in_date",
      "in": "query",
      "required": false,
      "schema": {
       "anyOf": [
        {
         "type": "string",
         "format": "date"
        },
        {
         "type": "null"
        }
       ],
       "description": "Exact check-in date in `YYYY-MM-DD` form.",
       "examples": [
        "2029-02-01"
       ],
       "title": "Check In Date"
      },
      "description": "Exact check-in date in `YYYY-MM-DD` form."
     },
     {
      "name": "check_out_date",
      "in": "query",
      "required": false,
      "schema": {
       "anyOf": [
        {
         "type": "string",
         "format": "date"
        },
        {
         "type": "null"
        }
       ],
       "description": "Exact check-out date; defaults to the next day.",
       "examples": [
        "2029-02-03"
       ],
       "title": "Check Out Date"
      },
      "description": "Exact check-out date; defaults to the next day."
     },
     {
      "name": "time_period",
      "in": "query",
      "required": false,
      "schema": {
       "anyOf": [
        {
         "type": "string"
        },
        {
         "type": "null"
        }
       ],
       "description": "Flexible dates: `weekend_trip`, `one_week`, or `one_month`; cannot be mixed with exact dates.",
       "examples": [
        "weekend_trip"
       ],
       "enum": [
        "one_month",
        "one_week",
        "weekend_trip"
       ],
       "title": "Time Period"
      },
      "description": "Flexible dates: `weekend_trip`, `one_week`, or `one_month`; cannot be mixed with exact dates."
     },
     {
      "name": "adults",
      "in": "query",
      "required": false,
      "schema": {
       "anyOf": [
        {
         "type": "integer"
        },
        {
         "type": "null"
        }
       ],
       "description": "Adults aged 13+, from 0 through 16.",
       "examples": [
        2
       ],
       "title": "Adults"
      },
      "description": "Adults aged 13+, from 0 through 16."
     },
     {
      "name": "children",
      "in": "query",
      "required": false,
      "schema": {
       "anyOf": [
        {
         "type": "integer"
        },
        {
         "type": "null"
        }
       ],
       "description": "Children aged 2–12, from 0 through 15.",
       "examples": [
        1
       ],
       "title": "Children"
      },
      "description": "Children aged 2–12, from 0 through 15."
     },
     {
      "name": "infants",
      "in": "query",
      "required": false,
      "schema": {
       "anyOf": [
        {
         "type": "integer"
        },
        {
         "type": "null"
        }
       ],
       "description": "Infants under 2, from 0 through 5.",
       "examples": [
        1
       ],
       "title": "Infants"
      },
      "description": "Infants under 2, from 0 through 5."
     },
     {
      "name": "pets",
      "in": "query",
      "required": false,
      "schema": {
       "anyOf": [
        {
         "type": "integer"
        },
        {
         "type": "null"
        }
       ],
       "description": "Pets, from 0 through 5.",
       "examples": [
        1
       ],
       "title": "Pets"
      },
      "description": "Pets, from 0 through 5."
     },
     {
      "name": "price_min",
      "in": "query",
      "required": false,
      "schema": {
       "anyOf": [
        {
         "type": "integer"
        },
        {
         "type": "null"
        }
       ],
       "description": "Minimum displayed trip price.",
       "examples": [
        100
       ],
       "title": "Price Min"
      },
      "description": "Minimum displayed trip price."
     },
     {
      "name": "price_max",
      "in": "query",
      "required": false,
      "schema": {
       "anyOf": [
        {
         "type": "integer"
        },
        {
         "type": "null"
        }
       ],
       "description": "Maximum displayed trip price.",
       "examples": [
        500
       ],
       "title": "Price Max"
      },
      "description": "Maximum displayed trip price."
     },
     {
      "name": "type_of_place",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "description": "`any`, `room`, or `entire_home`.",
       "examples": [
        "entire_home"
       ],
       "enum": [
        "any",
        "entire_home",
        "room"
       ],
       "default": "any",
       "title": "Type Of Place"
      },
      "description": "`any`, `room`, or `entire_home`."
     },
     {
      "name": "property_types",
      "in": "query",
      "required": false,
      "schema": {
       "anyOf": [
        {
         "type": "string"
        },
        {
         "type": "null"
        }
       ],
       "description": "Comma-separated `house`, `guesthouse`, `apartment`, and/or `hotel`.",
       "examples": [
        "house,apartment"
       ],
       "x-options": [
        "apartment",
        "guesthouse",
        "hotel",
        "house"
       ],
       "x-multiple": true,
       "title": "Property Types"
      },
      "description": "Comma-separated `house`, `guesthouse`, `apartment`, and/or `hotel`."
     },
     {
      "name": "bedrooms",
      "in": "query",
      "required": false,
      "schema": {
       "anyOf": [
        {
         "type": "integer"
        },
        {
         "type": "null"
        }
       ],
       "description": "Minimum bedrooms, from 0 through 8.",
       "examples": [
        2
       ],
       "title": "Bedrooms"
      },
      "description": "Minimum bedrooms, from 0 through 8."
     },
     {
      "name": "beds",
      "in": "query",
      "required": false,
      "schema": {
       "anyOf": [
        {
         "type": "integer"
        },
        {
         "type": "null"
        }
       ],
       "description": "Minimum beds, from 0 through 8.",
       "examples": [
        2
       ],
       "title": "Beds"
      },
      "description": "Minimum beds, from 0 through 8."
     },
     {
      "name": "bathrooms",
      "in": "query",
      "required": false,
      "schema": {
       "anyOf": [
        {
         "type": "integer"
        },
        {
         "type": "null"
        }
       ],
       "description": "Minimum bathrooms, from 0 through 8.",
       "examples": [
        1
       ],
       "title": "Bathrooms"
      },
      "description": "Minimum bathrooms, from 0 through 8."
     },
     {
      "name": "amenities",
      "in": "query",
      "required": false,
      "schema": {
       "anyOf": [
        {
         "type": "string"
        },
        {
         "type": "null"
        }
       ],
       "description": "Comma-separated SearchAPI amenity names.",
       "examples": [
        "wifi,kitchen"
       ],
       "x-options": [
        "24_hour_check_in",
        "air_conditioning",
        "bbq_grill",
        "breakfast",
        "buzzer_wireless_intercom",
        "cable_tv",
        "carbon_monoxide_alarm",
        "cats",
        "crib",
        "dedicated_workspace",
        "dogs",
        "doorman",
        "dryer",
        "elevator",
        "essentials",
        "ev_charger",
        "family_kid_friendly",
        "fire_extinguisher",
        "first_aid_kit",
        "free_parking_on_premises",
        "free_street_parking",
        "garage_parking",
        "guest_favorite",
        "gym",
        "hair_dryer",
        "hangers",
        "heating",
        "hot_tub",
        "indoor_fireplace",
        "instant_book",
        "internet",
        "iron",
        "jacuzzi_tub",
        "kitchen",
        "lock_on_bedroom_door",
        "lockbox",
        "luxe",
        "other_pets",
        "paid_parking_off_premises",
        "permit_parking",
        "pets_allowed",
        "pets_live_on_this_property",
        "pool",
        "private_entrance",
        "safety_card",
        "self_check_in",
        "shampoo",
        "smoke_alarm",
        "smoking_allowed",
        "suitable_for_events",
        "tv",
        "washer",
        "wheelchair_accessible",
        "wifi"
       ],
       "x-multiple": true,
       "title": "Amenities"
      },
      "description": "Comma-separated SearchAPI amenity names."
     },
     {
      "name": "next_page_token",
      "in": "query",
      "required": false,
      "schema": {
       "anyOf": [
        {
         "type": "string"
        },
        {
         "type": "null"
        }
       ],
       "description": "Opaque cursor from `pagination.next_page_token` on the prior page.",
       "examples": [
        "eyJzZWN0aW9uX29mZnNldCI6MH0="
       ],
       "title": "Next Page Token"
      },
      "description": "Opaque cursor from `pagination.next_page_token` on the prior page."
     },
     {
      "name": "zero_retention",
      "in": "query",
      "required": false,
      "schema": {
       "type": "boolean",
       "description": "Accepted for SearchAPI compatibility; raw search HTML and results are never persisted.",
       "default": false,
       "title": "Zero Retention"
      },
      "description": "Accepted for SearchAPI compatibility; raw search HTML and results are never persisted."
     }
    ],
    "responses": {
     "200": {
      "description": "SearchAPI-compatible Airbnb destination results with live prices",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/AirbnbSearchResponse"
        },
        "example": {
         "search_metadata": {
          "id": "search_2af4914e869a4a36958659ef",
          "status": "Success",
          "created_at": "2026-08-06T18:46:11+00:00",
          "request_time_taken": 1.3,
          "parsing_time_taken": 0.02,
          "total_time_taken": 1.32,
          "request_url": "https://www.airbnb.ca/s/Toronto/homes?...",
          "wire_bytes": 918246
         },
         "search_parameters": {
          "engine": "airbnb",
          "airbnb_domain": "airbnb.ca",
          "currency": "CAD",
          "q": "Toronto",
          "check_in_date": "2029-02-01",
          "check_out_date": "2029-02-03",
          "adults": "2",
          "include_taxes": "true"
         },
         "search_information": {
          "query_displayed": "Homes in Toronto, Canada",
          "results": "Over 1,000 homes in Toronto",
          "check_in_date": "2029-02-01",
          "check_out_date": "2029-02-03",
          "adults": 2,
          "guests": "2 guests"
         },
         "properties": [
          {
           "position": 1,
           "id": "734254017349424949",
           "title": "Chic Studio w Balcony Fast WiFi by Yonge-Dundas",
           "description": "Condo in Toronto",
           "link": "https://www.airbnb.ca/rooms/734254017349424949",
           "booking_link": "https://www.airbnb.ca/rooms/734254017349424949?check_in=2026-09-10&check_out=2026-09-12&adults=2&children=0&infants=0&pets=0",
           "booking_token": "eyJjaGVja19pbiI6IjIwMjYtMDktMTAiLCJwcm9wZXJ0eV9pZCI6IjczNDI1NDAxNzM0OTQyNDk0OSJ9",
           "rating": 4.96,
           "reviews": 166,
           "price": {
            "total_price": "$737 CAD",
            "extracted_total_price": 737,
            "total_with_taxes": "$737 CAD",
            "extracted_total_with_taxes": 737,
            "qualifier": "for 2 nights",
            "extracted_qualifier": 2,
            "price_per_qualifier": "2 nights x $310.00 CAD",
            "extracted_price_per_qualifier": 310,
            "breakdown": [
             {
              "description": "2 nights x $310.00 CAD",
              "price": "$620.00 CAD",
              "extracted_price": 620
             },
             {
              "description": "Taxes",
              "price": "$117.00 CAD",
              "extracted_price": 117
             }
            ]
           },
           "check_in_date": "2029-02-01",
           "check_out_date": "2029-02-03",
           "time_period": "Sep 10 – 12",
           "accommodations": [
            "1 bedroom",
            "1 queen bed",
            "1 bath"
           ],
           "gps_coordinates": {
            "latitude": 43.654,
            "longitude": -79.38
           },
           "has_free_cancellation": true,
           "badges": [
            "Guest favourite"
           ],
           "images": [
            "https://a0.muscache.com/im/pictures/example.jpeg"
           ]
          }
         ],
         "pagination": {
          "next_page_token": "eyJzZWN0aW9uX29mZnNldCI6MH0="
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/serp/google_hotels_property": {
   "post": {
    "tags": [
     "SearchAPI compatibility"
    ],
    "summary": "google_hotels_property, drop-in",
    "description": "Drop-in shape for SearchAPI's google_hotels_property.\n\nRepointing an existing integration is a base-URL change. `extracted_price`\nis populated where SearchAPI may omit it, and prices are exact floats\nrather than rounded integers.\n\nCredits: 3 (failed requests are free)",
    "operationId": "serp_google_hotels_property",
    "x-credits": 3,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/SerpPropertyRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "SearchAPI's google_hotels_property shape. `extracted_price` is populated, which theirs omits",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/SerpPropertyResponse"
        },
        "example": {
         "search_parameters": {
          "engine": "google_hotels_property",
          "property_token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
          "check_in_date": "2029-02-05",
          "check_out_date": "2029-02-06",
          "adults": 2,
          "currency": "USD",
          "gl": "us",
          "nights": 1
         },
         "property": {
          "property_token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
          "name": "Hilton Chicago",
          "hotel_class": "4-star hotel",
          "hotel_class_stars": 4,
          "rating": 4.3,
          "reviews": 10695,
          "deal": "25% less than usual",
          "deal_description": "Great Deal",
          "has_deal": true,
          "price_insights": {
           "lowest_price": "$304",
           "price_level": "typical",
           "price_level_code": 2,
           "typical_price_range": {
            "low_price": "$304",
            "high_price": "$521"
           }
          },
          "all_offers": [
           {
            "source": "Hilton Chicago",
            "is_official": true,
            "num_guests": 2,
            "room_id": "rate-plan-42",
            "price_per_night": {
             "price": "$2,907",
             "extracted_price": 2907.11,
             "extracted_price_before_taxes": 2445.0,
             "currency": "USD"
            },
            "total_price": {
             "price": "$2,907",
             "extracted_price": 2907.11,
             "extracted_price_before_taxes": 2445.0,
             "currency": "USD"
            },
            "tax_basis": "deeplink",
            "is_outlier": false
           }
          ],
          "featured_offers": [
           {
            "source": "Hilton Chicago",
            "is_official": true,
            "num_guests": 2,
            "room_id": "rate-plan-42",
            "price_per_night": {
             "price": "$2,907",
             "extracted_price": 2907.11,
             "extracted_price_before_taxes": 2445.0,
             "currency": "USD"
            },
            "total_price": {
             "price": "$2,907",
             "extracted_price": 2907.11,
             "extracted_price_before_taxes": 2445.0,
             "currency": "USD"
            },
            "tax_basis": "deeplink",
            "is_outlier": false
           }
          ],
          "price_per_night": {
           "price": "$2,208",
           "extracted_price": 2207.96
          },
          "currency_verified": true,
          "tax_profile": {
           "rate": 0.208,
           "confidence": "low"
          }
         },
         "meta": {
          "wire_bytes": 2754373,
          "elapsed_s": 1.548,
          "offers": 15,
          "priced": 15,
          "property_fetch": "miss",
          "tax_profile_cache": "hit"
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/ValidationError"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/serp/google_hotels_calendar": {
   "post": {
    "tags": [
     "SearchAPI compatibility"
    ],
    "summary": "Horizon sweep in SearchAPI's parameter style",
    "description": "No SearchAPI equivalent — a whole forward horizon in one call.\n\nSearchAPI bills one request per stay date; this returns ~330 nights in a\nsingle ~105 KB response. `extracted_price_before_taxes` uses SearchAPI's\nbase-plus-mandatory-fees basis; `extracted_price_base` and `fees` preserve\nthe itemised values.\n\nCredits: 5 (failed requests are free)",
    "operationId": "serp_google_hotels_calendar",
    "x-credits": 5,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/SerpCalendarRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "A whole horizon in one call, in SearchAPI's shape",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/SerpCalendarResponse"
        },
        "example": {
         "search_parameters": {
          "engine": "google_hotels_calendar",
          "property_token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
          "days": 5,
          "adults": 2,
          "currency": "USD",
          "gl": "us",
          "los": 1
         },
         "calendar": [
          {
           "date": "2028-12-26",
           "price": {
            "price": "$327",
            "extracted_price": 327.11
           },
           "extracted_price_before_taxes": 352.11,
           "extracted_price_base": 327.11,
           "extracted_price_total": 418.65,
           "tax": 66.54,
           "fees": 25,
           "currency": "USD",
           "rates_include_tax": false,
           "provenance": {
            "schema_version": 1,
            "observation_id": "rateobs_0123456789abcdef0123456789abcdef",
            "collection_id": "ratecol_0123456789abcdef0123456789abcdef",
            "observed_at": "2026-08-07T01:23:45.678Z",
            "source": "google_hotels_calendar",
            "source_kind": "calendar",
            "collector": "scrapingme.google_calendar",
            "source_property_id": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
            "requested_market": "US",
            "requested_currency": "USD",
            "returned_currency": "USD",
            "egress_mode": "direct",
            "price_basis": "room_base_before_taxes_and_fees",
            "derivation": "normalized_upstream"
           }
          },
          {
           "date": "2028-12-27",
           "price": {
            "price": "$324",
            "extracted_price": 324.37
           },
           "extracted_price_before_taxes": 349.37,
           "extracted_price_base": 324.37,
           "extracted_price_total": 415.4,
           "tax": 66.03,
           "fees": 25,
           "currency": "USD",
           "rates_include_tax": false
          }
         ],
         "unavailable_dates": [],
         "tax_profile": {
          "rate": 0.2051,
          "confidence": "high"
         },
         "meta": {
          "coverage": 1.0,
          "wire_bytes": 1839,
          "elapsed_s": 0.171,
          "retries": 0
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/ValidationError"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/serp/google_flights": {
   "post": {
    "tags": [
     "SearchAPI compatibility"
    ],
    "summary": "Google Flights search for itineraries",
    "description": "Every itinerary Google Flights offers, with per-segment detail.\n\nOne request (~0.3 s for a typical one-way):\nGoogle's best and other flights, flight numbers, operating carrier,\naircraft, legroom, amenities, layovers, emissions, bags included, price\ninsights and a Google Flights link per itinerary. Round trips and\nmulti-city return the first leg's options with a `departure_token` for\n`/v1/serp/google_flights_return`; complete itineraries carry a\n`booking_token` for `/v1/serp/google_flights_booking`.\n\nCredits: 3 (failed requests are free)",
    "operationId": "serp_google_flights",
    "x-credits": 3,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/FlightsSearchRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Every itinerary for the first leg. Round-trip and multi-city options carry `departure_token`; complete ones (one-way, last leg) carry `booking_token` and `booking_url` instead",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/FlightsSearchResponse"
        },
        "example": {
         "departure_airport": "YUL",
         "arrival_airport": "CDG",
         "departure_date": "2029-03-28",
         "currency": "USD",
         "adults": 1,
         "itineraries": [
          {
           "legs": [
            {
             "segments": [
              {
               "departure_airport": "YUL",
               "arrival_airport": "CDG",
               "departure_time": "2026-11-04T18:10:00",
               "arrival_time": "2026-11-05T07:20:00",
               "airline": "Air Canada",
               "airline_code": "AC",
               "flight_number": "AC 874",
               "duration_minutes": 430,
               "aircraft": "Airbus A330",
               "cabin_class": "economy",
               "departure_airport_name": "Montréal-Pierre Elliott Trudeau International Airport",
               "arrival_airport_name": "Aéroport de Paris-Charles de Gaulle",
               "ticket_also_sold_by": [
                "LH 6809",
                "SN 9636"
               ],
               "legroom": "31 in",
               "legroom_category": "average",
               "overnight": true,
               "red_eye": false,
               "often_delayed_by_over_30_min": false,
               "carbon_emissions_kg": 325,
               "extensions": [
                "Average legroom (31 in)",
                "Wi-Fi for a fee",
                "In-seat power & USB outlets",
                "On-demand video",
                "Carbon emissions estimate: 325 kg"
               ],
               "airline_logo": "https://www.gstatic.com/flights/airline_logos/70px/AC.png"
              }
             ],
             "departure_airport": "YUL",
             "arrival_airport": "CDG",
             "duration_minutes": 430,
             "stops": 0,
             "layover_airports": [],
             "is_direct": true,
             "layovers": [],
             "airlines": [
              "Air Canada"
             ],
             "departure_time": "2026-11-04T18:10:00",
             "arrival_time": "2026-11-05T07:20:00"
            }
           ],
           "price": 527.0,
           "currency": "USD",
           "display_price": "$527",
           "carbon_emissions_kg": 325,
           "carbon_emissions_comparison": "19% lower than typical",
           "trip_type": "round_trip",
           "total_stops": 0,
           "is_direct": true,
           "departure_token": "gf1.eNqFUMkKwjAU_Jd3TiGpVqU3TVuhBO1iIhpyEhe09NJWBfHfTRexxS2BlxneMvNygzPYBMEObJkWSYKqQOpHKo0kQbi8Cr3yn4IsD6w4A12rVMmBOtOGVSW4VQ4mNgcGwQax4Dmg7u5k6hF1x5hqPhr2Qf3w0quU29JdW9-NmCb8WbEReFMnCkFWfWMONtBj5C1db8bdq8dEFMRYzBm3AkHJhAnfC_klj0XkL04iDoW_1kttdBuPHY0OiYbbVKN9iYoM7g_hQ347",
           "google_flights_url": "https://www.google.com/travel/flights/search?tfs=CBwQAho_EgoyMDI2LTExLTA0Ih8KA1lVTBIKMjAyNi0xMS0wNBoDQ0RHKgJBQzIDODc0agc...",
           "group": "best",
           "price_exact": 526.19,
           "carbon_emissions": {
            "this_flight": 325000,
            "typical_for_this_route": 399000,
            "difference_percent": -19
           },
           "total_duration_minutes": 430,
           "carry_on_bags_included": 1,
           "airline_logo": "https://www.gstatic.com/flights/airline_logos/70px/AC.png"
          },
          {
           "legs": [
            {
             "segments": [
              {
               "departure_airport": "YUL",
               "arrival_airport": "YYZ",
               "departure_time": "2026-11-04T10:10:00",
               "arrival_time": "2026-11-04T11:45:00",
               "airline": "Air Canada",
               "airline_code": "AC",
               "flight_number": "AC 407",
               "duration_minutes": 95,
               "aircraft": "Airbus A321",
               "cabin_class": "economy",
               "departure_airport_name": "Montréal-Pierre Elliott Trudeau International Airport",
               "arrival_airport_name": "Toronto Pearson International Airport",
               "ticket_also_sold_by": [],
               "legroom": "31 in",
               "legroom_category": "average",
               "overnight": false,
               "red_eye": false,
               "often_delayed_by_over_30_min": false,
               "carbon_emissions_kg": 71,
               "extensions": [
                "Average legroom (31 in)",
                "Free Wi-Fi",
                "In-seat power & USB outlets",
                "On-demand video",
                "Carbon emissions estimate: 71 kg"
               ],
               "airline_logo": "https://www.gstatic.com/flights/airline_logos/70px/AC.png"
              },
              {
               "departure_airport": "YYZ",
               "arrival_airport": "CDG",
               "departure_time": "2026-11-04T21:10:00",
               "arrival_time": "2026-11-05T10:20:00",
               "airline": "Air Canada",
               "airline_code": "AC",
               "flight_number": "AC 872",
               "duration_minutes": 430,
               "aircraft": "Boeing 777",
               "cabin_class": "economy",
               "departure_airport_name": "Toronto Pearson International Airport",
               "arrival_airport_name": "Aéroport de Paris-Charles de Gaulle",
               "ticket_also_sold_by": [],
               "legroom": "31 in",
               "legroom_category": "average",
               "overnight": true,
               "red_eye": true,
               "often_delayed_by_over_30_min": true,
               "carbon_emissions_kg": 394,
               "extensions": [
                "Average legroom (31 in)",
                "Wi-Fi for a fee",
                "In-seat power & USB outlets",
                "On-demand video",
                "Carbon emissions estimate: 394 kg"
               ],
               "airline_logo": "https://www.gstatic.com/flights/airline_logos/70px/AC.png"
              }
             ],
             "departure_airport": "YUL",
             "arrival_airport": "CDG",
             "duration_minutes": 1090,
             "stops": 1,
             "layover_airports": [
              "YYZ"
             ],
             "is_direct": false,
             "layovers": [
              {
               "duration_minutes": 565,
               "airport": "YYZ",
               "airport_name": "Toronto Pearson International Airport",
               "city": "Toronto",
               "departure_airport": "YYZ",
               "change_of_airport": false,
               "overnight": false
              }
             ],
             "airlines": [
              "Air Canada"
             ],
             "departure_time": "2026-11-04T10:10:00",
             "arrival_time": "2026-11-05T10:20:00"
            }
           ],
           "price": 535.0,
           "currency": "USD",
           "display_price": "$535",
           "carbon_emissions_kg": 464,
           "carbon_emissions_comparison": "16% higher than typical",
           "trip_type": "round_trip",
           "total_stops": 1,
           "is_direct": false,
           "departure_token": "gf1.eNqFUMkKwjAU_Jd3TiGpVqU3TVuhBO1iIhpyEhe09NJWBfHfTRexxS2BlxneMvNygzPYBMEObJkWSYKqQOpHKo0kQbi8Cr3yn4IsD6w4A12rVMmBOtOGVSW4VQ4mNgcGwQax4Dmg7u5k6hF1x5hqPhr2Qf3w0quU29JdW9-NmCb8WbEReFMnCkFWfWMONtBj5C1db8bdq8dEFMRYzBm3AkHJhAnfC_klj0XkL04iDoW_1kttdBuPHY0OiYbbVKN9iYoM7g_hQ347",
           "google_flights_url": "https://www.google.com/travel/flights/search?tfs=CBwQAhpgEgoyMDI2LTExLTA0Ih8KA1lVTBIKMjAyNi0xMS0wNBoDWVlaKgJBQzIDNDA3Ih8...",
           "group": "other",
           "price_exact": 534.12,
           "carbon_emissions": {
            "this_flight": 464000,
            "typical_for_this_route": 399000,
            "difference_percent": 16
           },
           "total_duration_minutes": 1090,
           "carry_on_bags_included": 1,
           "airline_logo": "https://www.gstatic.com/flights/airline_logos/70px/AC.png"
          }
         ],
         "wire_bytes": 330950,
         "elapsed_s": 0.942,
         "cheapest_price": 527.0,
         "trip_type": "round_trip",
         "leg_index": 0,
         "legs_total": 2,
         "itinerary_count": 69,
         "best_count": 3,
         "price_insights": {
          "lowest_price": 527,
          "price_level": "typical",
          "typical_price_range": [
           475,
           530
          ],
          "price_history": [
           [
            1790568000,
            528
           ],
           [
            1790654400,
            528
           ],
           [
            1790740800,
            527
           ]
          ]
         },
         "airlines_available": [
          {
           "code": "ONEWORLD",
           "name": "Oneworld",
           "type": "alliance"
          },
          {
           "code": "SKYTEAM",
           "name": "SkyTeam",
           "type": "alliance"
          },
          {
           "code": "STAR_ALLIANCE",
           "name": "Star Alliance",
           "type": "alliance"
          },
          {
           "code": "A3",
           "name": "Aegean",
           "type": "airline"
          }
         ],
         "google_flights_url": "https://www.google.com/travel/flights/search?tfs=CBwQAhoeEgoyMDI2LTExLTA0agcIARIDWVVMcgcIARIDQ0RHGh4SCjIwMjYtMTEtMTFqBwgBEgNDREdyBwgBEgNZVUxAAUgBcAGCAQsI____________AZgBAQ&hl=en&gl=us&curr=USD",
         "source": "rpc",
         "return_date": "2029-04-04"
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/serp/google_flights_return": {
   "post": {
    "tags": [
     "SearchAPI compatibility"
    ],
    "summary": "Google Flights return or next-leg options",
    "description": "The return flights for a chosen outbound (or the next multi-city leg).\n\nSerpApi/SearchApi's `departure_token` flow: pass the `departure_token`\nof an itinerary from `/v1/serp/google_flights`. Prices are for the whole\ntrip, as Google shows them. Last-leg options carry a `booking_token`.\n\nCredits: 3 (failed requests are free)",
    "operationId": "serp_google_flights_return",
    "x-credits": 3,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/FlightsReturnRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Return-leg options for the chosen outbound, priced for the whole trip, each with a `booking_token`",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/FlightsReturnResponse"
        },
        "example": {
         "departure_airport": "CDG",
         "arrival_airport": "YUL",
         "departure_date": "2029-04-04",
         "currency": "USD",
         "adults": 1,
         "itineraries": [
          {
           "legs": [
            {
             "segments": [
              {
               "departure_airport": "CDG",
               "arrival_airport": "ZRH",
               "departure_time": "2026-11-11T07:15:00",
               "arrival_time": "2026-11-11T08:35:00",
               "airline": "SWISS",
               "airline_code": "LX",
               "flight_number": "LX 647",
               "duration_minutes": 80,
               "aircraft": "Airbus A320",
               "cabin_class": "economy",
               "departure_airport_name": "Aéroport de Paris-Charles de Gaulle",
               "arrival_airport_name": "Zurich Airport",
               "ticket_also_sold_by": [],
               "legroom": "29 in",
               "legroom_category": "below_average",
               "overnight": false,
               "red_eye": false,
               "often_delayed_by_over_30_min": false,
               "carbon_emissions_kg": 62,
               "extensions": [
                "Below average legroom (29 in)",
                "Carbon emissions estimate: 62 kg"
               ],
               "airline_logo": "https://www.gstatic.com/flights/airline_logos/70px/LX.png"
              },
              {
               "departure_airport": "ZRH",
               "arrival_airport": "YUL",
               "departure_time": "2026-11-11T12:40:00",
               "arrival_time": "2026-11-11T15:10:00",
               "airline": "SWISS",
               "airline_code": "LX",
               "flight_number": "LX 86",
               "duration_minutes": 510,
               "aircraft": "Airbus A330",
               "cabin_class": "economy",
               "departure_airport_name": "Zurich Airport",
               "arrival_airport_name": "Montréal-Pierre Elliott Trudeau International Airport",
               "ticket_also_sold_by": [
                "AC 6821"
               ],
               "legroom": "31 in",
               "legroom_category": "average",
               "overnight": false,
               "red_eye": false,
               "often_delayed_by_over_30_min": true,
               "carbon_emissions_kg": 351,
               "extensions": [
                "Average legroom (31 in)",
                "Wi-Fi for a fee",
                "On-demand video",
                "Carbon emissions estimate: 351 kg"
               ],
               "airline_logo": "https://www.gstatic.com/flights/airline_logos/70px/LX.png"
              }
             ],
             "departure_airport": "CDG",
             "arrival_airport": "YUL",
             "duration_minutes": 835,
             "stops": 1,
             "layover_airports": [
              "ZRH"
             ],
             "is_direct": false,
             "layovers": [
              {
               "duration_minutes": 245,
               "airport": "ZRH",
               "airport_name": "Zurich Airport",
               "city": "Zürich",
               "departure_airport": "ZRH",
               "change_of_airport": false,
               "overnight": false
              }
             ],
             "airlines": [
              "SWISS"
             ],
             "departure_time": "2026-11-11T07:15:00",
             "arrival_time": "2026-11-11T15:10:00"
            }
           ],
           "price": 527.0,
           "currency": "USD",
           "display_price": "$527",
           "booking_token": "gf1.eNp9T8sKwjAQ_Jc9p5BUqqU3tc0hBm0bE8WQk_hASy9tVRD_3aRVVBSzsJlhZjabK5wgIgi2EOmyKQrUNr-7tEEEaYKwK4Ne-q-m3QFGJ2C9xjgOfLh8sNaC3-zgY7_vEeyRAJ4DuvSH0o3oEjG3nAzCEMyfZXrfIjEIqvabNUQwPuR0kdCpTC6UqzwVWM24DFI1JiOuGM3kuRYqZ_OjEpliK_vo2sakiC3aFxZuSot2DjUV3O6AWl_r",
           "booking_url": "https://www.google.com/travel/flights/booking?tfs=CBwQAho_EgoyMDI2LTExLTA0Ih8KA1lVTBIKMjAyNi0xMS0wNBoDQ0RHKgJBQzIDODc0ag...",
           "carbon_emissions_kg": 413,
           "carbon_emissions_comparison": "6% higher than typical",
           "trip_type": "round_trip",
           "total_stops": 1,
           "is_direct": false,
           "google_flights_url": "https://www.google.com/travel/flights/booking?tfs=CBwQAho_EgoyMDI2LTExLTA0Ih8KA1lVTBIKMjAyNi0xMS0wNBoDQ0RHKgJBQzIDODc0ag...",
           "group": "other",
           "price_exact": 526.18,
           "carbon_emissions": {
            "this_flight": 413000,
            "typical_for_this_route": 390000,
            "difference_percent": 6
           },
           "total_duration_minutes": 835,
           "carry_on_bags_included": 1,
           "airline_logo": "https://www.gstatic.com/flights/airline_logos/70px/LX.png"
          }
         ],
         "wire_bytes": 104612,
         "elapsed_s": 0.543,
         "cheapest_price": 527.0,
         "trip_type": "round_trip",
         "leg_index": 1,
         "legs_total": 2,
         "itinerary_count": 16,
         "best_count": 0,
         "airlines_available": [
          {
           "code": "ONEWORLD",
           "name": "Oneworld",
           "type": "alliance"
          },
          {
           "code": "SKYTEAM",
           "name": "SkyTeam",
           "type": "alliance"
          },
          {
           "code": "STAR_ALLIANCE",
           "name": "Star Alliance",
           "type": "alliance"
          }
         ],
         "google_flights_url": "https://www.google.com/travel/flights/search?tfs=CBwQAho_EgoyMDI2LTExLTA0Ih8KA1lVTBIKMjAyNi0xMS0wNBoDQ0RHKgJBQzIDODc0agcIARIDWVVMcgcIARIDQ0RHGh4SCjIwMjYtMTEtMTFqBwgBEgNDREdyBwgBEgNZVUxAAUgBcAGCAQsI____________AZgBAQ&hl=en&gl=us&curr=USD",
         "source": "rpc",
         "return_date": "2029-04-04"
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/serp/google_flights_booking": {
   "post": {
    "tags": [
     "SearchAPI compatibility"
    ],
    "summary": "Google Flights booking options for an itinerary",
    "description": "Who sells the itinerary and for how much (SerpApi `booking_options`).\n\nAirline direct and OTAs, each with price, fare name and rules, bag fees,\nthe seller's local-currency price and Google's click-through as both a\nPOST form (`booking_request`) and a GET link (`booking_url`). Google\ngathers seller prices while the request is open: expect 3-12 s.\n\nCredits: 3 (failed requests are free)",
    "operationId": "serp_google_flights_booking",
    "x-credits": 3,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/FlightsBookingRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Sellers of the chosen itinerary with prices, fare rules, bag fees and click-through links",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/FlightsBookingResponse"
        },
        "example": {
         "currency": "USD",
         "trip_type": "round_trip",
         "legs": [
          {
           "segments": [
            {
             "departure_airport": "YUL",
             "arrival_airport": "CDG",
             "departure_time": "2026-11-04T18:10:00",
             "arrival_time": "2026-11-05T07:20:00",
             "airline": "Air Canada",
             "airline_code": "AC",
             "flight_number": "AC 874",
             "duration_minutes": 430,
             "aircraft": "Airbus A330",
             "cabin_class": "economy",
             "departure_airport_name": "Montréal-Pierre Elliott Trudeau International Airport",
             "arrival_airport_name": "Aéroport de Paris-Charles de Gaulle",
             "ticket_also_sold_by": [
              "LH 6809",
              "SN 9636"
             ],
             "legroom": "31 in",
             "legroom_category": "average",
             "overnight": true,
             "red_eye": false,
             "often_delayed_by_over_30_min": false,
             "carbon_emissions_kg": 325,
             "extensions": [
              "Average legroom (31 in)",
              "Wi-Fi for a fee",
              "In-seat power & USB outlets",
              "On-demand video",
              "Carbon emissions estimate: 325 kg"
             ],
             "airline_logo": "https://www.gstatic.com/flights/airline_logos/70px/AC.png"
            }
           ],
           "departure_airport": "YUL",
           "arrival_airport": "CDG",
           "duration_minutes": 430,
           "stops": 0,
           "layover_airports": [],
           "is_direct": true,
           "layovers": [],
           "airlines": [
            "Air Canada"
           ],
           "departure_time": "2026-11-04T18:10:00",
           "arrival_time": "2026-11-05T07:20:00"
          },
          {
           "segments": [
            {
             "departure_airport": "CDG",
             "arrival_airport": "ZRH",
             "departure_time": "2026-11-11T07:15:00",
             "arrival_time": "2026-11-11T08:35:00",
             "airline": "SWISS",
             "airline_code": "LX",
             "flight_number": "LX 647",
             "duration_minutes": 80,
             "aircraft": "Airbus A320",
             "cabin_class": "economy",
             "departure_airport_name": "Aéroport de Paris-Charles de Gaulle",
             "arrival_airport_name": "Zurich Airport",
             "ticket_also_sold_by": [],
             "legroom": "29 in",
             "legroom_category": "below_average",
             "overnight": false,
             "red_eye": false,
             "often_delayed_by_over_30_min": false,
             "carbon_emissions_kg": 62,
             "extensions": [
              "Below average legroom (29 in)",
              "Carbon emissions estimate: 62 kg"
             ],
             "airline_logo": "https://www.gstatic.com/flights/airline_logos/70px/LX.png"
            },
            {
             "departure_airport": "ZRH",
             "arrival_airport": "YUL",
             "departure_time": "2026-11-11T12:40:00",
             "arrival_time": "2026-11-11T15:10:00",
             "airline": "SWISS",
             "airline_code": "LX",
             "flight_number": "LX 86",
             "duration_minutes": 510,
             "aircraft": "Airbus A330",
             "cabin_class": "economy",
             "departure_airport_name": "Zurich Airport",
             "arrival_airport_name": "Montréal-Pierre Elliott Trudeau International Airport",
             "ticket_also_sold_by": [
              "AC 6821"
             ],
             "legroom": "31 in",
             "legroom_category": "average",
             "overnight": false,
             "red_eye": false,
             "often_delayed_by_over_30_min": true,
             "carbon_emissions_kg": 351,
             "extensions": [
              "Average legroom (31 in)",
              "Wi-Fi for a fee",
              "On-demand video",
              "Carbon emissions estimate: 351 kg"
             ],
             "airline_logo": "https://www.gstatic.com/flights/airline_logos/70px/LX.png"
            }
           ],
           "departure_airport": "CDG",
           "arrival_airport": "YUL",
           "duration_minutes": 835,
           "stops": 1,
           "layover_airports": [
            "ZRH"
           ],
           "is_direct": false,
           "layovers": [
            {
             "duration_minutes": 245,
             "airport": "ZRH",
             "airport_name": "Zurich Airport",
             "city": "Zürich",
             "departure_airport": "ZRH",
             "change_of_airport": false,
             "overnight": false
            }
           ],
           "airlines": [
            "SWISS"
           ],
           "departure_time": "2026-11-11T07:15:00",
           "arrival_time": "2026-11-11T15:10:00"
          }
         ],
         "booking_options": [
          {
           "book_with": "SWISS",
           "seller_code": "LX",
           "is_airline": true,
           "price": 527.0,
           "currency": "USD",
           "display_price": "$527",
           "local_prices": [
            {
             "currency": "CAD",
             "price": 749
            }
           ],
           "marketed_as": [
            "LH 6809",
            "LX 647",
            "LX 86"
           ],
           "booking_request": {
            "url": "https://www.google.com/travel/clk/f",
            "post_data": "u=ADowPOL...&v=1"
           },
           "booking_url": "https://www.google.com/travel/clk/f?u=ADowPOL...&v=1",
           "seller_domain": "www.swiss.com/...",
           "separate_tickets": false,
           "sellers": [
            "SWISS"
           ],
           "extensions": [],
           "baggage_prices": [
            "1st checked bag: $127",
            "2nd checked bag: $183",
            "1 free carry-on"
           ]
          },
          {
           "book_with": "Lufthansa",
           "seller_code": "LH",
           "is_airline": true,
           "price": 527.0,
           "currency": "USD",
           "display_price": "$527",
           "local_prices": [
            {
             "currency": "CAD",
             "price": 749
            }
           ],
           "marketed_as": [
            "LH 6809",
            "LX 647",
            "LX 86"
           ],
           "booking_request": {
            "url": "https://www.google.com/travel/clk/f",
            "post_data": "u=ADowPOL...&v=1"
           },
           "booking_url": "https://www.google.com/travel/clk/f?u=ADowPOL...&v=1",
           "seller_domain": "www.lufthansa.com/...",
           "separate_tickets": false,
           "sellers": [
            "Lufthansa"
           ],
           "extensions": [],
           "baggage_prices": [
            "1st checked bag: $127",
            "2nd checked bag: $183",
            "1 free carry-on"
           ]
          }
         ],
         "option_count": 9,
         "cheapest_price": 527.0,
         "price_insights": {
          "lowest_price": 527,
          "price_level": "typical",
          "typical_price_range": [
           495,
           880
          ],
          "price_history": [
           [
            1790568000,
            529
           ],
           [
            1790654400,
            528
           ],
           [
            1790740800,
            527
           ]
          ]
         },
         "google_flights_url": "https://www.google.com/travel/flights/booking?tfs=CBwQAho_EgoyMDI2LTExLTA0Ih8KA1lVTBIKMjAyNi0xMS0wNBoDQ0RHKgJBQzIDODc0ag...",
         "wire_bytes": 79626,
         "elapsed_s": 6.247
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/serp/google_flights_location_search": {
   "post": {
    "tags": [
     "SearchAPI compatibility"
    ],
    "summary": "Resolve a city or airport to IATA codes",
    "description": "Google Flights' own autocomplete: airports, cities (with their\nairports) and regions for a name. A city's `id` (`/m/...`) is accepted\nas `departure`/`arrival` by `/v1/serp/google_flights`. ~0.1 s; repeated\nqueries are served from a 6-hour cache.\n\nCredits: 1 (failed requests are free)",
    "operationId": "serp_google_flights_location_search",
    "x-credits": 1,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/FlightsLocationSearchRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Airports, cities (with their airports) and regions matching the query",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/FlightsLocationSearchResponse"
        },
        "example": {
         "q": "paris",
         "locations": [
          {
           "type": "city",
           "name": "Paris, France",
           "id": "/m/05qtj",
           "city": "Paris",
           "description": "Capital of France",
           "airports": [
            {
             "iata": "CDG",
             "name": "Aéroport de Paris-Charles de Gaulle",
             "city": "Paris",
             "type": "airport",
             "distance": "14 mi"
            },
            {
             "iata": "ORY",
             "name": "Paris Orly Airport",
             "city": "Paris",
             "type": "airport",
             "distance": "9 mi"
            },
            {
             "iata": "BVA",
             "name": "Paris Beauvais Airport",
             "city": "Paris",
             "type": "airport",
             "distance": "42 mi"
            },
            {
             "iata": "XHP",
             "name": "Gare de l'Est",
             "city": "Paris",
             "type": "train_station",
             "distance": "1 mi"
            },
            {
             "iata": "XPG",
             "name": "Gare du Nord",
             "city": "Paris",
             "type": "train_station",
             "distance": "1 mi"
            }
           ]
          },
          {
           "type": "airport",
           "name": "Paris Airport-Le Bourget",
           "iata": "LBG",
           "id": "/m/02vwgn",
           "city": "Paris",
           "description": "Airport in France",
           "airports": []
          }
         ],
         "count": 5,
         "wire_bytes": 1593,
         "elapsed_s": 0.146,
         "cached": false
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/serp/google_flights_calendar": {
   "post": {
    "tags": [
     "SearchAPI compatibility"
    ],
    "summary": "Google Flights date-grid pricing",
    "description": "Google Flights calendar/date-grid pricing.\n\nSimilar to SearchAPI's google_flights_calendar. Returns cheapest prices\nacross a date range for flexible-date comparison.\n\nCredits: 5 (failed requests are free)",
    "operationId": "serp_google_flights_calendar",
    "x-credits": 5,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/FlightsCalendarRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Date-grid pricing for flexible-date comparison",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/FlightsCalendarResponse"
        },
        "example": {
         "departure_airport": "JFK",
         "arrival_airport": "LAX",
         "currency": "USD",
         "adults": 1,
         "trip_type": "round_trip",
         "wire_bytes": 98234,
         "elapsed_s": 1.12,
         "cheapest_price": 198.0,
         "coverage": "14/15",
         "prices": [
          {
           "departure_date": "2029-03-01",
           "return_date": "2029-03-06",
           "price": 245.0,
           "currency": "USD",
           "display_price": "$245",
           "is_priced": true
          },
          {
           "departure_date": "2029-03-02",
           "return_date": "2029-03-07",
           "price": 198.0,
           "currency": "USD",
           "display_price": "$198",
           "is_priced": true
          },
          {
           "departure_date": "2029-03-03",
           "return_date": "2029-03-08",
           "price": 223.0,
           "currency": "USD",
           "display_price": "$223",
           "is_priced": true
          }
         ]
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "422": {
      "$ref": "#/components/responses/ValidationError"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     }
    }
   }
  },
  "/v1/airbnb/calendar": {
   "post": {
    "tags": [
     "Airbnb"
    ],
    "summary": "Priced Airbnb nightly calendar",
    "description": "Day-by-day availability for 1-12 months with Airbnb's own quoted prices.\n\nOne upstream call returns availability, min/max nights and check-in /\ncheck-out rules. With `price_nights` = `sample` or `all`, each priced\ndate is the check-in of a real quoted stay (`stay_nights`, default the\ndate's minimum stay) from the query the listing page's booking sidebar\nruns: the nightly figure, taxes, discounts and total the guest would see.\n\nCredits: 8, plus 1 per night actually priced (at most 92, so at most 100 a call); refused, failed and unsampled nights and failed requests are free",
    "operationId": "airbnb_calendar",
    "x-credits": 8,
    "x-credits-variable": true,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/AirbnbCalendarRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "Day-by-day availability with quoted nightly prices (trimmed to 3 days)",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/AirbnbCalendarResponse"
        },
        "example": {
         "listing_id": "34397368",
         "link": "https://www.airbnb.ca/rooms/34397368",
         "airbnb_domain": "airbnb.ca",
         "currency": "CAD",
         "requested_currency": "CAD",
         "guests": {
          "adults": 2,
          "children": 0,
          "infants": 0,
          "pets": 0
         },
         "start_month": 10,
         "start_year": 2026,
         "months": 2,
         "price_nights": "sample",
         "max_price_quotes": 8,
         "listing": {
          "constant_min_nights": 2,
          "max_guests": 2,
          "pets_allowed": false,
          "children_allowed": true
         },
         "summary": {
          "days": 61,
          "available": 35,
          "available_for_checkin": 31,
          "bookable": 34,
          "priced": 8,
          "min_price_per_night": 169.5,
          "max_price_per_night": 178.0,
          "median_price_per_night": 178.0,
          "price_status": {
           "check_in_not_allowed": 4,
           "not_sampled": 23,
           "priced": 8,
           "unavailable": 26
          }
         },
         "days": [
          {
           "date": "2029-03-03",
           "available": false,
           "available_for_checkin": false,
           "available_for_checkout": false,
           "bookable": false,
           "min_nights": 2,
           "max_nights": 27,
           "closed_to_arrival": false,
           "closed_to_departure": false,
           "price_status": "unavailable"
          },
          {
           "date": "2029-03-07",
           "available": true,
           "available_for_checkin": true,
           "available_for_checkout": true,
           "bookable": true,
           "min_nights": 2,
           "max_nights": 27,
           "closed_to_arrival": false,
           "closed_to_departure": false,
           "price_status": "priced",
           "price": {
            "price_per_night": 178.0,
            "currency": "CAD",
            "check_in": "2029-03-07",
            "check_out": "2029-03-09",
            "nights": 2,
            "accommodation": 356.0,
            "taxes": 67.64,
            "total": 423.64,
            "price_per_night_text": "$178.00 CAD",
            "total_text": "$423.64 CAD",
            "display_total": "$424 CAD",
            "price_basis": "nightly_all_in_before_taxes",
            "display_style": "REGULATED_TOTAL",
            "breakdown": [
             {
              "description": "2 nights x $178.00 CAD",
              "price": "$356.00 CAD",
              "extracted_price": 356.0,
              "kind": "nights"
             },
             {
              "description": "Taxes",
              "price": "$67.64 CAD",
              "extracted_price": 67.64,
              "kind": "tax"
             },
             {
              "description": "Total",
              "price": "$423.64 CAD",
              "extracted_price": 423.64,
              "kind": "total"
             }
            ],
            "provenance": {
             "schema_version": 1,
             "observation_id": "rateobs_9e60ad832506e113550acd2fe556ad55",
             "collection_id": "ratecol_c328ca4cf9a747448dc64c2e80f86e25",
             "observed_at": "2026-09-30T22:48:15.032Z",
             "source": "airbnb",
             "source_kind": "vacation_rental_stay_quote",
             "collector": "scrapingme.ota.airbnb_calendar",
             "source_property_id": "34397368",
             "requested_market": "airbnb.ca",
             "requested_currency": "CAD",
             "returned_currency": "CAD",
             "egress_mode": "direct",
             "price_basis": "nightly_all_in_before_taxes",
             "derivation": "airbnb_stay_average_nightly"
            }
           }
          },
          {
           "date": "2029-03-08",
           "available": true,
           "available_for_checkin": true,
           "available_for_checkout": true,
           "bookable": true,
           "min_nights": 2,
           "max_nights": 27,
           "closed_to_arrival": false,
           "closed_to_departure": false,
           "price_status": "not_sampled"
          }
         ],
         "metadata": {
          "collection_id": "ratecol_c328ca4cf9a747448dc64c2e80f86e25",
          "observed_at": "2026-09-30T22:48:15.032Z",
          "calendar_operation": "PdpAvailabilityCalendar",
          "upstream_requests": 9,
          "price_quotes": 8,
          "wire_bytes": 8913,
          "request_time_taken": 4.69,
          "parsing_time_taken": 0.001,
          "total_time_taken": 1.52,
          "egress": [
           "direct"
          ]
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/serp/airbnb_property_availability_calendar": {
   "post": {
    "tags": [
     "Airbnb"
    ],
    "summary": "Airbnb availability calendar, SearchAPI-compatible, with prices",
    "description": "SearchAPI's `airbnb_property_availability_calendar`, field for field.\n\n`property_id`, `start_month`, `start_year`, `months` and `airbnb_domain`\nkeep SearchAPI's names and defaults, and every day keeps `date`,\n`is_available`, `is_available_for_checkin`, `is_available_for_checkout`,\n`is_bookable`, `min_nights` and `max_nights`. SearchAPI has no prices;\nset `price_nights` to add a `price` object to priced days (SearchAPI's\nAirbnb search price vocabulary). The default `none` costs 8 credits.\n\nCredits: 8 with the default `price_nights: none`; with `sample` or `all`, plus 1 per night actually priced (at most 92). Failed requests are free",
    "operationId": "serp_airbnb_property_availability_calendar",
    "x-credits": 8,
    "x-credits-variable": true,
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/AirbnbAvailabilityCalendarRequest"
       }
      }
     },
     "required": true
    },
    "responses": {
     "200": {
      "description": "SearchAPI airbnb_property_availability_calendar fields, plus prices",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/AirbnbAvailabilityCalendarResponse"
        },
        "example": {
         "search_metadata": {
          "id": "search_5b0f8c1d2e3a4f5061728394",
          "status": "Success",
          "created_at": "2026-09-30T22:48:15+00:00",
          "request_time_taken": 3.61,
          "parsing_time_taken": 0.001,
          "total_time_taken": 1.46,
          "request_url": "https://www.airbnb.ca/rooms/34397368",
          "collection_id": "ratecol_c328ca4cf9a747448dc64c2e80f86e25",
          "observed_at": "2026-09-30T22:48:15.032Z",
          "wire_bytes": 7003,
          "upstream_requests": 7
         },
         "search_parameters": {
          "engine": "airbnb_property_availability_calendar",
          "airbnb_domain": "airbnb.ca",
          "property_id": "34397368",
          "start_month": 10,
          "start_year": 2026,
          "months": 2,
          "currency": "CAD",
          "adults": 2,
          "price_nights": "sample",
          "max_price_quotes": 6
         },
         "months": [
          {
           "year": 2026,
           "month": 10,
           "days": [
            {
             "date": "2029-03-06",
             "is_available": true,
             "is_available_for_checkin": true,
             "is_available_for_checkout": true,
             "is_bookable": true,
             "min_nights": 2,
             "max_nights": 27,
             "price_status": "not_sampled"
            },
            {
             "date": "2029-03-07",
             "is_available": true,
             "is_available_for_checkin": true,
             "is_available_for_checkout": true,
             "is_bookable": true,
             "min_nights": 2,
             "max_nights": 27,
             "price_status": "priced",
             "price": {
              "check_in_date": "2029-03-07",
              "check_out_date": "2029-03-09",
              "currency": "CAD",
              "price_per_night": "$178.00 CAD",
              "extracted_price_per_night": 178.0,
              "total_price": "$424 CAD",
              "extracted_total_price": 424,
              "qualifier": "for 2 nights",
              "extracted_qualifier": 2,
              "price_per_qualifier": "2 nights x $178.00 CAD",
              "extracted_price_per_qualifier": 178.0,
              "total_with_taxes": "$423.64 CAD",
              "extracted_total_with_taxes": 423.64,
              "breakdown": [
               {
                "description": "2 nights x $178.00 CAD",
                "price": "$356.00 CAD",
                "extracted_price": 356.0
               },
               {
                "description": "Taxes",
                "price": "$67.64 CAD",
                "extracted_price": 67.64
               },
               {
                "description": "Total",
                "price": "$423.64 CAD",
                "extracted_price": 423.64
               }
              ],
              "provenance": {
               "schema_version": 1,
               "observation_id": "rateobs_9e60ad832506e113550acd2fe556ad55",
               "collection_id": "ratecol_c328ca4cf9a747448dc64c2e80f86e25",
               "observed_at": "2026-09-30T22:48:15.032Z",
               "source": "airbnb",
               "source_kind": "vacation_rental_stay_quote",
               "collector": "scrapingme.ota.airbnb_calendar",
               "source_property_id": "34397368",
               "requested_market": "airbnb.ca",
               "requested_currency": "CAD",
               "returned_currency": "CAD",
               "egress_mode": "direct",
               "price_basis": "nightly_all_in_before_taxes",
               "derivation": "airbnb_stay_average_nightly"
              }
             }
            }
           ]
          }
         ],
         "price_summary": {
          "days": 61,
          "available": 35,
          "available_for_checkin": 31,
          "bookable": 34,
          "priced": 6,
          "min_price_per_night": 169.5,
          "max_price_per_night": 178.0,
          "median_price_per_night": 178.0,
          "price_status": {
           "check_in_not_allowed": 4,
           "not_sampled": 25,
           "priced": 6,
           "unavailable": 26
          }
         }
        }
       }
      },
      "headers": {
       "x-credits-charged": {
        "$ref": "#/components/headers/CreditsCharged"
       },
       "x-credits-remaining": {
        "$ref": "#/components/headers/CreditsRemaining"
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "402": {
      "$ref": "#/components/responses/InsufficientCredits"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/UnprocessableRequest"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "502": {
      "$ref": "#/components/responses/UpstreamError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/billing": {
   "get": {
    "tags": [
     "Billing"
    ],
    "summary": "Plan, credit balance and period",
    "description": "Credits: 0 (failed requests are free)",
    "operationId": "billing_summary",
    "x-credits": 0,
    "responses": {
     "200": {
      "description": "Plan, balance and current period",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/BillingSummary"
        },
        "example": {
         "mode": "shadow",
         "plan": {
          "code": "starter",
          "name": "Starter",
          "monthly_credits": 50000,
          "price_usd": 49,
          "concurrency": 10
         },
         "credits": {
          "balance": 48210,
          "reserved": 20,
          "available": 48190,
          "credits_used": 1790,
          "credits_refunded": 0,
          "billable_requests": 312
         },
         "period": {
          "start": "2026-10-01T00:00:00+00:00",
          "end": "2026-11-01T00:00:00+00:00"
         },
         "subscription": {
          "status": "active",
          "stripe_managed": true
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     }
    }
   }
  },
  "/v1/billing/ledger": {
   "get": {
    "tags": [
     "Billing"
    ],
    "summary": "Credit movements, newest first",
    "description": "Credits: 0 (failed requests are free)",
    "operationId": "billing_ledger",
    "x-credits": 0,
    "parameters": [
     {
      "name": "limit",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "maximum": 200,
       "minimum": 1,
       "default": 50,
       "title": "Limit"
      }
     },
     {
      "name": "before",
      "in": "query",
      "required": false,
      "schema": {
       "anyOf": [
        {
         "type": "integer",
         "minimum": 1
        },
        {
         "type": "null"
        }
       ],
       "description": "Return entries with an id below this.",
       "title": "Before"
      },
      "description": "Return entries with an id below this."
     }
    ],
    "responses": {
     "200": {
      "description": "Credit movements, newest first",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/BillingLedger"
        },
        "example": {
         "entries": [
          {
           "id": 912,
           "kind": "usage",
           "amount": -5,
           "balance_after": 48210,
           "route": "/v1/calendar",
           "request_id": "req_0123456789abcdef0123456789abcdef",
           "detail": {},
           "created_at": "2026-10-14T09:12:44.120000+00:00"
          },
          {
           "id": 3,
           "kind": "grant",
           "amount": 50000,
           "balance_after": 50000,
           "detail": {
            "plan": "starter",
            "reason": "plan change"
           },
           "created_at": "2026-10-01T00:00:03.000000+00:00"
          }
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/ValidationError"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     }
    }
   }
  },
  "/v1/billing/plans": {
   "get": {
    "tags": [
     "Billing"
    ],
    "summary": "Plans and per-endpoint credit costs",
    "description": "Credits: 0 (failed requests are free)",
    "operationId": "billing_plans",
    "x-credits": 0,
    "responses": {
     "200": {
      "description": "Plans and per-endpoint credit costs",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/BillingPlans"
        },
        "example": {
         "plans": [
          {
           "code": "free",
           "name": "Free",
           "monthly_credits": 1000,
           "price_usd": 0,
           "concurrency": 2
          },
          {
           "code": "starter",
           "name": "Starter",
           "monthly_credits": 50000,
           "price_usd": 49,
           "concurrency": 10
          }
         ],
         "costs": [
          {
           "method": "POST",
           "path": "/v1/calendar",
           "credits": 5
          },
          {
           "method": "POST",
           "path": "/v1/ota/compare",
           "credits": 20
          }
         ],
         "free": [
          "GET /v1/billing",
          "GET /v1/usage"
         ],
         "notes": [
          "Failed, blocked and empty results are not charged."
         ],
         "mode": "shadow"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     }
    }
   }
  }
 },
 "components": {
  "securitySchemes": {
   "ApiKeyAuth": {
    "type": "apiKey",
    "in": "header",
    "name": "x-api-key",
    "description": "API key in the `x-api-key` header (recommended). Keys look like `sk_` followed by random characters."
   },
   "BearerAuth": {
    "type": "http",
    "scheme": "bearer",
    "description": "The same API key sent as `Authorization: Bearer <key>`."
   },
   "ApiKeyQuery": {
    "type": "apiKey",
    "in": "query",
    "name": "api_key",
    "description": "The same API key as an `api_key` query parameter. Supported for SearchAPI-style GET integrations; prefer the header."
   }
  },
  "headers": {
   "CreditsCharged": {
    "description": "Credits charged for this request: the operation's cost on success, 0 for failed or empty results. Sent when the key is linked to a customer account.",
    "schema": {
     "type": "integer",
     "minimum": 0
    },
    "example": 5
   },
   "CreditsRemaining": {
    "description": "Credits available on the account after this request. Sent with `x-credits-charged` on charged requests.",
    "schema": {
     "type": "integer"
    },
    "example": 48190
   }
  },
  "responses": {
   "BadRequest": {
    "description": "Bad request: the parameters are well-formed but unusable (for example an unknown market or a malformed token).",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/ErrorResponse"
      },
      "example": {
       "detail": "end must be on or after start"
      }
     }
    }
   },
   "Unauthorized": {
    "description": "Missing or invalid API key.",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/ErrorResponse"
      },
      "example": {
       "detail": "missing or invalid API key"
      }
     }
    }
   },
   "NotFound": {
    "description": "The property, stay, job or record was not found.",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/ErrorResponse"
      },
      "example": {
       "detail": "job not found"
      }
     }
    }
   },
   "Conflict": {
    "description": "The Idempotency-Key was already used for a different request body.",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/ErrorResponse"
      },
      "example": {
       "detail": "Idempotency-Key was already used for a different request"
      }
     }
    }
   },
   "ValidationError": {
    "description": "Request validation failed.",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/HTTPValidationError"
      },
      "example": {
       "detail": [
        {
         "loc": [
          "body",
          "token"
         ],
         "msg": "Field required",
         "type": "missing"
        }
       ]
      }
     }
    }
   },
   "UnprocessableRequest": {
    "description": "Request validation failed. `detail` is a list of problems for schema errors, or a string for semantic checks performed by the endpoint.",
    "content": {
     "application/json": {
      "schema": {
       "anyOf": [
        {
         "$ref": "#/components/schemas/HTTPValidationError"
        },
        {
         "$ref": "#/components/schemas/ErrorResponse"
        }
       ]
      },
      "example": {
       "detail": [
        {
         "loc": [
          "body",
          "name"
         ],
         "msg": "Field required",
         "type": "missing"
        }
       ]
      }
     }
    }
   },
   "RateLimited": {
    "description": "Too many requests: the key's requests-per-minute limit was exceeded, or (once credit enforcement is on) the plan's concurrent-request limit. No rate-limit or Retry-After headers are sent; back off and retry.",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/ErrorResponse"
      },
      "example": {
       "detail": "rate limit 60/min exceeded"
      }
     }
    }
   },
   "InsufficientCredits": {
    "description": "Not enough credits for this request. Only returned once credit enforcement is switched on; during the beta metering runs in shadow mode and never blocks.",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/ErrorResponse"
      },
      "example": {
       "detail": "insufficient credits: this request costs 5, 0 available. Credits renew 2026-11-01."
      }
     }
    }
   },
   "UpstreamError": {
    "description": "The upstream source failed, blocked the request or returned an unusable answer. Safe to retry later; failed requests are not charged.",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/ErrorResponse"
      },
      "example": {
       "detail": "RuntimeError"
      }
     }
    }
   },
   "ServiceUnavailable": {
    "description": "Temporarily unavailable: a dependency of this endpoint is down, or the upstream source changed its contract. Retry later.",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/ErrorResponse"
      },
      "example": {
       "detail": "database unavailable: OperationalError"
      }
     }
    }
   }
  },
  "schemas": {
   "AgodaRequest": {
    "properties": {
     "property_id": {
      "type": "string",
      "minLength": 1,
      "title": "Property Id",
      "description": "Numeric id returned by `POST /v1/ota/agoda/search`, or from the Agoda URL — the digits in `agoda.com/…/hotel/…-h8795952.html`, or the `hotelId` query parameter.",
      "examples": [
       "8795952"
      ]
     },
     "check_in": {
      "type": "string",
      "format": "date",
      "title": "Check In",
      "description": "First night of the stay, `YYYY-MM-DD`.",
      "examples": [
       "2029-02-05"
      ]
     },
     "check_out": {
      "anyOf": [
       {
        "type": "string",
        "format": "date"
       },
       {
        "type": "null"
       }
      ],
      "title": "Check Out",
      "description": "Departure date. An alternative to `nights` — if both are given, this wins.",
      "examples": [
       "2029-02-06"
      ]
     },
     "nights": {
      "type": "integer",
      "maximum": 30.0,
      "minimum": 1.0,
      "title": "Nights",
      "description": "Length of stay. Ignored when `check_out` is supplied.",
      "default": 1,
      "examples": [
       1
      ]
     },
     "adults": {
      "type": "integer",
      "maximum": 8.0,
      "minimum": 1.0,
      "title": "Adults",
      "description": "Adults in the room. Two is the hotel default; pass one for a hostel, which is priced per bed. Any value from 1 to 8 is accepted.",
      "default": 2,
      "examples": [
       2
      ]
     },
     "rooms": {
      "type": "integer",
      "maximum": 8.0,
      "minimum": 1.0,
      "title": "Rooms",
      "description": "Rooms requested.",
      "default": 1,
      "examples": [
       1
      ]
     },
     "currency": {
      "type": "string",
      "enum": [
       "AED",
       "AUD",
       "BRL",
       "CAD",
       "CHF",
       "CZK",
       "EUR",
       "GBP",
       "HKD",
       "IDR",
       "INR",
       "JPY",
       "KRW",
       "MYR",
       "NZD",
       "PHP",
       "PLN",
       "SEK",
       "SGD",
       "THB",
       "TWD",
       "USD",
       "ZAR"
      ],
      "title": "Currency",
      "description": "One of 23 supported. Unlike Hotels.com these ARE comparable — Agoda converts one underlying rate.",
      "default": "USD",
      "examples": [
       "USD"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "property_id",
     "check_in"
    ],
    "title": "AgodaRequest",
    "description": "Agoda's own room types and rate plans. Its currencies are genuine FX\nconversions of a single rate.",
    "examples": [
     {
      "adults": 2,
      "check_in": "2029-02-05",
      "currency": "USD",
      "nights": 1,
      "property_id": "8795952"
     }
    ]
   },
   "AgodaSearchRequest": {
    "properties": {
     "name": {
      "type": "string",
      "minLength": 1,
      "title": "Name",
      "description": "Hotel name as a guest would search for it.",
      "examples": [
       "Moxy Boston Downtown"
      ]
     },
     "city": {
      "type": "string",
      "title": "City",
      "description": "Strongly recommended. Included in Agoda's query and used to rank same-brand results in the intended city.",
      "default": "",
      "examples": [
       "Boston"
      ]
     },
     "origin": {
      "type": "string",
      "enum": [
       "AD",
       "AE",
       "AF",
       "AG",
       "AI",
       "AL",
       "AM",
       "AO",
       "AQ",
       "AR",
       "AS",
       "AT",
       "AU",
       "AW",
       "AX",
       "AZ",
       "BA",
       "BB",
       "BD",
       "BE",
       "BF",
       "BG",
       "BH",
       "BI",
       "BJ",
       "BL",
       "BM",
       "BN",
       "BO",
       "BQ",
       "BR",
       "BS",
       "BT",
       "BV",
       "BW",
       "BY",
       "BZ",
       "CA",
       "CC",
       "CD",
       "CF",
       "CG",
       "CH",
       "CI",
       "CK",
       "CL",
       "CM",
       "CN",
       "CO",
       "CR",
       "CU",
       "CV",
       "CW",
       "CX",
       "CY",
       "CZ",
       "DE",
       "DJ",
       "DK",
       "DM",
       "DO",
       "DZ",
       "EC",
       "EE",
       "EG",
       "EH",
       "ER",
       "ES",
       "ET",
       "FI",
       "FJ",
       "FK",
       "FM",
       "FO",
       "FR",
       "GA",
       "GB",
       "GD",
       "GE",
       "GF",
       "GG",
       "GH",
       "GI",
       "GL",
       "GM",
       "GN",
       "GP",
       "GQ",
       "GR",
       "GS",
       "GT",
       "GU",
       "GW",
       "GY",
       "HK",
       "HM",
       "HN",
       "HR",
       "HT",
       "HU",
       "ID",
       "IE",
       "IL",
       "IM",
       "IN",
       "IO",
       "IQ",
       "IR",
       "IS",
       "IT",
       "JE",
       "JM",
       "JO",
       "JP",
       "KE",
       "KG",
       "KH",
       "KI",
       "KM",
       "KN",
       "KP",
       "KR",
       "KW",
       "KY",
       "KZ",
       "LA",
       "LB",
       "LC",
       "LI",
       "LK",
       "LR",
       "LS",
       "LT",
       "LU",
       "LV",
       "LY",
       "MA",
       "MC",
       "MD",
       "ME",
       "MF",
       "MG",
       "MH",
       "MK",
       "ML",
       "MM",
       "MN",
       "MO",
       "MP",
       "MQ",
       "MR",
       "MS",
       "MT",
       "MU",
       "MV",
       "MW",
       "MX",
       "MY",
       "MZ",
       "NA",
       "NC",
       "NE",
       "NF",
       "NG",
       "NI",
       "NL",
       "NO",
       "NP",
       "NR",
       "NU",
       "NZ",
       "OM",
       "PA",
       "PE",
       "PF",
       "PG",
       "PH",
       "PK",
       "PL",
       "PM",
       "PN",
       "PR",
       "PS",
       "PT",
       "PW",
       "PY",
       "QA",
       "RE",
       "RO",
       "RS",
       "RU",
       "RW",
       "SA",
       "SB",
       "SC",
       "SD",
       "SE",
       "SG",
       "SH",
       "SI",
       "SJ",
       "SK",
       "SL",
       "SM",
       "SN",
       "SO",
       "SR",
       "SS",
       "ST",
       "SV",
       "SX",
       "SY",
       "SZ",
       "TC",
       "TD",
       "TF",
       "TG",
       "TH",
       "TJ",
       "TK",
       "TL",
       "TM",
       "TN",
       "TO",
       "TR",
       "TT",
       "TV",
       "TW",
       "TZ",
       "UA",
       "UG",
       "UK",
       "UM",
       "US",
       "UY",
       "UZ",
       "VA",
       "VC",
       "VE",
       "VG",
       "VI",
       "VN",
       "VU",
       "WF",
       "WS",
       "XK",
       "YE",
       "YT",
       "ZA",
       "ZM",
       "ZW"
      ],
      "maxLength": 2,
      "minLength": 2,
      "title": "Origin",
      "description": "Two-letter user-country context sent to Agoda. This is not the hotel's country; `city` identifies the location.",
      "default": "US",
      "examples": [
       "US"
      ]
     },
     "limit": {
      "type": "integer",
      "maximum": 10.0,
      "minimum": 1.0,
      "title": "Limit",
      "description": "Maximum hotel candidates to return, best match first.",
      "default": 5,
      "examples": [
       5
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "name"
    ],
    "title": "AgodaSearchRequest",
    "description": "Find Agoda's numeric property id from a hotel name.\n\nRead `recommended_match`, not `matches[0]`. It is null when the provider\nreturned only weak or ambiguous candidates.",
    "examples": [
     {
      "city": "Boston",
      "limit": 5,
      "name": "Moxy Boston Downtown",
      "origin": "US"
     }
    ]
   },
   "AirbnbAvailabilityCalendarRequest": {
    "properties": {
     "currency": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "enum": [
       "AED",
       "AUD",
       "BAM",
       "BGN",
       "BRL",
       "CAD",
       "CHF",
       "CLP",
       "CNY",
       "COP",
       "CRC",
       "CZK",
       "DKK",
       "EGP",
       "EUR",
       "GBP",
       "GHS",
       "GTQ",
       "HKD",
       "HNL",
       "HUF",
       "IDR",
       "ILS",
       "INR",
       "JPY",
       "KES",
       "KRW",
       "KZT",
       "MAD",
       "MXN",
       "MYR",
       "NOK",
       "NZD",
       "PEN",
       "PHP",
       "PLN",
       "QAR",
       "RON",
       "RUB",
       "SAR",
       "SEK",
       "SGD",
       "THB",
       "TRY",
       "TWD",
       "UAH",
       "UGX",
       "USD",
       "UYU",
       "VND",
       "ZAR"
      ],
      "title": "Currency",
      "description": "Airbnb-supported ISO 4217 currency for quoted prices. Omit for the domain's default; the currency Airbnb actually priced in is returned on every priced day.",
      "examples": [
       "CAD"
      ]
     },
     "adults": {
      "type": "integer",
      "maximum": 16.0,
      "minimum": 1.0,
      "title": "Adults",
      "description": "Adults aged 13+; quotes are priced for this party.",
      "default": 1,
      "examples": [
       2
      ]
     },
     "children": {
      "type": "integer",
      "maximum": 15.0,
      "minimum": 0.0,
      "title": "Children",
      "description": "Children aged 2-12.",
      "default": 0,
      "examples": [
       0
      ]
     },
     "infants": {
      "type": "integer",
      "maximum": 5.0,
      "minimum": 0.0,
      "title": "Infants",
      "description": "Infants under 2.",
      "default": 0,
      "examples": [
       0
      ]
     },
     "pets": {
      "type": "integer",
      "maximum": 5.0,
      "minimum": 0.0,
      "title": "Pets",
      "description": "Pets.",
      "default": 0,
      "examples": [
       0
      ]
     },
     "max_price_quotes": {
      "anyOf": [
       {
        "type": "integer",
        "maximum": 92.0,
        "minimum": 1.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Max Price Quotes",
      "description": "Upper bound on price quotes, 1-92. The request holds 8 + this many credits and is charged 8 + the nights actually priced.",
      "examples": [
       12
      ]
     },
     "stay_nights": {
      "anyOf": [
       {
        "type": "integer",
        "maximum": 28.0,
        "minimum": 1.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Stay Nights",
      "description": "Length of the stay each priced date is quoted for. Omit to use each date's own minimum stay. Airbnb folds cleaning and service fees into its nightly rate, so the same night costs less per night on a longer stay. 1-28.",
      "examples": [
       2
      ]
     },
     "engine": {
      "type": "string",
      "const": "airbnb_property_availability_calendar",
      "title": "Engine",
      "description": "Accepted for SearchAPI request compatibility; the path already selects the engine.",
      "default": "airbnb_property_availability_calendar"
     },
     "property_id": {
      "type": "string",
      "pattern": "^\\d{1,25}$",
      "title": "Property Id",
      "description": "Numeric Airbnb listing id: the number in `https://www.airbnb.com/rooms/<id>`, or `properties[].id` from `/v1/serp/airbnb`.",
      "examples": [
       "34397368"
      ]
     },
     "start_month": {
      "anyOf": [
       {
        "type": "integer",
        "maximum": 12.0,
        "minimum": 1.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Start Month",
      "description": "SearchAPI `start_month`: first month, 1-12. Defaults to the current month.",
      "examples": [
       10
      ]
     },
     "start_year": {
      "anyOf": [
       {
        "type": "integer",
        "maximum": 2100.0,
        "minimum": 2020.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Start Year",
      "description": "SearchAPI `start_year`. Defaults to the current year.",
      "examples": [
       2026
      ]
     },
     "months": {
      "type": "integer",
      "maximum": 12.0,
      "minimum": 1.0,
      "title": "Months",
      "description": "SearchAPI `months`: 1-12, default 12.",
      "default": 12,
      "examples": [
       12
      ]
     },
     "airbnb_domain": {
      "type": "string",
      "enum": [
       "airbnb.ae",
       "airbnb.am",
       "airbnb.at",
       "airbnb.az",
       "airbnb.ba",
       "airbnb.be",
       "airbnb.ca",
       "airbnb.cat",
       "airbnb.ch",
       "airbnb.cl",
       "airbnb.cn",
       "airbnb.co.cr",
       "airbnb.co.id",
       "airbnb.co.in",
       "airbnb.co.kr",
       "airbnb.co.nz",
       "airbnb.co.uk",
       "airbnb.co.ve",
       "airbnb.com",
       "airbnb.com.ar",
       "airbnb.com.au",
       "airbnb.com.bo",
       "airbnb.com.br",
       "airbnb.com.bz",
       "airbnb.com.co",
       "airbnb.com.ec",
       "airbnb.com.ee",
       "airbnb.com.gt",
       "airbnb.com.hk",
       "airbnb.com.hn",
       "airbnb.com.my",
       "airbnb.com.ni",
       "airbnb.com.pa",
       "airbnb.com.pe",
       "airbnb.com.ph",
       "airbnb.com.py",
       "airbnb.com.ro",
       "airbnb.com.sg",
       "airbnb.com.sv",
       "airbnb.com.tr",
       "airbnb.com.tw",
       "airbnb.com.ua",
       "airbnb.com.vn",
       "airbnb.cz",
       "airbnb.de",
       "airbnb.dk",
       "airbnb.es",
       "airbnb.fi",
       "airbnb.fr",
       "airbnb.gr",
       "airbnb.gy",
       "airbnb.hu",
       "airbnb.ie",
       "airbnb.is",
       "airbnb.it",
       "airbnb.jp",
       "airbnb.lt",
       "airbnb.lu",
       "airbnb.lv",
       "airbnb.me",
       "airbnb.mx",
       "airbnb.nl",
       "airbnb.no",
       "airbnb.pl",
       "airbnb.pt",
       "airbnb.rs",
       "airbnb.ru",
       "airbnb.se",
       "airbnb.si",
       "ar.airbnb.com",
       "bg.airbnb.com",
       "de.airbnb.lu",
       "es.airbnb.com",
       "fr.airbnb.be",
       "fr.airbnb.ca",
       "fr.airbnb.ch",
       "ga.airbnb.ie",
       "he.airbnb.com",
       "hi.airbnb.co.in",
       "hr.airbnb.com",
       "it.airbnb.ch",
       "ka.airbnb.com",
       "kn.airbnb.co.in",
       "mk.airbnb.com",
       "mr.airbnb.co.in",
       "mt.airbnb.com.mt",
       "sk.airbnb.com",
       "sq.airbnb.com",
       "sw.airbnb.com",
       "th.airbnb.com",
       "xh.airbnb.co.za",
       "zh-t.airbnb.com",
       "zh.airbnb.com",
       "zu.airbnb.co.za"
      ],
      "title": "Airbnb Domain",
      "description": "Country/language Airbnb host. The host does not change prices; it picks the market and the default currency.",
      "default": "airbnb.com",
      "examples": [
       "airbnb.ca"
      ]
     },
     "price_nights": {
      "type": "string",
      "enum": [
       "none",
       "sample",
       "all"
      ],
      "title": "Price Nights",
      "description": "ScraperCompany addition. Default `none` returns exactly SearchAPI's fields at the base cost. `none`: availability only (one upstream request). `sample`: quote `max_price_quotes` check-in dates spread evenly over the valid ones (default 12). `all`: quote every valid check-in date in order, up to `max_price_quotes` (default and maximum 92). Each quote is one ~0.9 KB upstream request and one credit.",
      "default": "none",
      "examples": [
       "sample"
      ]
     },
     "zero_retention": {
      "type": "boolean",
      "title": "Zero Retention",
      "description": "Accepted for SearchAPI compatibility; calendars and quotes are never persisted.",
      "default": false
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "property_id"
    ],
    "title": "AirbnbAvailabilityCalendarRequest",
    "description": "SearchAPI's ``airbnb_property_availability_calendar`` contract, plus prices.",
    "examples": [
     {
      "adults": 2,
      "airbnb_domain": "airbnb.ca",
      "currency": "CAD",
      "max_price_quotes": 6,
      "months": 2,
      "price_nights": "sample",
      "property_id": "34397368"
     }
    ]
   },
   "AirbnbCalendarRequest": {
    "properties": {
     "currency": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "enum": [
       "AED",
       "AUD",
       "BAM",
       "BGN",
       "BRL",
       "CAD",
       "CHF",
       "CLP",
       "CNY",
       "COP",
       "CRC",
       "CZK",
       "DKK",
       "EGP",
       "EUR",
       "GBP",
       "GHS",
       "GTQ",
       "HKD",
       "HNL",
       "HUF",
       "IDR",
       "ILS",
       "INR",
       "JPY",
       "KES",
       "KRW",
       "KZT",
       "MAD",
       "MXN",
       "MYR",
       "NOK",
       "NZD",
       "PEN",
       "PHP",
       "PLN",
       "QAR",
       "RON",
       "RUB",
       "SAR",
       "SEK",
       "SGD",
       "THB",
       "TRY",
       "TWD",
       "UAH",
       "UGX",
       "USD",
       "UYU",
       "VND",
       "ZAR"
      ],
      "title": "Currency",
      "description": "Airbnb-supported ISO 4217 currency for quoted prices. Omit for the domain's default; the currency Airbnb actually priced in is returned on every priced day.",
      "examples": [
       "CAD"
      ]
     },
     "adults": {
      "type": "integer",
      "maximum": 16.0,
      "minimum": 1.0,
      "title": "Adults",
      "description": "Adults aged 13+; quotes are priced for this party.",
      "default": 1,
      "examples": [
       2
      ]
     },
     "children": {
      "type": "integer",
      "maximum": 15.0,
      "minimum": 0.0,
      "title": "Children",
      "description": "Children aged 2-12.",
      "default": 0,
      "examples": [
       0
      ]
     },
     "infants": {
      "type": "integer",
      "maximum": 5.0,
      "minimum": 0.0,
      "title": "Infants",
      "description": "Infants under 2.",
      "default": 0,
      "examples": [
       0
      ]
     },
     "pets": {
      "type": "integer",
      "maximum": 5.0,
      "minimum": 0.0,
      "title": "Pets",
      "description": "Pets.",
      "default": 0,
      "examples": [
       0
      ]
     },
     "max_price_quotes": {
      "anyOf": [
       {
        "type": "integer",
        "maximum": 92.0,
        "minimum": 1.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Max Price Quotes",
      "description": "Upper bound on price quotes, 1-92. The request holds 8 + this many credits and is charged 8 + the nights actually priced.",
      "examples": [
       12
      ]
     },
     "stay_nights": {
      "anyOf": [
       {
        "type": "integer",
        "maximum": 28.0,
        "minimum": 1.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Stay Nights",
      "description": "Length of the stay each priced date is quoted for. Omit to use each date's own minimum stay. Airbnb folds cleaning and service fees into its nightly rate, so the same night costs less per night on a longer stay. 1-28.",
      "examples": [
       2
      ]
     },
     "listing_id": {
      "type": "string",
      "pattern": "^\\d{1,25}$",
      "title": "Listing Id",
      "description": "Numeric Airbnb listing id: the number in `https://www.airbnb.com/rooms/<id>`, or `properties[].id` from `/v1/serp/airbnb`.",
      "examples": [
       "34397368"
      ]
     },
     "airbnb_domain": {
      "type": "string",
      "enum": [
       "airbnb.ae",
       "airbnb.am",
       "airbnb.at",
       "airbnb.az",
       "airbnb.ba",
       "airbnb.be",
       "airbnb.ca",
       "airbnb.cat",
       "airbnb.ch",
       "airbnb.cl",
       "airbnb.cn",
       "airbnb.co.cr",
       "airbnb.co.id",
       "airbnb.co.in",
       "airbnb.co.kr",
       "airbnb.co.nz",
       "airbnb.co.uk",
       "airbnb.co.ve",
       "airbnb.com",
       "airbnb.com.ar",
       "airbnb.com.au",
       "airbnb.com.bo",
       "airbnb.com.br",
       "airbnb.com.bz",
       "airbnb.com.co",
       "airbnb.com.ec",
       "airbnb.com.ee",
       "airbnb.com.gt",
       "airbnb.com.hk",
       "airbnb.com.hn",
       "airbnb.com.my",
       "airbnb.com.ni",
       "airbnb.com.pa",
       "airbnb.com.pe",
       "airbnb.com.ph",
       "airbnb.com.py",
       "airbnb.com.ro",
       "airbnb.com.sg",
       "airbnb.com.sv",
       "airbnb.com.tr",
       "airbnb.com.tw",
       "airbnb.com.ua",
       "airbnb.com.vn",
       "airbnb.cz",
       "airbnb.de",
       "airbnb.dk",
       "airbnb.es",
       "airbnb.fi",
       "airbnb.fr",
       "airbnb.gr",
       "airbnb.gy",
       "airbnb.hu",
       "airbnb.ie",
       "airbnb.is",
       "airbnb.it",
       "airbnb.jp",
       "airbnb.lt",
       "airbnb.lu",
       "airbnb.lv",
       "airbnb.me",
       "airbnb.mx",
       "airbnb.nl",
       "airbnb.no",
       "airbnb.pl",
       "airbnb.pt",
       "airbnb.rs",
       "airbnb.ru",
       "airbnb.se",
       "airbnb.si",
       "ar.airbnb.com",
       "bg.airbnb.com",
       "de.airbnb.lu",
       "es.airbnb.com",
       "fr.airbnb.be",
       "fr.airbnb.ca",
       "fr.airbnb.ch",
       "ga.airbnb.ie",
       "he.airbnb.com",
       "hi.airbnb.co.in",
       "hr.airbnb.com",
       "it.airbnb.ch",
       "ka.airbnb.com",
       "kn.airbnb.co.in",
       "mk.airbnb.com",
       "mr.airbnb.co.in",
       "mt.airbnb.com.mt",
       "sk.airbnb.com",
       "sq.airbnb.com",
       "sw.airbnb.com",
       "th.airbnb.com",
       "xh.airbnb.co.za",
       "zh-t.airbnb.com",
       "zh.airbnb.com",
       "zu.airbnb.co.za"
      ],
      "title": "Airbnb Domain",
      "description": "Country/language Airbnb host. The host does not change prices; it picks the market and the default currency.",
      "default": "airbnb.com",
      "examples": [
       "airbnb.ca"
      ]
     },
     "months": {
      "type": "integer",
      "maximum": 12.0,
      "minimum": 1.0,
      "title": "Months",
      "description": "Calendar months to return, starting at `start_month` (default 3).",
      "default": 3,
      "examples": [
       3
      ]
     },
     "start_month": {
      "anyOf": [
       {
        "type": "integer",
        "maximum": 12.0,
        "minimum": 1.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Start Month",
      "description": "First month, 1-12. Defaults to the current month.",
      "examples": [
       10
      ]
     },
     "start_year": {
      "anyOf": [
       {
        "type": "integer",
        "maximum": 2100.0,
        "minimum": 2020.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Start Year",
      "description": "Year of `start_month`. Defaults to the current year.",
      "examples": [
       2026
      ]
     },
     "price_nights": {
      "type": "string",
      "enum": [
       "none",
       "sample",
       "all"
      ],
      "title": "Price Nights",
      "description": "`none`: availability only (one upstream request). `sample`: quote `max_price_quotes` check-in dates spread evenly over the valid ones (default 12). `all`: quote every valid check-in date in order, up to `max_price_quotes` (default and maximum 92). Each quote is one ~0.9 KB upstream request and one credit.",
      "default": "sample",
      "examples": [
       "sample"
      ]
     },
     "include_listing": {
      "type": "boolean",
      "title": "Include Listing",
      "description": "Add title, property type, rating, capacity and coordinates from one extra ~10 KB upstream request. No extra credits.",
      "default": false
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "listing_id"
    ],
    "title": "AirbnbCalendarRequest",
    "description": "Native priced Airbnb nightly calendar.",
    "examples": [
     {
      "adults": 2,
      "airbnb_domain": "airbnb.ca",
      "currency": "CAD",
      "listing_id": "34397368",
      "max_price_quotes": 8,
      "months": 2,
      "price_nights": "sample"
     }
    ]
   },
   "AirbnbSearchRequest": {
    "properties": {
     "q": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "title": "Q",
      "description": "Destination text. Required unless `bounding_box` is supplied; ignored for map bounds only when the two conflict.",
      "examples": [
       "Toronto"
      ]
     },
     "bounding_box": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "title": "Bounding Box",
      "description": "Map bounds as `[[ne_lat,ne_lng],[sw_lat,sw_lng]]`. Takes precedence over `q`.",
      "examples": [
       "[[43.72,-79.27],[43.62,-79.49]]"
      ]
     },
     "airbnb_domain": {
      "type": "string",
      "enum": [
       "airbnb.ae",
       "airbnb.am",
       "airbnb.at",
       "airbnb.az",
       "airbnb.ba",
       "airbnb.be",
       "airbnb.ca",
       "airbnb.cat",
       "airbnb.ch",
       "airbnb.cl",
       "airbnb.cn",
       "airbnb.co.cr",
       "airbnb.co.id",
       "airbnb.co.in",
       "airbnb.co.kr",
       "airbnb.co.nz",
       "airbnb.co.uk",
       "airbnb.co.ve",
       "airbnb.com",
       "airbnb.com.ar",
       "airbnb.com.au",
       "airbnb.com.bo",
       "airbnb.com.br",
       "airbnb.com.bz",
       "airbnb.com.co",
       "airbnb.com.ec",
       "airbnb.com.ee",
       "airbnb.com.gt",
       "airbnb.com.hk",
       "airbnb.com.hn",
       "airbnb.com.my",
       "airbnb.com.ni",
       "airbnb.com.pa",
       "airbnb.com.pe",
       "airbnb.com.ph",
       "airbnb.com.py",
       "airbnb.com.ro",
       "airbnb.com.sg",
       "airbnb.com.sv",
       "airbnb.com.tr",
       "airbnb.com.tw",
       "airbnb.com.ua",
       "airbnb.com.vn",
       "airbnb.cz",
       "airbnb.de",
       "airbnb.dk",
       "airbnb.es",
       "airbnb.fi",
       "airbnb.fr",
       "airbnb.gr",
       "airbnb.gy",
       "airbnb.hu",
       "airbnb.ie",
       "airbnb.is",
       "airbnb.it",
       "airbnb.jp",
       "airbnb.lt",
       "airbnb.lu",
       "airbnb.lv",
       "airbnb.me",
       "airbnb.mx",
       "airbnb.nl",
       "airbnb.no",
       "airbnb.pl",
       "airbnb.pt",
       "airbnb.rs",
       "airbnb.ru",
       "airbnb.se",
       "airbnb.si",
       "ar.airbnb.com",
       "bg.airbnb.com",
       "de.airbnb.lu",
       "es.airbnb.com",
       "fr.airbnb.be",
       "fr.airbnb.ca",
       "fr.airbnb.ch",
       "ga.airbnb.ie",
       "he.airbnb.com",
       "hi.airbnb.co.in",
       "hr.airbnb.com",
       "it.airbnb.ch",
       "ka.airbnb.com",
       "kn.airbnb.co.in",
       "mk.airbnb.com",
       "mr.airbnb.co.in",
       "mt.airbnb.com.mt",
       "sk.airbnb.com",
       "sq.airbnb.com",
       "sw.airbnb.com",
       "th.airbnb.com",
       "xh.airbnb.co.za",
       "zh-t.airbnb.com",
       "zh.airbnb.com",
       "zu.airbnb.co.za"
      ],
      "title": "Airbnb Domain",
      "description": "Country/language Airbnb host, such as `airbnb.com`, `airbnb.ca` or `fr.airbnb.ca`.",
      "default": "airbnb.com",
      "examples": [
       "airbnb.ca"
      ]
     },
     "currency": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "enum": [
       "AED",
       "AUD",
       "BAM",
       "BGN",
       "BRL",
       "CAD",
       "CHF",
       "CLP",
       "CNY",
       "COP",
       "CRC",
       "CZK",
       "DKK",
       "EGP",
       "EUR",
       "GBP",
       "GHS",
       "GTQ",
       "HKD",
       "HNL",
       "HUF",
       "IDR",
       "ILS",
       "INR",
       "JPY",
       "KES",
       "KRW",
       "KZT",
       "MAD",
       "MXN",
       "MYR",
       "NOK",
       "NZD",
       "PEN",
       "PHP",
       "PLN",
       "QAR",
       "RON",
       "RUB",
       "SAR",
       "SEK",
       "SGD",
       "THB",
       "TRY",
       "TWD",
       "UAH",
       "UGX",
       "USD",
       "UYU",
       "VND",
       "ZAR"
      ],
      "title": "Currency",
      "description": "Airbnb-supported ISO 4217 display currency. Omit to use the selected domain's default.",
      "examples": [
       "CAD"
      ]
     },
     "include_taxes": {
      "type": "boolean",
      "title": "Include Taxes",
      "description": "Expose tax-inclusive totals when Airbnb includes a tax line in the search price breakdown.",
      "default": false
     },
     "check_in_date": {
      "anyOf": [
       {
        "type": "string",
        "format": "date"
       },
       {
        "type": "null"
       }
      ],
      "title": "Check In Date",
      "description": "Exact check-in date, `YYYY-MM-DD`. Cannot be mixed with `time_period`.",
      "examples": [
       "2029-02-01"
      ]
     },
     "check_out_date": {
      "anyOf": [
       {
        "type": "string",
        "format": "date"
       },
       {
        "type": "null"
       }
      ],
      "title": "Check Out Date",
      "description": "Exact departure date. Requires `check_in_date`; defaults to the next day when omitted.",
      "examples": [
       "2029-02-03"
      ]
     },
     "time_period": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "enum": [
       "one_month",
       "one_week",
       "weekend_trip"
      ],
      "title": "Time Period",
      "description": "Flexible date search: `weekend_trip`, `one_week` or `one_month`. Defaults to `one_week` when no exact dates are supplied.",
      "examples": [
       "weekend_trip"
      ]
     },
     "adults": {
      "anyOf": [
       {
        "type": "integer",
        "maximum": 16.0,
        "minimum": 0.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Adults",
      "description": "Adults aged 13+, from 0 through 16. Defaults to one when another guest count is set.",
      "examples": [
       2
      ]
     },
     "children": {
      "anyOf": [
       {
        "type": "integer",
        "maximum": 15.0,
        "minimum": 0.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Children",
      "description": "Children aged 2–12. Maximum 15.",
      "examples": [
       1
      ]
     },
     "infants": {
      "anyOf": [
       {
        "type": "integer",
        "maximum": 5.0,
        "minimum": 0.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Infants",
      "description": "Infants under 2. Maximum 5.",
      "examples": [
       1
      ]
     },
     "pets": {
      "anyOf": [
       {
        "type": "integer",
        "maximum": 5.0,
        "minimum": 0.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Pets",
      "description": "Pets. Maximum 5.",
      "examples": [
       1
      ]
     },
     "price_min": {
      "anyOf": [
       {
        "type": "integer",
        "minimum": 0.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Price Min",
      "description": "Minimum displayed trip price.",
      "examples": [
       100
      ]
     },
     "price_max": {
      "anyOf": [
       {
        "type": "integer",
        "minimum": 0.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Price Max",
      "description": "Maximum displayed trip price.",
      "examples": [
       500
      ]
     },
     "type_of_place": {
      "type": "string",
      "enum": [
       "any",
       "entire_home",
       "room"
      ],
      "title": "Type Of Place",
      "description": "`any`, `room`, or `entire_home`.",
      "default": "any",
      "examples": [
       "entire_home"
      ]
     },
     "property_types": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "title": "Property Types",
      "description": "Comma-separated `house`, `guesthouse`, `apartment` and/or `hotel`.",
      "examples": [
       "house,apartment"
      ],
      "x-multiple": true,
      "x-options": [
       "apartment",
       "guesthouse",
       "hotel",
       "house"
      ]
     },
     "bedrooms": {
      "anyOf": [
       {
        "type": "integer",
        "maximum": 8.0,
        "minimum": 0.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Bedrooms",
      "description": "Minimum bedrooms, 0–8.",
      "examples": [
       2
      ]
     },
     "beds": {
      "anyOf": [
       {
        "type": "integer",
        "maximum": 8.0,
        "minimum": 0.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Beds",
      "description": "Minimum beds, 0–8.",
      "examples": [
       2
      ]
     },
     "bathrooms": {
      "anyOf": [
       {
        "type": "integer",
        "maximum": 8.0,
        "minimum": 0.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Bathrooms",
      "description": "Minimum bathrooms, 0–8.",
      "examples": [
       1
      ]
     },
     "amenities": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "title": "Amenities",
      "description": "Comma-separated SearchAPI amenity names, such as `guest_favorite,wifi,kitchen,instant_book`.",
      "examples": [
       "wifi,kitchen"
      ],
      "x-multiple": true,
      "x-options": [
       "24_hour_check_in",
       "air_conditioning",
       "bbq_grill",
       "breakfast",
       "buzzer_wireless_intercom",
       "cable_tv",
       "carbon_monoxide_alarm",
       "cats",
       "crib",
       "dedicated_workspace",
       "dogs",
       "doorman",
       "dryer",
       "elevator",
       "essentials",
       "ev_charger",
       "family_kid_friendly",
       "fire_extinguisher",
       "first_aid_kit",
       "free_parking_on_premises",
       "free_street_parking",
       "garage_parking",
       "guest_favorite",
       "gym",
       "hair_dryer",
       "hangers",
       "heating",
       "hot_tub",
       "indoor_fireplace",
       "instant_book",
       "internet",
       "iron",
       "jacuzzi_tub",
       "kitchen",
       "lock_on_bedroom_door",
       "lockbox",
       "luxe",
       "other_pets",
       "paid_parking_off_premises",
       "permit_parking",
       "pets_allowed",
       "pets_live_on_this_property",
       "pool",
       "private_entrance",
       "safety_card",
       "self_check_in",
       "shampoo",
       "smoke_alarm",
       "smoking_allowed",
       "suitable_for_events",
       "tv",
       "washer",
       "wheelchair_accessible",
       "wifi"
      ]
     },
     "next_page_token": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "title": "Next Page Token",
      "description": "Opaque cursor returned in `pagination.next_page_token`.",
      "examples": [
       "eyJzZWN0aW9uX29mZnNldCI6MH0="
      ]
     },
     "zero_retention": {
      "type": "boolean",
      "title": "Zero Retention",
      "description": "Accepted for SearchAPI request compatibility. This endpoint never stores raw HTML or search results, regardless of the value.",
      "default": false
     }
    },
    "additionalProperties": false,
    "type": "object",
    "title": "AirbnbSearchRequest",
    "description": "SearchAPI's ``engine=airbnb`` request contract.",
    "examples": [
     {
      "adults": 2,
      "airbnb_domain": "airbnb.ca",
      "amenities": "wifi,kitchen",
      "check_in_date": "2029-02-01",
      "check_out_date": "2029-02-03",
      "currency": "CAD",
      "include_taxes": true,
      "q": "Toronto"
     }
    ]
   },
   "AmazonReviewsRequest": {
    "properties": {
     "asin": {
      "type": "string",
      "maxLength": 10,
      "minLength": 10,
      "pattern": "^[A-Z0-9]+$",
      "title": "Asin",
      "description": "Product ASIN.",
      "examples": [
       "B084PBWBJR"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "asin"
    ],
    "title": "AmazonReviewsRequest",
    "description": "A product's ratings histogram and featured reviews.\n\nThe `/product-reviews` list requires sign-in, so this answers with the\nproduct page's own reviews widget: the 5→1 histogram, the global\nratings count, and the featured reviews. Rendered in a real browser.",
    "examples": [
     {
      "asin": "B084PBWBJR"
     }
    ]
   },
   "AmazonSearchRequest": {
    "properties": {
     "q": {
      "type": "string",
      "maxLength": 300,
      "minLength": 1,
      "title": "Q",
      "description": "Search query.",
      "examples": [
       "bathrobe"
      ]
     },
     "page": {
      "type": "integer",
      "maximum": 20.0,
      "minimum": 1.0,
      "title": "Page",
      "description": "Result page.",
      "default": 1,
      "examples": [
       1
      ]
     },
     "sort": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "enum": [
       "date-desc-rank",
       "price-asc-rank",
       "price-desc-rank",
       "relevanceblanks",
       "review-rank"
      ],
      "title": "Sort",
      "description": "Amazon's own sort values.",
      "examples": [
       null
      ]
     },
     "min_rating": {
      "anyOf": [
       {
        "type": "number",
        "maximum": 4.5,
        "minimum": 0.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Min Rating",
      "description": "Amazon's customer-rating filter (0..4.5).",
      "examples": [
       null
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "q"
    ],
    "title": "AmazonSearchRequest",
    "description": "Amazon product search over plain HTTP.\n\nOne page (~48) of result cards. Prices follow the local\npoint-of-sale (a Canadian exit answers CAD): `price_text` is the\ndisplay string verbatim with a best-effort `currency` guess — never\nsilently USD'd. Sponsored rows are labelled, not dropped.",
    "examples": [
     {
      "q": "bathrobe"
     }
    ]
   },
   "BingSearchRequest": {
    "properties": {
     "q": {
      "type": "string",
      "maxLength": 400,
      "minLength": 1,
      "title": "Q",
      "description": "Search query.",
      "examples": [
       "Hilton Chicago"
      ]
     },
     "first": {
      "anyOf": [
       {
        "type": "integer",
        "maximum": 1000.0,
        "minimum": 1.0
       },
       {
        "type": "null"
       }
      ],
      "title": "First",
      "description": "1-based result to start from; 11 pages past the first ten.",
      "examples": [
       null
      ]
     },
     "count": {
      "type": "integer",
      "maximum": 35.0,
      "minimum": 1.0,
      "title": "Count",
      "description": "Results per page (Bing serves up to 35).",
      "default": 10,
      "examples": [
       10
      ]
     },
     "market": {
      "anyOf": [
       {
        "type": "string",
        "pattern": "^[a-z]{2,3}-[A-Za-z]{2,4}$"
       },
       {
        "type": "null"
       }
      ],
      "title": "Market",
      "description": "Bing `mkt` (`en-US`, `fr-CA`); Bing geo-resolves when omitted.",
      "examples": [
       "en-US"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "q"
    ],
    "title": "BingSearchRequest",
    "description": "Bing organic web search over plain HTTP.\n\nOne page of up to 35 organic results with the click tracker decoded\nback to the destination URL. `first` is the 1-based result to start\nfrom (11 = second page of ten); `market` is Bing's own `mkt` value.",
    "examples": [
     {
      "count": 10,
      "q": "Hilton Chicago"
     }
    ]
   },
   "BookingRequest": {
    "properties": {
     "pagename": {
      "type": "string",
      "minLength": 2,
      "title": "Pagename",
      "description": "URL slug returned by `POST /v1/ota/booking/search`. For `booking.com/hotel/us/moxy-boston-downtown.html` the slug is `moxy-boston-downtown` and `country` is `us`.",
      "examples": [
       "moxy-boston-downtown"
      ]
     },
     "country": {
      "type": "string",
      "enum": [
       "ad",
       "ae",
       "af",
       "ag",
       "ai",
       "al",
       "am",
       "ao",
       "aq",
       "ar",
       "as",
       "at",
       "au",
       "aw",
       "ax",
       "az",
       "ba",
       "bb",
       "bd",
       "be",
       "bf",
       "bg",
       "bh",
       "bi",
       "bj",
       "bl",
       "bm",
       "bn",
       "bo",
       "bq",
       "br",
       "bs",
       "bt",
       "bv",
       "bw",
       "by",
       "bz",
       "ca",
       "cc",
       "cd",
       "cf",
       "cg",
       "ch",
       "ci",
       "ck",
       "cl",
       "cm",
       "cn",
       "co",
       "cr",
       "cu",
       "cv",
       "cw",
       "cx",
       "cy",
       "cz",
       "de",
       "dj",
       "dk",
       "dm",
       "do",
       "dz",
       "ec",
       "ee",
       "eg",
       "eh",
       "er",
       "es",
       "et",
       "fi",
       "fj",
       "fk",
       "fm",
       "fo",
       "fr",
       "ga",
       "gb",
       "gd",
       "ge",
       "gf",
       "gg",
       "gh",
       "gi",
       "gl",
       "gm",
       "gn",
       "gp",
       "gq",
       "gr",
       "gs",
       "gt",
       "gu",
       "gw",
       "gy",
       "hk",
       "hm",
       "hn",
       "hr",
       "ht",
       "hu",
       "id",
       "ie",
       "il",
       "im",
       "in",
       "io",
       "iq",
       "ir",
       "is",
       "it",
       "je",
       "jm",
       "jo",
       "jp",
       "ke",
       "kg",
       "kh",
       "ki",
       "km",
       "kn",
       "kp",
       "kr",
       "kw",
       "ky",
       "kz",
       "la",
       "lb",
       "lc",
       "li",
       "lk",
       "lr",
       "ls",
       "lt",
       "lu",
       "lv",
       "ly",
       "ma",
       "mc",
       "md",
       "me",
       "mf",
       "mg",
       "mh",
       "mk",
       "ml",
       "mm",
       "mn",
       "mo",
       "mp",
       "mq",
       "mr",
       "ms",
       "mt",
       "mu",
       "mv",
       "mw",
       "mx",
       "my",
       "mz",
       "na",
       "nc",
       "ne",
       "nf",
       "ng",
       "ni",
       "nl",
       "no",
       "np",
       "nr",
       "nu",
       "nz",
       "om",
       "pa",
       "pe",
       "pf",
       "pg",
       "ph",
       "pk",
       "pl",
       "pm",
       "pn",
       "pr",
       "ps",
       "pt",
       "pw",
       "py",
       "qa",
       "re",
       "ro",
       "rs",
       "ru",
       "rw",
       "sa",
       "sb",
       "sc",
       "sd",
       "se",
       "sg",
       "sh",
       "si",
       "sj",
       "sk",
       "sl",
       "sm",
       "sn",
       "so",
       "sr",
       "ss",
       "st",
       "sv",
       "sx",
       "sy",
       "sz",
       "tc",
       "td",
       "tf",
       "tg",
       "th",
       "tj",
       "tk",
       "tl",
       "tm",
       "tn",
       "to",
       "tr",
       "tt",
       "tv",
       "tw",
       "tz",
       "ua",
       "ug",
       "uk",
       "um",
       "us",
       "uy",
       "uz",
       "va",
       "vc",
       "ve",
       "vg",
       "vi",
       "vn",
       "vu",
       "wf",
       "ws",
       "xk",
       "ye",
       "yt",
       "za",
       "zm",
       "zw"
      ],
      "maxLength": 2,
      "minLength": 2,
      "title": "Country",
      "description": "The two-letter segment in the URL *before* the slug — part of the property's address on Booking, not your own location.",
      "default": "us",
      "examples": [
       "us"
      ]
     },
     "start": {
      "anyOf": [
       {
        "type": "string",
        "format": "date"
       },
       {
        "type": "null"
       }
      ],
      "title": "Start",
      "description": "Defaults to today.",
      "examples": [
       "2029-02-05"
      ]
     },
     "days": {
      "type": "integer",
      "maximum": 365.0,
      "minimum": 1.0,
      "title": "Days",
      "description": "Booking truncates any single response to 61 days, so larger windows are paged automatically — a year is 6 calls, not 1.",
      "default": 61,
      "examples": [
       61
      ]
     },
     "currency": {
      "type": "string",
      "enum": [
       "AED",
       "ARS",
       "AUD",
       "BRL",
       "CAD",
       "CHF",
       "CLP",
       "CNY",
       "COP",
       "CZK",
       "DKK",
       "EGP",
       "EUR",
       "GBP",
       "HKD",
       "HUF",
       "IDR",
       "ILS",
       "INR",
       "JPY",
       "KRW",
       "MXN",
       "MYR",
       "NOK",
       "NZD",
       "PEN",
       "PHP",
       "PLN",
       "QAR",
       "RON",
       "SAR",
       "SEK",
       "SGD",
       "THB",
       "TRY",
       "TWD",
       "USD",
       "VND",
       "ZAR"
      ],
      "title": "Currency",
      "description": "ISO 4217 code for the returned prices. Major currencies include AED, AUD, BRL, CAD, CHF, CNY, EUR, GBP, HKD, INR, JPY, KRW, MXN, NZD, SGD, USD; all 39 supported codes are listed in the enum.",
      "default": "USD",
      "examples": [
       "USD"
      ]
     },
     "adults": {
      "type": "integer",
      "maximum": 8.0,
      "minimum": 1.0,
      "title": "Adults",
      "description": "Adults in the room. Two is the hotel default; pass one for a hostel, which is priced per bed. Any value from 1 to 8 is accepted.",
      "default": 2,
      "examples": [
       2
      ]
     },
     "rooms": {
      "type": "integer",
      "maximum": 8.0,
      "minimum": 1.0,
      "title": "Rooms",
      "description": "Rooms requested.",
      "default": 1,
      "examples": [
       1
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "pagename"
    ],
    "title": "BookingRequest",
    "description": "Booking.com's own price calendar — 61 priced dates for ~5.5 KB.",
    "examples": [
     {
      "adults": 2,
      "country": "us",
      "currency": "USD",
      "days": 61,
      "pagename": "moxy-boston-downtown",
      "start": "2029-02-05"
     }
    ]
   },
   "BookingReviewsRequest": {
    "properties": {
     "pagename": {
      "type": "string",
      "minLength": 2,
      "title": "Pagename",
      "description": "URL slug returned by `POST /v1/ota/booking/search`.",
      "examples": [
       "newbury-guest-house"
      ]
     },
     "country": {
      "type": "string",
      "enum": [
       "ad",
       "ae",
       "af",
       "ag",
       "ai",
       "al",
       "am",
       "ao",
       "aq",
       "ar",
       "as",
       "at",
       "au",
       "aw",
       "ax",
       "az",
       "ba",
       "bb",
       "bd",
       "be",
       "bf",
       "bg",
       "bh",
       "bi",
       "bj",
       "bl",
       "bm",
       "bn",
       "bo",
       "bq",
       "br",
       "bs",
       "bt",
       "bv",
       "bw",
       "by",
       "bz",
       "ca",
       "cc",
       "cd",
       "cf",
       "cg",
       "ch",
       "ci",
       "ck",
       "cl",
       "cm",
       "cn",
       "co",
       "cr",
       "cu",
       "cv",
       "cw",
       "cx",
       "cy",
       "cz",
       "de",
       "dj",
       "dk",
       "dm",
       "do",
       "dz",
       "ec",
       "ee",
       "eg",
       "eh",
       "er",
       "es",
       "et",
       "fi",
       "fj",
       "fk",
       "fm",
       "fo",
       "fr",
       "ga",
       "gb",
       "gd",
       "ge",
       "gf",
       "gg",
       "gh",
       "gi",
       "gl",
       "gm",
       "gn",
       "gp",
       "gq",
       "gr",
       "gs",
       "gt",
       "gu",
       "gw",
       "gy",
       "hk",
       "hm",
       "hn",
       "hr",
       "ht",
       "hu",
       "id",
       "ie",
       "il",
       "im",
       "in",
       "io",
       "iq",
       "ir",
       "is",
       "it",
       "je",
       "jm",
       "jo",
       "jp",
       "ke",
       "kg",
       "kh",
       "ki",
       "km",
       "kn",
       "kp",
       "kr",
       "kw",
       "ky",
       "kz",
       "la",
       "lb",
       "lc",
       "li",
       "lk",
       "lr",
       "ls",
       "lt",
       "lu",
       "lv",
       "ly",
       "ma",
       "mc",
       "md",
       "me",
       "mf",
       "mg",
       "mh",
       "mk",
       "ml",
       "mm",
       "mn",
       "mo",
       "mp",
       "mq",
       "mr",
       "ms",
       "mt",
       "mu",
       "mv",
       "mw",
       "mx",
       "my",
       "mz",
       "na",
       "nc",
       "ne",
       "nf",
       "ng",
       "ni",
       "nl",
       "no",
       "np",
       "nr",
       "nu",
       "nz",
       "om",
       "pa",
       "pe",
       "pf",
       "pg",
       "ph",
       "pk",
       "pl",
       "pm",
       "pn",
       "pr",
       "ps",
       "pt",
       "pw",
       "py",
       "qa",
       "re",
       "ro",
       "rs",
       "ru",
       "rw",
       "sa",
       "sb",
       "sc",
       "sd",
       "se",
       "sg",
       "sh",
       "si",
       "sj",
       "sk",
       "sl",
       "sm",
       "sn",
       "so",
       "sr",
       "ss",
       "st",
       "sv",
       "sx",
       "sy",
       "sz",
       "tc",
       "td",
       "tf",
       "tg",
       "th",
       "tj",
       "tk",
       "tl",
       "tm",
       "tn",
       "to",
       "tr",
       "tt",
       "tv",
       "tw",
       "tz",
       "ua",
       "ug",
       "uk",
       "um",
       "us",
       "uy",
       "uz",
       "va",
       "vc",
       "ve",
       "vg",
       "vi",
       "vn",
       "vu",
       "wf",
       "ws",
       "xk",
       "ye",
       "yt",
       "za",
       "zm",
       "zw"
      ],
      "title": "Country",
      "description": "Two-letter segment before the slug in that URL.",
      "default": "us",
      "examples": [
       "us"
      ]
     },
     "skip": {
      "type": "integer",
      "minimum": 0.0,
      "title": "Skip",
      "description": "Reviews to skip before this page.",
      "default": 0,
      "examples": [
       0
      ]
     },
     "limit": {
      "type": "integer",
      "maximum": 25.0,
      "minimum": 1.0,
      "title": "Limit",
      "description": "Reviews per page (Booking caps at 25).",
      "default": 10,
      "examples": [
       10
      ]
     },
     "sort": {
      "type": "string",
      "enum": [
       "MOST_RELEVANT",
       "NEWEST_FIRST",
       "OLDEST_FIRST"
      ],
      "title": "Sort",
      "description": "One of Booking's own sort enums.",
      "default": "MOST_RELEVANT",
      "examples": [
       "MOST_RELEVANT"
      ]
     },
     "text": {
      "anyOf": [
       {
        "type": "string",
        "maxLength": 100
       },
       {
        "type": "null"
       }
      ],
      "title": "Text",
      "description": "Keyword filter Booking applies server-side.",
      "examples": [
       "clean"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "pagename"
    ],
    "title": "BookingReviewsRequest",
    "description": "Booking.com guest reviews from the property page's own query document.\n\nRatings are 0-10. `sort` accepts the enums Booking's own UI lists.\n`text` filters reviews by keyword — Booking counts matches upstream, so\na keyworded page can return fewer rows than `limit`.",
    "examples": [
     {
      "country": "us",
      "limit": 10,
      "pagename": "newbury-guest-house",
      "skip": 0
     }
    ]
   },
   "BookingRoomsRequest": {
    "properties": {
     "pagename": {
      "type": "string",
      "minLength": 2,
      "title": "Pagename",
      "description": "URL slug returned by `POST /v1/ota/booking/search`, e.g. `moxy-boston-downtown` from `booking.com/hotel/us/moxy-boston-downtown.html`.",
      "examples": [
       "moxy-boston-downtown"
      ]
     },
     "country": {
      "type": "string",
      "enum": [
       "ad",
       "ae",
       "af",
       "ag",
       "ai",
       "al",
       "am",
       "ao",
       "aq",
       "ar",
       "as",
       "at",
       "au",
       "aw",
       "ax",
       "az",
       "ba",
       "bb",
       "bd",
       "be",
       "bf",
       "bg",
       "bh",
       "bi",
       "bj",
       "bl",
       "bm",
       "bn",
       "bo",
       "bq",
       "br",
       "bs",
       "bt",
       "bv",
       "bw",
       "by",
       "bz",
       "ca",
       "cc",
       "cd",
       "cf",
       "cg",
       "ch",
       "ci",
       "ck",
       "cl",
       "cm",
       "cn",
       "co",
       "cr",
       "cu",
       "cv",
       "cw",
       "cx",
       "cy",
       "cz",
       "de",
       "dj",
       "dk",
       "dm",
       "do",
       "dz",
       "ec",
       "ee",
       "eg",
       "eh",
       "er",
       "es",
       "et",
       "fi",
       "fj",
       "fk",
       "fm",
       "fo",
       "fr",
       "ga",
       "gb",
       "gd",
       "ge",
       "gf",
       "gg",
       "gh",
       "gi",
       "gl",
       "gm",
       "gn",
       "gp",
       "gq",
       "gr",
       "gs",
       "gt",
       "gu",
       "gw",
       "gy",
       "hk",
       "hm",
       "hn",
       "hr",
       "ht",
       "hu",
       "id",
       "ie",
       "il",
       "im",
       "in",
       "io",
       "iq",
       "ir",
       "is",
       "it",
       "je",
       "jm",
       "jo",
       "jp",
       "ke",
       "kg",
       "kh",
       "ki",
       "km",
       "kn",
       "kp",
       "kr",
       "kw",
       "ky",
       "kz",
       "la",
       "lb",
       "lc",
       "li",
       "lk",
       "lr",
       "ls",
       "lt",
       "lu",
       "lv",
       "ly",
       "ma",
       "mc",
       "md",
       "me",
       "mf",
       "mg",
       "mh",
       "mk",
       "ml",
       "mm",
       "mn",
       "mo",
       "mp",
       "mq",
       "mr",
       "ms",
       "mt",
       "mu",
       "mv",
       "mw",
       "mx",
       "my",
       "mz",
       "na",
       "nc",
       "ne",
       "nf",
       "ng",
       "ni",
       "nl",
       "no",
       "np",
       "nr",
       "nu",
       "nz",
       "om",
       "pa",
       "pe",
       "pf",
       "pg",
       "ph",
       "pk",
       "pl",
       "pm",
       "pn",
       "pr",
       "ps",
       "pt",
       "pw",
       "py",
       "qa",
       "re",
       "ro",
       "rs",
       "ru",
       "rw",
       "sa",
       "sb",
       "sc",
       "sd",
       "se",
       "sg",
       "sh",
       "si",
       "sj",
       "sk",
       "sl",
       "sm",
       "sn",
       "so",
       "sr",
       "ss",
       "st",
       "sv",
       "sx",
       "sy",
       "sz",
       "tc",
       "td",
       "tf",
       "tg",
       "th",
       "tj",
       "tk",
       "tl",
       "tm",
       "tn",
       "to",
       "tr",
       "tt",
       "tv",
       "tw",
       "tz",
       "ua",
       "ug",
       "uk",
       "um",
       "us",
       "uy",
       "uz",
       "va",
       "vc",
       "ve",
       "vg",
       "vi",
       "vn",
       "vu",
       "wf",
       "ws",
       "xk",
       "ye",
       "yt",
       "za",
       "zm",
       "zw"
      ],
      "title": "Country",
      "description": "Two-letter segment before the slug in that URL.",
      "default": "us",
      "examples": [
       "us"
      ]
     },
     "check_in": {
      "type": "string",
      "format": "date",
      "title": "Check In",
      "description": "First night of the stay, `YYYY-MM-DD`.",
      "examples": [
       "2029-02-05"
      ]
     },
     "nights": {
      "type": "integer",
      "maximum": 30.0,
      "minimum": 1.0,
      "title": "Nights",
      "description": "Length of stay. Ignored when `check_out` is supplied.",
      "default": 1,
      "examples": [
       1
      ]
     },
     "adults": {
      "type": "integer",
      "maximum": 8.0,
      "minimum": 1.0,
      "title": "Adults",
      "description": "Adults in the room. Two is the hotel default; pass one for a hostel, which is priced per bed. Any value from 1 to 8 is accepted.",
      "default": 2,
      "examples": [
       2
      ]
     },
     "rooms": {
      "type": "integer",
      "maximum": 8.0,
      "minimum": 1.0,
      "title": "Rooms",
      "description": "Rooms requested.",
      "default": 1,
      "examples": [
       1
      ]
     },
     "currency": {
      "type": "string",
      "enum": [
       "AED",
       "ARS",
       "AUD",
       "BRL",
       "CAD",
       "CHF",
       "CLP",
       "CNY",
       "COP",
       "CZK",
       "DKK",
       "EGP",
       "EUR",
       "GBP",
       "HKD",
       "HUF",
       "IDR",
       "ILS",
       "INR",
       "JPY",
       "KRW",
       "MXN",
       "MYR",
       "NOK",
       "NZD",
       "PEN",
       "PHP",
       "PLN",
       "QAR",
       "RON",
       "SAR",
       "SEK",
       "SGD",
       "THB",
       "TRY",
       "TWD",
       "USD",
       "VND",
       "ZAR"
      ],
      "title": "Currency",
      "description": "ISO 4217 code for the returned prices. Major currencies include AED, AUD, BRL, CAD, CHF, CNY, EUR, GBP, HKD, INR, JPY, KRW, MXN, NZD, SGD, USD; all 39 supported codes are listed in the enum.",
      "default": "USD",
      "examples": [
       "USD"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "pagename",
     "check_in"
    ],
    "title": "BookingRoomsRequest",
    "description": "Booking.com room types and rate plans for one night.\n\nPrices come from the property page's room grid, enriched with room\nsize and occupancy when Booking.com provides them.",
    "examples": [
     {
      "adults": 2,
      "check_in": "2029-02-05",
      "country": "us",
      "currency": "USD",
      "nights": 1,
      "pagename": "moxy-boston-downtown"
     }
    ]
   },
   "BookingSearchRequest": {
    "properties": {
     "name": {
      "type": "string",
      "minLength": 1,
      "title": "Name",
      "description": "Hotel name as a guest would search for it.",
      "examples": [
       "Moxy Boston Downtown"
      ]
     },
     "city": {
      "type": "string",
      "title": "City",
      "description": "Strongly recommended for common hotel names. It is sent to Booking.com with the name so results come from the intended city.",
      "default": "",
      "examples": [
       "Boston"
      ]
     },
     "limit": {
      "type": "integer",
      "maximum": 10.0,
      "minimum": 1.0,
      "title": "Limit",
      "description": "Maximum candidates to return, best match first.",
      "default": 5,
      "examples": [
       5
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "name"
    ],
    "title": "BookingSearchRequest",
    "description": "Find Booking.com's country and URL slug from a hotel name.\n\nRead `recommended_match`, not `matches[0]`. It is null when the provider\nreturned only weak or ambiguous candidates.",
    "examples": [
     {
      "city": "Boston",
      "limit": 5,
      "name": "Moxy Boston Downtown"
     }
    ]
   },
   "CalendarJobItem": {
    "properties": {
     "token": {
      "type": "string",
      "minLength": 8,
      "title": "Token",
      "description": "Google property token. Get one from `POST /v1/search` — it is the `token` on each match. Looks like `ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ`.",
      "examples": [
       "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ"
      ]
     },
     "market": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "enum": [
       "AG",
       "AT",
       "AU",
       "BE",
       "BZ",
       "CA",
       "CH",
       "DE",
       "ES",
       "FR",
       "GB",
       "IE",
       "IT",
       "MX",
       "NL",
       "NZ",
       "PT",
       "US"
      ],
      "title": "Market",
      "description": "Market/country, e.g. `US`, `MX`, `AU`, `GB`. Sets `gl` and the default tax basis. Omit to derive it from `currency`.",
      "examples": [
       "US"
      ]
     },
     "country": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "enum": [
       "ad",
       "ae",
       "af",
       "ag",
       "ai",
       "al",
       "am",
       "ao",
       "aq",
       "ar",
       "as",
       "at",
       "au",
       "aw",
       "ax",
       "az",
       "ba",
       "bb",
       "bd",
       "be",
       "bf",
       "bg",
       "bh",
       "bi",
       "bj",
       "bl",
       "bm",
       "bn",
       "bo",
       "bq",
       "br",
       "bs",
       "bt",
       "bv",
       "bw",
       "by",
       "bz",
       "ca",
       "cc",
       "cd",
       "cf",
       "cg",
       "ch",
       "ci",
       "ck",
       "cl",
       "cm",
       "cn",
       "co",
       "cr",
       "cu",
       "cv",
       "cw",
       "cx",
       "cy",
       "cz",
       "de",
       "dj",
       "dk",
       "dm",
       "do",
       "dz",
       "ec",
       "ee",
       "eg",
       "eh",
       "er",
       "es",
       "et",
       "fi",
       "fj",
       "fk",
       "fm",
       "fo",
       "fr",
       "ga",
       "gb",
       "gd",
       "ge",
       "gf",
       "gg",
       "gh",
       "gi",
       "gl",
       "gm",
       "gn",
       "gp",
       "gq",
       "gr",
       "gs",
       "gt",
       "gu",
       "gw",
       "gy",
       "hk",
       "hm",
       "hn",
       "hr",
       "ht",
       "hu",
       "id",
       "ie",
       "il",
       "im",
       "in",
       "io",
       "iq",
       "ir",
       "is",
       "it",
       "je",
       "jm",
       "jo",
       "jp",
       "ke",
       "kg",
       "kh",
       "ki",
       "km",
       "kn",
       "kp",
       "kr",
       "kw",
       "ky",
       "kz",
       "la",
       "lb",
       "lc",
       "li",
       "lk",
       "lr",
       "ls",
       "lt",
       "lu",
       "lv",
       "ly",
       "ma",
       "mc",
       "md",
       "me",
       "mf",
       "mg",
       "mh",
       "mk",
       "ml",
       "mm",
       "mn",
       "mo",
       "mp",
       "mq",
       "mr",
       "ms",
       "mt",
       "mu",
       "mv",
       "mw",
       "mx",
       "my",
       "mz",
       "na",
       "nc",
       "ne",
       "nf",
       "ng",
       "ni",
       "nl",
       "no",
       "np",
       "nr",
       "nu",
       "nz",
       "om",
       "pa",
       "pe",
       "pf",
       "pg",
       "ph",
       "pk",
       "pl",
       "pm",
       "pn",
       "pr",
       "ps",
       "pt",
       "pw",
       "py",
       "qa",
       "re",
       "ro",
       "rs",
       "ru",
       "rw",
       "sa",
       "sb",
       "sc",
       "sd",
       "se",
       "sg",
       "sh",
       "si",
       "sj",
       "sk",
       "sl",
       "sm",
       "sn",
       "so",
       "sr",
       "ss",
       "st",
       "sv",
       "sx",
       "sy",
       "sz",
       "tc",
       "td",
       "tf",
       "tg",
       "th",
       "tj",
       "tk",
       "tl",
       "tm",
       "tn",
       "to",
       "tr",
       "tt",
       "tv",
       "tw",
       "tz",
       "ua",
       "ug",
       "uk",
       "um",
       "us",
       "uy",
       "uz",
       "va",
       "vc",
       "ve",
       "vg",
       "vi",
       "vn",
       "vu",
       "wf",
       "ws",
       "xk",
       "ye",
       "yt",
       "za",
       "zm",
       "zw"
      ],
      "title": "Country",
      "description": "Two-letter `gl` override. Normally set by `market`.",
      "examples": [
       "us"
      ]
     },
     "currency": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "enum": [
       "AED",
       "ARS",
       "AUD",
       "BRL",
       "CAD",
       "CHF",
       "CLP",
       "CNY",
       "COP",
       "CZK",
       "DKK",
       "EGP",
       "EUR",
       "GBP",
       "HKD",
       "HUF",
       "IDR",
       "ILS",
       "INR",
       "JPY",
       "KRW",
       "MXN",
       "MYR",
       "NOK",
       "NZD",
       "PEN",
       "PHP",
       "PLN",
       "QAR",
       "RON",
       "SAR",
       "SEK",
       "SGD",
       "THB",
       "TRY",
       "TWD",
       "USD",
       "VND",
       "ZAR"
      ],
      "title": "Currency",
      "description": "ISO currency for the returned prices.",
      "examples": [
       "USD"
      ]
     },
     "days": {
      "type": "integer",
      "maximum": 330.0,
      "minimum": 1.0,
      "title": "Days",
      "description": "Nights to price, starting at `start`. Max 330.",
      "default": 90,
      "examples": [
       90
      ]
     },
     "start": {
      "anyOf": [
       {
        "type": "string",
        "format": "date"
       },
       {
        "type": "null"
       }
      ],
      "title": "Start",
      "description": "First stay date. Defaults to tomorrow.",
      "examples": [
       "2029-02-05"
      ]
     },
     "adults": {
      "type": "integer",
      "maximum": 8.0,
      "minimum": 1.0,
      "title": "Adults",
      "description": "Occupancy: number of adults, 1-8. Children are not supported by the Google calendar.",
      "default": 2,
      "examples": [
       2
      ]
     },
     "los": {
      "type": "integer",
      "maximum": 30.0,
      "minimum": 1.0,
      "title": "Los",
      "description": "Length of stay per quote. Nightly price genuinely moves with LOS.",
      "default": 1,
      "examples": [
       1
      ]
     },
     "rates_include_tax": {
      "anyOf": [
       {
        "type": "boolean"
       },
       {
        "type": "null"
       }
      ],
      "title": "Rates Include Tax",
      "description": "Overrides the market default; pass the property's own setting"
     },
     "is_hostel": {
      "type": "boolean",
      "title": "Is Hostel",
      "description": "Hostels are priced per bed rather than per room, so occupancy changes the rate differently. Set this and the per-person maths is applied.",
      "default": false
     },
     "probe_min_stay": {
      "type": "boolean",
      "title": "Probe Min Stay",
      "description": "Re-ask for any night that will not price as a single night. Google returns a two-night-minimum night identically to a sold-out one — empty, with no reason and no min-stay field — so without this, weekends silently vanish. On a beach market in August that was every Friday and Saturday on half the comp set. Filled rows carry `min_length_of_stay` and a per-night rate derived from the longer stay. Costs one extra call per probe level, not per date.",
      "default": true
     },
     "basis": {
      "type": "string",
      "enum": [
       "cheapest",
       "mainstream"
      ],
      "pattern": "^(cheapest|mainstream)$",
      "title": "Basis",
      "description": "What the nightly figure should mean.\n\n**`cheapest` (default)** is the fast calendar path: one small request for the whole horizon. It returns Google's lowest bookable rate, including aggregators. The base/fees/taxes/total split and SearchAPI-compatible `rate_before_taxes_with_fees` remain populated.\n\n**`mainstream`** also returns `rate_mainstream_total` / `rate_mainstream_base` / `mainstream_source` / `aggregator_discount` — the cheapest rate on Booking, Expedia, Hotels.com, Priceline, Tripadvisor or Agoda, which is what a comp-set audit means by 'the OTA rate'. `rate_total` is left untouched, so both bases are available. This is intentionally expensive: it samples multi-megabyte offers pages and, when an aggregator sets the floor, re-prices each date. Measured on a 14-day request it took about 8s versus 0.4s for `cheapest`; use it selectively. `basis_applied` reports which path ran.",
      "default": "cheapest"
     },
     "verify_sources": {
      "type": "integer",
      "maximum": 5.0,
      "minimum": 0.0,
      "title": "Verify Sources",
      "description": "Spot-check this many nights against the per-OTA offers page and return a `source_check` block. The Google calendar gives one price per night and never says which source it came from — usually a mainstream OTA, but where a discounter undercuts them it reports the discounter. Measured on four properties: three matched the cheapest mainstream OTA to the cent, the fourth's figure was Super.com's at 15% under. Costs one ~3 MB offers fetch per sampled night, so it is a sample, not every date.",
      "default": 0
     },
     "label": {
      "anyOf": [
       {
        "type": "string",
        "maxLength": 200
       },
       {
        "type": "null"
       }
      ],
      "title": "Label",
      "description": "Optional customer label returned with this item.",
      "examples": [
       "Boston Marriott Copley Place"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "token"
    ],
    "title": "CalendarJobItem",
    "description": "One property in an asynchronous calendar batch.",
    "examples": [
     {
      "adults": 2,
      "basis": "cheapest",
      "currency": "USD",
      "days": 90,
      "los": 1,
      "market": "US",
      "token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ"
     }
    ]
   },
   "CalendarJobRequest": {
    "properties": {
     "items": {
      "items": {
       "$ref": "#/components/schemas/CalendarJobItem"
      },
      "type": "array",
      "maxItems": 50,
      "minItems": 1,
      "title": "Items",
      "description": "One to 50 Google calendar requests. Each item keeps its own market, currency, horizon, occupancy and price basis."
     },
     "priority": {
      "type": "integer",
      "maximum": 9.0,
      "minimum": 0.0,
      "title": "Priority",
      "description": "Queue priority from 0 (lowest) to 9 (highest). FIFO is preserved among jobs with the same priority.",
      "default": 5,
      "examples": [
       5
      ]
     },
     "callback_url": {
      "anyOf": [
       {
        "type": "string",
        "maxLength": 2048
       },
       {
        "type": "null"
       }
      ],
      "title": "Callback Url",
      "description": "Optional public HTTPS endpoint. ScraperCompany POSTs a signed `job.completed` event to it after the batch finishes. If webhook delivery is not enabled for the service, a submission with `callback_url` is rejected with 503.",
      "examples": [
       "https://example.com/webhooks/scrapercompany"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "items"
    ],
    "title": "CalendarJobRequest",
    "description": "A durable, asynchronously executed batch of calendar requests.",
    "examples": [
     {
      "callback_url": "https://example.com/webhooks/scrapercompany",
      "items": [
       {
        "basis": "cheapest",
        "currency": "USD",
        "days": 90,
        "label": "Boston Marriott Copley Place",
        "market": "US",
        "token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ"
       }
      ],
      "priority": 5
     }
    ]
   },
   "CalendarRequest": {
    "properties": {
     "token": {
      "type": "string",
      "minLength": 8,
      "title": "Token",
      "description": "Google property token. Get one from `POST /v1/search` — it is the `token` on each match. Looks like `ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ`.",
      "examples": [
       "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ"
      ]
     },
     "market": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "enum": [
       "AG",
       "AT",
       "AU",
       "BE",
       "BZ",
       "CA",
       "CH",
       "DE",
       "ES",
       "FR",
       "GB",
       "IE",
       "IT",
       "MX",
       "NL",
       "NZ",
       "PT",
       "US"
      ],
      "title": "Market",
      "description": "Market/country, e.g. `US`, `MX`, `AU`, `GB`. Sets `gl` and the default tax basis. Omit to derive it from `currency`.",
      "examples": [
       "US"
      ]
     },
     "country": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "enum": [
       "ad",
       "ae",
       "af",
       "ag",
       "ai",
       "al",
       "am",
       "ao",
       "aq",
       "ar",
       "as",
       "at",
       "au",
       "aw",
       "ax",
       "az",
       "ba",
       "bb",
       "bd",
       "be",
       "bf",
       "bg",
       "bh",
       "bi",
       "bj",
       "bl",
       "bm",
       "bn",
       "bo",
       "bq",
       "br",
       "bs",
       "bt",
       "bv",
       "bw",
       "by",
       "bz",
       "ca",
       "cc",
       "cd",
       "cf",
       "cg",
       "ch",
       "ci",
       "ck",
       "cl",
       "cm",
       "cn",
       "co",
       "cr",
       "cu",
       "cv",
       "cw",
       "cx",
       "cy",
       "cz",
       "de",
       "dj",
       "dk",
       "dm",
       "do",
       "dz",
       "ec",
       "ee",
       "eg",
       "eh",
       "er",
       "es",
       "et",
       "fi",
       "fj",
       "fk",
       "fm",
       "fo",
       "fr",
       "ga",
       "gb",
       "gd",
       "ge",
       "gf",
       "gg",
       "gh",
       "gi",
       "gl",
       "gm",
       "gn",
       "gp",
       "gq",
       "gr",
       "gs",
       "gt",
       "gu",
       "gw",
       "gy",
       "hk",
       "hm",
       "hn",
       "hr",
       "ht",
       "hu",
       "id",
       "ie",
       "il",
       "im",
       "in",
       "io",
       "iq",
       "ir",
       "is",
       "it",
       "je",
       "jm",
       "jo",
       "jp",
       "ke",
       "kg",
       "kh",
       "ki",
       "km",
       "kn",
       "kp",
       "kr",
       "kw",
       "ky",
       "kz",
       "la",
       "lb",
       "lc",
       "li",
       "lk",
       "lr",
       "ls",
       "lt",
       "lu",
       "lv",
       "ly",
       "ma",
       "mc",
       "md",
       "me",
       "mf",
       "mg",
       "mh",
       "mk",
       "ml",
       "mm",
       "mn",
       "mo",
       "mp",
       "mq",
       "mr",
       "ms",
       "mt",
       "mu",
       "mv",
       "mw",
       "mx",
       "my",
       "mz",
       "na",
       "nc",
       "ne",
       "nf",
       "ng",
       "ni",
       "nl",
       "no",
       "np",
       "nr",
       "nu",
       "nz",
       "om",
       "pa",
       "pe",
       "pf",
       "pg",
       "ph",
       "pk",
       "pl",
       "pm",
       "pn",
       "pr",
       "ps",
       "pt",
       "pw",
       "py",
       "qa",
       "re",
       "ro",
       "rs",
       "ru",
       "rw",
       "sa",
       "sb",
       "sc",
       "sd",
       "se",
       "sg",
       "sh",
       "si",
       "sj",
       "sk",
       "sl",
       "sm",
       "sn",
       "so",
       "sr",
       "ss",
       "st",
       "sv",
       "sx",
       "sy",
       "sz",
       "tc",
       "td",
       "tf",
       "tg",
       "th",
       "tj",
       "tk",
       "tl",
       "tm",
       "tn",
       "to",
       "tr",
       "tt",
       "tv",
       "tw",
       "tz",
       "ua",
       "ug",
       "uk",
       "um",
       "us",
       "uy",
       "uz",
       "va",
       "vc",
       "ve",
       "vg",
       "vi",
       "vn",
       "vu",
       "wf",
       "ws",
       "xk",
       "ye",
       "yt",
       "za",
       "zm",
       "zw"
      ],
      "title": "Country",
      "description": "Two-letter `gl` override. Normally set by `market`.",
      "examples": [
       "us"
      ]
     },
     "currency": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "enum": [
       "AED",
       "ARS",
       "AUD",
       "BRL",
       "CAD",
       "CHF",
       "CLP",
       "CNY",
       "COP",
       "CZK",
       "DKK",
       "EGP",
       "EUR",
       "GBP",
       "HKD",
       "HUF",
       "IDR",
       "ILS",
       "INR",
       "JPY",
       "KRW",
       "MXN",
       "MYR",
       "NOK",
       "NZD",
       "PEN",
       "PHP",
       "PLN",
       "QAR",
       "RON",
       "SAR",
       "SEK",
       "SGD",
       "THB",
       "TRY",
       "TWD",
       "USD",
       "VND",
       "ZAR"
      ],
      "title": "Currency",
      "description": "ISO currency for the returned prices.",
      "examples": [
       "USD"
      ]
     },
     "days": {
      "type": "integer",
      "maximum": 330.0,
      "minimum": 1.0,
      "title": "Days",
      "description": "Nights to price, starting at `start`. Max 330.",
      "default": 90,
      "examples": [
       90
      ]
     },
     "start": {
      "anyOf": [
       {
        "type": "string",
        "format": "date"
       },
       {
        "type": "null"
       }
      ],
      "title": "Start",
      "description": "First stay date. Defaults to tomorrow.",
      "examples": [
       "2029-02-05"
      ]
     },
     "adults": {
      "type": "integer",
      "maximum": 8.0,
      "minimum": 1.0,
      "title": "Adults",
      "description": "Occupancy: number of adults, 1-8. Children are not supported by the Google calendar.",
      "default": 2,
      "examples": [
       2
      ]
     },
     "los": {
      "type": "integer",
      "maximum": 30.0,
      "minimum": 1.0,
      "title": "Los",
      "description": "Length of stay per quote. Nightly price genuinely moves with LOS.",
      "default": 1,
      "examples": [
       1
      ]
     },
     "rates_include_tax": {
      "anyOf": [
       {
        "type": "boolean"
       },
       {
        "type": "null"
       }
      ],
      "title": "Rates Include Tax",
      "description": "Overrides the market default; pass the property's own setting"
     },
     "is_hostel": {
      "type": "boolean",
      "title": "Is Hostel",
      "description": "Hostels are priced per bed rather than per room, so occupancy changes the rate differently. Set this and the per-person maths is applied.",
      "default": false
     },
     "probe_min_stay": {
      "type": "boolean",
      "title": "Probe Min Stay",
      "description": "Re-ask for any night that will not price as a single night. Google returns a two-night-minimum night identically to a sold-out one — empty, with no reason and no min-stay field — so without this, weekends silently vanish. On a beach market in August that was every Friday and Saturday on half the comp set. Filled rows carry `min_length_of_stay` and a per-night rate derived from the longer stay. Costs one extra call per probe level, not per date.",
      "default": true
     },
     "basis": {
      "type": "string",
      "enum": [
       "cheapest",
       "mainstream"
      ],
      "pattern": "^(cheapest|mainstream)$",
      "title": "Basis",
      "description": "What the nightly figure should mean.\n\n**`cheapest` (default)** is the fast calendar path: one small request for the whole horizon. It returns Google's lowest bookable rate, including aggregators. The base/fees/taxes/total split and SearchAPI-compatible `rate_before_taxes_with_fees` remain populated.\n\n**`mainstream`** also returns `rate_mainstream_total` / `rate_mainstream_base` / `mainstream_source` / `aggregator_discount` — the cheapest rate on Booking, Expedia, Hotels.com, Priceline, Tripadvisor or Agoda, which is what a comp-set audit means by 'the OTA rate'. `rate_total` is left untouched, so both bases are available. This is intentionally expensive: it samples multi-megabyte offers pages and, when an aggregator sets the floor, re-prices each date. Measured on a 14-day request it took about 8s versus 0.4s for `cheapest`; use it selectively. `basis_applied` reports which path ran.",
      "default": "cheapest"
     },
     "verify_sources": {
      "type": "integer",
      "maximum": 5.0,
      "minimum": 0.0,
      "title": "Verify Sources",
      "description": "Spot-check this many nights against the per-OTA offers page and return a `source_check` block. The Google calendar gives one price per night and never says which source it came from — usually a mainstream OTA, but where a discounter undercuts them it reports the discounter. Measured on four properties: three matched the cheapest mainstream OTA to the cent, the fourth's figure was Super.com's at 15% under. Costs one ~3 MB offers fetch per sampled night, so it is a sample, not every date.",
      "default": 0
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "token"
    ],
    "title": "CalendarRequest",
    "description": "A forward horizon of nightly rates for one property.\n\nThe cheapest call here by a wide margin: one request returns the\nwhole window in ~30 KB, so a 90-night sweep costs one request, not 90.",
    "examples": [
     {
      "adults": 2,
      "basis": "cheapest",
      "currency": "USD",
      "days": 90,
      "los": 1,
      "market": "US",
      "token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ"
     }
    ]
   },
   "CompareRequest": {
    "properties": {
     "check_in": {
      "type": "string",
      "format": "date",
      "title": "Check In",
      "description": "First night of the stay, `YYYY-MM-DD`.",
      "examples": [
       "2029-02-05"
      ]
     },
     "check_out": {
      "anyOf": [
       {
        "type": "string",
        "format": "date"
       },
       {
        "type": "null"
       }
      ],
      "title": "Check Out",
      "description": "Departure date. An alternative to `nights` — if both are given, this wins.",
      "examples": [
       "2029-02-06"
      ]
     },
     "nights": {
      "type": "integer",
      "maximum": 30.0,
      "minimum": 1.0,
      "title": "Nights",
      "description": "Length of stay. Ignored when `check_out` is supplied.",
      "default": 1,
      "examples": [
       1
      ]
     },
     "adults": {
      "type": "integer",
      "maximum": 8.0,
      "minimum": 1.0,
      "title": "Adults",
      "description": "Adults in the room. Two is the hotel default; pass one for a hostel, which is priced per bed. Any value from 1 to 8 is accepted.",
      "default": 2,
      "examples": [
       2
      ]
     },
     "currency": {
      "type": "string",
      "enum": [
       "AED",
       "ARS",
       "AUD",
       "BRL",
       "CAD",
       "CHF",
       "CLP",
       "CNY",
       "COP",
       "CZK",
       "DKK",
       "EGP",
       "EUR",
       "GBP",
       "HKD",
       "HUF",
       "IDR",
       "ILS",
       "INR",
       "JPY",
       "KRW",
       "MXN",
       "MYR",
       "NOK",
       "NZD",
       "PEN",
       "PHP",
       "PLN",
       "QAR",
       "RON",
       "SAR",
       "SEK",
       "SGD",
       "THB",
       "TRY",
       "TWD",
       "USD",
       "VND",
       "ZAR"
      ],
      "title": "Currency",
      "description": "ISO 4217 code for the returned prices. Major currencies include AED, AUD, BRL, CAD, CHF, CNY, EUR, GBP, HKD, INR, JPY, KRW, MXN, NZD, SGD, USD; all 39 supported codes are listed in the enum.",
      "default": "USD",
      "examples": [
       "USD"
      ]
     },
     "booking_pagename": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "title": "Booking Pagename",
      "description": "Booking slug. Omit to skip Booking entirely.",
      "examples": [
       "moxy-boston-downtown"
      ]
     },
     "booking_country": {
      "type": "string",
      "enum": [
       "ad",
       "ae",
       "af",
       "ag",
       "ai",
       "al",
       "am",
       "ao",
       "aq",
       "ar",
       "as",
       "at",
       "au",
       "aw",
       "ax",
       "az",
       "ba",
       "bb",
       "bd",
       "be",
       "bf",
       "bg",
       "bh",
       "bi",
       "bj",
       "bl",
       "bm",
       "bn",
       "bo",
       "bq",
       "br",
       "bs",
       "bt",
       "bv",
       "bw",
       "by",
       "bz",
       "ca",
       "cc",
       "cd",
       "cf",
       "cg",
       "ch",
       "ci",
       "ck",
       "cl",
       "cm",
       "cn",
       "co",
       "cr",
       "cu",
       "cv",
       "cw",
       "cx",
       "cy",
       "cz",
       "de",
       "dj",
       "dk",
       "dm",
       "do",
       "dz",
       "ec",
       "ee",
       "eg",
       "eh",
       "er",
       "es",
       "et",
       "fi",
       "fj",
       "fk",
       "fm",
       "fo",
       "fr",
       "ga",
       "gb",
       "gd",
       "ge",
       "gf",
       "gg",
       "gh",
       "gi",
       "gl",
       "gm",
       "gn",
       "gp",
       "gq",
       "gr",
       "gs",
       "gt",
       "gu",
       "gw",
       "gy",
       "hk",
       "hm",
       "hn",
       "hr",
       "ht",
       "hu",
       "id",
       "ie",
       "il",
       "im",
       "in",
       "io",
       "iq",
       "ir",
       "is",
       "it",
       "je",
       "jm",
       "jo",
       "jp",
       "ke",
       "kg",
       "kh",
       "ki",
       "km",
       "kn",
       "kp",
       "kr",
       "kw",
       "ky",
       "kz",
       "la",
       "lb",
       "lc",
       "li",
       "lk",
       "lr",
       "ls",
       "lt",
       "lu",
       "lv",
       "ly",
       "ma",
       "mc",
       "md",
       "me",
       "mf",
       "mg",
       "mh",
       "mk",
       "ml",
       "mm",
       "mn",
       "mo",
       "mp",
       "mq",
       "mr",
       "ms",
       "mt",
       "mu",
       "mv",
       "mw",
       "mx",
       "my",
       "mz",
       "na",
       "nc",
       "ne",
       "nf",
       "ng",
       "ni",
       "nl",
       "no",
       "np",
       "nr",
       "nu",
       "nz",
       "om",
       "pa",
       "pe",
       "pf",
       "pg",
       "ph",
       "pk",
       "pl",
       "pm",
       "pn",
       "pr",
       "ps",
       "pt",
       "pw",
       "py",
       "qa",
       "re",
       "ro",
       "rs",
       "ru",
       "rw",
       "sa",
       "sb",
       "sc",
       "sd",
       "se",
       "sg",
       "sh",
       "si",
       "sj",
       "sk",
       "sl",
       "sm",
       "sn",
       "so",
       "sr",
       "ss",
       "st",
       "sv",
       "sx",
       "sy",
       "sz",
       "tc",
       "td",
       "tf",
       "tg",
       "th",
       "tj",
       "tk",
       "tl",
       "tm",
       "tn",
       "to",
       "tr",
       "tt",
       "tv",
       "tw",
       "tz",
       "ua",
       "ug",
       "uk",
       "um",
       "us",
       "uy",
       "uz",
       "va",
       "vc",
       "ve",
       "vg",
       "vi",
       "vn",
       "vu",
       "wf",
       "ws",
       "xk",
       "ye",
       "yt",
       "za",
       "zm",
       "zw"
      ],
      "title": "Booking Country",
      "description": "Two-letter segment before the slug in the Booking URL.",
      "default": "us",
      "examples": [
       "us"
      ]
     },
     "hotels_property_id": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "title": "Hotels Property Id",
      "description": "Hotels.com numeric id. Omit to skip Hotels.com.",
      "examples": [
       "38766175"
      ]
     },
     "hotels_market": {
      "type": "string",
      "enum": [
       "AU",
       "CA",
       "DE",
       "EU",
       "FR",
       "GB",
       "IE",
       "IT",
       "NL",
       "NZ",
       "US"
      ],
      "title": "Hotels Market",
      "description": "Hotels.com point-of-sale; also picks its currency.",
      "default": "US",
      "examples": [
       "US"
      ]
     },
     "agoda_property_id": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "title": "Agoda Property Id",
      "description": "Agoda numeric id. Omit to skip Agoda.",
      "examples": [
       "8795952"
      ]
     },
     "expedia_property_id": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "title": "Expedia Property Id",
      "description": "Expedia numeric id from `POST /v1/ota/expedia/search`. Omit to skip Expedia.",
      "examples": [
       "38766175"
      ]
     },
     "expedia_market": {
      "type": "string",
      "enum": [
       "CA",
       "US"
      ],
      "title": "Expedia Market",
      "description": "Expedia point-of-sale; also picks its currency.",
      "default": "US",
      "examples": [
       "US"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "check_in"
    ],
    "title": "CompareRequest",
    "description": "One night across every source an identifier is supplied for.\n\nIdentifiers differ per site and there is no shared key, so each is named\nexplicitly rather than pretending one id resolves everywhere.\n\n**The three ids are unrelated strings and nothing here can check they name\nthe same hotel.** Pass a Booking slug for one property and an Agoda id for\nanother and you get a confident, meaningless spread. `comparison.identifiers`\nechoes back what was used so the mistake is visible in the answer.\n\nLeave any identifier out to skip that source. Fail-soft per source: a\nblocked OTA comes back as a row with a status, not a lost result.\n`comparison.comparable` is false when fewer than two prices return or the\nsources return different currencies; mixed-currency minima are suppressed.",
    "examples": [
     {
      "agoda_property_id": "8795952",
      "booking_country": "us",
      "booking_pagename": "moxy-boston-downtown",
      "check_in": "2029-02-05",
      "currency": "USD",
      "nights": 1
     }
    ]
   },
   "ExpediaRequest": {
    "properties": {
     "property_id": {
      "type": "string",
      "minLength": 1,
      "pattern": "^\\d+$",
      "title": "Property Id",
      "description": "Numeric id returned by `POST /v1/ota/expedia/search`. For `expedia.com/Chicago-Hotels-Hilton-Chicago.h12570.Hotel-Information` it is `12570`. Not always the Hotels.com id: older properties differ between brands.",
      "examples": [
       "12570"
      ]
     },
     "check_in": {
      "type": "string",
      "format": "date",
      "title": "Check In",
      "description": "First night of the stay, `YYYY-MM-DD`.",
      "examples": [
       "2029-04-10"
      ]
     },
     "check_out": {
      "anyOf": [
       {
        "type": "string",
        "format": "date"
       },
       {
        "type": "null"
       }
      ],
      "title": "Check Out",
      "description": "Departure date. An alternative to `nights` — if both are given, this wins.",
      "examples": [
       "2029-04-11"
      ]
     },
     "nights": {
      "type": "integer",
      "maximum": 28.0,
      "minimum": 1.0,
      "title": "Nights",
      "description": "Length of stay. Ignored when `check_out` is supplied.",
      "default": 1,
      "examples": [
       1
      ]
     },
     "adults": {
      "type": "integer",
      "maximum": 8.0,
      "minimum": 1.0,
      "title": "Adults",
      "description": "Adults in the room.",
      "default": 2,
      "examples": [
       2
      ]
     },
     "market": {
      "type": "string",
      "enum": [
       "CA",
       "US"
      ],
      "title": "Market",
      "description": "Expedia point-of-sale, which is how currency is selected - there is no currency field. `US` prices in USD on www.expedia.com, `CA` in CAD on www.expedia.ca. The display basis differs by market (the US room card leads with the stay total, CA with the nightly price), so compare within one market.",
      "default": "US",
      "examples": [
       "US"
      ]
     },
     "rooms": {
      "type": "boolean",
      "title": "Rooms",
      "description": "Return every room type and rate plan (~50-250 KB upstream). False returns the headline price only (~6 KB). Same credit cost.",
      "default": true,
      "examples": [
       true
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "property_id",
     "check_in"
    ],
    "title": "ExpediaRequest",
    "description": "Expedia rooms, rate plans and headline price for one stay window.\n\nOne request. Each offer carries the upstream stay total\n(taxes and fees included, as Expedia labels it), the nightly price before\ntaxes, and the combined taxes and fees derived from the two.",
    "examples": [
     {
      "adults": 2,
      "check_in": "2029-04-10",
      "market": "US",
      "nights": 1,
      "property_id": "12570",
      "rooms": true
     }
    ]
   },
   "ExpediaReviewsRequest": {
    "properties": {
     "property_id": {
      "type": "string",
      "minLength": 1,
      "pattern": "^\\d+$",
      "title": "Property Id",
      "description": "Numeric id returned by `POST /v1/ota/expedia/search`.",
      "examples": [
       "12570"
      ]
     },
     "size": {
      "type": "integer",
      "maximum": 25.0,
      "minimum": 1.0,
      "title": "Size",
      "description": "Reviews per page.",
      "default": 10,
      "examples": [
       10
      ]
     },
     "start_index": {
      "type": "integer",
      "minimum": 0.0,
      "title": "Start Index",
      "description": "Row to start from; page by `start_index += size`.",
      "default": 0,
      "examples": [
       0
      ]
     },
     "market": {
      "type": "string",
      "enum": [
       "CA",
       "US"
      ],
      "title": "Market",
      "description": "Point-of-sale; also selects the currency.",
      "default": "US",
      "examples": [
       "US"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "property_id"
    ],
    "title": "ExpediaReviewsRequest",
    "description": "Expedia guest reviews for one property.\n\nOne registered query, without a browser. Ratings are 0-10, parsed\nfrom the upstream score label; the \"Verified review\" disclaimer and\n\"Liked: …\" themes ride in `labels`, exactly as Expedia publishes them.",
    "examples": [
     {
      "property_id": "12570",
      "size": 10,
      "start_index": 0
     }
    ]
   },
   "ExpediaSearchRequest": {
    "properties": {
     "name": {
      "type": "string",
      "minLength": 1,
      "title": "Name",
      "description": "Hotel name as a guest would search for it.",
      "examples": [
       "Hilton Chicago"
      ]
     },
     "city": {
      "type": "string",
      "title": "City",
      "description": "Strongly recommended. Sent with the name to Expedia's typeahead and used to rank same-brand hotels in other cities lower.",
      "default": "",
      "examples": [
       "Chicago"
      ]
     },
     "market": {
      "type": "string",
      "enum": [
       "CA",
       "US"
      ],
      "title": "Market",
      "description": "Expedia point-of-sale, which is how currency is selected - there is no currency field. `US` prices in USD on www.expedia.com, `CA` in CAD on www.expedia.ca. The display basis differs by market (the US room card leads with the stay total, CA with the nightly price), so compare within one market.",
      "default": "US",
      "examples": [
       "US"
      ]
     },
     "limit": {
      "type": "integer",
      "maximum": 10.0,
      "minimum": 1.0,
      "title": "Limit",
      "description": "Maximum hotel candidates to return, best match first.",
      "default": 5,
      "examples": [
       5
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "name"
    ],
    "title": "ExpediaSearchRequest",
    "description": "Find Expedia's numeric property id from a hotel name.\n\nRead `recommended_match`, not `matches[0]`. It is null when the provider\nreturned only weak or ambiguous candidates.",
    "examples": [
     {
      "city": "Chicago",
      "limit": 5,
      "market": "US",
      "name": "Hilton Chicago"
     }
    ]
   },
   "FlightsBookingRequest": {
    "properties": {
     "booking_token": {
      "type": "string",
      "pattern": "^gf1\\.[A-Za-z0-9_\\-]{16,16384}$",
      "title": "Booking Token",
      "description": "`booking_token` of a complete itinerary: a one-way result of `/v1/serp/google_flights`, or a return/last-leg result of `/v1/serp/google_flights_return`.",
      "examples": [
       "gf1.eNp9T8sKwjAQ_Jc9p5BUqqU3tc0hBm0bE8WQk_hASy9tVRD_3aRVVBSzsJlhZjabK5wgIgi2EOmyKQrUNr-7tEEEaYKwK4Ne-q-m3QFGJ2C9xjgOfLh8sNaC3-zgY7_vEeyRAJ4DuvSH0o3oEjG3nAzCEMyfZXrfIjEIqvabNUQwPuR0kdCpTC6UqzwVWM24DFI1JiOuGM3kuRYqZ_OjEpliK_vo2sakiC3aFxZuSot2DjUV3O6AWl_r"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "booking_token"
    ],
    "title": "FlightsBookingRequest",
    "description": "Sellers of a complete itinerary: airline direct and OTAs, with prices,\nfare names and click-through links (SerpApi `booking_options`).",
    "examples": [
     {
      "booking_token": "gf1.eNp9T8sKwjAQ_Jc9p5BUqqU3tc0hBm0bE8WQk_hASy9tVRD_3aRVVBSzsJlhZjabK5wgIgi2EOmyKQrUNr-7tEEEaYKwK4Ne-q-m3QFGJ2C9xjgOfLh8sNaC3-zgY7_vEeyRAJ4DuvSH0o3oEjG3nAzCEMyfZXrfIjEIqvabNUQwPuR0kdCpTC6UqzwVWM24DFI1JiOuGM3kuRYqZ_OjEpliK_vo2sakiC3aFxZuSot2DjUV3O6AWl_r"
     }
    ]
   },
   "FlightsCalendarRequest": {
    "properties": {
     "departure": {
      "type": "string",
      "maxLength": 3,
      "minLength": 3,
      "title": "Departure",
      "description": "IATA departure airport code.",
      "examples": [
       "JFK"
      ]
     },
     "arrival": {
      "type": "string",
      "maxLength": 3,
      "minLength": 3,
      "title": "Arrival",
      "description": "IATA arrival airport code.",
      "examples": [
       "LAX"
      ]
     },
     "departure_date": {
      "type": "string",
      "format": "date",
      "title": "Departure Date",
      "description": "Target outbound date (center of date range).",
      "examples": [
       "2029-03-08"
      ]
     },
     "return_date": {
      "anyOf": [
       {
        "type": "string",
        "format": "date"
       },
       {
        "type": "null"
       }
      ],
      "title": "Return Date",
      "description": "Target return date for round-trip. Omit for one-way.",
      "examples": [
       "2029-03-13"
      ]
     },
     "adults": {
      "type": "integer",
      "maximum": 9.0,
      "minimum": 1.0,
      "title": "Adults",
      "description": "Number of passengers.",
      "default": 1,
      "examples": [
       1
      ]
     },
     "currency": {
      "type": "string",
      "enum": [
       "AED",
       "ARS",
       "AUD",
       "BRL",
       "CAD",
       "CHF",
       "CLP",
       "CNY",
       "COP",
       "CZK",
       "DKK",
       "EGP",
       "EUR",
       "GBP",
       "HKD",
       "HUF",
       "IDR",
       "ILS",
       "INR",
       "JPY",
       "KRW",
       "MXN",
       "MYR",
       "NOK",
       "NZD",
       "PEN",
       "PHP",
       "PLN",
       "QAR",
       "RON",
       "SAR",
       "SEK",
       "SGD",
       "THB",
       "TRY",
       "TWD",
       "USD",
       "VND",
       "ZAR"
      ],
      "title": "Currency",
      "description": "ISO 4217 code for the returned prices. Major currencies include AED, AUD, BRL, CAD, CHF, CNY, EUR, GBP, HKD, INR, JPY, KRW, MXN, NZD, SGD, USD; all 39 supported codes are listed in the enum.",
      "default": "USD",
      "examples": [
       "USD"
      ]
     },
     "hl": {
      "type": "string",
      "title": "Hl",
      "description": "Language code.",
      "default": "en",
      "examples": [
       "en"
      ]
     },
     "gl": {
      "type": "string",
      "enum": [
       "ad",
       "ae",
       "af",
       "ag",
       "ai",
       "al",
       "am",
       "ao",
       "aq",
       "ar",
       "as",
       "at",
       "au",
       "aw",
       "ax",
       "az",
       "ba",
       "bb",
       "bd",
       "be",
       "bf",
       "bg",
       "bh",
       "bi",
       "bj",
       "bl",
       "bm",
       "bn",
       "bo",
       "bq",
       "br",
       "bs",
       "bt",
       "bv",
       "bw",
       "by",
       "bz",
       "ca",
       "cc",
       "cd",
       "cf",
       "cg",
       "ch",
       "ci",
       "ck",
       "cl",
       "cm",
       "cn",
       "co",
       "cr",
       "cu",
       "cv",
       "cw",
       "cx",
       "cy",
       "cz",
       "de",
       "dj",
       "dk",
       "dm",
       "do",
       "dz",
       "ec",
       "ee",
       "eg",
       "eh",
       "er",
       "es",
       "et",
       "fi",
       "fj",
       "fk",
       "fm",
       "fo",
       "fr",
       "ga",
       "gb",
       "gd",
       "ge",
       "gf",
       "gg",
       "gh",
       "gi",
       "gl",
       "gm",
       "gn",
       "gp",
       "gq",
       "gr",
       "gs",
       "gt",
       "gu",
       "gw",
       "gy",
       "hk",
       "hm",
       "hn",
       "hr",
       "ht",
       "hu",
       "id",
       "ie",
       "il",
       "im",
       "in",
       "io",
       "iq",
       "ir",
       "is",
       "it",
       "je",
       "jm",
       "jo",
       "jp",
       "ke",
       "kg",
       "kh",
       "ki",
       "km",
       "kn",
       "kp",
       "kr",
       "kw",
       "ky",
       "kz",
       "la",
       "lb",
       "lc",
       "li",
       "lk",
       "lr",
       "ls",
       "lt",
       "lu",
       "lv",
       "ly",
       "ma",
       "mc",
       "md",
       "me",
       "mf",
       "mg",
       "mh",
       "mk",
       "ml",
       "mm",
       "mn",
       "mo",
       "mp",
       "mq",
       "mr",
       "ms",
       "mt",
       "mu",
       "mv",
       "mw",
       "mx",
       "my",
       "mz",
       "na",
       "nc",
       "ne",
       "nf",
       "ng",
       "ni",
       "nl",
       "no",
       "np",
       "nr",
       "nu",
       "nz",
       "om",
       "pa",
       "pe",
       "pf",
       "pg",
       "ph",
       "pk",
       "pl",
       "pm",
       "pn",
       "pr",
       "ps",
       "pt",
       "pw",
       "py",
       "qa",
       "re",
       "ro",
       "rs",
       "ru",
       "rw",
       "sa",
       "sb",
       "sc",
       "sd",
       "se",
       "sg",
       "sh",
       "si",
       "sj",
       "sk",
       "sl",
       "sm",
       "sn",
       "so",
       "sr",
       "ss",
       "st",
       "sv",
       "sx",
       "sy",
       "sz",
       "tc",
       "td",
       "tf",
       "tg",
       "th",
       "tj",
       "tk",
       "tl",
       "tm",
       "tn",
       "to",
       "tr",
       "tt",
       "tv",
       "tw",
       "tz",
       "ua",
       "ug",
       "uk",
       "um",
       "us",
       "uy",
       "uz",
       "va",
       "vc",
       "ve",
       "vg",
       "vi",
       "vn",
       "vu",
       "wf",
       "ws",
       "xk",
       "ye",
       "yt",
       "za",
       "zm",
       "zw"
      ],
      "title": "Gl",
      "description": "Market/country code.",
      "default": "us",
      "examples": [
       "us"
      ]
     },
     "date_window_days": {
      "type": "integer",
      "maximum": 30.0,
      "minimum": 1.0,
      "title": "Date Window Days",
      "description": "Days before/after target date to include in grid.",
      "default": 7,
      "examples": [
       7
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "departure",
     "arrival",
     "departure_date"
    ],
    "title": "FlightsCalendarRequest",
    "description": "Google Flights calendar/date-grid pricing.\n\nReturns cheapest prices across a date range, similar to SearchAPI's\ngoogle_flights_calendar. Useful for flexible-date price comparison.",
    "examples": [
     {
      "adults": 1,
      "arrival": "LAX",
      "currency": "USD",
      "date_window_days": 7,
      "departure": "JFK",
      "departure_date": "2029-03-08",
      "return_date": "2029-03-13"
     }
    ]
   },
   "FlightsLegSpec": {
    "properties": {
     "departure": {
      "type": "string",
      "maxLength": 80,
      "minLength": 3,
      "title": "Departure",
      "description": "IATA airport code (`JFK`), IATA city code (`NYC`, `LON`, `PAR`: every airport of the city), a Google city id from `/v1/serp/google_flights_location_search` (`/m/02_286`), or up to 7 of these comma-separated (`JFK,EWR`).",
      "examples": [
       "YUL"
      ]
     },
     "arrival": {
      "type": "string",
      "maxLength": 80,
      "minLength": 3,
      "title": "Arrival",
      "description": "IATA airport code (`JFK`), IATA city code (`NYC`, `LON`, `PAR`: every airport of the city), a Google city id from `/v1/serp/google_flights_location_search` (`/m/02_286`), or up to 7 of these comma-separated (`JFK,EWR`).",
      "examples": [
       "CDG"
      ]
     },
     "date": {
      "type": "string",
      "format": "date",
      "title": "Date",
      "description": "Departure date of this leg, `YYYY-MM-DD`.",
      "examples": [
       "2029-03-28"
      ]
     },
     "times": {
      "anyOf": [
       {
        "type": "string",
        "pattern": "^\\d{1,2},\\d{1,2}(,\\d{1,2},\\d{1,2})?$"
       },
       {
        "type": "null"
       }
      ],
      "title": "Times",
      "description": "Hour window `from,to` for departure, optionally followed by `from,to` for arrival (0-23; `8,12` = leaves 08:00-12:59). SerpApi's format.",
      "examples": [
       "6,20"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "departure",
     "arrival",
     "date"
    ],
    "title": "FlightsLegSpec",
    "description": "One leg of a multi-city trip."
   },
   "FlightsLocationSearchRequest": {
    "properties": {
     "q": {
      "type": "string",
      "maxLength": 100,
      "minLength": 1,
      "title": "Q",
      "description": "City, airport or region name, or a code (`paris`, `Heathrow`, `NYC`).",
      "examples": [
       "paris"
      ]
     },
     "hl": {
      "type": "string",
      "pattern": "^[A-Za-z]{2,3}(-[A-Za-z]{2,4})?$",
      "title": "Hl",
      "description": "Language of the returned names.",
      "default": "en",
      "examples": [
       "en"
      ]
     },
     "gl": {
      "type": "string",
      "enum": [
       "ad",
       "ae",
       "af",
       "ag",
       "ai",
       "al",
       "am",
       "ao",
       "aq",
       "ar",
       "as",
       "at",
       "au",
       "aw",
       "ax",
       "az",
       "ba",
       "bb",
       "bd",
       "be",
       "bf",
       "bg",
       "bh",
       "bi",
       "bj",
       "bl",
       "bm",
       "bn",
       "bo",
       "bq",
       "br",
       "bs",
       "bt",
       "bv",
       "bw",
       "by",
       "bz",
       "ca",
       "cc",
       "cd",
       "cf",
       "cg",
       "ch",
       "ci",
       "ck",
       "cl",
       "cm",
       "cn",
       "co",
       "cr",
       "cu",
       "cv",
       "cw",
       "cx",
       "cy",
       "cz",
       "de",
       "dj",
       "dk",
       "dm",
       "do",
       "dz",
       "ec",
       "ee",
       "eg",
       "eh",
       "er",
       "es",
       "et",
       "fi",
       "fj",
       "fk",
       "fm",
       "fo",
       "fr",
       "ga",
       "gb",
       "gd",
       "ge",
       "gf",
       "gg",
       "gh",
       "gi",
       "gl",
       "gm",
       "gn",
       "gp",
       "gq",
       "gr",
       "gs",
       "gt",
       "gu",
       "gw",
       "gy",
       "hk",
       "hm",
       "hn",
       "hr",
       "ht",
       "hu",
       "id",
       "ie",
       "il",
       "im",
       "in",
       "io",
       "iq",
       "ir",
       "is",
       "it",
       "je",
       "jm",
       "jo",
       "jp",
       "ke",
       "kg",
       "kh",
       "ki",
       "km",
       "kn",
       "kp",
       "kr",
       "kw",
       "ky",
       "kz",
       "la",
       "lb",
       "lc",
       "li",
       "lk",
       "lr",
       "ls",
       "lt",
       "lu",
       "lv",
       "ly",
       "ma",
       "mc",
       "md",
       "me",
       "mf",
       "mg",
       "mh",
       "mk",
       "ml",
       "mm",
       "mn",
       "mo",
       "mp",
       "mq",
       "mr",
       "ms",
       "mt",
       "mu",
       "mv",
       "mw",
       "mx",
       "my",
       "mz",
       "na",
       "nc",
       "ne",
       "nf",
       "ng",
       "ni",
       "nl",
       "no",
       "np",
       "nr",
       "nu",
       "nz",
       "om",
       "pa",
       "pe",
       "pf",
       "pg",
       "ph",
       "pk",
       "pl",
       "pm",
       "pn",
       "pr",
       "ps",
       "pt",
       "pw",
       "py",
       "qa",
       "re",
       "ro",
       "rs",
       "ru",
       "rw",
       "sa",
       "sb",
       "sc",
       "sd",
       "se",
       "sg",
       "sh",
       "si",
       "sj",
       "sk",
       "sl",
       "sm",
       "sn",
       "so",
       "sr",
       "ss",
       "st",
       "sv",
       "sx",
       "sy",
       "sz",
       "tc",
       "td",
       "tf",
       "tg",
       "th",
       "tj",
       "tk",
       "tl",
       "tm",
       "tn",
       "to",
       "tr",
       "tt",
       "tv",
       "tw",
       "tz",
       "ua",
       "ug",
       "uk",
       "um",
       "us",
       "uy",
       "uz",
       "va",
       "vc",
       "ve",
       "vg",
       "vi",
       "vn",
       "vu",
       "wf",
       "ws",
       "xk",
       "ye",
       "yt",
       "za",
       "zm",
       "zw"
      ],
      "title": "Gl",
      "description": "Market/country code (two letters).",
      "default": "us",
      "examples": [
       "us"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "q"
    ],
    "title": "FlightsLocationSearchRequest",
    "description": "Resolve a city or airport name to IATA codes and Google city ids.",
    "examples": [
     {
      "gl": "us",
      "hl": "en",
      "q": "paris"
     }
    ]
   },
   "FlightsReturnRequest": {
    "properties": {
     "departure_token": {
      "type": "string",
      "pattern": "^gf1\\.[A-Za-z0-9_\\-]{16,16384}$",
      "title": "Departure Token",
      "description": "`departure_token` of an itinerary from `/v1/serp/google_flights` (or of a previous `/v1/serp/google_flights_return` leg of a multi-city trip). It carries the search, so nothing else is needed.",
      "examples": [
       "gf1.eNqFUMkKwjAU_Jd3TiGpVqU3TVuhBO1iIhpyEhe09NJWBfHfTRexxS2BlxneMvNygzPYBMEObJkWSYKqQOpHKo0kQbi8Cr3yn4IsD6w4A12rVMmBOtOGVSW4VQ4mNgcGwQax4Dmg7u5k6hF1x5hqPhr2Qf3w0quU29JdW9-NmCb8WbEReFMnCkFWfWMONtBj5C1db8bdq8dEFMRYzBm3AkHJhAnfC_klj0XkL04iDoW_1kttdBuPHY0OiYbbVKN9iYoM7g_hQ347"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "departure_token"
    ],
    "title": "FlightsReturnRequest",
    "description": "Options for the next leg after the one a `departure_token` chose.\n\nFor a round trip these are the return flights (priced for the whole\ntrip, each with a `booking_token`); for multi-city, the next leg.",
    "examples": [
     {
      "departure_token": "gf1.eNqFUMkKwjAU_Jd3TiGpVqU3TVuhBO1iIhpyEhe09NJWBfHfTRexxS2BlxneMvNygzPYBMEObJkWSYKqQOpHKo0kQbi8Cr3yn4IsD6w4A12rVMmBOtOGVSW4VQ4mNgcGwQax4Dmg7u5k6hF1x5hqPhr2Qf3w0quU29JdW9-NmCb8WbEReFMnCkFWfWMONtBj5C1db8bdq8dEFMRYzBm3AkHJhAnfC_klj0XkL04iDoW_1kttdBuPHY0OiYbbVKN9iYoM7g_hQ347"
     }
    ]
   },
   "FlightsSearchRequest": {
    "properties": {
     "departure": {
      "type": "string",
      "maxLength": 3,
      "minLength": 3,
      "title": "Departure",
      "description": "IATA airport code (`JFK`) or IATA city code (`NYC`, `LON`, `PAR`, `TYO`...: every airport of that city). For several airports or a Google city id use `departure_id`.",
      "examples": [
       "JFK"
      ]
     },
     "arrival": {
      "type": "string",
      "maxLength": 3,
      "minLength": 3,
      "title": "Arrival",
      "description": "IATA airport code (`JFK`) or IATA city code (`NYC`, `LON`, `PAR`, `TYO`...: every airport of that city). For several airports or a Google city id use `arrival_id`.",
      "examples": [
       "LAX"
      ]
     },
     "departure_date": {
      "type": "string",
      "format": "date",
      "title": "Departure Date",
      "description": "Outbound flight date, `YYYY-MM-DD`.",
      "examples": [
       "2029-03-08"
      ]
     },
     "return_date": {
      "anyOf": [
       {
        "type": "string",
        "format": "date"
       },
       {
        "type": "null"
       }
      ],
      "title": "Return Date",
      "description": "Return flight date for round-trip. Omit for one-way.",
      "examples": [
       "2029-03-13"
      ]
     },
     "departure_id": {
      "anyOf": [
       {
        "type": "string",
        "maxLength": 200,
        "minLength": 3
       },
       {
        "type": "null"
       }
      ],
      "title": "Departure Id",
      "description": "SerpApi's `departure_id`: overrides `departure` with comma-separated IATA airport/city codes and/or Google city ids (`/m/02_286`), up to 7. `departure` is then only the label echoed back.",
      "examples": [
       "JFK,EWR"
      ]
     },
     "arrival_id": {
      "anyOf": [
       {
        "type": "string",
        "maxLength": 200,
        "minLength": 3
       },
       {
        "type": "null"
       }
      ],
      "title": "Arrival Id",
      "description": "SerpApi's `arrival_id`: overrides `arrival` the same way, e.g. a city id from `/v1/serp/google_flights_location_search`.",
      "examples": [
       "/m/05qtj"
      ]
     },
     "multi_city": {
      "anyOf": [
       {
        "items": {
         "$ref": "#/components/schemas/FlightsLegSpec"
        },
        "type": "array",
        "maxItems": 4,
        "minItems": 1
       },
       {
        "type": "null"
       }
      ],
      "title": "Multi City",
      "description": "Makes the trip multi-city: the legs after the first (`departure` -> `arrival` on `departure_date`), 1-4 of them, in date order. The response lists options for the first leg; follow `departure_token` for each next leg. Not combinable with `return_date`."
     },
     "adults": {
      "type": "integer",
      "maximum": 9.0,
      "minimum": 1.0,
      "title": "Adults",
      "description": "Number of adult passengers (12+ years old).",
      "default": 1,
      "examples": [
       1
      ]
     },
     "children": {
      "type": "integer",
      "maximum": 8.0,
      "minimum": 0.0,
      "title": "Children",
      "description": "Number of children (2-11 years old).",
      "default": 0,
      "examples": [
       0
      ]
     },
     "infants_in_seat": {
      "type": "integer",
      "maximum": 4.0,
      "minimum": 0.0,
      "title": "Infants In Seat",
      "description": "Number of infants with seat (under 2 years old).",
      "default": 0,
      "examples": [
       0
      ]
     },
     "infants_on_lap": {
      "type": "integer",
      "maximum": 4.0,
      "minimum": 0.0,
      "title": "Infants On Lap",
      "description": "Number of lap infants (under 2 years old); at most one per adult.",
      "default": 0,
      "examples": [
       0
      ]
     },
     "cabin_class": {
      "type": "string",
      "enum": [
       "business",
       "economy",
       "first",
       "premium_economy"
      ],
      "pattern": "^(economy|premium_economy|business|first)$",
      "title": "Cabin Class",
      "description": "Cabin class: economy, premium_economy, business, first.",
      "default": "economy",
      "examples": [
       "economy"
      ]
     },
     "currency": {
      "type": "string",
      "enum": [
       "AED",
       "ARS",
       "AUD",
       "BRL",
       "CAD",
       "CHF",
       "CLP",
       "CNY",
       "COP",
       "CZK",
       "DKK",
       "EGP",
       "EUR",
       "GBP",
       "HKD",
       "HUF",
       "IDR",
       "ILS",
       "INR",
       "JPY",
       "KRW",
       "MXN",
       "MYR",
       "NOK",
       "NZD",
       "PEN",
       "PHP",
       "PLN",
       "QAR",
       "RON",
       "SAR",
       "SEK",
       "SGD",
       "THB",
       "TRY",
       "TWD",
       "USD",
       "VND",
       "ZAR"
      ],
      "title": "Currency",
      "description": "ISO 4217 code for the returned prices. Major currencies include AED, AUD, BRL, CAD, CHF, CNY, EUR, GBP, HKD, INR, JPY, KRW, MXN, NZD, SGD, USD; all 39 supported codes are listed in the enum.",
      "default": "USD",
      "examples": [
       "USD"
      ]
     },
     "hl": {
      "type": "string",
      "title": "Hl",
      "description": "Language code for results.",
      "default": "en",
      "examples": [
       "en"
      ]
     },
     "gl": {
      "type": "string",
      "enum": [
       "ad",
       "ae",
       "af",
       "ag",
       "ai",
       "al",
       "am",
       "ao",
       "aq",
       "ar",
       "as",
       "at",
       "au",
       "aw",
       "ax",
       "az",
       "ba",
       "bb",
       "bd",
       "be",
       "bf",
       "bg",
       "bh",
       "bi",
       "bj",
       "bl",
       "bm",
       "bn",
       "bo",
       "bq",
       "br",
       "bs",
       "bt",
       "bv",
       "bw",
       "by",
       "bz",
       "ca",
       "cc",
       "cd",
       "cf",
       "cg",
       "ch",
       "ci",
       "ck",
       "cl",
       "cm",
       "cn",
       "co",
       "cr",
       "cu",
       "cv",
       "cw",
       "cx",
       "cy",
       "cz",
       "de",
       "dj",
       "dk",
       "dm",
       "do",
       "dz",
       "ec",
       "ee",
       "eg",
       "eh",
       "er",
       "es",
       "et",
       "fi",
       "fj",
       "fk",
       "fm",
       "fo",
       "fr",
       "ga",
       "gb",
       "gd",
       "ge",
       "gf",
       "gg",
       "gh",
       "gi",
       "gl",
       "gm",
       "gn",
       "gp",
       "gq",
       "gr",
       "gs",
       "gt",
       "gu",
       "gw",
       "gy",
       "hk",
       "hm",
       "hn",
       "hr",
       "ht",
       "hu",
       "id",
       "ie",
       "il",
       "im",
       "in",
       "io",
       "iq",
       "ir",
       "is",
       "it",
       "je",
       "jm",
       "jo",
       "jp",
       "ke",
       "kg",
       "kh",
       "ki",
       "km",
       "kn",
       "kp",
       "kr",
       "kw",
       "ky",
       "kz",
       "la",
       "lb",
       "lc",
       "li",
       "lk",
       "lr",
       "ls",
       "lt",
       "lu",
       "lv",
       "ly",
       "ma",
       "mc",
       "md",
       "me",
       "mf",
       "mg",
       "mh",
       "mk",
       "ml",
       "mm",
       "mn",
       "mo",
       "mp",
       "mq",
       "mr",
       "ms",
       "mt",
       "mu",
       "mv",
       "mw",
       "mx",
       "my",
       "mz",
       "na",
       "nc",
       "ne",
       "nf",
       "ng",
       "ni",
       "nl",
       "no",
       "np",
       "nr",
       "nu",
       "nz",
       "om",
       "pa",
       "pe",
       "pf",
       "pg",
       "ph",
       "pk",
       "pl",
       "pm",
       "pn",
       "pr",
       "ps",
       "pt",
       "pw",
       "py",
       "qa",
       "re",
       "ro",
       "rs",
       "ru",
       "rw",
       "sa",
       "sb",
       "sc",
       "sd",
       "se",
       "sg",
       "sh",
       "si",
       "sj",
       "sk",
       "sl",
       "sm",
       "sn",
       "so",
       "sr",
       "ss",
       "st",
       "sv",
       "sx",
       "sy",
       "sz",
       "tc",
       "td",
       "tf",
       "tg",
       "th",
       "tj",
       "tk",
       "tl",
       "tm",
       "tn",
       "to",
       "tr",
       "tt",
       "tv",
       "tw",
       "tz",
       "ua",
       "ug",
       "uk",
       "um",
       "us",
       "uy",
       "uz",
       "va",
       "vc",
       "ve",
       "vg",
       "vi",
       "vn",
       "vu",
       "wf",
       "ws",
       "xk",
       "ye",
       "yt",
       "za",
       "zm",
       "zw"
      ],
      "title": "Gl",
      "description": "Market/country code (two letters).",
      "default": "us",
      "examples": [
       "us"
      ]
     },
     "stops": {
      "anyOf": [
       {
        "type": "integer",
        "maximum": 2.0,
        "minimum": 0.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Stops",
      "description": "Maximum stops filter: 0=nonstop only, 1=max 1 stop, 2=max 2 stops. Omit for any number of stops.",
      "examples": [
       null
      ]
     },
     "include_airlines": {
      "anyOf": [
       {
        "type": "string",
        "pattern": "^[A-Za-z0-9_]{2,13}(,[A-Za-z0-9_]{2,13}){0,19}$"
       },
       {
        "type": "null"
       }
      ],
      "title": "Include Airlines",
      "description": "Comma-separated IATA airline codes and/or alliances (`STAR_ALLIANCE`, `SKYTEAM`, `ONEWORLD`) to keep, e.g. `AC,UA`. Cannot be combined with `exclude_airlines`.",
      "examples": [
       "AC,UA"
      ]
     },
     "exclude_airlines": {
      "anyOf": [
       {
        "type": "string",
        "pattern": "^[A-Za-z0-9_]{2,13}(,[A-Za-z0-9_]{2,13}){0,19}$"
       },
       {
        "type": "null"
       }
      ],
      "title": "Exclude Airlines",
      "description": "Comma-separated airline codes to drop. Google's rule: an itinerary also sold under a codeshare partner that is not excluded is kept.",
      "examples": [
       "B6"
      ]
     },
     "max_price": {
      "anyOf": [
       {
        "type": "integer",
        "maximum": 1000000.0,
        "minimum": 1.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Max Price",
      "description": "Only itineraries at or below this price, in `currency`.",
      "examples": [
       400
      ]
     },
     "max_duration": {
      "anyOf": [
       {
        "type": "integer",
        "maximum": 5760.0,
        "minimum": 30.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Max Duration",
      "description": "Maximum door-to-door travel time per leg, minutes.",
      "examples": [
       600
      ]
     },
     "outbound_times": {
      "anyOf": [
       {
        "type": "string",
        "pattern": "^\\d{1,2},\\d{1,2}(,\\d{1,2},\\d{1,2})?$"
       },
       {
        "type": "null"
       }
      ],
      "title": "Outbound Times",
      "description": "Hour window `from,to` for departure, optionally followed by `from,to` for arrival (0-23; `8,12` = leaves 08:00-12:59). SerpApi's format. First leg.",
      "examples": [
       "6,12"
      ]
     },
     "return_times": {
      "anyOf": [
       {
        "type": "string",
        "pattern": "^\\d{1,2},\\d{1,2}(,\\d{1,2},\\d{1,2})?$"
       },
       {
        "type": "null"
       }
      ],
      "title": "Return Times",
      "description": "Hour window `from,to` for departure, optionally followed by `from,to` for arrival (0-23; `8,12` = leaves 08:00-12:59). SerpApi's format. Return leg; needs `return_date`.",
      "examples": [
       "14,23"
      ]
     },
     "carry_on_bags": {
      "type": "integer",
      "maximum": 1.0,
      "minimum": 0.0,
      "title": "Carry On Bags",
      "description": "Carry-on bags per passenger to include in the price (Google adds the airline's bag fees).",
      "default": 0,
      "examples": [
       0
      ]
     },
     "checked_bags": {
      "type": "integer",
      "maximum": 2.0,
      "minimum": 0.0,
      "title": "Checked Bags",
      "description": "Checked bags per passenger to include in the price.",
      "default": 0,
      "examples": [
       0
      ]
     },
     "exclude_basic_economy": {
      "type": "boolean",
      "title": "Exclude Basic Economy",
      "description": "Hide basic-economy fares (Google's \"Economy (exclude Basic)\"; offered on US routes).",
      "default": false,
      "examples": [
       false
      ]
     },
     "less_emissions": {
      "type": "boolean",
      "title": "Less Emissions",
      "description": "Only flights with lower-than-typical emissions.",
      "default": false,
      "examples": [
       false
      ]
     },
     "layover_duration": {
      "anyOf": [
       {
        "type": "string",
        "pattern": "^\\d{1,4},\\d{1,4}$"
       },
       {
        "type": "null"
       }
      ],
      "title": "Layover Duration",
      "description": "Layover length window `min,max` in minutes, e.g. `60,240`.",
      "examples": [
       "60,240"
      ]
     },
     "connecting_airports": {
      "anyOf": [
       {
        "type": "string",
        "pattern": "^[A-Za-z0-9]{3}(,[A-Za-z0-9]{3}){0,19}$"
       },
       {
        "type": "null"
       }
      ],
      "title": "Connecting Airports",
      "description": "Only connect through these airports (comma-separated IATA codes).",
      "examples": [
       "ORD,DTW"
      ]
     },
     "exclude_connecting_airports": {
      "anyOf": [
       {
        "type": "string",
        "pattern": "^[A-Za-z0-9]{3}(,[A-Za-z0-9]{3}){0,19}$"
       },
       {
        "type": "null"
       }
      ],
      "title": "Exclude Connecting Airports",
      "description": "Never connect through these airports.",
      "examples": [
       "YYZ"
      ]
     },
     "sort_by": {
      "type": "string",
      "enum": [
       "arrival_time",
       "departure_time",
       "duration",
       "emissions",
       "price",
       "top_flights"
      ],
      "pattern": "^(top_flights|price|departure_time|arrival_time|duration|emissions)$",
      "title": "Sort By",
      "description": "Result order (SerpApi `sort_by` 1-6 in the same order): top_flights, price, departure_time, arrival_time, duration, emissions. With anything but top_flights Google returns no separate best group.",
      "default": "top_flights",
      "examples": [
       "top_flights"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "departure",
     "arrival",
     "departure_date"
    ],
    "title": "FlightsSearchRequest",
    "description": "Google Flights search: every itinerary Google offers, with segments.\n\nOne-way when `return_date` is omitted; round trip when it is given (the\nresponse lists outbound options priced for the whole trip, each with a\n`departure_token` for `/v1/serp/google_flights_return`); multi-city when\n`multi_city` lists the legs after the first. Complete itineraries carry a\n`booking_token` for `/v1/serp/google_flights_booking`.",
    "examples": [
     {
      "adults": 1,
      "arrival": "LAX",
      "cabin_class": "economy",
      "currency": "USD",
      "departure": "JFK",
      "departure_date": "2029-03-08",
      "return_date": "2029-03-13"
     },
     {
      "arrival": "NYC",
      "checked_bags": 1,
      "departure": "YUL",
      "departure_date": "2029-03-08",
      "exclude_airlines": "B6",
      "outbound_times": "6,12",
      "sort_by": "price",
      "stops": 0
     },
     {
      "arrival": "PAR",
      "arrival_id": "/m/05qtj",
      "departure": "YUL",
      "departure_date": "2029-03-08",
      "multi_city": [
       {
        "arrival": "FCO",
        "date": "2029-03-13",
        "departure": "CDG,ORY"
       },
       {
        "arrival": "YUL",
        "date": "2029-03-19",
        "departure": "FCO"
       }
      ]
     }
    ]
   },
   "GoogleHotelsPropertyRequest": {
    "properties": {
     "property_token": {
      "type": "string",
      "maxLength": 200,
      "minLength": 10,
      "title": "Property Token",
      "description": "Token returned by `POST /v1/hotels/search`.",
      "examples": [
       "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ"
      ]
     },
     "currency": {
      "type": "string",
      "enum": [
       "AED",
       "ARS",
       "AUD",
       "BRL",
       "CAD",
       "CHF",
       "CLP",
       "CNY",
       "COP",
       "CZK",
       "DKK",
       "EGP",
       "EUR",
       "GBP",
       "HKD",
       "HUF",
       "IDR",
       "ILS",
       "INR",
       "JPY",
       "KRW",
       "MXN",
       "MYR",
       "NOK",
       "NZD",
       "PEN",
       "PHP",
       "PLN",
       "QAR",
       "RON",
       "SAR",
       "SEK",
       "SGD",
       "THB",
       "TRY",
       "TWD",
       "USD",
       "VND",
       "ZAR"
      ],
      "title": "Currency",
      "description": "ISO 4217 code for the returned prices. Major currencies include AED, AUD, BRL, CAD, CHF, CNY, EUR, GBP, HKD, INR, JPY, KRW, MXN, NZD, SGD, USD; all 39 supported codes are listed in the enum.",
      "default": "USD",
      "examples": [
       "USD"
      ]
     },
     "gl": {
      "type": "string",
      "enum": [
       "ad",
       "ae",
       "af",
       "ag",
       "ai",
       "al",
       "am",
       "ao",
       "aq",
       "ar",
       "as",
       "at",
       "au",
       "aw",
       "ax",
       "az",
       "ba",
       "bb",
       "bd",
       "be",
       "bf",
       "bg",
       "bh",
       "bi",
       "bj",
       "bl",
       "bm",
       "bn",
       "bo",
       "bq",
       "br",
       "bs",
       "bt",
       "bv",
       "bw",
       "by",
       "bz",
       "ca",
       "cc",
       "cd",
       "cf",
       "cg",
       "ch",
       "ci",
       "ck",
       "cl",
       "cm",
       "cn",
       "co",
       "cr",
       "cu",
       "cv",
       "cw",
       "cx",
       "cy",
       "cz",
       "de",
       "dj",
       "dk",
       "dm",
       "do",
       "dz",
       "ec",
       "ee",
       "eg",
       "eh",
       "er",
       "es",
       "et",
       "fi",
       "fj",
       "fk",
       "fm",
       "fo",
       "fr",
       "ga",
       "gb",
       "gd",
       "ge",
       "gf",
       "gg",
       "gh",
       "gi",
       "gl",
       "gm",
       "gn",
       "gp",
       "gq",
       "gr",
       "gs",
       "gt",
       "gu",
       "gw",
       "gy",
       "hk",
       "hm",
       "hn",
       "hr",
       "ht",
       "hu",
       "id",
       "ie",
       "il",
       "im",
       "in",
       "io",
       "iq",
       "ir",
       "is",
       "it",
       "je",
       "jm",
       "jo",
       "jp",
       "ke",
       "kg",
       "kh",
       "ki",
       "km",
       "kn",
       "kp",
       "kr",
       "kw",
       "ky",
       "kz",
       "la",
       "lb",
       "lc",
       "li",
       "lk",
       "lr",
       "ls",
       "lt",
       "lu",
       "lv",
       "ly",
       "ma",
       "mc",
       "md",
       "me",
       "mf",
       "mg",
       "mh",
       "mk",
       "ml",
       "mm",
       "mn",
       "mo",
       "mp",
       "mq",
       "mr",
       "ms",
       "mt",
       "mu",
       "mv",
       "mw",
       "mx",
       "my",
       "mz",
       "na",
       "nc",
       "ne",
       "nf",
       "ng",
       "ni",
       "nl",
       "no",
       "np",
       "nr",
       "nu",
       "nz",
       "om",
       "pa",
       "pe",
       "pf",
       "pg",
       "ph",
       "pk",
       "pl",
       "pm",
       "pn",
       "pr",
       "ps",
       "pt",
       "pw",
       "py",
       "qa",
       "re",
       "ro",
       "rs",
       "ru",
       "rw",
       "sa",
       "sb",
       "sc",
       "sd",
       "se",
       "sg",
       "sh",
       "si",
       "sj",
       "sk",
       "sl",
       "sm",
       "sn",
       "so",
       "sr",
       "ss",
       "st",
       "sv",
       "sx",
       "sy",
       "sz",
       "tc",
       "td",
       "tf",
       "tg",
       "th",
       "tj",
       "tk",
       "tl",
       "tm",
       "tn",
       "to",
       "tr",
       "tt",
       "tv",
       "tw",
       "tz",
       "ua",
       "ug",
       "uk",
       "um",
       "us",
       "uy",
       "uz",
       "va",
       "vc",
       "ve",
       "vg",
       "vi",
       "vn",
       "vu",
       "wf",
       "ws",
       "xk",
       "ye",
       "yt",
       "za",
       "zm",
       "zw"
      ],
      "title": "Gl",
      "description": "Country for the request.",
      "default": "us",
      "examples": [
       "us"
      ]
     },
     "hl": {
      "type": "string",
      "title": "Hl",
      "description": "Language for the request.",
      "default": "en",
      "examples": [
       "en"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "property_token"
    ],
    "title": "GoogleHotelsPropertyRequest",
    "description": "One Google Hotels property's details record, by token.\n\nThis is the address-bearing render: the search card omits the mailing\naddress, the pinned property answers with it. Use it to confirm a\n`POST /v1/hotels/search` result is the property you meant.",
    "examples": [
     {
      "currency": "USD",
      "property_token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ"
     }
    ]
   },
   "GoogleHotelsResolveRequest": {
    "properties": {
     "q": {
      "type": "string",
      "maxLength": 200,
      "minLength": 2,
      "title": "Q",
      "description": "Hotel name plus city, region or country.",
      "examples": [
       "Hilton Chicago"
      ]
     },
     "gl": {
      "type": "string",
      "enum": [
       "ad",
       "ae",
       "af",
       "ag",
       "ai",
       "al",
       "am",
       "ao",
       "aq",
       "ar",
       "as",
       "at",
       "au",
       "aw",
       "ax",
       "az",
       "ba",
       "bb",
       "bd",
       "be",
       "bf",
       "bg",
       "bh",
       "bi",
       "bj",
       "bl",
       "bm",
       "bn",
       "bo",
       "bq",
       "br",
       "bs",
       "bt",
       "bv",
       "bw",
       "by",
       "bz",
       "ca",
       "cc",
       "cd",
       "cf",
       "cg",
       "ch",
       "ci",
       "ck",
       "cl",
       "cm",
       "cn",
       "co",
       "cr",
       "cu",
       "cv",
       "cw",
       "cx",
       "cy",
       "cz",
       "de",
       "dj",
       "dk",
       "dm",
       "do",
       "dz",
       "ec",
       "ee",
       "eg",
       "eh",
       "er",
       "es",
       "et",
       "fi",
       "fj",
       "fk",
       "fm",
       "fo",
       "fr",
       "ga",
       "gb",
       "gd",
       "ge",
       "gf",
       "gg",
       "gh",
       "gi",
       "gl",
       "gm",
       "gn",
       "gp",
       "gq",
       "gr",
       "gs",
       "gt",
       "gu",
       "gw",
       "gy",
       "hk",
       "hm",
       "hn",
       "hr",
       "ht",
       "hu",
       "id",
       "ie",
       "il",
       "im",
       "in",
       "io",
       "iq",
       "ir",
       "is",
       "it",
       "je",
       "jm",
       "jo",
       "jp",
       "ke",
       "kg",
       "kh",
       "ki",
       "km",
       "kn",
       "kp",
       "kr",
       "kw",
       "ky",
       "kz",
       "la",
       "lb",
       "lc",
       "li",
       "lk",
       "lr",
       "ls",
       "lt",
       "lu",
       "lv",
       "ly",
       "ma",
       "mc",
       "md",
       "me",
       "mf",
       "mg",
       "mh",
       "mk",
       "ml",
       "mm",
       "mn",
       "mo",
       "mp",
       "mq",
       "mr",
       "ms",
       "mt",
       "mu",
       "mv",
       "mw",
       "mx",
       "my",
       "mz",
       "na",
       "nc",
       "ne",
       "nf",
       "ng",
       "ni",
       "nl",
       "no",
       "np",
       "nr",
       "nu",
       "nz",
       "om",
       "pa",
       "pe",
       "pf",
       "pg",
       "ph",
       "pk",
       "pl",
       "pm",
       "pn",
       "pr",
       "ps",
       "pt",
       "pw",
       "py",
       "qa",
       "re",
       "ro",
       "rs",
       "ru",
       "rw",
       "sa",
       "sb",
       "sc",
       "sd",
       "se",
       "sg",
       "sh",
       "si",
       "sj",
       "sk",
       "sl",
       "sm",
       "sn",
       "so",
       "sr",
       "ss",
       "st",
       "sv",
       "sx",
       "sy",
       "sz",
       "tc",
       "td",
       "tf",
       "tg",
       "th",
       "tj",
       "tk",
       "tl",
       "tm",
       "tn",
       "to",
       "tr",
       "tt",
       "tv",
       "tw",
       "tz",
       "ua",
       "ug",
       "uk",
       "um",
       "us",
       "uy",
       "uz",
       "va",
       "vc",
       "ve",
       "vg",
       "vi",
       "vn",
       "vu",
       "wf",
       "ws",
       "xk",
       "ye",
       "yt",
       "za",
       "zm",
       "zw"
      ],
      "title": "Gl",
      "description": "Country market for the search.",
      "default": "us",
      "examples": [
       "us"
      ]
     },
     "hl": {
      "type": "string",
      "title": "Hl",
      "description": "Language for the search.",
      "default": "en",
      "examples": [
       "en"
      ]
     },
     "limit": {
      "type": "integer",
      "maximum": 3.0,
      "minimum": 1.0,
      "title": "Limit",
      "description": "How many candidates to resolve with addresses (1-3).",
      "default": 3,
      "examples": [
       3
      ]
     },
     "currency": {
      "type": "string",
      "enum": [
       "AED",
       "ARS",
       "AUD",
       "BRL",
       "CAD",
       "CHF",
       "CLP",
       "CNY",
       "COP",
       "CZK",
       "DKK",
       "EGP",
       "EUR",
       "GBP",
       "HKD",
       "HUF",
       "IDR",
       "ILS",
       "INR",
       "JPY",
       "KRW",
       "MXN",
       "MYR",
       "NOK",
       "NZD",
       "PEN",
       "PHP",
       "PLN",
       "QAR",
       "RON",
       "SAR",
       "SEK",
       "SGD",
       "THB",
       "TRY",
       "TWD",
       "USD",
       "VND",
       "ZAR"
      ],
      "title": "Currency",
      "description": "ISO 4217 code for the returned prices. Major currencies include AED, AUD, BRL, CAD, CHF, CNY, EUR, GBP, HKD, INR, JPY, KRW, MXN, NZD, SGD, USD; all 39 supported codes are listed in the enum.",
      "default": "USD",
      "examples": [
       "USD"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "q"
    ],
    "title": "GoogleHotelsResolveRequest",
    "description": "Find Google Hotels properties by name and place, with addresses.\n\nRuns the destination search for `q` (name plus city, region or country —\n`gl` biases the market), then fetches each candidate's details record to\nattach the mailing address. Returns the top `limit` properties with\ntheir `property_token`, ready for `/v1/calendar`, `/v1/offers` and\n`/v1/hotels/reviews`.",
    "examples": [
     {
      "gl": "us",
      "limit": 3,
      "q": "Hilton Chicago"
     }
    ]
   },
   "GoogleHotelsReviewsRequest": {
    "properties": {
     "property_token": {
      "type": "string",
      "maxLength": 200,
      "minLength": 10,
      "title": "Property Token",
      "description": "Token returned by `POST /v1/hotels/search` or `POST /v1/hotels/property`.",
      "examples": [
       "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ"
      ]
     },
     "pages": {
      "type": "integer",
      "maximum": 10.0,
      "minimum": 1.0,
      "title": "Pages",
      "description": "How many 10-review pages to follow.",
      "default": 1,
      "examples": [
       1
      ]
     },
     "page_token": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "title": "Page Token",
      "description": "Continuation token from a previous answer's `next_page_token`.",
      "examples": [
       null
      ]
     },
     "gl": {
      "type": "string",
      "enum": [
       "ad",
       "ae",
       "af",
       "ag",
       "ai",
       "al",
       "am",
       "ao",
       "aq",
       "ar",
       "as",
       "at",
       "au",
       "aw",
       "ax",
       "az",
       "ba",
       "bb",
       "bd",
       "be",
       "bf",
       "bg",
       "bh",
       "bi",
       "bj",
       "bl",
       "bm",
       "bn",
       "bo",
       "bq",
       "br",
       "bs",
       "bt",
       "bv",
       "bw",
       "by",
       "bz",
       "ca",
       "cc",
       "cd",
       "cf",
       "cg",
       "ch",
       "ci",
       "ck",
       "cl",
       "cm",
       "cn",
       "co",
       "cr",
       "cu",
       "cv",
       "cw",
       "cx",
       "cy",
       "cz",
       "de",
       "dj",
       "dk",
       "dm",
       "do",
       "dz",
       "ec",
       "ee",
       "eg",
       "eh",
       "er",
       "es",
       "et",
       "fi",
       "fj",
       "fk",
       "fm",
       "fo",
       "fr",
       "ga",
       "gb",
       "gd",
       "ge",
       "gf",
       "gg",
       "gh",
       "gi",
       "gl",
       "gm",
       "gn",
       "gp",
       "gq",
       "gr",
       "gs",
       "gt",
       "gu",
       "gw",
       "gy",
       "hk",
       "hm",
       "hn",
       "hr",
       "ht",
       "hu",
       "id",
       "ie",
       "il",
       "im",
       "in",
       "io",
       "iq",
       "ir",
       "is",
       "it",
       "je",
       "jm",
       "jo",
       "jp",
       "ke",
       "kg",
       "kh",
       "ki",
       "km",
       "kn",
       "kp",
       "kr",
       "kw",
       "ky",
       "kz",
       "la",
       "lb",
       "lc",
       "li",
       "lk",
       "lr",
       "ls",
       "lt",
       "lu",
       "lv",
       "ly",
       "ma",
       "mc",
       "md",
       "me",
       "mf",
       "mg",
       "mh",
       "mk",
       "ml",
       "mm",
       "mn",
       "mo",
       "mp",
       "mq",
       "mr",
       "ms",
       "mt",
       "mu",
       "mv",
       "mw",
       "mx",
       "my",
       "mz",
       "na",
       "nc",
       "ne",
       "nf",
       "ng",
       "ni",
       "nl",
       "no",
       "np",
       "nr",
       "nu",
       "nz",
       "om",
       "pa",
       "pe",
       "pf",
       "pg",
       "ph",
       "pk",
       "pl",
       "pm",
       "pn",
       "pr",
       "ps",
       "pt",
       "pw",
       "py",
       "qa",
       "re",
       "ro",
       "rs",
       "ru",
       "rw",
       "sa",
       "sb",
       "sc",
       "sd",
       "se",
       "sg",
       "sh",
       "si",
       "sj",
       "sk",
       "sl",
       "sm",
       "sn",
       "so",
       "sr",
       "ss",
       "st",
       "sv",
       "sx",
       "sy",
       "sz",
       "tc",
       "td",
       "tf",
       "tg",
       "th",
       "tj",
       "tk",
       "tl",
       "tm",
       "tn",
       "to",
       "tr",
       "tt",
       "tv",
       "tw",
       "tz",
       "ua",
       "ug",
       "uk",
       "um",
       "us",
       "uy",
       "uz",
       "va",
       "vc",
       "ve",
       "vg",
       "vi",
       "vn",
       "vu",
       "wf",
       "ws",
       "xk",
       "ye",
       "yt",
       "za",
       "zm",
       "zw"
      ],
      "title": "Gl",
      "description": "Country for the request.",
      "default": "us",
      "examples": [
       "us"
      ]
     },
     "hl": {
      "type": "string",
      "title": "Hl",
      "description": "Language for the request.",
      "default": "en",
      "examples": [
       "en"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "property_token"
    ],
    "title": "GoogleHotelsReviewsRequest",
    "description": "Google Hotels guest reviews for one property.\n\n`property_token` is the `Ch…` token `POST /v1/hotels/search` returns.\nGoogle mixes its own reviews with Tripadvisor's, Priceline's and others;\neach row names its `provider`, and ratings follow that provider's scale\n(5 for Google/Tripadvisor, 10 for Priceline). Dates are the relative\nstrings Google shows (\"a month ago\") — Google publishes no absolute\ndates here. Ten reviews per page; `pages` follows the continuation\ntoken up to ten pages in one call.",
    "examples": [
     {
      "pages": 1,
      "property_token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ"
     }
    ]
   },
   "GoogleHotelsSearchRequest": {
    "properties": {
     "q": {
      "type": "string",
      "maxLength": 200,
      "minLength": 2,
      "title": "Q",
      "description": "Destination query exactly as a traveller would type it into Google Hotels, e.g. `hotels in Montreal`, `Paris`, `hotels near JFK`. Google resolves it to a place; the response reports which in `search_information.location`.",
      "examples": [
       "hotels in Montreal"
      ]
     },
     "adults": {
      "type": "integer",
      "maximum": 10.0,
      "minimum": 1.0,
      "title": "Adults",
      "description": "Adults in the room. Encoded as one guest entry each, the way Google's own control sends them.",
      "default": 2,
      "examples": [
       2
      ]
     },
     "currency": {
      "type": "string",
      "enum": [
       "AED",
       "ARS",
       "AUD",
       "BRL",
       "CAD",
       "CHF",
       "CLP",
       "CNY",
       "COP",
       "CZK",
       "DKK",
       "EGP",
       "EUR",
       "GBP",
       "HKD",
       "HUF",
       "IDR",
       "ILS",
       "INR",
       "JPY",
       "KRW",
       "MXN",
       "MYR",
       "NOK",
       "NZD",
       "PEN",
       "PHP",
       "PLN",
       "QAR",
       "RON",
       "SAR",
       "SEK",
       "SGD",
       "THB",
       "TRY",
       "TWD",
       "USD",
       "VND",
       "ZAR"
      ],
      "title": "Currency",
      "description": "ISO 4217 code for the returned prices. Major currencies include AED, AUD, BRL, CAD, CHF, CNY, EUR, GBP, HKD, INR, JPY, KRW, MXN, NZD, SGD, USD; all 39 supported codes are listed in the enum.",
      "default": "USD",
      "examples": [
       "CAD"
      ]
     },
     "gl": {
      "type": "string",
      "enum": [
       "ad",
       "ae",
       "af",
       "ag",
       "ai",
       "al",
       "am",
       "ao",
       "aq",
       "ar",
       "as",
       "at",
       "au",
       "aw",
       "ax",
       "az",
       "ba",
       "bb",
       "bd",
       "be",
       "bf",
       "bg",
       "bh",
       "bi",
       "bj",
       "bl",
       "bm",
       "bn",
       "bo",
       "bq",
       "br",
       "bs",
       "bt",
       "bv",
       "bw",
       "by",
       "bz",
       "ca",
       "cc",
       "cd",
       "cf",
       "cg",
       "ch",
       "ci",
       "ck",
       "cl",
       "cm",
       "cn",
       "co",
       "cr",
       "cu",
       "cv",
       "cw",
       "cx",
       "cy",
       "cz",
       "de",
       "dj",
       "dk",
       "dm",
       "do",
       "dz",
       "ec",
       "ee",
       "eg",
       "eh",
       "er",
       "es",
       "et",
       "fi",
       "fj",
       "fk",
       "fm",
       "fo",
       "fr",
       "ga",
       "gb",
       "gd",
       "ge",
       "gf",
       "gg",
       "gh",
       "gi",
       "gl",
       "gm",
       "gn",
       "gp",
       "gq",
       "gr",
       "gs",
       "gt",
       "gu",
       "gw",
       "gy",
       "hk",
       "hm",
       "hn",
       "hr",
       "ht",
       "hu",
       "id",
       "ie",
       "il",
       "im",
       "in",
       "io",
       "iq",
       "ir",
       "is",
       "it",
       "je",
       "jm",
       "jo",
       "jp",
       "ke",
       "kg",
       "kh",
       "ki",
       "km",
       "kn",
       "kp",
       "kr",
       "kw",
       "ky",
       "kz",
       "la",
       "lb",
       "lc",
       "li",
       "lk",
       "lr",
       "ls",
       "lt",
       "lu",
       "lv",
       "ly",
       "ma",
       "mc",
       "md",
       "me",
       "mf",
       "mg",
       "mh",
       "mk",
       "ml",
       "mm",
       "mn",
       "mo",
       "mp",
       "mq",
       "mr",
       "ms",
       "mt",
       "mu",
       "mv",
       "mw",
       "mx",
       "my",
       "mz",
       "na",
       "nc",
       "ne",
       "nf",
       "ng",
       "ni",
       "nl",
       "no",
       "np",
       "nr",
       "nu",
       "nz",
       "om",
       "pa",
       "pe",
       "pf",
       "pg",
       "ph",
       "pk",
       "pl",
       "pm",
       "pn",
       "pr",
       "ps",
       "pt",
       "pw",
       "py",
       "qa",
       "re",
       "ro",
       "rs",
       "ru",
       "rw",
       "sa",
       "sb",
       "sc",
       "sd",
       "se",
       "sg",
       "sh",
       "si",
       "sj",
       "sk",
       "sl",
       "sm",
       "sn",
       "so",
       "sr",
       "ss",
       "st",
       "sv",
       "sx",
       "sy",
       "sz",
       "tc",
       "td",
       "tf",
       "tg",
       "th",
       "tj",
       "tk",
       "tl",
       "tm",
       "tn",
       "to",
       "tr",
       "tt",
       "tv",
       "tw",
       "tz",
       "ua",
       "ug",
       "uk",
       "um",
       "us",
       "uy",
       "uz",
       "va",
       "vc",
       "ve",
       "vg",
       "vi",
       "vn",
       "vu",
       "wf",
       "ws",
       "xk",
       "ye",
       "yt",
       "za",
       "zm",
       "zw"
      ],
      "title": "Gl",
      "description": "Two-letter Google country (market). Sets the market; the currency is requested separately.",
      "default": "us",
      "examples": [
       "ca"
      ]
     },
     "hl": {
      "type": "string",
      "pattern": "^[a-z]{2,3}(-[A-Za-z]{2,4})?$",
      "title": "Hl",
      "description": "Interface language. Display strings follow it; hotel amenity names are always English.",
      "default": "en",
      "examples": [
       "en"
      ]
     },
     "sort_by": {
      "type": "string",
      "enum": [
       "highest_rating",
       "lowest_price",
       "most_reviewed",
       "relevance"
      ],
      "title": "Sort By",
      "description": "Result order, as Google's Sort by control.",
      "default": "relevance"
     },
     "price_min": {
      "anyOf": [
       {
        "type": "integer",
        "minimum": 0.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Price Min",
      "description": "Minimum nightly price in `currency`.",
      "examples": [
       50
      ]
     },
     "price_max": {
      "anyOf": [
       {
        "type": "integer",
        "minimum": 0.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Price Max",
      "description": "Maximum nightly price in `currency`.",
      "examples": [
       300
      ]
     },
     "free_cancellation": {
      "type": "boolean",
      "title": "Free Cancellation",
      "description": "Only properties Google lists with free cancellation.",
      "default": false
     },
     "special_offers": {
      "type": "boolean",
      "title": "Special Offers",
      "description": "Only properties with a special offer.",
      "default": false
     },
     "eco_certified": {
      "type": "boolean",
      "title": "Eco Certified",
      "description": "Only eco-certified properties.",
      "default": false
     },
     "check_in": {
      "type": "string",
      "format": "date",
      "title": "Check In",
      "description": "First night of the stay, `YYYY-MM-DD`.",
      "examples": [
       "2029-03-14"
      ]
     },
     "check_out": {
      "type": "string",
      "format": "date",
      "title": "Check Out",
      "description": "Departure date, after `check_in`; at most 30 nights.",
      "examples": [
       "2029-03-16"
      ]
     },
     "children_ages": {
      "items": {
       "type": "integer"
      },
      "type": "array",
      "maxItems": 8,
      "title": "Children Ages",
      "description": "One age (0-17) per child. Google prices on each age; the response is rejected if Google priced a different party.",
      "default": [],
      "examples": [
       [
        8
       ]
      ]
     },
     "page_token": {
      "anyOf": [
       {
        "type": "string",
        "pattern": "^[A-Za-z0-9_\\-+/=]{1,200}$"
       },
       {
        "type": "null"
       }
      ],
      "title": "Page Token",
      "description": "Opaque cursor from `pagination.next_page_token` of the previous page. Resend the same query, stay, occupancy and filters with it, exactly as with SearchAPI.",
      "examples": [
       "CBI="
      ]
     },
     "min_rating": {
      "anyOf": [
       {
        "type": "number"
       },
       {
        "type": "null"
       }
      ],
      "enum": [
       3.5,
       4.0,
       4.5
      ],
      "title": "Min Rating",
      "description": "Minimum guest rating: 3.5, 4.0 or 4.5.",
      "examples": [
       4.0
      ]
     },
     "hotel_class": {
      "items": {
       "type": "integer"
      },
      "type": "array",
      "maxItems": 4,
      "title": "Hotel Class",
      "description": "Star classes to include, 2-5.",
      "default": [],
      "examples": [
       [
        4,
        5
       ]
      ],
      "x-multiple": true,
      "x-options": [
       2,
       3,
       4,
       5
      ]
     },
     "amenities": {
      "items": {
       "type": "integer"
      },
      "type": "array",
      "maxItems": 19,
      "title": "Amenities",
      "description": "Amenity filter ids: 1 Free parking, 3 Parking, 4 Indoor pool, 5 Outdoor pool, 6 Pool, 7 Fitness center, 8 Restaurant, 9 Free breakfast, 10 Spa, 11 Beach access, 12 Child-friendly, 15 Bar, 19 Pet-friendly, 22 Room service, 35 Free Wi-Fi, 40 Air-conditioned, 52 All-inclusive available, 53 Wheelchair accessible, 61 EV charger.",
      "default": [],
      "examples": [
       [
        6,
        35
       ]
      ],
      "x-multiple": true,
      "x-options": [
       1,
       3,
       4,
       5,
       6,
       7,
       8,
       9,
       10,
       11,
       12,
       15,
       19,
       22,
       35,
       40,
       52,
       53,
       61
      ]
     },
     "property_types": {
      "items": {
       "type": "integer"
      },
      "type": "array",
      "maxItems": 13,
      "title": "Property Types",
      "description": "Property-type filter ids: 12 Beach hotels, 13 Boutique hotels, 14 Hostels, 15 Inns, 16 Motels, 17 Resorts, 18 Spa hotels, 19 Bed and breakfasts, 20 Other, 21 Apartment hotels, 22 Minshuku, 23 Japanese-style business hotels, 24 Ryokan.",
      "default": [],
      "examples": [
       [
        19
       ]
      ],
      "x-multiple": true,
      "x-options": [
       12,
       13,
       14,
       15,
       16,
       17,
       18,
       19,
       20,
       21,
       22,
       23,
       24
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "q",
     "check_in",
     "check_out"
    ],
    "title": "GoogleHotelsSearchRequest",
    "description": "Search a destination on Google Hotels (native field names).\n\nOne request is one page of about 20 properties. Page on with\n`page_token`; every page costs the same.",
    "examples": [
     {
      "adults": 2,
      "check_in": "2029-03-14",
      "check_out": "2029-03-16",
      "currency": "CAD",
      "gl": "ca",
      "hl": "en",
      "hotel_class": [
       3,
       4,
       5
      ],
      "min_rating": 4.0,
      "price_max": 300,
      "q": "hotels in Montreal",
      "sort_by": "relevance"
     }
    ]
   },
   "GoogleJobsRequest": {
    "properties": {
     "q": {
      "type": "string",
      "maxLength": 300,
      "minLength": 1,
      "title": "Q",
      "description": "Jobs query.",
      "examples": [
       "hotel jobs chicago"
      ]
     },
     "gl": {
      "type": "string",
      "enum": [
       "ad",
       "ae",
       "af",
       "ag",
       "ai",
       "al",
       "am",
       "ao",
       "aq",
       "ar",
       "as",
       "at",
       "au",
       "aw",
       "ax",
       "az",
       "ba",
       "bb",
       "bd",
       "be",
       "bf",
       "bg",
       "bh",
       "bi",
       "bj",
       "bl",
       "bm",
       "bn",
       "bo",
       "bq",
       "br",
       "bs",
       "bt",
       "bv",
       "bw",
       "by",
       "bz",
       "ca",
       "cc",
       "cd",
       "cf",
       "cg",
       "ch",
       "ci",
       "ck",
       "cl",
       "cm",
       "cn",
       "co",
       "cr",
       "cu",
       "cv",
       "cw",
       "cx",
       "cy",
       "cz",
       "de",
       "dj",
       "dk",
       "dm",
       "do",
       "dz",
       "ec",
       "ee",
       "eg",
       "eh",
       "er",
       "es",
       "et",
       "fi",
       "fj",
       "fk",
       "fm",
       "fo",
       "fr",
       "ga",
       "gb",
       "gd",
       "ge",
       "gf",
       "gg",
       "gh",
       "gi",
       "gl",
       "gm",
       "gn",
       "gp",
       "gq",
       "gr",
       "gs",
       "gt",
       "gu",
       "gw",
       "gy",
       "hk",
       "hm",
       "hn",
       "hr",
       "ht",
       "hu",
       "id",
       "ie",
       "il",
       "im",
       "in",
       "io",
       "iq",
       "ir",
       "is",
       "it",
       "je",
       "jm",
       "jo",
       "jp",
       "ke",
       "kg",
       "kh",
       "ki",
       "km",
       "kn",
       "kp",
       "kr",
       "kw",
       "ky",
       "kz",
       "la",
       "lb",
       "lc",
       "li",
       "lk",
       "lr",
       "ls",
       "lt",
       "lu",
       "lv",
       "ly",
       "ma",
       "mc",
       "md",
       "me",
       "mf",
       "mg",
       "mh",
       "mk",
       "ml",
       "mm",
       "mn",
       "mo",
       "mp",
       "mq",
       "mr",
       "ms",
       "mt",
       "mu",
       "mv",
       "mw",
       "mx",
       "my",
       "mz",
       "na",
       "nc",
       "ne",
       "nf",
       "ng",
       "ni",
       "nl",
       "no",
       "np",
       "nr",
       "nu",
       "nz",
       "om",
       "pa",
       "pe",
       "pf",
       "pg",
       "ph",
       "pk",
       "pl",
       "pm",
       "pn",
       "pr",
       "ps",
       "pt",
       "pw",
       "py",
       "qa",
       "re",
       "ro",
       "rs",
       "ru",
       "rw",
       "sa",
       "sb",
       "sc",
       "sd",
       "se",
       "sg",
       "sh",
       "si",
       "sj",
       "sk",
       "sl",
       "sm",
       "sn",
       "so",
       "sr",
       "ss",
       "st",
       "sv",
       "sx",
       "sy",
       "sz",
       "tc",
       "td",
       "tf",
       "tg",
       "th",
       "tj",
       "tk",
       "tl",
       "tm",
       "tn",
       "to",
       "tr",
       "tt",
       "tv",
       "tw",
       "tz",
       "ua",
       "ug",
       "uk",
       "um",
       "us",
       "uy",
       "uz",
       "va",
       "vc",
       "ve",
       "vg",
       "vi",
       "vn",
       "vu",
       "wf",
       "ws",
       "xk",
       "ye",
       "yt",
       "za",
       "zm",
       "zw"
      ],
      "title": "Gl",
      "description": "Country market.",
      "default": "us",
      "examples": [
       "us"
      ]
     },
     "hl": {
      "type": "string",
      "title": "Hl",
      "description": "Language.",
      "default": "en",
      "examples": [
       "en"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "q"
    ],
    "title": "GoogleJobsRequest",
    "description": "Google Jobs listings for a query.\n\nGoogle serves a JavaScript shell to plain HTTP, so this renders the\njobs panel in a real browser (seconds per call). Each card carries the\ntitle, company, location, the upstream publisher (`via`), the relative\nposting age, the employment type, and the apply links (Google\nredirects, with their sources).",
    "examples": [
     {
      "q": "hotel jobs chicago"
     }
    ]
   },
   "GoogleNewsRequest": {
    "properties": {
     "q": {
      "anyOf": [
       {
        "type": "string",
        "maxLength": 200
       },
       {
        "type": "null"
       }
      ],
      "title": "Q",
      "description": "Search query. Omit to read `topic` (or top stories).",
      "examples": [
       "Hilton Chicago"
      ]
     },
     "topic": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "enum": [
       "business",
       "entertainment",
       "health",
       "nation",
       "science",
       "sports",
       "technology",
       "top_stories",
       "world"
      ],
      "title": "Topic",
      "description": "Section feed: one of Google's reader sections.",
      "examples": [
       "business"
      ]
     },
     "when": {
      "anyOf": [
       {
        "type": "string",
        "pattern": "^\\d+[hdmy]$"
       },
       {
        "type": "null"
       }
      ],
      "title": "When",
      "description": "Freshness window appended to `q` (`1h`, `1d`, `7d`, `1y`).",
      "examples": [
       "1y"
      ]
     },
     "gl": {
      "type": "string",
      "enum": [
       "ad",
       "ae",
       "af",
       "ag",
       "ai",
       "al",
       "am",
       "ao",
       "aq",
       "ar",
       "as",
       "at",
       "au",
       "aw",
       "ax",
       "az",
       "ba",
       "bb",
       "bd",
       "be",
       "bf",
       "bg",
       "bh",
       "bi",
       "bj",
       "bl",
       "bm",
       "bn",
       "bo",
       "bq",
       "br",
       "bs",
       "bt",
       "bv",
       "bw",
       "by",
       "bz",
       "ca",
       "cc",
       "cd",
       "cf",
       "cg",
       "ch",
       "ci",
       "ck",
       "cl",
       "cm",
       "cn",
       "co",
       "cr",
       "cu",
       "cv",
       "cw",
       "cx",
       "cy",
       "cz",
       "de",
       "dj",
       "dk",
       "dm",
       "do",
       "dz",
       "ec",
       "ee",
       "eg",
       "eh",
       "er",
       "es",
       "et",
       "fi",
       "fj",
       "fk",
       "fm",
       "fo",
       "fr",
       "ga",
       "gb",
       "gd",
       "ge",
       "gf",
       "gg",
       "gh",
       "gi",
       "gl",
       "gm",
       "gn",
       "gp",
       "gq",
       "gr",
       "gs",
       "gt",
       "gu",
       "gw",
       "gy",
       "hk",
       "hm",
       "hn",
       "hr",
       "ht",
       "hu",
       "id",
       "ie",
       "il",
       "im",
       "in",
       "io",
       "iq",
       "ir",
       "is",
       "it",
       "je",
       "jm",
       "jo",
       "jp",
       "ke",
       "kg",
       "kh",
       "ki",
       "km",
       "kn",
       "kp",
       "kr",
       "kw",
       "ky",
       "kz",
       "la",
       "lb",
       "lc",
       "li",
       "lk",
       "lr",
       "ls",
       "lt",
       "lu",
       "lv",
       "ly",
       "ma",
       "mc",
       "md",
       "me",
       "mf",
       "mg",
       "mh",
       "mk",
       "ml",
       "mm",
       "mn",
       "mo",
       "mp",
       "mq",
       "mr",
       "ms",
       "mt",
       "mu",
       "mv",
       "mw",
       "mx",
       "my",
       "mz",
       "na",
       "nc",
       "ne",
       "nf",
       "ng",
       "ni",
       "nl",
       "no",
       "np",
       "nr",
       "nu",
       "nz",
       "om",
       "pa",
       "pe",
       "pf",
       "pg",
       "ph",
       "pk",
       "pl",
       "pm",
       "pn",
       "pr",
       "ps",
       "pt",
       "pw",
       "py",
       "qa",
       "re",
       "ro",
       "rs",
       "ru",
       "rw",
       "sa",
       "sb",
       "sc",
       "sd",
       "se",
       "sg",
       "sh",
       "si",
       "sj",
       "sk",
       "sl",
       "sm",
       "sn",
       "so",
       "sr",
       "ss",
       "st",
       "sv",
       "sx",
       "sy",
       "sz",
       "tc",
       "td",
       "tf",
       "tg",
       "th",
       "tj",
       "tk",
       "tl",
       "tm",
       "tn",
       "to",
       "tr",
       "tt",
       "tv",
       "tw",
       "tz",
       "ua",
       "ug",
       "uk",
       "um",
       "us",
       "uy",
       "uz",
       "va",
       "vc",
       "ve",
       "vg",
       "vi",
       "vn",
       "vu",
       "wf",
       "ws",
       "xk",
       "ye",
       "yt",
       "za",
       "zm",
       "zw"
      ],
      "title": "Gl",
      "description": "Country market.",
      "default": "us",
      "examples": [
       "us"
      ]
     },
     "hl": {
      "type": "string",
      "title": "Hl",
      "description": "Language.",
      "default": "en",
      "examples": [
       "en"
      ]
     },
     "ceid": {
      "anyOf": [
       {
        "type": "string",
        "pattern": "^[A-Z]{2}:[a-z]{2}$"
       },
       {
        "type": "null"
       }
      ],
      "title": "Ceid",
      "description": "Explicit edition override (`CA:fr`, `GB:en`); built from `gl`/`hl` when omitted.",
      "examples": [
       null
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "title": "GoogleNewsRequest",
    "description": "Google News search or section headlines, via Google's own RSS feed.\n\nPass `q` to search, or `topic` for a section feed — not both. `when`\nappends Google's `when:` operator (`1h`, `1d`, `7d`, `1y`), the feed's\nonly freshness control. One page returns up to 100 stories.",
    "examples": [
     {
      "q": "Hilton Chicago",
      "when": "1y"
     }
    ]
   },
   "GoogleSearchRequest": {
    "properties": {
     "q": {
      "type": "string",
      "maxLength": 400,
      "minLength": 1,
      "title": "Q",
      "description": "Search query.",
      "examples": [
       "Hilton Chicago"
      ]
     },
     "page": {
      "type": "integer",
      "maximum": 10.0,
      "minimum": 1.0,
      "title": "Page",
      "description": "Result page (10 results per page).",
      "default": 1,
      "examples": [
       1
      ]
     },
     "num": {
      "type": "integer",
      "maximum": 20.0,
      "minimum": 1.0,
      "title": "Num",
      "description": "Results per page.",
      "default": 10,
      "examples": [
       10
      ]
     },
     "gl": {
      "type": "string",
      "enum": [
       "ad",
       "ae",
       "af",
       "ag",
       "ai",
       "al",
       "am",
       "ao",
       "aq",
       "ar",
       "as",
       "at",
       "au",
       "aw",
       "ax",
       "az",
       "ba",
       "bb",
       "bd",
       "be",
       "bf",
       "bg",
       "bh",
       "bi",
       "bj",
       "bl",
       "bm",
       "bn",
       "bo",
       "bq",
       "br",
       "bs",
       "bt",
       "bv",
       "bw",
       "by",
       "bz",
       "ca",
       "cc",
       "cd",
       "cf",
       "cg",
       "ch",
       "ci",
       "ck",
       "cl",
       "cm",
       "cn",
       "co",
       "cr",
       "cu",
       "cv",
       "cw",
       "cx",
       "cy",
       "cz",
       "de",
       "dj",
       "dk",
       "dm",
       "do",
       "dz",
       "ec",
       "ee",
       "eg",
       "eh",
       "er",
       "es",
       "et",
       "fi",
       "fj",
       "fk",
       "fm",
       "fo",
       "fr",
       "ga",
       "gb",
       "gd",
       "ge",
       "gf",
       "gg",
       "gh",
       "gi",
       "gl",
       "gm",
       "gn",
       "gp",
       "gq",
       "gr",
       "gs",
       "gt",
       "gu",
       "gw",
       "gy",
       "hk",
       "hm",
       "hn",
       "hr",
       "ht",
       "hu",
       "id",
       "ie",
       "il",
       "im",
       "in",
       "io",
       "iq",
       "ir",
       "is",
       "it",
       "je",
       "jm",
       "jo",
       "jp",
       "ke",
       "kg",
       "kh",
       "ki",
       "km",
       "kn",
       "kp",
       "kr",
       "kw",
       "ky",
       "kz",
       "la",
       "lb",
       "lc",
       "li",
       "lk",
       "lr",
       "ls",
       "lt",
       "lu",
       "lv",
       "ly",
       "ma",
       "mc",
       "md",
       "me",
       "mf",
       "mg",
       "mh",
       "mk",
       "ml",
       "mm",
       "mn",
       "mo",
       "mp",
       "mq",
       "mr",
       "ms",
       "mt",
       "mu",
       "mv",
       "mw",
       "mx",
       "my",
       "mz",
       "na",
       "nc",
       "ne",
       "nf",
       "ng",
       "ni",
       "nl",
       "no",
       "np",
       "nr",
       "nu",
       "nz",
       "om",
       "pa",
       "pe",
       "pf",
       "pg",
       "ph",
       "pk",
       "pl",
       "pm",
       "pn",
       "pr",
       "ps",
       "pt",
       "pw",
       "py",
       "qa",
       "re",
       "ro",
       "rs",
       "ru",
       "rw",
       "sa",
       "sb",
       "sc",
       "sd",
       "se",
       "sg",
       "sh",
       "si",
       "sj",
       "sk",
       "sl",
       "sm",
       "sn",
       "so",
       "sr",
       "ss",
       "st",
       "sv",
       "sx",
       "sy",
       "sz",
       "tc",
       "td",
       "tf",
       "tg",
       "th",
       "tj",
       "tk",
       "tl",
       "tm",
       "tn",
       "to",
       "tr",
       "tt",
       "tv",
       "tw",
       "tz",
       "ua",
       "ug",
       "uk",
       "um",
       "us",
       "uy",
       "uz",
       "va",
       "vc",
       "ve",
       "vg",
       "vi",
       "vn",
       "vu",
       "wf",
       "ws",
       "xk",
       "ye",
       "yt",
       "za",
       "zm",
       "zw"
      ],
      "title": "Gl",
      "description": "Country market.",
      "default": "us",
      "examples": [
       "us"
      ]
     },
     "hl": {
      "type": "string",
      "title": "Hl",
      "description": "Language.",
      "default": "en",
      "examples": [
       "en"
      ]
     },
     "resolve": {
      "type": "boolean",
      "title": "Resolve",
      "description": "Follow each result's `/goto` redirect to the destination URL (one HTTP request per result).",
      "default": false,
      "examples": [
       false
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "q"
    ],
    "title": "GoogleSearchRequest",
    "description": "Google web search: organic results, People Also Ask, AI overview.\n\nGoogle serves a JavaScript shell to plain HTTP, so this renders the page\nin a real browser (seconds, not milliseconds). `link` values are\nGoogle's `/goto` redirects unless `resolve=true`, which follows each\nredirect (one request per result) and returns the destination.",
    "examples": [
     {
      "q": "best time to visit japan"
     }
    ]
   },
   "GoogleShoppingRequest": {
    "properties": {
     "q": {
      "type": "string",
      "maxLength": 300,
      "minLength": 1,
      "title": "Q",
      "description": "Shopping query.",
      "examples": [
       "hilton bathrobe"
      ]
     },
     "gl": {
      "type": "string",
      "enum": [
       "ad",
       "ae",
       "af",
       "ag",
       "ai",
       "al",
       "am",
       "ao",
       "aq",
       "ar",
       "as",
       "at",
       "au",
       "aw",
       "ax",
       "az",
       "ba",
       "bb",
       "bd",
       "be",
       "bf",
       "bg",
       "bh",
       "bi",
       "bj",
       "bl",
       "bm",
       "bn",
       "bo",
       "bq",
       "br",
       "bs",
       "bt",
       "bv",
       "bw",
       "by",
       "bz",
       "ca",
       "cc",
       "cd",
       "cf",
       "cg",
       "ch",
       "ci",
       "ck",
       "cl",
       "cm",
       "cn",
       "co",
       "cr",
       "cu",
       "cv",
       "cw",
       "cx",
       "cy",
       "cz",
       "de",
       "dj",
       "dk",
       "dm",
       "do",
       "dz",
       "ec",
       "ee",
       "eg",
       "eh",
       "er",
       "es",
       "et",
       "fi",
       "fj",
       "fk",
       "fm",
       "fo",
       "fr",
       "ga",
       "gb",
       "gd",
       "ge",
       "gf",
       "gg",
       "gh",
       "gi",
       "gl",
       "gm",
       "gn",
       "gp",
       "gq",
       "gr",
       "gs",
       "gt",
       "gu",
       "gw",
       "gy",
       "hk",
       "hm",
       "hn",
       "hr",
       "ht",
       "hu",
       "id",
       "ie",
       "il",
       "im",
       "in",
       "io",
       "iq",
       "ir",
       "is",
       "it",
       "je",
       "jm",
       "jo",
       "jp",
       "ke",
       "kg",
       "kh",
       "ki",
       "km",
       "kn",
       "kp",
       "kr",
       "kw",
       "ky",
       "kz",
       "la",
       "lb",
       "lc",
       "li",
       "lk",
       "lr",
       "ls",
       "lt",
       "lu",
       "lv",
       "ly",
       "ma",
       "mc",
       "md",
       "me",
       "mf",
       "mg",
       "mh",
       "mk",
       "ml",
       "mm",
       "mn",
       "mo",
       "mp",
       "mq",
       "mr",
       "ms",
       "mt",
       "mu",
       "mv",
       "mw",
       "mx",
       "my",
       "mz",
       "na",
       "nc",
       "ne",
       "nf",
       "ng",
       "ni",
       "nl",
       "no",
       "np",
       "nr",
       "nu",
       "nz",
       "om",
       "pa",
       "pe",
       "pf",
       "pg",
       "ph",
       "pk",
       "pl",
       "pm",
       "pn",
       "pr",
       "ps",
       "pt",
       "pw",
       "py",
       "qa",
       "re",
       "ro",
       "rs",
       "ru",
       "rw",
       "sa",
       "sb",
       "sc",
       "sd",
       "se",
       "sg",
       "sh",
       "si",
       "sj",
       "sk",
       "sl",
       "sm",
       "sn",
       "so",
       "sr",
       "ss",
       "st",
       "sv",
       "sx",
       "sy",
       "sz",
       "tc",
       "td",
       "tf",
       "tg",
       "th",
       "tj",
       "tk",
       "tl",
       "tm",
       "tn",
       "to",
       "tr",
       "tt",
       "tv",
       "tw",
       "tz",
       "ua",
       "ug",
       "uk",
       "um",
       "us",
       "uy",
       "uz",
       "va",
       "vc",
       "ve",
       "vg",
       "vi",
       "vn",
       "vu",
       "wf",
       "ws",
       "xk",
       "ye",
       "yt",
       "za",
       "zm",
       "zw"
      ],
      "title": "Gl",
      "description": "Country market.",
      "default": "us",
      "examples": [
       "us"
      ]
     },
     "hl": {
      "type": "string",
      "title": "Hl",
      "description": "Language.",
      "default": "en",
      "examples": [
       "en"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "q"
    ],
    "title": "GoogleShoppingRequest",
    "description": "Google Shopping products for a query.\n\nGoogle serves a JavaScript shell to plain HTTP, so this renders the\nshopping SERP in a real browser (seconds per call). Each card carries\nthe title, price, merchant and condition chips, plus Google's\n`data-pid` product id. Products dedupe by `data-pid`.",
    "examples": [
     {
      "q": "hilton bathrobe"
     }
    ]
   },
   "HTTPValidationError": {
    "properties": {
     "detail": {
      "items": {
       "$ref": "#/components/schemas/ValidationError"
      },
      "type": "array",
      "title": "Detail"
     }
    },
    "type": "object",
    "title": "HTTPValidationError"
   },
   "HostelworldRequest": {
    "properties": {
     "property_id": {
      "type": "string",
      "minLength": 1,
      "title": "Property Id",
      "description": "Numeric property id from Hostelworld URL, e.g. `hostelworld.com/pwa/hosteldetails.php/88047/...`",
      "examples": [
       "88047"
      ]
     },
     "check_in": {
      "type": "string",
      "format": "date",
      "title": "Check In",
      "description": "First night of the stay, `YYYY-MM-DD`.",
      "examples": [
       "2029-03-03"
      ]
     },
     "check_out": {
      "anyOf": [
       {
        "type": "string",
        "format": "date"
       },
       {
        "type": "null"
       }
      ],
      "title": "Check Out",
      "description": "Departure date. An alternative to `nights` — if both are given, this wins.",
      "examples": [
       "2029-03-04"
      ]
     },
     "nights": {
      "type": "integer",
      "maximum": 30.0,
      "minimum": 1.0,
      "title": "Nights",
      "description": "Length of stay. Ignored when `check_out` is supplied.",
      "default": 1,
      "examples": [
       1
      ]
     },
     "guests": {
      "type": "integer",
      "maximum": 8.0,
      "minimum": 1.0,
      "title": "Guests",
      "description": "Number of guests. For dorms, this is the number of beds needed. For private rooms, this is the occupancy.",
      "default": 1,
      "examples": [
       1
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "property_id",
     "check_in"
    ],
    "title": "HostelworldRequest",
    "description": "Hostelworld: every dorm bed and private room with rate plans.\n\nCurrency is NOT selectable — Hostelworld returns the property's native\ncurrency (typically GBP for UK hostels). Per-bed pricing for dorms,\nper-room pricing for privates.",
    "examples": [
     {
      "check_in": "2029-03-03",
      "guests": 1,
      "nights": 1,
      "property_id": "88047"
     }
    ]
   },
   "HotelsRequest": {
    "properties": {
     "property_id": {
      "type": "string",
      "minLength": 1,
      "title": "Property Id",
      "description": "Numeric id returned by `POST /v1/ota/hotels/search`. For `hotels.com/h38766175.Hotel-Information` it is `38766175` — digits only, no leading `h`. The `ho…` number in a page URL is a legacy id the rate endpoints do not price.",
      "examples": [
       "12570"
      ]
     },
     "check_in": {
      "type": "string",
      "format": "date",
      "title": "Check In",
      "description": "First night of the stay, `YYYY-MM-DD`.",
      "examples": [
       "2029-02-05"
      ]
     },
     "check_out": {
      "anyOf": [
       {
        "type": "string",
        "format": "date"
       },
       {
        "type": "null"
       }
      ],
      "title": "Check Out",
      "description": "Departure date. An alternative to `nights` — if both are given, this wins.",
      "examples": [
       "2029-02-06"
      ]
     },
     "nights": {
      "type": "integer",
      "maximum": 30.0,
      "minimum": 1.0,
      "title": "Nights",
      "description": "Length of stay. Ignored when `check_out` is supplied.",
      "default": 1,
      "examples": [
       1
      ]
     },
     "adults": {
      "type": "integer",
      "maximum": 8.0,
      "minimum": 1.0,
      "title": "Adults",
      "description": "Adults in the room. Two is the hotel default; pass one for a hostel, which is priced per bed. Any value from 1 to 8 is accepted.",
      "default": 2,
      "examples": [
       2
      ]
     },
     "market": {
      "type": "string",
      "enum": [
       "AU",
       "CA",
       "DE",
       "EU",
       "FR",
       "GB",
       "IE",
       "IT",
       "NL",
       "NZ",
       "US"
      ],
      "title": "Market",
      "description": "Point-of-sale, which is how currency is selected — there is no currency field. **Prices are not comparable across markets**: the display basis differs, so the same night reads 527 USD on `US` and 585 CAD on `CA`, an implied 1.11 against a real rate near 1.37. Pick one market per comparison.",
      "default": "US",
      "examples": [
       "US"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "property_id",
     "check_in"
    ],
    "title": "HotelsRequest",
    "description": "Hotels.com headline price for one stay window.\n\nNo price calendar exists on this OTA, so it is one call per date — use it\non the dates that matter rather than sweeping a horizon.",
    "examples": [
     {
      "adults": 2,
      "check_in": "2029-04-10",
      "market": "US",
      "nights": 1,
      "property_id": "12570"
     }
    ]
   },
   "HotelsReviewsRequest": {
    "properties": {
     "property_id": {
      "type": "string",
      "minLength": 1,
      "pattern": "^\\d+$",
      "title": "Property Id",
      "description": "Numeric id returned by `POST /v1/ota/hotels/search`, or from `hotels.com/h38766175.Hotel-Information` (not the legacy `ho…` number).",
      "examples": [
       "12570"
      ]
     },
     "size": {
      "type": "integer",
      "maximum": 25.0,
      "minimum": 1.0,
      "title": "Size",
      "description": "Reviews per page.",
      "default": 10,
      "examples": [
       10
      ]
     },
     "start_index": {
      "type": "integer",
      "minimum": 0.0,
      "title": "Start Index",
      "description": "Row to start from; page by `start_index += size`.",
      "default": 0,
      "examples": [
       0
      ]
     },
     "market": {
      "type": "string",
      "enum": [
       "AU",
       "CA",
       "DE",
       "EU",
       "FR",
       "GB",
       "IE",
       "IT",
       "NL",
       "NZ",
       "US"
      ],
      "title": "Market",
      "description": "Point-of-sale; also selects the currency.",
      "default": "US",
      "examples": [
       "US"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "property_id"
    ],
    "title": "HotelsReviewsRequest",
    "description": "Hotels.com guest reviews for one property.\n\nSame registered query as Expedia's, POSTed to the Hotels.com host with\nthe Hotels.com point-of-sale. Ratings are 0-10; the \"Verified review\"\ndisclaimer and \"Liked: …\" themes ride in `labels`.",
    "examples": [
     {
      "market": "US",
      "property_id": "12570",
      "size": 10,
      "start_index": 0
     }
    ]
   },
   "HotelsRoomsRequest": {
    "properties": {
     "property_id": {
      "type": "string",
      "minLength": 1,
      "title": "Property Id",
      "description": "Numeric id returned by `POST /v1/ota/hotels/search`, or from `hotels.com/h38766175.Hotel-Information` (not the legacy `ho…` number).",
      "examples": [
       "12570"
      ]
     },
     "check_in": {
      "type": "string",
      "format": "date",
      "title": "Check In",
      "description": "First night of the stay, `YYYY-MM-DD`.",
      "examples": [
       "2029-02-05"
      ]
     },
     "nights": {
      "type": "integer",
      "maximum": 30.0,
      "minimum": 1.0,
      "title": "Nights",
      "description": "Length of stay. Ignored when `check_out` is supplied.",
      "default": 1,
      "examples": [
       1
      ]
     },
     "adults": {
      "type": "integer",
      "maximum": 8.0,
      "minimum": 1.0,
      "title": "Adults",
      "description": "Adults in the room. Two is the hotel default; pass one for a hostel, which is priced per bed. Any value from 1 to 8 is accepted.",
      "default": 2,
      "examples": [
       2
      ]
     },
     "market": {
      "type": "string",
      "enum": [
       "AU",
       "CA",
       "DE",
       "EU",
       "FR",
       "GB",
       "IE",
       "IT",
       "NL",
       "NZ",
       "US"
      ],
      "title": "Market",
      "description": "Point-of-sale; also selects the currency.",
      "default": "US",
      "examples": [
       "US"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "property_id",
     "check_in"
    ],
    "title": "HotelsRoomsRequest",
    "description": "Hotels.com room types and rate plans for one stay window.\n\nOne request, ~100-200 KB against ~6 KB for the headline price. Per-date lookup, not a sweep.",
    "examples": [
     {
      "adults": 2,
      "check_in": "2029-04-10",
      "market": "US",
      "nights": 1,
      "property_id": "12570"
     }
    ]
   },
   "HotelsSearchRequest": {
    "properties": {
     "name": {
      "type": "string",
      "minLength": 1,
      "title": "Name",
      "description": "Hotel name as a guest would search for it.",
      "examples": [
       "Moxy Boston Downtown"
      ]
     },
     "city": {
      "type": "string",
      "title": "City",
      "description": "Strongly recommended. Used both in Hotels.com's query and in local candidate ranking so same-brand hotels in other cities rank lower.",
      "default": "",
      "examples": [
       "Boston"
      ]
     },
     "market": {
      "type": "string",
      "enum": [
       "AU",
       "CA",
       "DE",
       "EU",
       "FR",
       "GB",
       "IE",
       "IT",
       "NL",
       "NZ",
       "US"
      ],
      "title": "Market",
      "description": "Hotels.com point-of-sale used for search results. This also matches the market accepted by the rate and room endpoints.",
      "default": "US",
      "examples": [
       "US"
      ]
     },
     "limit": {
      "type": "integer",
      "maximum": 10.0,
      "minimum": 1.0,
      "title": "Limit",
      "description": "Maximum hotel candidates to return, best match first.",
      "default": 5,
      "examples": [
       5
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "name"
    ],
    "title": "HotelsSearchRequest",
    "description": "Find Hotels.com's numeric property id from a hotel name.\n\nRead `recommended_match`, not `matches[0]`. It is null when the provider\nreturned only weak or ambiguous candidates.",
    "examples": [
     {
      "city": "Boston",
      "limit": 5,
      "market": "US",
      "name": "Moxy Boston Downtown"
     }
    ]
   },
   "IndeedJobsRequest": {
    "properties": {
     "q": {
      "type": "string",
      "maxLength": 300,
      "minLength": 1,
      "title": "Q",
      "description": "Job query.",
      "examples": [
       "hotel jobs"
      ]
     },
     "location": {
      "anyOf": [
       {
        "type": "string",
        "maxLength": 120
       },
       {
        "type": "null"
       }
      ],
      "title": "Location",
      "description": "Indeed's `l` parameter: a city, state or `remote`.",
      "examples": [
       "Chicago, IL"
      ]
     },
     "page": {
      "type": "integer",
      "maximum": 30.0,
      "minimum": 1.0,
      "title": "Page",
      "description": "Result page.",
      "default": 1,
      "examples": [
       1
      ]
     },
     "radius_km": {
      "anyOf": [
       {
        "type": "integer",
        "maximum": 2000.0,
        "minimum": 0.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Radius Km",
      "description": "Indeed's `radius`, in km.",
      "examples": [
       null
      ]
     },
     "fromage_days": {
      "anyOf": [
       {
        "type": "integer",
        "maximum": 30.0,
        "minimum": 0.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Fromage Days",
      "description": "Posting age limit, in days (Indeed's `fromage`).",
      "examples": [
       null
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "q"
    ],
    "title": "IndeedJobsRequest",
    "description": "Indeed job search over plain HTTP.\n\nOne page (~45) of job records from Indeed's own embedded model.\nSponsored rows come labelled in `sponsored`, not dropped. Indeed's\njob links are its own redirects (`/rc/clk?jk=…`).",
    "examples": [
     {
      "location": "Chicago, IL",
      "q": "hotel jobs"
     }
    ]
   },
   "MapsDetailRequest": {
    "properties": {
     "place_token": {
      "type": "string",
      "minLength": 10,
      "title": "Place Token",
      "description": "Place token from `POST /v1/maps/search` (`0x…:0x…`).",
      "examples": [
       "0x880e2c99242c7a2f:0x4de3d4bb09dba1"
      ]
     },
     "name": {
      "type": "string",
      "maxLength": 200,
      "minLength": 1,
      "title": "Name",
      "description": "The place's name, from the same search row as the token.",
      "examples": [
       "Hilton Chicago"
      ]
     },
     "gl": {
      "type": "string",
      "enum": [
       "ad",
       "ae",
       "af",
       "ag",
       "ai",
       "al",
       "am",
       "ao",
       "aq",
       "ar",
       "as",
       "at",
       "au",
       "aw",
       "ax",
       "az",
       "ba",
       "bb",
       "bd",
       "be",
       "bf",
       "bg",
       "bh",
       "bi",
       "bj",
       "bl",
       "bm",
       "bn",
       "bo",
       "bq",
       "br",
       "bs",
       "bt",
       "bv",
       "bw",
       "by",
       "bz",
       "ca",
       "cc",
       "cd",
       "cf",
       "cg",
       "ch",
       "ci",
       "ck",
       "cl",
       "cm",
       "cn",
       "co",
       "cr",
       "cu",
       "cv",
       "cw",
       "cx",
       "cy",
       "cz",
       "de",
       "dj",
       "dk",
       "dm",
       "do",
       "dz",
       "ec",
       "ee",
       "eg",
       "eh",
       "er",
       "es",
       "et",
       "fi",
       "fj",
       "fk",
       "fm",
       "fo",
       "fr",
       "ga",
       "gb",
       "gd",
       "ge",
       "gf",
       "gg",
       "gh",
       "gi",
       "gl",
       "gm",
       "gn",
       "gp",
       "gq",
       "gr",
       "gs",
       "gt",
       "gu",
       "gw",
       "gy",
       "hk",
       "hm",
       "hn",
       "hr",
       "ht",
       "hu",
       "id",
       "ie",
       "il",
       "im",
       "in",
       "io",
       "iq",
       "ir",
       "is",
       "it",
       "je",
       "jm",
       "jo",
       "jp",
       "ke",
       "kg",
       "kh",
       "ki",
       "km",
       "kn",
       "kp",
       "kr",
       "kw",
       "ky",
       "kz",
       "la",
       "lb",
       "lc",
       "li",
       "lk",
       "lr",
       "ls",
       "lt",
       "lu",
       "lv",
       "ly",
       "ma",
       "mc",
       "md",
       "me",
       "mf",
       "mg",
       "mh",
       "mk",
       "ml",
       "mm",
       "mn",
       "mo",
       "mp",
       "mq",
       "mr",
       "ms",
       "mt",
       "mu",
       "mv",
       "mw",
       "mx",
       "my",
       "mz",
       "na",
       "nc",
       "ne",
       "nf",
       "ng",
       "ni",
       "nl",
       "no",
       "np",
       "nr",
       "nu",
       "nz",
       "om",
       "pa",
       "pe",
       "pf",
       "pg",
       "ph",
       "pk",
       "pl",
       "pm",
       "pn",
       "pr",
       "ps",
       "pt",
       "pw",
       "py",
       "qa",
       "re",
       "ro",
       "rs",
       "ru",
       "rw",
       "sa",
       "sb",
       "sc",
       "sd",
       "se",
       "sg",
       "sh",
       "si",
       "sj",
       "sk",
       "sl",
       "sm",
       "sn",
       "so",
       "sr",
       "ss",
       "st",
       "sv",
       "sx",
       "sy",
       "sz",
       "tc",
       "td",
       "tf",
       "tg",
       "th",
       "tj",
       "tk",
       "tl",
       "tm",
       "tn",
       "to",
       "tr",
       "tt",
       "tv",
       "tw",
       "tz",
       "ua",
       "ug",
       "uk",
       "um",
       "us",
       "uy",
       "uz",
       "va",
       "vc",
       "ve",
       "vg",
       "vi",
       "vn",
       "vu",
       "wf",
       "ws",
       "xk",
       "ye",
       "yt",
       "za",
       "zm",
       "zw"
      ],
      "title": "Gl",
      "description": "Country market.",
      "default": "us",
      "examples": [
       "us"
      ]
     },
     "hl": {
      "type": "string",
      "title": "Hl",
      "description": "Language.",
      "default": "en",
      "examples": [
       "en"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "place_token",
     "name"
    ],
    "title": "MapsDetailRequest",
    "description": "One Google Maps place's detail record, by token and name.\n\nThe detail card adds the review count to the search fields. The token\npin answers only when `name` matches the place — take both from the\nsame `POST /v1/maps/search` row.",
    "examples": [
     {
      "name": "Hilton Chicago",
      "place_token": "0x880e2c99242c7a2f:0x4de3d4bb09dba1"
     }
    ]
   },
   "MapsSearchRequest": {
    "properties": {
     "q": {
      "type": "string",
      "maxLength": 200,
      "minLength": 1,
      "title": "Q",
      "description": "Maps search query.",
      "examples": [
       "Hilton Chicago"
      ]
     },
     "gl": {
      "type": "string",
      "enum": [
       "ad",
       "ae",
       "af",
       "ag",
       "ai",
       "al",
       "am",
       "ao",
       "aq",
       "ar",
       "as",
       "at",
       "au",
       "aw",
       "ax",
       "az",
       "ba",
       "bb",
       "bd",
       "be",
       "bf",
       "bg",
       "bh",
       "bi",
       "bj",
       "bl",
       "bm",
       "bn",
       "bo",
       "bq",
       "br",
       "bs",
       "bt",
       "bv",
       "bw",
       "by",
       "bz",
       "ca",
       "cc",
       "cd",
       "cf",
       "cg",
       "ch",
       "ci",
       "ck",
       "cl",
       "cm",
       "cn",
       "co",
       "cr",
       "cu",
       "cv",
       "cw",
       "cx",
       "cy",
       "cz",
       "de",
       "dj",
       "dk",
       "dm",
       "do",
       "dz",
       "ec",
       "ee",
       "eg",
       "eh",
       "er",
       "es",
       "et",
       "fi",
       "fj",
       "fk",
       "fm",
       "fo",
       "fr",
       "ga",
       "gb",
       "gd",
       "ge",
       "gf",
       "gg",
       "gh",
       "gi",
       "gl",
       "gm",
       "gn",
       "gp",
       "gq",
       "gr",
       "gs",
       "gt",
       "gu",
       "gw",
       "gy",
       "hk",
       "hm",
       "hn",
       "hr",
       "ht",
       "hu",
       "id",
       "ie",
       "il",
       "im",
       "in",
       "io",
       "iq",
       "ir",
       "is",
       "it",
       "je",
       "jm",
       "jo",
       "jp",
       "ke",
       "kg",
       "kh",
       "ki",
       "km",
       "kn",
       "kp",
       "kr",
       "kw",
       "ky",
       "kz",
       "la",
       "lb",
       "lc",
       "li",
       "lk",
       "lr",
       "ls",
       "lt",
       "lu",
       "lv",
       "ly",
       "ma",
       "mc",
       "md",
       "me",
       "mf",
       "mg",
       "mh",
       "mk",
       "ml",
       "mm",
       "mn",
       "mo",
       "mp",
       "mq",
       "mr",
       "ms",
       "mt",
       "mu",
       "mv",
       "mw",
       "mx",
       "my",
       "mz",
       "na",
       "nc",
       "ne",
       "nf",
       "ng",
       "ni",
       "nl",
       "no",
       "np",
       "nr",
       "nu",
       "nz",
       "om",
       "pa",
       "pe",
       "pf",
       "pg",
       "ph",
       "pk",
       "pl",
       "pm",
       "pn",
       "pr",
       "ps",
       "pt",
       "pw",
       "py",
       "qa",
       "re",
       "ro",
       "rs",
       "ru",
       "rw",
       "sa",
       "sb",
       "sc",
       "sd",
       "se",
       "sg",
       "sh",
       "si",
       "sj",
       "sk",
       "sl",
       "sm",
       "sn",
       "so",
       "sr",
       "ss",
       "st",
       "sv",
       "sx",
       "sy",
       "sz",
       "tc",
       "td",
       "tf",
       "tg",
       "th",
       "tj",
       "tk",
       "tl",
       "tm",
       "tn",
       "to",
       "tr",
       "tt",
       "tv",
       "tw",
       "tz",
       "ua",
       "ug",
       "uk",
       "um",
       "us",
       "uy",
       "uz",
       "va",
       "vc",
       "ve",
       "vg",
       "vi",
       "vn",
       "vu",
       "wf",
       "ws",
       "xk",
       "ye",
       "yt",
       "za",
       "zm",
       "zw"
      ],
      "title": "Gl",
      "description": "Country market.",
      "default": "us",
      "examples": [
       "us"
      ]
     },
     "hl": {
      "type": "string",
      "title": "Hl",
      "description": "Language.",
      "default": "en",
      "examples": [
       "en"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "q"
    ],
    "title": "MapsSearchRequest",
    "description": "Google Maps places search.\n\n`q` is whatever the Google Maps search box takes: a business name, a\ncategory in a place (\"ramen near Shibuya\"), a landmark. One page of\nplace cards: name, address, coordinates, rating, phone, website,\ncategory and the `place_token` for `POST /v1/maps/detail`.",
    "examples": [
     {
      "q": "Hilton Chicago"
     }
    ]
   },
   "OffersRequest": {
    "properties": {
     "token": {
      "type": "string",
      "minLength": 8,
      "title": "Token",
      "description": "Google property token. Get one from `POST /v1/search` — it is the `token` on each match. Looks like `ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ`.",
      "examples": [
       "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ"
      ]
     },
     "check_in": {
      "type": "string",
      "format": "date",
      "title": "Check In",
      "description": "First night of the stay, `YYYY-MM-DD`.",
      "examples": [
       "2029-02-05"
      ]
     },
     "check_out": {
      "anyOf": [
       {
        "type": "string",
        "format": "date"
       },
       {
        "type": "null"
       }
      ],
      "title": "Check Out",
      "description": "Alternative to `nights`; wins if both are given.",
      "examples": [
       "2029-02-06"
      ]
     },
     "nights": {
      "type": "integer",
      "maximum": 30.0,
      "minimum": 1.0,
      "title": "Nights",
      "description": "Ignored when `check_out` is given.",
      "default": 1,
      "examples": [
       1
      ]
     },
     "market": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "enum": [
       "AG",
       "AT",
       "AU",
       "BE",
       "BZ",
       "CA",
       "CH",
       "DE",
       "ES",
       "FR",
       "GB",
       "IE",
       "IT",
       "MX",
       "NL",
       "NZ",
       "PT",
       "US"
      ],
      "title": "Market",
      "description": "Market/country, e.g. `US`, `MX`, `AU`, `GB`. Sets `gl` and the default tax basis. Omit to derive it from `currency`.",
      "examples": [
       "US"
      ]
     },
     "currency": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "enum": [
       "AED",
       "ARS",
       "AUD",
       "BRL",
       "CAD",
       "CHF",
       "CLP",
       "CNY",
       "COP",
       "CZK",
       "DKK",
       "EGP",
       "EUR",
       "GBP",
       "HKD",
       "HUF",
       "IDR",
       "ILS",
       "INR",
       "JPY",
       "KRW",
       "MXN",
       "MYR",
       "NOK",
       "NZD",
       "PEN",
       "PHP",
       "PLN",
       "QAR",
       "RON",
       "SAR",
       "SEK",
       "SGD",
       "THB",
       "TRY",
       "TWD",
       "USD",
       "VND",
       "ZAR"
      ],
      "title": "Currency",
      "description": "ISO currency for the returned prices.",
      "examples": [
       "USD"
      ]
     },
     "adults": {
      "type": "integer",
      "maximum": 8.0,
      "minimum": 1.0,
      "title": "Adults",
      "description": "Occupancy: number of adults, 1-8. Children are not supported by the Google calendar.",
      "default": 2,
      "examples": [
       2
      ]
     },
     "rates_include_tax": {
      "anyOf": [
       {
        "type": "boolean"
       },
       {
        "type": "null"
       }
      ],
      "title": "Rates Include Tax",
      "description": "Which basis the summary price uses. Defaults to the market convention."
     },
     "property_name": {
      "type": "string",
      "title": "Property Name",
      "description": "Improves official-site detection",
      "default": ""
     },
     "include_metasearch": {
      "type": "boolean",
      "title": "Include Metasearch",
      "description": "Include metasearch aggregators (Trivago, Vio, Kayak, Goseek) alongside real OTAs. Off by default: they resell other sources, so they inflate the offer count without adding inventory.",
      "default": false
     },
     "free_cancellation_only": {
      "type": "boolean",
      "title": "Free Cancellation Only",
      "description": "Only offers with a stated free-cancellation deadline",
      "default": false
     },
     "device": {
      "type": "string",
      "enum": [
       "android",
       "desktop",
       "iphone"
      ],
      "title": "Device",
      "description": "Render profile. Google returns a different offer list per device and desktop is the thinnest — iphone found 17 offers where desktop found 12 on the same property.",
      "default": "iphone"
     },
     "coverage": {
      "type": "integer",
      "maximum": 3.0,
      "minimum": 1.0,
      "title": "Coverage",
      "description": "Fetch this many device profiles and merge. Costs one ~3 MB page each; 2 is the sensible maximum.",
      "default": 1
     },
     "require_sources": {
      "anyOf": [
       {
        "items": {
         "type": "string"
        },
        "type": "array"
       },
       {
        "type": "null"
       }
      ],
      "title": "Require Sources",
      "description": "Sources to insist on; retries a thin render. Defaults to official + Booking + Hotels.com + Expedia + Agoda. Pass [] to disable."
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "token",
     "check_in"
    ],
    "title": "OffersRequest",
    "examples": [
     {
      "adults": 2,
      "check_in": "2029-02-05",
      "coverage": 2,
      "currency": "USD",
      "device": "iphone",
      "include_metasearch": false,
      "nights": 1,
      "token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ"
     }
    ]
   },
   "OfficialRequest": {
    "properties": {
     "url": {
      "type": "string",
      "minLength": 8,
      "title": "Url",
      "description": "The hotel's public homepage or property page. The API finds its booking link and detects the booking engine automatically; a direct booking URL is also accepted.",
      "examples": [
       "https://www.marriott.com/en-us/hotels/yyzrz-the-ritz-carlton-toronto/overview/"
      ]
     },
     "check_in": {
      "type": "string",
      "format": "date",
      "title": "Check In",
      "description": "First night of the stay, `YYYY-MM-DD`.",
      "examples": [
       "2029-02-05"
      ]
     },
     "check_out": {
      "anyOf": [
       {
        "type": "string",
        "format": "date"
       },
       {
        "type": "null"
       }
      ],
      "title": "Check Out",
      "description": "Departure date. An alternative to `nights` — if both are given, this wins.",
      "examples": [
       "2029-02-06"
      ]
     },
     "nights": {
      "type": "integer",
      "maximum": 30.0,
      "minimum": 1.0,
      "title": "Nights",
      "description": "Length of stay. Ignored when `check_out` is supplied.",
      "default": 1,
      "examples": [
       1
      ]
     },
     "adults": {
      "type": "integer",
      "maximum": 8.0,
      "minimum": 1.0,
      "title": "Adults",
      "description": "Adults in the room. Two is the hotel default; pass one for a hostel, which is priced per bed. Any value from 1 to 8 is accepted.",
      "default": 2,
      "examples": [
       2
      ]
     },
     "rooms": {
      "type": "integer",
      "maximum": 8.0,
      "minimum": 1.0,
      "title": "Rooms",
      "description": "Rooms requested.",
      "default": 1,
      "examples": [
       1
      ]
     },
     "currency": {
      "type": "string",
      "enum": [
       "AED",
       "ARS",
       "AUD",
       "BRL",
       "CAD",
       "CHF",
       "CLP",
       "CNY",
       "COP",
       "CZK",
       "DKK",
       "EGP",
       "EUR",
       "GBP",
       "HKD",
       "HUF",
       "IDR",
       "ILS",
       "INR",
       "JPY",
       "KRW",
       "MXN",
       "MYR",
       "NOK",
       "NZD",
       "PEN",
       "PHP",
       "PLN",
       "QAR",
       "RON",
       "SAR",
       "SEK",
       "SGD",
       "THB",
       "TRY",
       "TWD",
       "USD",
       "VND",
       "ZAR"
      ],
      "title": "Currency",
      "description": "ISO 4217 code for the returned prices. Major currencies include AED, AUD, BRL, CAD, CHF, CNY, EUR, GBP, HKD, INR, JPY, KRW, MXN, NZD, SGD, USD; all 39 supported codes are listed in the enum.",
      "default": "USD",
      "examples": [
       "USD"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "url",
     "check_in"
    ],
    "title": "OfficialRequest",
    "description": "One official-site lookup, whichever booking engine the hotel runs.\n\nPaste the hotel's public website. Discovery finds its reservation link,\nidentifies the PMS/booking engine, and routes to the right extractor. A\ndirect booking URL also works, but callers never select an engine.",
    "examples": [
     {
      "adults": 2,
      "check_in": "2029-02-05",
      "currency": "CAD",
      "nights": 1,
      "url": "https://www.marriott.com/en-us/hotels/yyzrz-the-ritz-carlton-toronto/overview/"
     }
    ]
   },
   "RoomMatrixRequest": {
    "properties": {
     "token": {
      "type": "string",
      "minLength": 8,
      "title": "Token",
      "description": "Google property token. Get one from `POST /v1/search` — it is the `token` on each match. Looks like `ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ`.",
      "examples": [
       "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ"
      ]
     },
     "check_in": {
      "type": "string",
      "format": "date",
      "title": "Check In",
      "description": "First night of the stay, `YYYY-MM-DD`.",
      "examples": [
       "2029-02-05"
      ]
     },
     "nights": {
      "type": "integer",
      "maximum": 30.0,
      "minimum": 1.0,
      "title": "Nights",
      "description": "Length of stay. Ignored when `check_out` is supplied.",
      "default": 1,
      "examples": [
       1
      ]
     },
     "market": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "enum": [
       "AG",
       "AT",
       "AU",
       "BE",
       "BZ",
       "CA",
       "CH",
       "DE",
       "ES",
       "FR",
       "GB",
       "IE",
       "IT",
       "MX",
       "NL",
       "NZ",
       "PT",
       "US"
      ],
      "title": "Market",
      "description": "Market/country, e.g. `US`, `MX`, `AU`, `GB`. Sets `gl` and the default tax basis. Omit to derive it from `currency`.",
      "examples": [
       "US"
      ]
     },
     "currency": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "enum": [
       "AED",
       "ARS",
       "AUD",
       "BRL",
       "CAD",
       "CHF",
       "CLP",
       "CNY",
       "COP",
       "CZK",
       "DKK",
       "EGP",
       "EUR",
       "GBP",
       "HKD",
       "HUF",
       "IDR",
       "ILS",
       "INR",
       "JPY",
       "KRW",
       "MXN",
       "MYR",
       "NOK",
       "NZD",
       "PEN",
       "PHP",
       "PLN",
       "QAR",
       "RON",
       "SAR",
       "SEK",
       "SGD",
       "THB",
       "TRY",
       "TWD",
       "USD",
       "VND",
       "ZAR"
      ],
      "title": "Currency",
      "description": "ISO currency for the returned prices.",
      "examples": [
       "USD"
      ]
     },
     "adults": {
      "type": "integer",
      "maximum": 8.0,
      "minimum": 1.0,
      "title": "Adults",
      "description": "Occupancy: number of adults, 1-8. Children are not supported by the Google calendar.",
      "default": 2,
      "examples": [
       2
      ]
     },
     "sources": {
      "anyOf": [
       {
        "items": {
         "type": "string"
        },
        "type": "array"
       },
       {
        "type": "null"
       }
      ],
      "title": "Sources",
      "description": "Defaults to ['Official site', 'Booking.com', 'Hotels.com', 'Expedia']"
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "token",
     "check_in"
    ],
    "title": "RoomMatrixRequest",
    "description": "Room types by OTA, aligned onto one comparable signature per row.",
    "examples": [
     {
      "adults": 2,
      "check_in": "2029-02-05",
      "currency": "USD",
      "nights": 1,
      "token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ"
     }
    ]
   },
   "SearchRequest": {
    "properties": {
     "name": {
      "type": "string",
      "title": "Name",
      "description": "Property name as a guest would type it. Fuzzy — exact punctuation does not matter.",
      "examples": [
       "Hilton Chicago"
      ]
     },
     "city": {
      "type": "string",
      "title": "City",
      "description": "Strongly recommended. Without it a common brand name matches the wrong city.",
      "default": "",
      "examples": [
       "Chicago"
      ]
     },
     "market": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "enum": [
       "AD",
       "AE",
       "AF",
       "AG",
       "AI",
       "AL",
       "AM",
       "AO",
       "AQ",
       "AR",
       "AS",
       "AT",
       "AU",
       "AW",
       "AX",
       "AZ",
       "BA",
       "BB",
       "BD",
       "BE",
       "BF",
       "BG",
       "BH",
       "BI",
       "BJ",
       "BL",
       "BM",
       "BN",
       "BO",
       "BQ",
       "BR",
       "BS",
       "BT",
       "BV",
       "BW",
       "BY",
       "BZ",
       "CA",
       "CC",
       "CD",
       "CF",
       "CG",
       "CH",
       "CI",
       "CK",
       "CL",
       "CM",
       "CN",
       "CO",
       "CR",
       "CU",
       "CV",
       "CW",
       "CX",
       "CY",
       "CZ",
       "DE",
       "DJ",
       "DK",
       "DM",
       "DO",
       "DZ",
       "EC",
       "EE",
       "EG",
       "EH",
       "ER",
       "ES",
       "ET",
       "FI",
       "FJ",
       "FK",
       "FM",
       "FO",
       "FR",
       "GA",
       "GB",
       "GD",
       "GE",
       "GF",
       "GG",
       "GH",
       "GI",
       "GL",
       "GM",
       "GN",
       "GP",
       "GQ",
       "GR",
       "GS",
       "GT",
       "GU",
       "GW",
       "GY",
       "HK",
       "HM",
       "HN",
       "HR",
       "HT",
       "HU",
       "ID",
       "IE",
       "IL",
       "IM",
       "IN",
       "IO",
       "IQ",
       "IR",
       "IS",
       "IT",
       "JE",
       "JM",
       "JO",
       "JP",
       "KE",
       "KG",
       "KH",
       "KI",
       "KM",
       "KN",
       "KP",
       "KR",
       "KW",
       "KY",
       "KZ",
       "LA",
       "LB",
       "LC",
       "LI",
       "LK",
       "LR",
       "LS",
       "LT",
       "LU",
       "LV",
       "LY",
       "MA",
       "MC",
       "MD",
       "ME",
       "MF",
       "MG",
       "MH",
       "MK",
       "ML",
       "MM",
       "MN",
       "MO",
       "MP",
       "MQ",
       "MR",
       "MS",
       "MT",
       "MU",
       "MV",
       "MW",
       "MX",
       "MY",
       "MZ",
       "NA",
       "NC",
       "NE",
       "NF",
       "NG",
       "NI",
       "NL",
       "NO",
       "NP",
       "NR",
       "NU",
       "NZ",
       "OM",
       "PA",
       "PE",
       "PF",
       "PG",
       "PH",
       "PK",
       "PL",
       "PM",
       "PN",
       "PR",
       "PS",
       "PT",
       "PW",
       "PY",
       "QA",
       "RE",
       "RO",
       "RS",
       "RU",
       "RW",
       "SA",
       "SB",
       "SC",
       "SD",
       "SE",
       "SG",
       "SH",
       "SI",
       "SJ",
       "SK",
       "SL",
       "SM",
       "SN",
       "SO",
       "SR",
       "SS",
       "ST",
       "SV",
       "SX",
       "SY",
       "SZ",
       "TC",
       "TD",
       "TF",
       "TG",
       "TH",
       "TJ",
       "TK",
       "TL",
       "TM",
       "TN",
       "TO",
       "TR",
       "TT",
       "TV",
       "TW",
       "TZ",
       "UA",
       "UG",
       "UK",
       "UM",
       "US",
       "UY",
       "UZ",
       "VA",
       "VC",
       "VE",
       "VG",
       "VI",
       "VN",
       "VU",
       "WF",
       "WS",
       "XK",
       "YE",
       "YT",
       "ZA",
       "ZM",
       "ZW"
      ],
      "title": "Market",
      "description": "ISO country/Google market to try first, e.g. `US`, `MX`, `GD`. Search accepts markets beyond the pricing markets listed by `GET /v1/markets` because property tokens are global; the response reports where it matched.",
      "examples": [
       "GD"
      ]
     },
     "fallback_markets": {
      "items": {
       "type": "string"
      },
      "type": "array",
      "maxItems": 5,
      "title": "Fallback Markets",
      "description": "Markets tried in order only when the requested market returns zero candidates. Defaults to `US`, which often indexes Caribbean properties absent from their local Google market. Pass `[]` to disable fallback. The response always reports `attempted_markets`, `matched_market`, and `market_fallback_used`.",
      "default": [
       "US"
      ],
      "examples": [
       [
        "US"
       ]
      ],
      "x-multiple": true,
      "x-options": [
       "AD",
       "AE",
       "AF",
       "AG",
       "AI",
       "AL",
       "AM",
       "AO",
       "AQ",
       "AR",
       "AS",
       "AT",
       "AU",
       "AW",
       "AX",
       "AZ",
       "BA",
       "BB",
       "BD",
       "BE",
       "BF",
       "BG",
       "BH",
       "BI",
       "BJ",
       "BL",
       "BM",
       "BN",
       "BO",
       "BQ",
       "BR",
       "BS",
       "BT",
       "BV",
       "BW",
       "BY",
       "BZ",
       "CA",
       "CC",
       "CD",
       "CF",
       "CG",
       "CH",
       "CI",
       "CK",
       "CL",
       "CM",
       "CN",
       "CO",
       "CR",
       "CU",
       "CV",
       "CW",
       "CX",
       "CY",
       "CZ",
       "DE",
       "DJ",
       "DK",
       "DM",
       "DO",
       "DZ",
       "EC",
       "EE",
       "EG",
       "EH",
       "ER",
       "ES",
       "ET",
       "FI",
       "FJ",
       "FK",
       "FM",
       "FO",
       "FR",
       "GA",
       "GB",
       "GD",
       "GE",
       "GF",
       "GG",
       "GH",
       "GI",
       "GL",
       "GM",
       "GN",
       "GP",
       "GQ",
       "GR",
       "GS",
       "GT",
       "GU",
       "GW",
       "GY",
       "HK",
       "HM",
       "HN",
       "HR",
       "HT",
       "HU",
       "ID",
       "IE",
       "IL",
       "IM",
       "IN",
       "IO",
       "IQ",
       "IR",
       "IS",
       "IT",
       "JE",
       "JM",
       "JO",
       "JP",
       "KE",
       "KG",
       "KH",
       "KI",
       "KM",
       "KN",
       "KP",
       "KR",
       "KW",
       "KY",
       "KZ",
       "LA",
       "LB",
       "LC",
       "LI",
       "LK",
       "LR",
       "LS",
       "LT",
       "LU",
       "LV",
       "LY",
       "MA",
       "MC",
       "MD",
       "ME",
       "MF",
       "MG",
       "MH",
       "MK",
       "ML",
       "MM",
       "MN",
       "MO",
       "MP",
       "MQ",
       "MR",
       "MS",
       "MT",
       "MU",
       "MV",
       "MW",
       "MX",
       "MY",
       "MZ",
       "NA",
       "NC",
       "NE",
       "NF",
       "NG",
       "NI",
       "NL",
       "NO",
       "NP",
       "NR",
       "NU",
       "NZ",
       "OM",
       "PA",
       "PE",
       "PF",
       "PG",
       "PH",
       "PK",
       "PL",
       "PM",
       "PN",
       "PR",
       "PS",
       "PT",
       "PW",
       "PY",
       "QA",
       "RE",
       "RO",
       "RS",
       "RU",
       "RW",
       "SA",
       "SB",
       "SC",
       "SD",
       "SE",
       "SG",
       "SH",
       "SI",
       "SJ",
       "SK",
       "SL",
       "SM",
       "SN",
       "SO",
       "SR",
       "SS",
       "ST",
       "SV",
       "SX",
       "SY",
       "SZ",
       "TC",
       "TD",
       "TF",
       "TG",
       "TH",
       "TJ",
       "TK",
       "TL",
       "TM",
       "TN",
       "TO",
       "TR",
       "TT",
       "TV",
       "TW",
       "TZ",
       "UA",
       "UG",
       "UK",
       "UM",
       "US",
       "UY",
       "UZ",
       "VA",
       "VC",
       "VE",
       "VG",
       "VI",
       "VN",
       "VU",
       "WF",
       "WS",
       "XK",
       "YE",
       "YT",
       "ZA",
       "ZM",
       "ZW"
      ]
     },
     "currency": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "enum": [
       "AED",
       "ARS",
       "AUD",
       "BRL",
       "CAD",
       "CHF",
       "CLP",
       "CNY",
       "COP",
       "CZK",
       "DKK",
       "EGP",
       "EUR",
       "GBP",
       "HKD",
       "HUF",
       "IDR",
       "ILS",
       "INR",
       "JPY",
       "KRW",
       "MXN",
       "MYR",
       "NOK",
       "NZD",
       "PEN",
       "PHP",
       "PLN",
       "QAR",
       "RON",
       "SAR",
       "SEK",
       "SGD",
       "THB",
       "TRY",
       "TWD",
       "USD",
       "VND",
       "ZAR"
      ],
      "title": "Currency",
      "description": "ISO 4217 code for the returned prices. Major currencies include AED, AUD, BRL, CAD, CHF, CNY, EUR, GBP, HKD, INR, JPY, KRW, MXN, NZD, SGD, USD; all 39 supported codes are listed in the enum.",
      "examples": [
       "USD"
      ]
     },
     "limit": {
      "type": "integer",
      "maximum": 10.0,
      "minimum": 1.0,
      "title": "Limit",
      "description": "Candidates to return, best match first.",
      "default": 5,
      "examples": [
       5
      ]
     },
     "verify": {
      "type": "boolean",
      "title": "Verify",
      "description": "Fetch each candidate to confirm the token resolves and read back its real name. Slower, far fewer wrong matches.",
      "default": true
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "name"
    ],
    "title": "SearchRequest",
    "description": "Find a property token by name. **Start here if you have no token.**",
    "examples": [
     {
      "city": "St George's",
      "fallback_markets": [
       "US"
      ],
      "limit": 5,
      "market": "GD",
      "name": "Blue Horizons Garden Resort",
      "verify": true
     }
    ]
   },
   "SerpCalendarRequest": {
    "properties": {
     "property_token": {
      "type": "string",
      "minLength": 8,
      "title": "Property Token",
      "description": "Google property token, as returned by `/v1/search`.",
      "examples": [
       "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ"
      ]
     },
     "days": {
      "type": "integer",
      "maximum": 330.0,
      "minimum": 1.0,
      "title": "Days",
      "description": "Nights to price in one call. Max 330.",
      "default": 90,
      "examples": [
       90
      ]
     },
     "start": {
      "anyOf": [
       {
        "type": "string",
        "format": "date"
       },
       {
        "type": "null"
       }
      ],
      "title": "Start",
      "description": "First stay date. Defaults to tomorrow.",
      "examples": [
       "2029-02-05"
      ]
     },
     "adults": {
      "type": "integer",
      "maximum": 8.0,
      "minimum": 1.0,
      "title": "Adults",
      "description": "Adults in the room. Two is the hotel default; pass one for a hostel, which is priced per bed. Any value from 1 to 8 is accepted.",
      "default": 2,
      "examples": [
       2
      ]
     },
     "currency": {
      "type": "string",
      "enum": [
       "AED",
       "ARS",
       "AUD",
       "BRL",
       "CAD",
       "CHF",
       "CLP",
       "CNY",
       "COP",
       "CZK",
       "DKK",
       "EGP",
       "EUR",
       "GBP",
       "HKD",
       "HUF",
       "IDR",
       "ILS",
       "INR",
       "JPY",
       "KRW",
       "MXN",
       "MYR",
       "NOK",
       "NZD",
       "PEN",
       "PHP",
       "PLN",
       "QAR",
       "RON",
       "SAR",
       "SEK",
       "SGD",
       "THB",
       "TRY",
       "TWD",
       "USD",
       "VND",
       "ZAR"
      ],
      "title": "Currency",
      "description": "ISO 4217 code for the returned prices. Major currencies include AED, AUD, BRL, CAD, CHF, CNY, EUR, GBP, HKD, INR, JPY, KRW, MXN, NZD, SGD, USD; all 39 supported codes are listed in the enum.",
      "default": "USD",
      "examples": [
       "USD"
      ]
     },
     "gl": {
      "type": "string",
      "enum": [
       "ad",
       "ae",
       "af",
       "ag",
       "ai",
       "al",
       "am",
       "ao",
       "aq",
       "ar",
       "as",
       "at",
       "au",
       "aw",
       "ax",
       "az",
       "ba",
       "bb",
       "bd",
       "be",
       "bf",
       "bg",
       "bh",
       "bi",
       "bj",
       "bl",
       "bm",
       "bn",
       "bo",
       "bq",
       "br",
       "bs",
       "bt",
       "bv",
       "bw",
       "by",
       "bz",
       "ca",
       "cc",
       "cd",
       "cf",
       "cg",
       "ch",
       "ci",
       "ck",
       "cl",
       "cm",
       "cn",
       "co",
       "cr",
       "cu",
       "cv",
       "cw",
       "cx",
       "cy",
       "cz",
       "de",
       "dj",
       "dk",
       "dm",
       "do",
       "dz",
       "ec",
       "ee",
       "eg",
       "eh",
       "er",
       "es",
       "et",
       "fi",
       "fj",
       "fk",
       "fm",
       "fo",
       "fr",
       "ga",
       "gb",
       "gd",
       "ge",
       "gf",
       "gg",
       "gh",
       "gi",
       "gl",
       "gm",
       "gn",
       "gp",
       "gq",
       "gr",
       "gs",
       "gt",
       "gu",
       "gw",
       "gy",
       "hk",
       "hm",
       "hn",
       "hr",
       "ht",
       "hu",
       "id",
       "ie",
       "il",
       "im",
       "in",
       "io",
       "iq",
       "ir",
       "is",
       "it",
       "je",
       "jm",
       "jo",
       "jp",
       "ke",
       "kg",
       "kh",
       "ki",
       "km",
       "kn",
       "kp",
       "kr",
       "kw",
       "ky",
       "kz",
       "la",
       "lb",
       "lc",
       "li",
       "lk",
       "lr",
       "ls",
       "lt",
       "lu",
       "lv",
       "ly",
       "ma",
       "mc",
       "md",
       "me",
       "mf",
       "mg",
       "mh",
       "mk",
       "ml",
       "mm",
       "mn",
       "mo",
       "mp",
       "mq",
       "mr",
       "ms",
       "mt",
       "mu",
       "mv",
       "mw",
       "mx",
       "my",
       "mz",
       "na",
       "nc",
       "ne",
       "nf",
       "ng",
       "ni",
       "nl",
       "no",
       "np",
       "nr",
       "nu",
       "nz",
       "om",
       "pa",
       "pe",
       "pf",
       "pg",
       "ph",
       "pk",
       "pl",
       "pm",
       "pn",
       "pr",
       "ps",
       "pt",
       "pw",
       "py",
       "qa",
       "re",
       "ro",
       "rs",
       "ru",
       "rw",
       "sa",
       "sb",
       "sc",
       "sd",
       "se",
       "sg",
       "sh",
       "si",
       "sj",
       "sk",
       "sl",
       "sm",
       "sn",
       "so",
       "sr",
       "ss",
       "st",
       "sv",
       "sx",
       "sy",
       "sz",
       "tc",
       "td",
       "tf",
       "tg",
       "th",
       "tj",
       "tk",
       "tl",
       "tm",
       "tn",
       "to",
       "tr",
       "tt",
       "tv",
       "tw",
       "tz",
       "ua",
       "ug",
       "uk",
       "um",
       "us",
       "uy",
       "uz",
       "va",
       "vc",
       "ve",
       "vg",
       "vi",
       "vn",
       "vu",
       "wf",
       "ws",
       "xk",
       "ye",
       "yt",
       "za",
       "zm",
       "zw"
      ],
      "title": "Gl",
      "description": "Two-letter country for the request.",
      "default": "us",
      "examples": [
       "us"
      ]
     },
     "los": {
      "type": "integer",
      "maximum": 30.0,
      "minimum": 1.0,
      "title": "Los",
      "description": "Length of stay each night is priced at. The per-night figure genuinely moves with LOS.",
      "default": 1,
      "examples": [
       1
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "property_token"
    ],
    "title": "SerpCalendarRequest",
    "description": "A horizon sweep in SearchAPI's parameter style.\n\nSearchAPI has no calendar engine — it bills one `google_hotels_property`\ncall per stay date. This returns the whole window in a single request, so\nthe same 90-night sweep is 1 call rather than 90.",
    "examples": [
     {
      "adults": 2,
      "currency": "USD",
      "days": 90,
      "gl": "us",
      "los": 1,
      "property_token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
      "start": "2029-02-05"
     }
    ]
   },
   "SerpGoogleHotelsRequest": {
    "properties": {
     "q": {
      "type": "string",
      "maxLength": 200,
      "minLength": 2,
      "title": "Q",
      "description": "Destination query exactly as a traveller would type it into Google Hotels, e.g. `hotels in Montreal`, `Paris`, `hotels near JFK`. Google resolves it to a place; the response reports which in `search_information.location`.",
      "examples": [
       "hotels in Montreal"
      ]
     },
     "adults": {
      "type": "integer",
      "maximum": 10.0,
      "minimum": 1.0,
      "title": "Adults",
      "description": "Adults in the room. Encoded as one guest entry each, the way Google's own control sends them.",
      "default": 2,
      "examples": [
       2
      ]
     },
     "currency": {
      "type": "string",
      "enum": [
       "AED",
       "ARS",
       "AUD",
       "BRL",
       "CAD",
       "CHF",
       "CLP",
       "CNY",
       "COP",
       "CZK",
       "DKK",
       "EGP",
       "EUR",
       "GBP",
       "HKD",
       "HUF",
       "IDR",
       "ILS",
       "INR",
       "JPY",
       "KRW",
       "MXN",
       "MYR",
       "NOK",
       "NZD",
       "PEN",
       "PHP",
       "PLN",
       "QAR",
       "RON",
       "SAR",
       "SEK",
       "SGD",
       "THB",
       "TRY",
       "TWD",
       "USD",
       "VND",
       "ZAR"
      ],
      "title": "Currency",
      "description": "ISO 4217 code for the returned prices. Major currencies include AED, AUD, BRL, CAD, CHF, CNY, EUR, GBP, HKD, INR, JPY, KRW, MXN, NZD, SGD, USD; all 39 supported codes are listed in the enum.",
      "default": "USD",
      "examples": [
       "CAD"
      ]
     },
     "gl": {
      "type": "string",
      "enum": [
       "ad",
       "ae",
       "af",
       "ag",
       "ai",
       "al",
       "am",
       "ao",
       "aq",
       "ar",
       "as",
       "at",
       "au",
       "aw",
       "ax",
       "az",
       "ba",
       "bb",
       "bd",
       "be",
       "bf",
       "bg",
       "bh",
       "bi",
       "bj",
       "bl",
       "bm",
       "bn",
       "bo",
       "bq",
       "br",
       "bs",
       "bt",
       "bv",
       "bw",
       "by",
       "bz",
       "ca",
       "cc",
       "cd",
       "cf",
       "cg",
       "ch",
       "ci",
       "ck",
       "cl",
       "cm",
       "cn",
       "co",
       "cr",
       "cu",
       "cv",
       "cw",
       "cx",
       "cy",
       "cz",
       "de",
       "dj",
       "dk",
       "dm",
       "do",
       "dz",
       "ec",
       "ee",
       "eg",
       "eh",
       "er",
       "es",
       "et",
       "fi",
       "fj",
       "fk",
       "fm",
       "fo",
       "fr",
       "ga",
       "gb",
       "gd",
       "ge",
       "gf",
       "gg",
       "gh",
       "gi",
       "gl",
       "gm",
       "gn",
       "gp",
       "gq",
       "gr",
       "gs",
       "gt",
       "gu",
       "gw",
       "gy",
       "hk",
       "hm",
       "hn",
       "hr",
       "ht",
       "hu",
       "id",
       "ie",
       "il",
       "im",
       "in",
       "io",
       "iq",
       "ir",
       "is",
       "it",
       "je",
       "jm",
       "jo",
       "jp",
       "ke",
       "kg",
       "kh",
       "ki",
       "km",
       "kn",
       "kp",
       "kr",
       "kw",
       "ky",
       "kz",
       "la",
       "lb",
       "lc",
       "li",
       "lk",
       "lr",
       "ls",
       "lt",
       "lu",
       "lv",
       "ly",
       "ma",
       "mc",
       "md",
       "me",
       "mf",
       "mg",
       "mh",
       "mk",
       "ml",
       "mm",
       "mn",
       "mo",
       "mp",
       "mq",
       "mr",
       "ms",
       "mt",
       "mu",
       "mv",
       "mw",
       "mx",
       "my",
       "mz",
       "na",
       "nc",
       "ne",
       "nf",
       "ng",
       "ni",
       "nl",
       "no",
       "np",
       "nr",
       "nu",
       "nz",
       "om",
       "pa",
       "pe",
       "pf",
       "pg",
       "ph",
       "pk",
       "pl",
       "pm",
       "pn",
       "pr",
       "ps",
       "pt",
       "pw",
       "py",
       "qa",
       "re",
       "ro",
       "rs",
       "ru",
       "rw",
       "sa",
       "sb",
       "sc",
       "sd",
       "se",
       "sg",
       "sh",
       "si",
       "sj",
       "sk",
       "sl",
       "sm",
       "sn",
       "so",
       "sr",
       "ss",
       "st",
       "sv",
       "sx",
       "sy",
       "sz",
       "tc",
       "td",
       "tf",
       "tg",
       "th",
       "tj",
       "tk",
       "tl",
       "tm",
       "tn",
       "to",
       "tr",
       "tt",
       "tv",
       "tw",
       "tz",
       "ua",
       "ug",
       "uk",
       "um",
       "us",
       "uy",
       "uz",
       "va",
       "vc",
       "ve",
       "vg",
       "vi",
       "vn",
       "vu",
       "wf",
       "ws",
       "xk",
       "ye",
       "yt",
       "za",
       "zm",
       "zw"
      ],
      "title": "Gl",
      "description": "Two-letter Google country (market). Sets the market; the currency is requested separately.",
      "default": "us",
      "examples": [
       "ca"
      ]
     },
     "hl": {
      "type": "string",
      "pattern": "^[a-z]{2,3}(-[A-Za-z]{2,4})?$",
      "title": "Hl",
      "description": "Interface language. Display strings follow it; hotel amenity names are always English.",
      "default": "en",
      "examples": [
       "en"
      ]
     },
     "sort_by": {
      "type": "string",
      "enum": [
       "highest_rating",
       "lowest_price",
       "most_reviewed",
       "relevance"
      ],
      "title": "Sort By",
      "description": "Result order, as Google's Sort by control.",
      "default": "relevance"
     },
     "price_min": {
      "anyOf": [
       {
        "type": "integer",
        "minimum": 0.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Price Min",
      "description": "Minimum nightly price in `currency`.",
      "examples": [
       50
      ]
     },
     "price_max": {
      "anyOf": [
       {
        "type": "integer",
        "minimum": 0.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Price Max",
      "description": "Maximum nightly price in `currency`.",
      "examples": [
       300
      ]
     },
     "free_cancellation": {
      "type": "boolean",
      "title": "Free Cancellation",
      "description": "Only properties Google lists with free cancellation.",
      "default": false
     },
     "special_offers": {
      "type": "boolean",
      "title": "Special Offers",
      "description": "Only properties with a special offer.",
      "default": false
     },
     "eco_certified": {
      "type": "boolean",
      "title": "Eco Certified",
      "description": "Only eco-certified properties.",
      "default": false
     },
     "engine": {
      "type": "string",
      "enum": [
       "google_hotels"
      ],
      "const": "google_hotels",
      "title": "Engine",
      "description": "Accepted for SearchAPI compatibility; must be `google_hotels`.",
      "default": "google_hotels"
     },
     "property_type": {
      "type": "string",
      "enum": [
       "hotel",
       "vacation_rental"
      ],
      "title": "Property Type",
      "description": "`hotel` (default) is Google's own list, which Google may blend with vacation rentals; each result states its `type`. `vacation_rental` is refused with 422: Google does not honour the rentals-only category for this search, so it is refused rather than silently ignored.",
      "default": "hotel"
     },
     "check_in_date": {
      "type": "string",
      "format": "date",
      "title": "Check In Date",
      "description": "First night of the stay, `YYYY-MM-DD`.",
      "examples": [
       "2029-03-21"
      ]
     },
     "check_out_date": {
      "type": "string",
      "format": "date",
      "title": "Check Out Date",
      "description": "Departure date, after `check_in_date`; at most 30 nights.",
      "examples": [
       "2029-03-23"
      ]
     },
     "children_ages": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "items": {
         "type": "integer"
        },
        "type": "array"
       },
       {
        "type": "null"
       }
      ],
      "title": "Children Ages",
      "description": "Comma-separated child ages, 0-17 (SearchAPI: `2,5`).",
      "examples": [
       "8"
      ]
     },
     "rating": {
      "anyOf": [
       {
        "type": "integer"
       },
       {
        "type": "null"
       }
      ],
      "enum": [
       7,
       8,
       9
      ],
      "title": "Rating",
      "description": "SearchAPI rating code: 7 (3.5+), 8 (4.0+), 9 (4.5+).",
      "examples": [
       8
      ]
     },
     "hotel_class": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "items": {
         "type": "integer"
        },
        "type": "array"
       },
       {
        "type": "null"
       }
      ],
      "title": "Hotel Class",
      "description": "Comma-separated star classes, 2-5.",
      "examples": [
       "4,5"
      ]
     },
     "amenities": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "items": {
         "type": "integer"
        },
        "type": "array"
       },
       {
        "type": "null"
       }
      ],
      "title": "Amenities",
      "description": "Comma-separated amenity ids (same ids as SearchAPI/SerpApi, e.g. 6 Pool, 35 Free Wi-Fi).",
      "examples": [
       "6,35"
      ]
     },
     "property_types": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "items": {
         "type": "integer"
        },
        "type": "array"
       },
       {
        "type": "null"
       }
      ],
      "title": "Property Types",
      "description": "Comma-separated property-type ids, e.g. 19 Bed and breakfasts, 14 Hostels.",
      "examples": [
       "19"
      ]
     },
     "brands": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "items": {
         "type": "integer"
        },
        "type": "array"
       },
       {
        "type": "null"
       }
      ],
      "title": "Brands",
      "description": "Not supported: Google ignores brand filters on this search, so a non-empty value is refused with 422."
     },
     "for_displaced_individuals": {
      "type": "boolean",
      "title": "For Displaced Individuals",
      "description": "Not supported; `true` is refused with 422.",
      "default": false
     },
     "bedrooms": {
      "anyOf": [
       {
        "type": "integer",
        "minimum": 0.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Bedrooms",
      "description": "Vacation-rental filter. Not supported; a value above 0 is refused with 422."
     },
     "bathrooms": {
      "anyOf": [
       {
        "type": "integer",
        "minimum": 0.0
       },
       {
        "type": "null"
       }
      ],
      "title": "Bathrooms",
      "description": "Vacation-rental filter. Not supported; a value above 0 is refused with 422."
     },
     "bounding_box": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "title": "Bounding Box",
      "description": "Not supported; search by `q`."
     },
     "next_page_token": {
      "anyOf": [
       {
        "type": "string",
        "pattern": "^[A-Za-z0-9_\\-+/=]{1,200}$"
       },
       {
        "type": "null"
       }
      ],
      "title": "Next Page Token",
      "description": "Opaque cursor from `pagination.next_page_token` of the previous page. Resend the same query, stay, occupancy and filters with it, exactly as with SearchAPI.",
      "examples": [
       "CBI="
      ]
     },
     "zero_retention": {
      "type": "boolean",
      "title": "Zero Retention",
      "description": "Accepted for SearchAPI compatibility; search results are never persisted.",
      "default": false
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "q",
     "check_in_date",
     "check_out_date"
    ],
    "title": "SerpGoogleHotelsRequest",
    "description": "SearchAPI's `engine=google_hotels` request, field for field.\n\nComma-separated id lists (`hotel_class`, `amenities`, `property_types`,\n`children_ages`) are accepted as SearchAPI sends them, or as JSON arrays.\nParameters this source cannot honour are refused with a 422 rather than\nignored, because an ignored filter returns a plausible unfiltered list.",
    "examples": [
     {
      "adults": 2,
      "amenities": "6",
      "check_in_date": "2029-03-21",
      "check_out_date": "2029-03-23",
      "currency": "USD",
      "engine": "google_hotels",
      "gl": "us",
      "hl": "en",
      "hotel_class": "4,5",
      "q": "Hotels in Chicago",
      "rating": 8,
      "sort_by": "lowest_price"
     }
    ]
   },
   "SerpPropertyRequest": {
    "properties": {
     "property_token": {
      "type": "string",
      "minLength": 8,
      "title": "Property Token",
      "description": "Google property token — SearchAPI's name for the same value `/v1/search` returns as `token`.",
      "examples": [
       "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ"
      ]
     },
     "check_in_date": {
      "type": "string",
      "format": "date",
      "title": "Check In Date",
      "description": "First night of the stay, `YYYY-MM-DD`.",
      "examples": [
       "2029-02-05"
      ]
     },
     "check_out_date": {
      "type": "string",
      "format": "date",
      "title": "Check Out Date",
      "description": "Departure date. Must be after `check_in_date`.",
      "examples": [
       "2029-02-06"
      ]
     },
     "adults": {
      "type": "integer",
      "maximum": 8.0,
      "minimum": 1.0,
      "title": "Adults",
      "description": "Adults in the room. Two is the hotel default; pass one for a hostel, which is priced per bed. Any value from 1 to 8 is accepted.",
      "default": 2,
      "examples": [
       2
      ]
     },
     "currency": {
      "type": "string",
      "enum": [
       "AED",
       "ARS",
       "AUD",
       "BRL",
       "CAD",
       "CHF",
       "CLP",
       "CNY",
       "COP",
       "CZK",
       "DKK",
       "EGP",
       "EUR",
       "GBP",
       "HKD",
       "HUF",
       "IDR",
       "ILS",
       "INR",
       "JPY",
       "KRW",
       "MXN",
       "MYR",
       "NOK",
       "NZD",
       "PEN",
       "PHP",
       "PLN",
       "QAR",
       "RON",
       "SAR",
       "SEK",
       "SGD",
       "THB",
       "TRY",
       "TWD",
       "USD",
       "VND",
       "ZAR"
      ],
      "title": "Currency",
      "description": "ISO 4217 code for the returned prices. Major currencies include AED, AUD, BRL, CAD, CHF, CNY, EUR, GBP, HKD, INR, JPY, KRW, MXN, NZD, SGD, USD; all 39 supported codes are listed in the enum.",
      "default": "USD",
      "examples": [
       "USD"
      ]
     },
     "gl": {
      "type": "string",
      "enum": [
       "ad",
       "ae",
       "af",
       "ag",
       "ai",
       "al",
       "am",
       "ao",
       "aq",
       "ar",
       "as",
       "at",
       "au",
       "aw",
       "ax",
       "az",
       "ba",
       "bb",
       "bd",
       "be",
       "bf",
       "bg",
       "bh",
       "bi",
       "bj",
       "bl",
       "bm",
       "bn",
       "bo",
       "bq",
       "br",
       "bs",
       "bt",
       "bv",
       "bw",
       "by",
       "bz",
       "ca",
       "cc",
       "cd",
       "cf",
       "cg",
       "ch",
       "ci",
       "ck",
       "cl",
       "cm",
       "cn",
       "co",
       "cr",
       "cu",
       "cv",
       "cw",
       "cx",
       "cy",
       "cz",
       "de",
       "dj",
       "dk",
       "dm",
       "do",
       "dz",
       "ec",
       "ee",
       "eg",
       "eh",
       "er",
       "es",
       "et",
       "fi",
       "fj",
       "fk",
       "fm",
       "fo",
       "fr",
       "ga",
       "gb",
       "gd",
       "ge",
       "gf",
       "gg",
       "gh",
       "gi",
       "gl",
       "gm",
       "gn",
       "gp",
       "gq",
       "gr",
       "gs",
       "gt",
       "gu",
       "gw",
       "gy",
       "hk",
       "hm",
       "hn",
       "hr",
       "ht",
       "hu",
       "id",
       "ie",
       "il",
       "im",
       "in",
       "io",
       "iq",
       "ir",
       "is",
       "it",
       "je",
       "jm",
       "jo",
       "jp",
       "ke",
       "kg",
       "kh",
       "ki",
       "km",
       "kn",
       "kp",
       "kr",
       "kw",
       "ky",
       "kz",
       "la",
       "lb",
       "lc",
       "li",
       "lk",
       "lr",
       "ls",
       "lt",
       "lu",
       "lv",
       "ly",
       "ma",
       "mc",
       "md",
       "me",
       "mf",
       "mg",
       "mh",
       "mk",
       "ml",
       "mm",
       "mn",
       "mo",
       "mp",
       "mq",
       "mr",
       "ms",
       "mt",
       "mu",
       "mv",
       "mw",
       "mx",
       "my",
       "mz",
       "na",
       "nc",
       "ne",
       "nf",
       "ng",
       "ni",
       "nl",
       "no",
       "np",
       "nr",
       "nu",
       "nz",
       "om",
       "pa",
       "pe",
       "pf",
       "pg",
       "ph",
       "pk",
       "pl",
       "pm",
       "pn",
       "pr",
       "ps",
       "pt",
       "pw",
       "py",
       "qa",
       "re",
       "ro",
       "rs",
       "ru",
       "rw",
       "sa",
       "sb",
       "sc",
       "sd",
       "se",
       "sg",
       "sh",
       "si",
       "sj",
       "sk",
       "sl",
       "sm",
       "sn",
       "so",
       "sr",
       "ss",
       "st",
       "sv",
       "sx",
       "sy",
       "sz",
       "tc",
       "td",
       "tf",
       "tg",
       "th",
       "tj",
       "tk",
       "tl",
       "tm",
       "tn",
       "to",
       "tr",
       "tt",
       "tv",
       "tw",
       "tz",
       "ua",
       "ug",
       "uk",
       "um",
       "us",
       "uy",
       "uz",
       "va",
       "vc",
       "ve",
       "vg",
       "vi",
       "vn",
       "vu",
       "wf",
       "ws",
       "xk",
       "ye",
       "yt",
       "za",
       "zm",
       "zw"
      ],
      "title": "Gl",
      "description": "Two-letter country for the Google request, SearchAPI's spelling of `market`.",
      "default": "us",
      "examples": [
       "us"
      ]
     },
     "property_name": {
      "type": "string",
      "title": "Property Name",
      "description": "Optional. Improves official-site detection when the hotel's own row is labelled with its brand name.",
      "default": "",
      "examples": [
       "Hilton Chicago"
      ]
     },
     "sources": {
      "anyOf": [
       {
        "items": {
         "type": "string"
        },
        "type": "array",
        "maxItems": 20,
        "minItems": 1
       },
       {
        "type": "null"
       }
      ],
      "title": "Sources",
      "description": "Optional seller allowlist. Names are canonicalized, so `Expedia.com` and `Expedia` are equivalent. Omit for all Google sellers.",
      "examples": [
       [
        "Booking.com",
        "Hotels.com",
        "Agoda",
        "Official site"
       ]
      ],
      "x-multiple": true,
      "x-options": [
       "Agoda",
       "Booking.com",
       "Expedia",
       "Hotels.com",
       "Official site"
      ]
     },
     "source_coverage": {
      "type": "string",
      "enum": [
       "adaptive",
       "full"
      ],
      "title": "Source Coverage",
      "description": "`full` starts iPhone and desktop renders in parallel for maximum breadth. `adaptive` starts with iPhone and fetches desktop only when a requested seller is absent.",
      "default": "full"
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "property_token",
     "check_in_date",
     "check_out_date"
    ],
    "title": "SerpPropertyRequest",
    "description": "Mirrors SearchAPI's `google_hotels_property` parameters.\n\nField names are theirs, not ours, so an existing integration only needs its\nbase URL repointed. The optional `sources` and `source_coverage` fields are\nScraperCompany additions; omitting them preserves the full SearchAPI-shaped\noffer list.",
    "examples": [
     {
      "adults": 2,
      "check_in_date": "2029-02-05",
      "check_out_date": "2029-02-06",
      "currency": "USD",
      "gl": "us",
      "property_token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ"
     }
    ]
   },
   "StayRequest": {
    "properties": {
     "token": {
      "type": "string",
      "minLength": 8,
      "title": "Token",
      "description": "Google property token. Get one from `POST /v1/search` — it is the `token` on each match. Looks like `ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ`.",
      "examples": [
       "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ"
      ]
     },
     "check_in": {
      "type": "string",
      "format": "date",
      "title": "Check In",
      "description": "First night of the stay, `YYYY-MM-DD`.",
      "examples": [
       "2029-02-05"
      ]
     },
     "check_out": {
      "type": "string",
      "format": "date",
      "title": "Check Out",
      "description": "Must be after `check_in`. The gap is the LOS, and the per-night price does change with it.",
      "examples": [
       "2029-02-08"
      ]
     },
     "market": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "enum": [
       "AG",
       "AT",
       "AU",
       "BE",
       "BZ",
       "CA",
       "CH",
       "DE",
       "ES",
       "FR",
       "GB",
       "IE",
       "IT",
       "MX",
       "NL",
       "NZ",
       "PT",
       "US"
      ],
      "title": "Market",
      "description": "Market/country, e.g. `US`, `MX`, `AU`, `GB`. Sets `gl` and the default tax basis. Omit to derive it from `currency`.",
      "examples": [
       "US"
      ]
     },
     "country": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "enum": [
       "ad",
       "ae",
       "af",
       "ag",
       "ai",
       "al",
       "am",
       "ao",
       "aq",
       "ar",
       "as",
       "at",
       "au",
       "aw",
       "ax",
       "az",
       "ba",
       "bb",
       "bd",
       "be",
       "bf",
       "bg",
       "bh",
       "bi",
       "bj",
       "bl",
       "bm",
       "bn",
       "bo",
       "bq",
       "br",
       "bs",
       "bt",
       "bv",
       "bw",
       "by",
       "bz",
       "ca",
       "cc",
       "cd",
       "cf",
       "cg",
       "ch",
       "ci",
       "ck",
       "cl",
       "cm",
       "cn",
       "co",
       "cr",
       "cu",
       "cv",
       "cw",
       "cx",
       "cy",
       "cz",
       "de",
       "dj",
       "dk",
       "dm",
       "do",
       "dz",
       "ec",
       "ee",
       "eg",
       "eh",
       "er",
       "es",
       "et",
       "fi",
       "fj",
       "fk",
       "fm",
       "fo",
       "fr",
       "ga",
       "gb",
       "gd",
       "ge",
       "gf",
       "gg",
       "gh",
       "gi",
       "gl",
       "gm",
       "gn",
       "gp",
       "gq",
       "gr",
       "gs",
       "gt",
       "gu",
       "gw",
       "gy",
       "hk",
       "hm",
       "hn",
       "hr",
       "ht",
       "hu",
       "id",
       "ie",
       "il",
       "im",
       "in",
       "io",
       "iq",
       "ir",
       "is",
       "it",
       "je",
       "jm",
       "jo",
       "jp",
       "ke",
       "kg",
       "kh",
       "ki",
       "km",
       "kn",
       "kp",
       "kr",
       "kw",
       "ky",
       "kz",
       "la",
       "lb",
       "lc",
       "li",
       "lk",
       "lr",
       "ls",
       "lt",
       "lu",
       "lv",
       "ly",
       "ma",
       "mc",
       "md",
       "me",
       "mf",
       "mg",
       "mh",
       "mk",
       "ml",
       "mm",
       "mn",
       "mo",
       "mp",
       "mq",
       "mr",
       "ms",
       "mt",
       "mu",
       "mv",
       "mw",
       "mx",
       "my",
       "mz",
       "na",
       "nc",
       "ne",
       "nf",
       "ng",
       "ni",
       "nl",
       "no",
       "np",
       "nr",
       "nu",
       "nz",
       "om",
       "pa",
       "pe",
       "pf",
       "pg",
       "ph",
       "pk",
       "pl",
       "pm",
       "pn",
       "pr",
       "ps",
       "pt",
       "pw",
       "py",
       "qa",
       "re",
       "ro",
       "rs",
       "ru",
       "rw",
       "sa",
       "sb",
       "sc",
       "sd",
       "se",
       "sg",
       "sh",
       "si",
       "sj",
       "sk",
       "sl",
       "sm",
       "sn",
       "so",
       "sr",
       "ss",
       "st",
       "sv",
       "sx",
       "sy",
       "sz",
       "tc",
       "td",
       "tf",
       "tg",
       "th",
       "tj",
       "tk",
       "tl",
       "tm",
       "tn",
       "to",
       "tr",
       "tt",
       "tv",
       "tw",
       "tz",
       "ua",
       "ug",
       "uk",
       "um",
       "us",
       "uy",
       "uz",
       "va",
       "vc",
       "ve",
       "vg",
       "vi",
       "vn",
       "vu",
       "wf",
       "ws",
       "xk",
       "ye",
       "yt",
       "za",
       "zm",
       "zw"
      ],
      "title": "Country",
      "description": "`gl` override.",
      "examples": [
       "us"
      ]
     },
     "currency": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "enum": [
       "AED",
       "ARS",
       "AUD",
       "BRL",
       "CAD",
       "CHF",
       "CLP",
       "CNY",
       "COP",
       "CZK",
       "DKK",
       "EGP",
       "EUR",
       "GBP",
       "HKD",
       "HUF",
       "IDR",
       "ILS",
       "INR",
       "JPY",
       "KRW",
       "MXN",
       "MYR",
       "NOK",
       "NZD",
       "PEN",
       "PHP",
       "PLN",
       "QAR",
       "RON",
       "SAR",
       "SEK",
       "SGD",
       "THB",
       "TRY",
       "TWD",
       "USD",
       "VND",
       "ZAR"
      ],
      "title": "Currency",
      "description": "ISO currency for the returned prices.",
      "examples": [
       "USD"
      ]
     },
     "adults": {
      "type": "integer",
      "maximum": 8.0,
      "minimum": 1.0,
      "title": "Adults",
      "description": "Occupancy: number of adults, 1-8. Children are not supported by the Google calendar.",
      "default": 2,
      "examples": [
       2
      ]
     },
     "rates_include_tax": {
      "anyOf": [
       {
        "type": "boolean"
       },
       {
        "type": "null"
       }
      ],
      "title": "Rates Include Tax",
      "description": "Which basis the summary price uses. Omit to take the market convention; pass the property's own setting to override."
     },
     "is_hostel": {
      "type": "boolean",
      "title": "Is Hostel",
      "description": "Hostels are priced per bed rather than per room, so occupancy changes the rate differently. Set this and the per-person maths is applied.",
      "default": false
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "token",
     "check_in",
     "check_out"
    ],
    "title": "StayRequest",
    "description": "One explicit check-in/check-out window.",
    "examples": [
     {
      "adults": 2,
      "check_in": "2029-02-05",
      "check_out": "2029-02-08",
      "currency": "USD",
      "token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ"
     }
    ]
   },
   "TrendsInterestRequest": {
    "properties": {
     "keyword": {
      "type": "string",
      "maxLength": 200,
      "minLength": 1,
      "title": "Keyword",
      "description": "Search term to chart.",
      "examples": [
       "Hilton"
      ]
     },
     "geo": {
      "type": "string",
      "enum": [
       "AD",
       "AE",
       "AF",
       "AG",
       "AI",
       "AL",
       "AM",
       "AO",
       "AQ",
       "AR",
       "AS",
       "AT",
       "AU",
       "AW",
       "AX",
       "AZ",
       "BA",
       "BB",
       "BD",
       "BE",
       "BF",
       "BG",
       "BH",
       "BI",
       "BJ",
       "BL",
       "BM",
       "BN",
       "BO",
       "BQ",
       "BR",
       "BS",
       "BT",
       "BV",
       "BW",
       "BY",
       "BZ",
       "CA",
       "CC",
       "CD",
       "CF",
       "CG",
       "CH",
       "CI",
       "CK",
       "CL",
       "CM",
       "CN",
       "CO",
       "CR",
       "CU",
       "CV",
       "CW",
       "CX",
       "CY",
       "CZ",
       "DE",
       "DJ",
       "DK",
       "DM",
       "DO",
       "DZ",
       "EC",
       "EE",
       "EG",
       "EH",
       "ER",
       "ES",
       "ET",
       "FI",
       "FJ",
       "FK",
       "FM",
       "FO",
       "FR",
       "GA",
       "GB",
       "GD",
       "GE",
       "GF",
       "GG",
       "GH",
       "GI",
       "GL",
       "GM",
       "GN",
       "GP",
       "GQ",
       "GR",
       "GS",
       "GT",
       "GU",
       "GW",
       "GY",
       "HK",
       "HM",
       "HN",
       "HR",
       "HT",
       "HU",
       "ID",
       "IE",
       "IL",
       "IM",
       "IN",
       "IO",
       "IQ",
       "IR",
       "IS",
       "IT",
       "JE",
       "JM",
       "JO",
       "JP",
       "KE",
       "KG",
       "KH",
       "KI",
       "KM",
       "KN",
       "KP",
       "KR",
       "KW",
       "KY",
       "KZ",
       "LA",
       "LB",
       "LC",
       "LI",
       "LK",
       "LR",
       "LS",
       "LT",
       "LU",
       "LV",
       "LY",
       "MA",
       "MC",
       "MD",
       "ME",
       "MF",
       "MG",
       "MH",
       "MK",
       "ML",
       "MM",
       "MN",
       "MO",
       "MP",
       "MQ",
       "MR",
       "MS",
       "MT",
       "MU",
       "MV",
       "MW",
       "MX",
       "MY",
       "MZ",
       "NA",
       "NC",
       "NE",
       "NF",
       "NG",
       "NI",
       "NL",
       "NO",
       "NP",
       "NR",
       "NU",
       "NZ",
       "OM",
       "PA",
       "PE",
       "PF",
       "PG",
       "PH",
       "PK",
       "PL",
       "PM",
       "PN",
       "PR",
       "PS",
       "PT",
       "PW",
       "PY",
       "QA",
       "RE",
       "RO",
       "RS",
       "RU",
       "RW",
       "SA",
       "SB",
       "SC",
       "SD",
       "SE",
       "SG",
       "SH",
       "SI",
       "SJ",
       "SK",
       "SL",
       "SM",
       "SN",
       "SO",
       "SR",
       "SS",
       "ST",
       "SV",
       "SX",
       "SY",
       "SZ",
       "TC",
       "TD",
       "TF",
       "TG",
       "TH",
       "TJ",
       "TK",
       "TL",
       "TM",
       "TN",
       "TO",
       "TR",
       "TT",
       "TV",
       "TW",
       "TZ",
       "UA",
       "UG",
       "UK",
       "UM",
       "US",
       "UY",
       "UZ",
       "VA",
       "VC",
       "VE",
       "VG",
       "VI",
       "VN",
       "VU",
       "WF",
       "WS",
       "XK",
       "YE",
       "YT",
       "ZA",
       "ZM",
       "ZW"
      ],
      "title": "Geo",
      "description": "Two-letter country.",
      "default": "US",
      "examples": [
       "US"
      ]
     },
     "time_range": {
      "type": "string",
      "title": "Time Range",
      "description": "Google's window grammar: `today 1-m` (default), `now 7-d`, `today 12-m`, `all`, or `2026-01-01 2026-06-30`.",
      "default": "today 1-m",
      "examples": [
       "today 1-m"
      ]
     },
     "hl": {
      "type": "string",
      "title": "Hl",
      "description": "Language.",
      "default": "en-US",
      "examples": [
       "en-US"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "keyword"
    ],
    "title": "TrendsInterestRequest",
    "description": "Google Trends interest over time for one keyword.\n\nValues are 0-100 relative to the keyword's own peak in the window,\nexactly as Google's charts state. `time_range` uses Google's grammar.",
    "examples": [
     {
      "geo": "US",
      "keyword": "Hilton",
      "time_range": "today 1-m"
     }
    ]
   },
   "TrendsRelatedRequest": {
    "properties": {
     "keyword": {
      "type": "string",
      "maxLength": 200,
      "minLength": 1,
      "title": "Keyword",
      "description": "Search term.",
      "examples": [
       "Hilton"
      ]
     },
     "geo": {
      "type": "string",
      "enum": [
       "AD",
       "AE",
       "AF",
       "AG",
       "AI",
       "AL",
       "AM",
       "AO",
       "AQ",
       "AR",
       "AS",
       "AT",
       "AU",
       "AW",
       "AX",
       "AZ",
       "BA",
       "BB",
       "BD",
       "BE",
       "BF",
       "BG",
       "BH",
       "BI",
       "BJ",
       "BL",
       "BM",
       "BN",
       "BO",
       "BQ",
       "BR",
       "BS",
       "BT",
       "BV",
       "BW",
       "BY",
       "BZ",
       "CA",
       "CC",
       "CD",
       "CF",
       "CG",
       "CH",
       "CI",
       "CK",
       "CL",
       "CM",
       "CN",
       "CO",
       "CR",
       "CU",
       "CV",
       "CW",
       "CX",
       "CY",
       "CZ",
       "DE",
       "DJ",
       "DK",
       "DM",
       "DO",
       "DZ",
       "EC",
       "EE",
       "EG",
       "EH",
       "ER",
       "ES",
       "ET",
       "FI",
       "FJ",
       "FK",
       "FM",
       "FO",
       "FR",
       "GA",
       "GB",
       "GD",
       "GE",
       "GF",
       "GG",
       "GH",
       "GI",
       "GL",
       "GM",
       "GN",
       "GP",
       "GQ",
       "GR",
       "GS",
       "GT",
       "GU",
       "GW",
       "GY",
       "HK",
       "HM",
       "HN",
       "HR",
       "HT",
       "HU",
       "ID",
       "IE",
       "IL",
       "IM",
       "IN",
       "IO",
       "IQ",
       "IR",
       "IS",
       "IT",
       "JE",
       "JM",
       "JO",
       "JP",
       "KE",
       "KG",
       "KH",
       "KI",
       "KM",
       "KN",
       "KP",
       "KR",
       "KW",
       "KY",
       "KZ",
       "LA",
       "LB",
       "LC",
       "LI",
       "LK",
       "LR",
       "LS",
       "LT",
       "LU",
       "LV",
       "LY",
       "MA",
       "MC",
       "MD",
       "ME",
       "MF",
       "MG",
       "MH",
       "MK",
       "ML",
       "MM",
       "MN",
       "MO",
       "MP",
       "MQ",
       "MR",
       "MS",
       "MT",
       "MU",
       "MV",
       "MW",
       "MX",
       "MY",
       "MZ",
       "NA",
       "NC",
       "NE",
       "NF",
       "NG",
       "NI",
       "NL",
       "NO",
       "NP",
       "NR",
       "NU",
       "NZ",
       "OM",
       "PA",
       "PE",
       "PF",
       "PG",
       "PH",
       "PK",
       "PL",
       "PM",
       "PN",
       "PR",
       "PS",
       "PT",
       "PW",
       "PY",
       "QA",
       "RE",
       "RO",
       "RS",
       "RU",
       "RW",
       "SA",
       "SB",
       "SC",
       "SD",
       "SE",
       "SG",
       "SH",
       "SI",
       "SJ",
       "SK",
       "SL",
       "SM",
       "SN",
       "SO",
       "SR",
       "SS",
       "ST",
       "SV",
       "SX",
       "SY",
       "SZ",
       "TC",
       "TD",
       "TF",
       "TG",
       "TH",
       "TJ",
       "TK",
       "TL",
       "TM",
       "TN",
       "TO",
       "TR",
       "TT",
       "TV",
       "TW",
       "TZ",
       "UA",
       "UG",
       "UK",
       "UM",
       "US",
       "UY",
       "UZ",
       "VA",
       "VC",
       "VE",
       "VG",
       "VI",
       "VN",
       "VU",
       "WF",
       "WS",
       "XK",
       "YE",
       "YT",
       "ZA",
       "ZM",
       "ZW"
      ],
      "title": "Geo",
      "description": "Two-letter country.",
      "default": "US",
      "examples": [
       "US"
      ]
     },
     "time_range": {
      "type": "string",
      "title": "Time Range",
      "description": "Google's window grammar (see interest over time).",
      "default": "today 1-m",
      "examples": [
       "today 1-m"
      ]
     },
     "hl": {
      "type": "string",
      "title": "Hl",
      "description": "Language.",
      "default": "en-US",
      "examples": [
       "en-US"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "keyword"
    ],
    "title": "TrendsRelatedRequest",
    "description": "Google Trends related queries: top and rising.",
    "examples": [
     {
      "geo": "US",
      "keyword": "Hilton"
     }
    ]
   },
   "TripadvisorRequest": {
    "properties": {
     "location_id": {
      "type": "string",
      "minLength": 1,
      "title": "Location Id",
      "description": "Numeric Tripadvisor locationId: the digits after `-d` in the hotel's Tripadvisor URL (`/Hotel_Review-g{geoId}-d{locationId}-...`).",
      "examples": [
       "97679"
      ]
     },
     "check_in": {
      "type": "string",
      "format": "date",
      "title": "Check In",
      "description": "First night of the stay, `YYYY-MM-DD`.",
      "examples": [
       "2029-02-22"
      ]
     },
     "check_out": {
      "anyOf": [
       {
        "type": "string",
        "format": "date"
       },
       {
        "type": "null"
       }
      ],
      "title": "Check Out",
      "description": "Departure date. An alternative to `nights` — if both are given, this wins.",
      "examples": [
       "2029-02-23"
      ]
     },
     "nights": {
      "type": "integer",
      "maximum": 30.0,
      "minimum": 1.0,
      "title": "Nights",
      "description": "Length of stay. Ignored when `check_out` is supplied.",
      "default": 1,
      "examples": [
       1
      ]
     },
     "adults": {
      "type": "integer",
      "maximum": 8.0,
      "minimum": 1.0,
      "title": "Adults",
      "description": "Adults in the room. Two is the hotel default; pass one for a hostel, which is priced per bed. Any value from 1 to 8 is accepted.",
      "default": 2,
      "examples": [
       2
      ]
     },
     "rooms": {
      "type": "integer",
      "maximum": 8.0,
      "minimum": 1.0,
      "title": "Rooms",
      "description": "Rooms requested.",
      "default": 1,
      "examples": [
       1
      ]
     },
     "currency": {
      "type": "string",
      "enum": [
       "AED",
       "ARS",
       "AUD",
       "BRL",
       "CAD",
       "CHF",
       "CLP",
       "CNY",
       "CZK",
       "DKK",
       "EUR",
       "GBP",
       "HKD",
       "HUF",
       "IDR",
       "INR",
       "JPY",
       "KRW",
       "MXN",
       "MYR",
       "NOK",
       "NZD",
       "PHP",
       "PLN",
       "SAR",
       "SEK",
       "SGD",
       "THB",
       "TWD",
       "USD"
      ],
      "title": "Currency",
      "description": "One of 30 supported currencies.",
      "default": "USD",
      "examples": [
       "USD"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "location_id",
     "check_in"
    ],
    "title": "TripadvisorRequest",
    "description": "Tripadvisor hotel availability and pricing from multiple providers.\n\nTripadvisor aggregates prices from Booking, Hotels.com, Expedia, and others\nas a metasearch. Returns offers from all available providers for the given\ndates.",
    "examples": [
     {
      "adults": 2,
      "check_in": "2029-02-22",
      "currency": "USD",
      "location_id": "97679",
      "nights": 1
     }
    ]
   },
   "TripadvisorReviewsRequest": {
    "properties": {
     "location_id": {
      "type": "string",
      "minLength": 1,
      "pattern": "^\\d+$",
      "title": "Location Id",
      "description": "Numeric id in the property URL, e.g. `208453` from `/Hotel_Review-g60763-d208453-...`.",
      "examples": [
       "208453"
      ]
     },
     "limit": {
      "type": "integer",
      "maximum": 30.0,
      "minimum": 1.0,
      "title": "Limit",
      "description": "Reviews per page (the backend accepts up to 30).",
      "default": 10,
      "examples": [
       10
      ]
     },
     "offset": {
      "type": "integer",
      "minimum": 0.0,
      "title": "Offset",
      "description": "Row to start from; page by `offset += limit`.",
      "default": 0,
      "examples": [
       0
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "location_id"
    ],
    "title": "TripadvisorReviewsRequest",
    "description": "Tripadvisor guest reviews, newest first as the site orders them.\n\n`location_id` is the numeric id in the property URL\n(`/Hotel_Review-g{geoId}-d{locationId}-...`). Ratings are 0-5.",
    "examples": [
     {
      "limit": 10,
      "location_id": "208453",
      "offset": 0
     }
    ]
   },
   "TripadvisorSearchRequest": {
    "properties": {
     "query": {
      "type": "string",
      "minLength": 1,
      "title": "Query",
      "description": "Hotel name or location to search for.",
      "examples": [
       "Moxy Boston Downtown"
      ]
     },
     "limit": {
      "type": "integer",
      "maximum": 50.0,
      "minimum": 1.0,
      "title": "Limit",
      "description": "Maximum results to return.",
      "default": 10,
      "examples": [
       10
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "query"
    ],
    "title": "TripadvisorSearchRequest",
    "description": "Find Tripadvisor's locationId from a hotel name.\n\nRead `recommended_match`, not `matches[0]`. It is null when the provider\nreturned only weak or ambiguous candidates.",
    "examples": [
     {
      "limit": 10,
      "query": "Moxy Boston Downtown"
     }
    ]
   },
   "ValidationError": {
    "properties": {
     "loc": {
      "items": {
       "anyOf": [
        {
         "type": "string"
        },
        {
         "type": "integer"
        }
       ]
      },
      "type": "array",
      "title": "Location"
     },
     "msg": {
      "type": "string",
      "title": "Message"
     },
     "type": {
      "type": "string",
      "title": "Error Type"
     },
     "input": {
      "title": "Input"
     },
     "ctx": {
      "type": "object",
      "title": "Context"
     }
    },
    "type": "object",
    "required": [
     "loc",
     "msg",
     "type"
    ],
    "title": "ValidationError"
   },
   "VrboRequest": {
    "properties": {
     "property_id": {
      "anyOf": [
       {
        "type": "string",
        "pattern": "^\\d+$"
       },
       {
        "type": "null"
       }
      ],
      "title": "Property Id",
      "description": "Numeric id returned by `POST /v1/ota/vrbo/search` (`property_id` on each listing). Not the id in the Vrbo URL.",
      "examples": [
       "122942416"
      ]
     },
     "listing_id": {
      "anyOf": [
       {
        "type": "string",
        "pattern": "^\\d+(?:ha)?$"
       },
       {
        "type": "null"
       }
      ],
      "title": "Listing Id",
      "description": "The listing id in a Vrbo URL, e.g. `20218736ha` for `vrbo.com/20218736ha`. Resolved to `property_id` with one page load.",
      "examples": [
       "20218736ha"
      ]
     },
     "check_in": {
      "type": "string",
      "format": "date",
      "title": "Check In",
      "description": "First night of the stay, `YYYY-MM-DD`.",
      "examples": [
       "2029-04-10"
      ]
     },
     "check_out": {
      "anyOf": [
       {
        "type": "string",
        "format": "date"
       },
       {
        "type": "null"
       }
      ],
      "title": "Check Out",
      "description": "Departure date. An alternative to `nights` — if both are given, this wins.",
      "examples": [
       "2029-04-13"
      ]
     },
     "nights": {
      "type": "integer",
      "maximum": 28.0,
      "minimum": 1.0,
      "title": "Nights",
      "description": "Length of stay. Ignored when `check_out` is supplied.",
      "default": 1,
      "examples": [
       3
      ]
     },
     "adults": {
      "type": "integer",
      "maximum": 16.0,
      "minimum": 1.0,
      "title": "Adults",
      "description": "Guests (adults).",
      "default": 2,
      "examples": [
       2
      ]
     },
     "market": {
      "type": "string",
      "enum": [
       "US"
      ],
      "title": "Market",
      "description": "Vrbo point-of-sale. Only `US` (www.vrbo.com, USD) is verified.",
      "default": "US",
      "examples": [
       "US"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "check_in"
    ],
    "title": "VrboRequest",
    "description": "A Vrbo stay quote: nightly and total price, fees, payment model.\n\nSupply `property_id` (from `POST /v1/ota/vrbo/search`) or `listing_id`\n(the path segment of a Vrbo URL). A listing id costs one extra page load\nto resolve, so store the `property_id` the answer returns.",
    "examples": [
     {
      "adults": 2,
      "check_in": "2029-04-10",
      "nights": 3,
      "property_id": "122942416"
     }
    ]
   },
   "VrboSearchRequest": {
    "properties": {
     "destination": {
      "type": "string",
      "minLength": 2,
      "title": "Destination",
      "description": "Place as a guest would type it, e.g. `South Lake Tahoe, California`. Vrbo resolves it to a region.",
      "examples": [
       "South Lake Tahoe, California"
      ]
     },
     "check_in": {
      "type": "string",
      "format": "date",
      "title": "Check In",
      "description": "First night of the stay, `YYYY-MM-DD`.",
      "examples": [
       "2029-04-10"
      ]
     },
     "check_out": {
      "anyOf": [
       {
        "type": "string",
        "format": "date"
       },
       {
        "type": "null"
       }
      ],
      "title": "Check Out",
      "description": "Departure date. An alternative to `nights` — if both are given, this wins.",
      "examples": [
       "2029-04-13"
      ]
     },
     "nights": {
      "type": "integer",
      "maximum": 28.0,
      "minimum": 1.0,
      "title": "Nights",
      "description": "Length of stay. Ignored when `check_out` is supplied.",
      "default": 1,
      "examples": [
       3
      ]
     },
     "adults": {
      "type": "integer",
      "maximum": 16.0,
      "minimum": 1.0,
      "title": "Adults",
      "description": "Guests (adults).",
      "default": 2,
      "examples": [
       2
      ]
     },
     "limit": {
      "type": "integer",
      "maximum": 50.0,
      "minimum": 1.0,
      "title": "Limit",
      "description": "Maximum listings to return, in Vrbo's recommended order.",
      "default": 20,
      "examples": [
       10
      ]
     },
     "market": {
      "type": "string",
      "enum": [
       "US"
      ],
      "title": "Market",
      "description": "Vrbo point-of-sale. Only `US` (www.vrbo.com, USD) is verified.",
      "default": "US",
      "examples": [
       "US"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "destination",
     "check_in"
    ],
    "title": "VrboSearchRequest",
    "description": "Vrbo vacation-rental listings for a destination and stay window.\n\nEach listing carries the numeric `property_id` that `POST /v1/ota/vrbo`\nquotes, the listing id from Vrbo's URL, and Vrbo's own nightly and stay\nprices (\"All fees included\" is reported as `fees_included`).",
    "examples": [
     {
      "adults": 2,
      "check_in": "2029-04-10",
      "destination": "South Lake Tahoe, California",
      "limit": 10,
      "nights": 3
     }
    ]
   },
   "WalmartReviewsRequest": {
    "properties": {
     "item_id": {
      "type": "string",
      "minLength": 1,
      "pattern": "^\\d+$",
      "title": "Item Id",
      "description": "Numeric item id returned by `POST /v1/walmart/search`.",
      "examples": [
       "5255687930"
      ]
     },
     "page": {
      "type": "integer",
      "maximum": 100.0,
      "minimum": 1.0,
      "title": "Page",
      "description": "Review page.",
      "default": 1,
      "examples": [
       1
      ]
     },
     "sort": {
      "type": "string",
      "enum": [
       "highest-rating",
       "lowest-rating",
       "most-helpful",
       "most-recent",
       "relevancy"
      ],
      "title": "Sort",
      "description": "Walmart's own review sort.",
      "default": "relevancy",
      "examples": [
       "relevancy"
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "item_id"
    ],
    "title": "WalmartReviewsRequest",
    "description": "One page (10) of Walmart reviews for an item, without a browser.\n\nAnswers the review list plus the summary (average, total, per-star\ncounts and percentages, recommended percentage) and Walmart's own\n`next_page` url.",
    "examples": [
     {
      "item_id": "5255687930"
     }
    ]
   },
   "WalmartSearchRequest": {
    "properties": {
     "q": {
      "type": "string",
      "maxLength": 200,
      "minLength": 1,
      "title": "Q",
      "description": "Search query.",
      "examples": [
       "bathrobe"
      ]
     },
     "page": {
      "type": "integer",
      "maximum": 50.0,
      "minimum": 1.0,
      "title": "Page",
      "description": "Result page.",
      "default": 1,
      "examples": [
       1
      ]
     },
     "sort": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ],
      "enum": [
       "best_match",
       "best_seller",
       "new",
       "price_high",
       "price_low",
       "rating"
      ],
      "title": "Sort",
      "description": "Walmart's own sort values.",
      "examples": [
       null
      ]
     }
    },
    "additionalProperties": false,
    "type": "object",
    "required": [
     "q"
    ],
    "title": "WalmartSearchRequest",
    "description": "Walmart product search over plain HTTP.\n\nOne page (~40) of items from Walmart's own store JSON. Sponsored items\ncome labelled in `sponsored` rather than dropped.",
    "examples": [
     {
      "q": "bathrobe"
     }
    ]
   },
   "BillingPlan": {
    "type": "object",
    "required": [
     "code",
     "name",
     "monthly_credits",
     "price_usd",
     "concurrency"
    ],
    "properties": {
     "code": {
      "type": "string",
      "description": "Plan code.",
      "enum": [
       "free",
       "starter",
       "growth",
       "scale",
       "enterprise"
      ]
     },
     "name": {
      "type": "string"
     },
     "monthly_credits": {
      "type": "integer",
      "description": "Credits granted at the start of each period."
     },
     "price_usd": {
      "type": "integer",
      "description": "Monthly price in USD; 0 = free, -1 = custom (sales)."
     },
     "concurrency": {
      "type": "integer",
      "description": "Concurrent metered requests allowed once enforcement is on."
     }
    }
   },
   "BillingSummary": {
    "type": "object",
    "required": [
     "mode",
     "plan",
     "credits",
     "period"
    ],
    "properties": {
     "mode": {
      "type": "string",
      "description": "Credit metering mode: `shadow` (metered and recorded, never blocks) during the beta; `enforce` once paid plans are on sale.",
      "enum": [
       "off",
       "shadow",
       "enforce"
      ]
     },
     "plan": {
      "$ref": "#/components/schemas/BillingPlan"
     },
     "credits": {
      "type": "object",
      "required": [
       "balance",
       "reserved",
       "available",
       "credits_used",
       "credits_refunded",
       "billable_requests"
      ],
      "properties": {
       "balance": {
        "type": "integer",
        "description": "Credits on the account. In shadow mode this can go negative; the overdraft is forgiven at renewal."
       },
       "reserved": {
        "type": "integer",
        "description": "Credits held by requests that are still running."
       },
       "available": {
        "type": "integer",
        "description": "`balance - reserved`."
       },
       "credits_used": {
        "type": "integer",
        "description": "Credits charged this period."
       },
       "credits_refunded": {
        "type": "integer",
        "description": "Credits returned this period."
       },
       "billable_requests": {
        "type": "integer",
        "description": "Requests charged this period."
       }
      }
     },
     "period": {
      "type": "object",
      "required": [
       "start",
       "end"
      ],
      "properties": {
       "start": {
        "type": "string",
        "format": "date-time"
       },
       "end": {
        "type": "string",
        "description": "Renewal time; unspent credits expire then.",
        "format": "date-time"
       }
      }
     },
     "subscription": {
      "type": "object",
      "properties": {
       "status": {
        "type": "string"
       },
       "stripe_managed": {
        "type": "boolean"
       }
      }
     }
    }
   },
   "BillingLedgerEntry": {
    "type": "object",
    "required": [
     "id",
     "kind",
     "amount",
     "balance_after",
     "created_at"
    ],
    "properties": {
     "id": {
      "type": "integer",
      "description": "Entry id; pass the last one as `before` to page."
     },
     "kind": {
      "type": "string",
      "description": "`usage`, `grant`, `expiry`, `refund`, `adjustment`, ..."
     },
     "amount": {
      "type": "integer",
      "description": "Signed credit change (negative for usage)."
     },
     "balance_after": {
      "type": "integer"
     },
     "route": {
      "type": "string",
      "description": "Route template for usage entries."
     },
     "request_id": {
      "type": "string",
      "description": "`x-request-id` of the charged request."
     },
     "detail": {
      "type": "object"
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     }
    }
   },
   "BillingLedger": {
    "type": "object",
    "required": [
     "entries",
     "next_before"
    ],
    "properties": {
     "entries": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/BillingLedgerEntry"
      },
      "description": "Newest first."
     },
     "next_before": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Pass as `before` for the next page; null on the last page."
     }
    }
   },
   "BillingPlans": {
    "type": "object",
    "required": [
     "plans",
     "costs",
     "free",
     "notes",
     "mode"
    ],
    "properties": {
     "plans": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/BillingPlan"
      }
     },
     "costs": {
      "type": "array",
      "items": {
       "type": "object",
       "required": [
        "method",
        "path",
        "credits"
       ],
       "properties": {
        "method": {
         "type": "string"
        },
        "path": {
         "type": "string"
        },
        "credits": {
         "type": "integer"
        }
       }
      },
      "description": "Base credit cost of every metered operation."
     },
     "free": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Operations that never cost credits."
     },
     "notes": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "mode": {
      "type": "string",
      "enum": [
       "off",
       "shadow",
       "enforce"
      ]
     }
    }
   },
   "ErrorResponse": {
    "type": "object",
    "description": "Error body for every non-validation error: `{\"detail\": \"...\"}`.",
    "required": [
     "detail"
    ],
    "properties": {
     "detail": {
      "type": "string",
      "description": "Human-readable error message."
     }
    },
    "examples": [
     {
      "detail": "missing or invalid API key"
     }
    ]
   },
   "RateProvenance": {
    "type": "object",
    "description": "Where, when and how one normalized price was observed.",
    "required": [
     "schema_version",
     "observation_id",
     "collection_id",
     "observed_at",
     "source",
     "source_kind",
     "collector",
     "source_property_id",
     "requested_market",
     "requested_currency",
     "returned_currency",
     "egress_mode",
     "price_basis",
     "derivation",
     "upstream_rate_id"
    ],
    "properties": {
     "schema_version": {
      "type": "integer",
      "description": "Provenance schema version (currently 1)."
     },
     "observation_id": {
      "type": "string",
      "description": "Deterministic id of this price observation (`rateobs_...`)."
     },
     "collection_id": {
      "type": "string",
      "description": "Id shared by every price from one upstream fetch (`ratecol_...`)."
     },
     "observed_at": {
      "type": "string",
      "description": "UTC observation time, ISO-8601."
     },
     "source": {
      "type": "string",
      "description": "Upstream source, e.g. `google_hotels_calendar`."
     },
     "source_kind": {
      "type": "string",
      "description": "Kind of source, e.g. `calendar`, `offer`, `ota_calendar`, `official`."
     },
     "collector": {
      "type": "string",
      "description": "Identifier of the collector that produced the price."
     },
     "source_property_id": {
      "type": "string",
      "description": "Property identifier at the source."
     },
     "requested_market": {
      "type": [
       "string",
       "null"
      ]
     },
     "requested_currency": {
      "type": [
       "string",
       "null"
      ]
     },
     "returned_currency": {
      "type": [
       "string",
       "null"
      ]
     },
     "egress_mode": {
      "type": "string",
      "description": "How the request reached the source, e.g. `direct`."
     },
     "price_basis": {
      "type": "string",
      "description": "What the price represents, e.g. `room_base_before_taxes_and_fees`."
     },
     "derivation": {
      "type": "string",
      "description": "How the figure was derived, e.g. `normalized_upstream`."
     },
     "upstream_rate_id": {
      "type": [
       "string",
       "null"
      ],
      "description": "Source-native rate/room id when available."
     }
    }
   },
   "CalendarRateProvenance": {
    "allOf": [
     {
      "$ref": "#/components/schemas/RateProvenance"
     },
     {
      "type": "object",
      "required": [
       "derived_fields"
      ],
      "properties": {
       "derived_fields": {
        "type": "array",
        "items": {
         "type": "string"
        },
        "description": "Fields computed by ScraperCompany rather than read from the source."
       },
       "mainstream": {
        "type": "object",
        "description": "Present only when mainstream figures were added (`basis: mainstream`).",
        "required": [
         "source",
         "supplier",
         "method"
        ],
        "properties": {
         "source": {
          "type": "string"
         },
         "supplier": {
          "type": [
           "string",
           "null"
          ]
         },
         "method": {
          "type": "string"
         }
        }
       }
      }
     }
    ],
    "description": "Provenance of one calendar row."
   },
   "CalendarRate": {
    "type": "object",
    "description": "One priced night from the Google Hotels calendar.",
    "required": [
     "token",
     "stay_date",
     "rate",
     "rate_base",
     "rate_before_taxes_with_fees",
     "rate_total",
     "tax",
     "fees",
     "currency",
     "market",
     "rates_include_tax",
     "adults",
     "los",
     "min_length_of_stay",
     "rate_mainstream_base",
     "rate_mainstream_total",
     "mainstream_source",
     "aggregator_discount",
     "implied_tax_rate",
     "provenance"
    ],
    "properties": {
     "token": {
      "type": "string",
      "description": "Google property token."
     },
     "stay_date": {
      "type": "string",
      "description": "Stay (check-in) date.",
      "format": "date"
     },
     "rate": {
      "type": "number",
      "description": "The market-correct figure to store: all-in (`rate_total`) when `rates_include_tax` is true, otherwise the pre-tax base. For `POST /v1/stay` it is the whole-stay figure."
     },
     "rate_base": {
      "type": [
       "number",
       "null"
      ],
      "description": "Room-only price before tax and mandatory fees."
     },
     "rate_before_taxes_with_fees": {
      "type": [
       "number",
       "null"
      ],
      "description": "`rate_base` + `fees` (SearchAPI's `extracted_price_before_taxes` basis)."
     },
     "rate_total": {
      "type": [
       "number",
       "null"
      ],
      "description": "All-in price including tax and fees."
     },
     "tax": {
      "type": [
       "number",
       "null"
      ]
     },
     "fees": {
      "type": [
       "number",
       "null"
      ]
     },
     "currency": {
      "type": "string"
     },
     "market": {
      "type": "string"
     },
     "rates_include_tax": {
      "type": "boolean",
      "description": "Which basis `rate` uses."
     },
     "adults": {
      "type": "integer"
     },
     "los": {
      "type": "integer",
      "description": "Length of stay the price was quoted for."
     },
     "min_length_of_stay": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Set when the night only prices at a longer stay; `rate` is then a per-night figure derived from that stay."
     },
     "rate_mainstream_base": {
      "type": [
       "number",
       "null"
      ],
      "description": "Cheapest mainstream-OTA base price (only populated with `basis: mainstream`)."
     },
     "rate_mainstream_total": {
      "type": [
       "number",
       "null"
      ],
      "description": "Cheapest mainstream-OTA all-in price (only populated with `basis: mainstream`)."
     },
     "mainstream_source": {
      "type": [
       "string",
       "null"
      ],
      "description": "OTA that produced the mainstream figure."
     },
     "aggregator_discount": {
      "type": [
       "number",
       "null"
      ],
      "description": "`rate_mainstream_total - rate_total` when both exist."
     },
     "implied_tax_rate": {
      "type": [
       "number",
       "null"
      ],
      "description": "`tax / rate_base`."
     },
     "provenance": {
      "$ref": "#/components/schemas/CalendarRateProvenance"
     }
    }
   },
   "CalendarResponse": {
    "type": "object",
    "description": "Response of `POST /v1/calendar` (also each item `result` of a calendar job).",
    "required": [
     "token",
     "collection_id",
     "observed_at",
     "market",
     "requested_days",
     "coverage",
     "wire_bytes",
     "elapsed_s",
     "calendar_elapsed_s",
     "egress_mode",
     "tax_profile",
     "unpriced_dates",
     "validation",
     "rates"
    ],
    "properties": {
     "token": {
      "type": "string"
     },
     "collection_id": {
      "type": "string",
      "description": "Shared by every row of this collection (`ratecol_...`)."
     },
     "observed_at": {
      "type": "string",
      "description": "UTC observation time, ISO-8601."
     },
     "market": {
      "type": "string"
     },
     "requested_days": {
      "type": "integer",
      "description": "Nights requested (capped at 330)."
     },
     "coverage": {
      "type": "number",
      "description": "Share of requested nights that returned a priced row, 0-1 rounded to 4 decimals (e.g. `0.9333` = 84 of 90). A number, not an `N/M` string."
     },
     "wire_bytes": {
      "type": "integer"
     },
     "elapsed_s": {
      "type": "number",
      "description": "End-to-end seconds for this request."
     },
     "calendar_elapsed_s": {
      "type": "number",
      "description": "Seconds spent on the upstream calendar fetch."
     },
     "egress_mode": {
      "type": "string",
      "enum": [
       "direct",
       "proxy_fallback"
      ]
     },
     "tax_profile": {
      "anyOf": [
       {
        "type": "object",
        "required": [
         "rate",
         "confidence",
         "itemised",
         "derived"
        ],
        "properties": {
         "rate": {
          "type": "number",
          "description": "Median tax / base ratio observed across nights."
         },
         "confidence": {
          "type": "string",
          "enum": [
           "high",
           "low",
           "none"
          ]
         },
         "itemised": {
          "type": "integer",
          "description": "Nights where the tax split was itemised."
         },
         "derived": {
          "type": "integer",
          "description": "Nights where only a total was given and the split was derived."
         }
        }
       },
       {
        "type": "null"
       }
      ],
      "description": "The property's effective tax profile, derived from the returned nights."
     },
     "unpriced_dates": {
      "type": "array",
      "items": {
       "type": "string",
       "format": "date"
      },
      "description": "Requested nights with no bookable offer."
     },
     "validation": {
      "type": "object",
      "description": "Plausibility checks on the returned rows.",
      "required": [
       "ok",
       "errors",
       "warnings"
      ],
      "properties": {
       "ok": {
        "type": "boolean",
        "description": "False when any error-level finding exists."
       },
       "errors": {
        "type": "array",
        "items": {
         "type": "string"
        }
       },
       "warnings": {
        "type": "array",
        "items": {
         "type": "string"
        }
       }
      }
     },
     "booking_window": {
      "type": "object",
      "description": "How far out the property actually sells. Present on successful collections.",
      "required": [
       "requested_days",
       "priced_days",
       "last_priced_day",
       "dry_after_day",
       "note"
      ],
      "properties": {
       "requested_days": {
        "type": "integer"
       },
       "priced_days": {
        "type": "integer"
       },
       "last_priced_day": {
        "type": [
         "integer",
         "null"
        ],
        "description": "1-based day of the last priced night."
       },
       "contiguous_days": {
        "type": "integer",
        "description": "Priced nights from the start with no gap (absent when nothing priced)."
       },
       "dry_after_day": {
        "type": "integer"
       },
       "note": {
        "type": "string"
       }
      }
     },
     "basis_applied": {
      "type": "string",
      "description": "Present only with `basis: mainstream`.",
      "enum": [
       "mainstream:annotated",
       "mainstream:calendar-already-matched"
      ]
     },
     "source_check": {
      "type": "object",
      "description": "Present only when `verify_sources` > 0 or `basis: mainstream` sampled nights against the offers page.",
      "required": [
       "sampled",
       "mainstream_sources",
       "calendar_matches_mainstream",
       "note",
       "checks"
      ],
      "properties": {
       "sampled": {
        "type": "integer"
       },
       "mainstream_sources": {
        "type": "array",
        "items": {
         "type": "string"
        }
       },
       "calendar_matches_mainstream": {
        "type": "boolean"
       },
       "note": {
        "type": "string"
       },
       "checks": {
        "type": "array",
        "items": {
         "type": "object",
         "required": [
          "stay_date",
          "calendar_total",
          "cheapest_mainstream",
          "cheapest_any_source",
          "cheapest_source",
          "calendar_is_mainstream"
         ],
         "properties": {
          "stay_date": {
           "type": "string",
           "format": "date"
          },
          "calendar_total": {
           "type": [
            "number",
            "null"
           ]
          },
          "cheapest_mainstream": {
           "type": [
            "number",
            "null"
           ]
          },
          "cheapest_any_source": {
           "type": "number"
          },
          "cheapest_source": {
           "type": "string"
          },
          "calendar_is_mainstream": {
           "type": "boolean"
          }
         }
        }
       },
       "reprice": {
        "type": "object",
        "description": "Present when mainstream re-pricing ran.",
        "required": [
         "replaced",
         "dropped_no_mainstream_offer"
        ],
        "properties": {
         "replaced": {
          "type": "integer"
         },
         "dropped_no_mainstream_offer": {
          "type": "integer"
         }
        }
       }
      }
     },
     "rates": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/CalendarRate"
      },
      "description": "One row per priced night."
     }
    }
   },
   "StayResponse": {
    "allOf": [
     {
      "type": "object",
      "required": [
       "nights"
      ],
      "properties": {
       "nights": {
        "type": "integer",
        "description": "Nights between check_in and check_out."
       }
      }
     },
     {
      "$ref": "#/components/schemas/CalendarRate"
     }
    ],
    "description": "One priced stay window. `rate` is the WHOLE-STAY figure."
   },
   "SearchMatch": {
    "type": "object",
    "required": [
     "token",
     "rank",
     "verified",
     "name",
     "name_score"
    ],
    "properties": {
     "token": {
      "type": "string",
      "description": "Google property token; pass it as `token` / `property_token`."
     },
     "rank": {
      "type": "integer",
      "description": "Google's own ordering, 0 = first."
     },
     "verified": {
      "type": [
       "boolean",
       "null"
      ],
      "description": "Whether the token prices. `null` when `verify` was false."
     },
     "name": {
      "type": [
       "string",
       "null"
      ],
      "description": "Property name read back from Google. `null` when unchecked, empty string when checked but unreadable."
     },
     "name_score": {
      "type": [
       "number",
       "null"
      ],
      "description": "0-1 word-overlap between the requested and real name. `null` when unchecked."
     }
    }
   },
   "SearchResponse": {
    "type": "object",
    "required": [
     "query",
     "gl",
     "requested_market",
     "attempted_markets",
     "matched_market",
     "market_fallback_used",
     "search_status",
     "external_fallback_recommended",
     "matches"
    ],
    "properties": {
     "query": {
      "type": "string",
      "description": "`name` and `city` as searched."
     },
     "gl": {
      "type": "string",
      "description": "Google country (`gl`) of the market that matched, or of the first market tried."
     },
     "requested_market": {
      "type": "string"
     },
     "attempted_markets": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Markets tried, in order, up to and including the one that matched."
     },
     "matched_market": {
      "type": [
       "string",
       "null"
      ]
     },
     "market_fallback_used": {
      "type": "boolean"
     },
     "search_status": {
      "type": "string",
      "enum": [
       "matched",
       "not_found"
      ]
     },
     "external_fallback_recommended": {
      "type": "boolean",
      "description": "True when nothing matched."
     },
     "matches": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/SearchMatch"
      },
      "description": "Best match first when `verify` is on (verified, then name score, then Google rank)."
     }
    }
   },
   "Market": {
    "type": "object",
    "required": [
     "code",
     "currency",
     "label",
     "rates_include_tax"
    ],
    "properties": {
     "code": {
      "type": "string"
     },
     "currency": {
      "type": "string"
     },
     "label": {
      "type": "string"
     },
     "rates_include_tax": {
      "type": "boolean",
      "description": "Default tax basis for the market."
     }
    }
   },
   "MarketsResponse": {
    "type": "object",
    "required": [
     "markets"
    ],
    "properties": {
     "markets": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Market"
      }
     }
    }
   },
   "GoogleOfferRoom": {
    "type": "object",
    "required": [
     "name",
     "description",
     "link",
     "price_before_taxes",
     "price_total",
     "is_suite",
     "beds",
     "has_free_cancellation",
     "free_cancellation_until",
     "free_cancellation_time",
     "thumbnail"
    ],
    "properties": {
     "name": {
      "type": "string"
     },
     "description": {
      "type": "string"
     },
     "link": {
      "type": [
       "string",
       "null"
      ]
     },
     "price_before_taxes": {
      "type": [
       "number",
       "null"
      ]
     },
     "price_total": {
      "type": [
       "number",
       "null"
      ]
     },
     "is_suite": {
      "type": "boolean"
     },
     "beds": {
      "type": [
       "integer",
       "null"
      ]
     },
     "has_free_cancellation": {
      "type": "boolean"
     },
     "free_cancellation_until": {
      "type": [
       "string",
       "null"
      ]
     },
     "free_cancellation_time": {
      "type": [
       "string",
       "null"
      ]
     },
     "thumbnail": {
      "type": [
       "string",
       "null"
      ]
     }
    }
   },
   "GoogleOffer": {
    "type": "object",
    "required": [
     "source",
     "raw_source",
     "is_official",
     "currency",
     "nights",
     "room_id",
     "price_per_night",
     "price_per_night_before_taxes",
     "total",
     "tax",
     "fees",
     "has_free_cancellation",
     "free_cancellation_until",
     "free_cancellation_time",
     "discount_remarks",
     "has_member_rate",
     "rooms",
     "headline_price_total",
     "headline_price_before_taxes",
     "price_derived_from_room",
     "provenance"
    ],
    "properties": {
     "source": {
      "type": "string",
      "description": "Normalized seller name, e.g. `Booking.com`, `Official site`."
     },
     "raw_source": {
      "type": "string",
      "description": "Seller name exactly as Google rendered it."
     },
     "is_official": {
      "type": "boolean"
     },
     "currency": {
      "type": [
       "string",
       "null"
      ]
     },
     "nights": {
      "type": "integer"
     },
     "room_id": {
      "type": [
       "string",
       "null"
      ],
      "description": "Seller-native room / rate-plan id."
     },
     "price_per_night": {
      "type": [
       "number",
       "null"
      ],
      "description": "All-in price per night."
     },
     "price_per_night_before_taxes": {
      "type": [
       "number",
       "null"
      ]
     },
     "total": {
      "type": [
       "number",
       "null"
      ],
      "description": "All-in price for the stay window."
     },
     "tax": {
      "type": [
       "number",
       "null"
      ]
     },
     "fees": {
      "type": [
       "number",
       "null"
      ]
     },
     "has_free_cancellation": {
      "type": "boolean"
     },
     "free_cancellation_until": {
      "type": [
       "string",
       "null"
      ]
     },
     "free_cancellation_time": {
      "type": [
       "string",
       "null"
      ]
     },
     "discount_remarks": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Member/loyalty remarks shown beside the offer."
     },
     "has_member_rate": {
      "type": "boolean"
     },
     "rooms": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/GoogleOfferRoom"
      }
     },
     "headline_price_total": {
      "type": [
       "number",
       "null"
      ]
     },
     "headline_price_before_taxes": {
      "type": [
       "number",
       "null"
      ]
     },
     "price_derived_from_room": {
      "type": "boolean"
     },
     "provenance": {
      "$ref": "#/components/schemas/RateProvenance"
     }
    }
   },
   "PriceInsights": {
    "type": "object",
    "required": [
     "lowest_price",
     "price_level",
     "price_level_code",
     "typical_price_range"
    ],
    "properties": {
     "lowest_price": {
      "type": [
       "string",
       "null"
      ],
      "description": "As Google displays it, e.g. `$304`."
     },
     "price_level": {
      "type": [
       "string",
       "null"
      ]
     },
     "price_level_code": {
      "type": [
       "integer",
       "null"
      ]
     },
     "typical_price_range": {
      "anyOf": [
       {
        "type": "object",
        "required": [
         "low_price",
         "high_price"
        ],
        "properties": {
         "low_price": {
          "type": [
           "string",
           "null"
          ]
         },
         "high_price": {
          "type": [
           "string",
           "null"
          ]
         }
        }
       },
       {
        "type": "null"
       }
      ]
     }
    }
   },
   "OffersResponse": {
    "type": "object",
    "required": [
     "token",
     "check_in",
     "check_out",
     "nights",
     "adults",
     "device",
     "coverage",
     "currency",
     "currency_matches_request",
     "requested_market",
     "egress_market",
     "egress_geo_locked_ok",
     "price_insights_market_verified",
     "rates_include_tax",
     "lowest_price_per_night",
     "rooms_total",
     "name",
     "hotel_class",
     "hotel_class_stars",
     "rating",
     "reviews",
     "deal",
     "deal_description",
     "has_deal",
     "price_insights",
     "sources",
     "missing_sources",
     "refundable_offers",
     "wire_bytes",
     "elapsed_s",
     "warnings",
     "offers"
    ],
    "properties": {
     "token": {
      "type": "string"
     },
     "check_in": {
      "type": "string",
      "format": "date"
     },
     "check_out": {
      "type": "string",
      "format": "date"
     },
     "nights": {
      "type": "integer"
     },
     "adults": {
      "type": "integer"
     },
     "device": {
      "type": "string"
     },
     "coverage": {
      "type": "integer",
      "description": "Device profiles fetched (echo of the request)."
     },
     "currency": {
      "type": [
       "string",
       "null"
      ],
      "description": "Currency the page actually priced in."
     },
     "currency_matches_request": {
      "type": "boolean"
     },
     "requested_market": {
      "type": "string"
     },
     "egress_market": {
      "type": [
       "string",
       "null"
      ],
      "description": "Market the seller list is verified for, or null when unverified."
     },
     "egress_geo_locked_ok": {
      "type": "boolean"
     },
     "price_insights_market_verified": {
      "type": "boolean"
     },
     "rates_include_tax": {
      "type": "boolean",
      "description": "Basis used for `lowest_price_per_night`."
     },
     "lowest_price_per_night": {
      "type": [
       "number",
       "null"
      ]
     },
     "rooms_total": {
      "type": "integer"
     },
     "name": {
      "type": "string"
     },
     "hotel_class": {
      "type": "string"
     },
     "hotel_class_stars": {
      "type": [
       "integer",
       "null"
      ]
     },
     "rating": {
      "type": [
       "number",
       "null"
      ]
     },
     "reviews": {
      "type": [
       "integer",
       "null"
      ]
     },
     "deal": {
      "type": [
       "string",
       "null"
      ]
     },
     "deal_description": {
      "type": [
       "string",
       "null"
      ]
     },
     "has_deal": {
      "type": "boolean"
     },
     "price_insights": {
      "$ref": "#/components/schemas/PriceInsights"
     },
     "sources": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Distinct sellers in `offers`."
     },
     "missing_sources": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Required sources not offered after retry."
     },
     "refundable_offers": {
      "type": "integer"
     },
     "wire_bytes": {
      "type": "integer"
     },
     "elapsed_s": {
      "type": "number"
     },
     "warnings": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "offers": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/GoogleOffer"
      }
     }
    }
   },
   "RoomMatrixResponse": {
    "type": "object",
    "required": [
     "search_parameters",
     "property",
     "render",
     "sources",
     "rows",
     "totals"
    ],
    "properties": {
     "search_parameters": {
      "type": "object",
      "required": [
       "engine",
       "token",
       "check_in_date",
       "check_out_date",
       "adults",
       "currency",
       "sources"
      ],
      "properties": {
       "engine": {
        "type": "string",
        "enum": [
         "google_hotels_rooms"
        ]
       },
       "token": {
        "type": "string"
       },
       "check_in_date": {
        "type": "string",
        "format": "date"
       },
       "check_out_date": {
        "type": "string",
        "format": "date"
       },
       "adults": {
        "type": "integer"
       },
       "currency": {
        "type": "string"
       },
       "sources": {
        "type": "array",
        "items": {
         "type": "string"
        }
       }
      }
     },
     "property": {
      "type": "object",
      "required": [
       "name",
       "currency",
       "currency_matches_request",
       "requested_market",
       "egress_market",
       "egress_geo_locked_ok"
      ],
      "properties": {
       "name": {
        "type": "string"
       },
       "currency": {
        "type": "string"
       },
       "currency_matches_request": {
        "type": "boolean"
       },
       "requested_market": {
        "type": "string"
       },
       "egress_market": {
        "type": [
         "string",
         "null"
        ]
       },
       "egress_geo_locked_ok": {
        "type": "boolean"
       }
      }
     },
     "render": {
      "type": "object",
      "required": [
       "wire_bytes",
       "carried_room_detail"
      ],
      "properties": {
       "wire_bytes": {
        "type": "integer"
       },
       "carried_room_detail": {
        "type": "boolean"
       }
      }
     },
     "sources": {
      "type": "array",
      "items": {
       "type": "object",
       "required": [
        "source",
        "rooms",
        "cheapest",
        "dearest",
        "currency",
        "is_official",
        "duplicate_of",
        "provenance"
       ],
       "properties": {
        "source": {
         "type": "string"
        },
        "rooms": {
         "type": "integer",
         "description": "Distinct rooms this render carried for the source; 0 does NOT mean no inventory."
        },
        "cheapest": {
         "type": [
          "number",
          "null"
         ]
        },
        "dearest": {
         "type": [
          "number",
          "null"
         ]
        },
        "currency": {
         "type": "string"
        },
        "is_official": {
         "type": "boolean"
        },
        "duplicate_of": {
         "type": [
          "string",
          "null"
         ]
        },
        "provenance": {
         "anyOf": [
          {
           "$ref": "#/components/schemas/RateProvenance"
          },
          {
           "type": "null"
          }
         ]
        }
       }
      }
     },
     "rows": {
      "type": "array",
      "items": {
       "type": "object",
       "required": [
        "signature",
        "cells"
       ],
       "properties": {
        "signature": {
         "type": "string",
         "description": "Normalized room signature, e.g. `1 king`."
        },
        "cells": {
         "type": "object",
         "description": "Keyed by source name.",
         "additionalProperties": {
          "type": "object",
          "required": [
           "name",
           "price",
           "total",
           "provenance"
          ],
          "properties": {
           "name": {
            "type": "string",
            "description": "The source's own room name."
           },
           "price": {
            "type": [
             "number",
             "null"
            ],
            "description": "Price before taxes."
           },
           "total": {
            "type": [
             "number",
             "null"
            ]
           },
           "provenance": {
            "anyOf": [
             {
              "$ref": "#/components/schemas/RateProvenance"
             },
             {
              "type": "null"
             }
            ]
           }
          }
         }
        }
       }
      }
     },
     "totals": {
      "type": "object",
      "required": [
       "sources_present",
       "sources_with_rooms",
       "distinct_signatures"
      ],
      "properties": {
       "sources_present": {
        "type": "integer"
       },
       "sources_with_rooms": {
        "type": "integer"
       },
       "distinct_signatures": {
        "type": "integer"
       }
      }
     }
    }
   },
   "CalendarJobItemStatus": {
    "type": "object",
    "required": [
     "id",
     "item_index",
     "token",
     "label",
     "status",
     "request",
     "result",
     "error",
     "attempts",
     "started_at",
     "finished_at",
     "updated_at"
    ],
    "properties": {
     "id": {
      "type": "string",
      "description": "`refreshitem_...`"
     },
     "item_index": {
      "type": "integer"
     },
     "token": {
      "type": "string"
     },
     "label": {
      "type": [
       "string",
       "null"
      ]
     },
     "status": {
      "type": "string",
      "enum": [
       "queued",
       "running",
       "succeeded",
       "failed"
      ]
     },
     "request": {
      "$ref": "#/components/schemas/CalendarJobItem"
     },
     "result": {
      "anyOf": [
       {
        "$ref": "#/components/schemas/CalendarResponse"
       },
       {
        "type": "null"
       }
      ],
      "description": "The item's calendar payload. Only populated with `include_results=true` once the item succeeded; otherwise null."
     },
     "error": {
      "type": [
       "string",
       "null"
      ]
     },
     "attempts": {
      "type": "integer"
     },
     "started_at": {
      "type": [
       "string",
       "null"
      ],
      "description": "Timestamp string, e.g. `2026-08-10 14:05:00.123456+00`."
     },
     "finished_at": {
      "type": [
       "string",
       "null"
      ],
      "description": "Timestamp string, e.g. `2026-08-10 14:05:00.123456+00`."
     },
     "updated_at": {
      "type": "string",
      "description": "Timestamp string, e.g. `2026-08-10 14:05:00.123456+00`."
     }
    }
   },
   "CalendarJob": {
    "type": "object",
    "description": "A calendar batch and its per-item status (same shape for submit and poll).",
    "required": [
     "id",
     "job_id",
     "poll_url",
     "status",
     "priority",
     "callback_url",
     "callback_status",
     "callback_attempts",
     "callback_last_error",
     "artifact_uri",
     "artifact_sha256",
     "result_summary",
     "error",
     "items_total",
     "items_succeeded",
     "items_failed",
     "created_at",
     "started_at",
     "finished_at",
     "updated_at",
     "items"
    ],
    "properties": {
     "id": {
      "type": "string",
      "description": "`refreshjob_...`"
     },
     "job_id": {
      "type": "string",
      "description": "Same as `id`."
     },
     "poll_url": {
      "type": "string",
      "description": "`/v1/jobs/{job_id}`"
     },
     "status": {
      "type": "string",
      "enum": [
       "queued",
       "running",
       "succeeded",
       "partial",
       "failed"
      ]
     },
     "priority": {
      "type": "integer"
     },
     "callback_url": {
      "type": [
       "string",
       "null"
      ]
     },
     "callback_status": {
      "type": "string",
      "enum": [
       "not_configured",
       "pending",
       "delivered",
       "failed"
      ]
     },
     "callback_attempts": {
      "type": "integer"
     },
     "callback_last_error": {
      "type": [
       "string",
       "null"
      ]
     },
     "artifact_uri": {
      "type": [
       "string",
       "null"
      ]
     },
     "artifact_sha256": {
      "type": [
       "string",
       "null"
      ]
     },
     "result_summary": {
      "type": "object",
      "description": "Empty object until the job finishes.",
      "properties": {
       "rates": {
        "type": "integer"
       },
       "wire_bytes": {
        "type": "integer"
       },
       "database": {
        "type": "object",
        "required": [
         "run_id",
         "rows_written",
         "rows_changed",
         "rows_removed"
        ],
        "properties": {
         "run_id": {
          "type": "string"
         },
         "rows_written": {
          "type": "integer"
         },
         "rows_changed": {
          "type": "integer"
         },
         "rows_removed": {
          "type": "integer"
         }
        }
       }
      }
     },
     "error": {
      "type": [
       "string",
       "null"
      ]
     },
     "items_total": {
      "type": "integer"
     },
     "items_succeeded": {
      "type": "integer"
     },
     "items_failed": {
      "type": "integer"
     },
     "created_at": {
      "type": "string",
      "description": "Timestamp string, e.g. `2026-08-10 14:05:00.123456+00`."
     },
     "started_at": {
      "type": [
       "string",
       "null"
      ],
      "description": "Timestamp string, e.g. `2026-08-10 14:05:00.123456+00`."
     },
     "finished_at": {
      "type": [
       "string",
       "null"
      ],
      "description": "Timestamp string, e.g. `2026-08-10 14:05:00.123456+00`."
     },
     "updated_at": {
      "type": "string",
      "description": "Timestamp string, e.g. `2026-08-10 14:05:00.123456+00`."
     },
     "items": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/CalendarJobItemStatus"
      }
     }
    }
   },
   "UsageResponse": {
    "type": "object",
    "required": [
     "key",
     "period",
     "totals",
     "by_status",
     "by_endpoint",
     "by_day"
    ],
    "properties": {
     "key": {
      "type": "object",
      "required": [
       "name",
       "prefix",
       "rate_limit_per_min",
       "role"
      ],
      "properties": {
       "name": {
        "type": "string"
       },
       "prefix": {
        "type": "string",
        "description": "First characters of the key, for display."
       },
       "rate_limit_per_min": {
        "type": "integer",
        "description": "This key's requests-per-minute limit."
       },
       "role": {
        "type": "string"
       }
      }
     },
     "period": {
      "type": "object",
      "required": [
       "name",
       "start",
       "end"
      ],
      "properties": {
       "name": {
        "type": "string",
        "enum": [
         "24h",
         "7d",
         "30d",
         "90d"
        ]
       },
       "start": {
        "type": "string",
        "format": "date-time"
       },
       "end": {
        "type": "string",
        "format": "date-time"
       }
      }
     },
     "totals": {
      "type": "object",
      "required": [
       "requests",
       "successful",
       "errors",
       "rate_limited",
       "response_bytes",
       "avg_duration_ms",
       "p95_duration_ms"
      ],
      "properties": {
       "requests": {
        "type": "integer"
       },
       "successful": {
        "type": "integer"
       },
       "errors": {
        "type": "integer"
       },
       "rate_limited": {
        "type": "integer"
       },
       "response_bytes": {
        "type": "integer"
       },
       "avg_duration_ms": {
        "type": "integer"
       },
       "p95_duration_ms": {
        "type": "integer"
       }
      }
     },
     "by_status": {
      "type": "array",
      "items": {
       "type": "object",
       "required": [
        "status",
        "requests"
       ],
       "properties": {
        "status": {
         "type": "integer"
        },
        "requests": {
         "type": "integer"
        }
       }
      }
     },
     "by_endpoint": {
      "type": "array",
      "items": {
       "type": "object",
       "required": [
        "method",
        "path",
        "requests",
        "errors",
        "avg_duration_ms",
        "p95_duration_ms"
       ],
       "properties": {
        "method": {
         "type": "string"
        },
        "path": {
         "type": "string"
        },
        "requests": {
         "type": "integer"
        },
        "errors": {
         "type": "integer"
        },
        "avg_duration_ms": {
         "type": "integer"
        },
        "p95_duration_ms": {
         "type": "integer"
        }
       }
      },
      "description": "Top 50 endpoints by request count."
     },
     "by_day": {
      "type": "array",
      "items": {
       "type": "object",
       "required": [
        "date",
        "requests",
        "errors",
        "response_bytes"
       ],
       "properties": {
        "date": {
         "type": "string",
         "format": "date"
        },
        "requests": {
         "type": "integer"
        },
        "errors": {
         "type": "integer"
        },
        "response_bytes": {
         "type": "integer"
        }
       }
      }
     }
    }
   },
   "RequestRecord": {
    "type": "object",
    "required": [
     "id",
     "method",
     "path",
     "status",
     "duration_ms",
     "response_bytes",
     "request",
     "created_at"
    ],
    "properties": {
     "id": {
      "type": "string",
      "description": "`req_...`; equals the `x-request-id` response header."
     },
     "method": {
      "type": "string"
     },
     "path": {
      "type": "string",
      "description": "Route path, e.g. `/v1/calendar`."
     },
     "status": {
      "type": "integer"
     },
     "duration_ms": {
      "type": "integer"
     },
     "response_bytes": {
      "type": "integer"
     },
     "request": {
      "type": "object",
      "description": "Sanitized request metadata; each key present only when the request had it.",
      "properties": {
       "path": {
        "type": "object",
        "description": "Path parameters."
       },
       "query": {
        "type": "object",
        "description": "Query parameters (credentials redacted)."
       },
       "body": {
        "description": "JSON body (credentials redacted), or `{truncated, bytes}` / `{invalid_json, bytes}`."
       }
      }
     },
     "created_at": {
      "type": "string",
      "description": "Timestamp string, e.g. `2026-08-10 14:05:00.123456+00`."
     }
    }
   },
   "RequestHistoryResponse": {
    "type": "object",
    "required": [
     "requests",
     "count",
     "has_more"
    ],
    "properties": {
     "requests": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/RequestRecord"
      },
      "description": "Newest first."
     },
     "count": {
      "type": "integer"
     },
     "has_more": {
      "type": "boolean"
     },
     "next_cursor": {
      "type": "string",
      "description": "Present only when `has_more` is true; pass it back as the `cursor` query parameter."
     }
    }
   },
   "StoredRate": {
    "type": "object",
    "required": [
     "property_name",
     "stay_date",
     "occupancy_key",
     "los",
     "rate",
     "rate_base",
     "rate_before_taxes_with_fees",
     "rate_total",
     "tax",
     "fees",
     "currency",
     "market",
     "rates_include_tax",
     "min_length_of_stay",
     "observed_at",
     "last_changed_at",
     "collection_id",
     "observation_id",
     "provenance"
    ],
    "properties": {
     "property_name": {
      "type": "string"
     },
     "stay_date": {
      "type": "string",
      "format": "date"
     },
     "occupancy_key": {
      "type": "string",
      "description": "e.g. `adults=2`"
     },
     "los": {
      "type": "integer"
     },
     "rate": {
      "type": [
       "number",
       "null"
      ]
     },
     "rate_base": {
      "type": [
       "number",
       "null"
      ]
     },
     "rate_before_taxes_with_fees": {
      "type": [
       "number",
       "null"
      ]
     },
     "rate_total": {
      "type": [
       "number",
       "null"
      ]
     },
     "tax": {
      "type": [
       "number",
       "null"
      ]
     },
     "fees": {
      "type": [
       "number",
       "null"
      ]
     },
     "currency": {
      "type": "string"
     },
     "market": {
      "type": [
       "string",
       "null"
      ]
     },
     "rates_include_tax": {
      "type": "boolean"
     },
     "min_length_of_stay": {
      "type": [
       "integer",
       "null"
      ]
     },
     "observed_at": {
      "type": "string",
      "description": "Timestamp string, e.g. `2026-08-10 14:05:00.123456+00`."
     },
     "last_changed_at": {
      "type": "string",
      "description": "Timestamp string, e.g. `2026-08-10 14:05:00.123456+00`."
     },
     "collection_id": {
      "type": "string"
     },
     "observation_id": {
      "type": "string"
     },
     "provenance": {
      "$ref": "#/components/schemas/CalendarRateProvenance"
     }
    }
   },
   "StoredRatesResponse": {
    "type": "object",
    "required": [
     "source",
     "source_property_id",
     "count",
     "last_observed_at",
     "last_success_at",
     "age_seconds",
     "freshness",
     "rates"
    ],
    "properties": {
     "source": {
      "type": "string",
      "enum": [
       "google_hotels"
      ]
     },
     "source_property_id": {
      "type": "string",
      "description": "The requested token."
     },
     "count": {
      "type": "integer"
     },
     "last_observed_at": {
      "type": [
       "string",
       "null"
      ],
      "description": "Timestamp string, e.g. `2026-08-10 14:05:00.123456+00`."
     },
     "last_success_at": {
      "type": [
       "string",
       "null"
      ],
      "description": "Timestamp string, e.g. `2026-08-10 14:05:00.123456+00`."
     },
     "age_seconds": {
      "type": [
       "integer",
       "null"
      ]
     },
     "freshness": {
      "type": "string",
      "description": "`fresh` <= 24 h, `stale` <= 48 h, `expired` older, `missing` when never collected.",
      "enum": [
       "missing",
       "fresh",
       "stale",
       "expired"
      ]
     },
     "rates": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/StoredRate"
      }
     }
    }
   },
   "OtaSearchMeta": {
    "type": "object",
    "required": [
     "source",
     "matches",
     "selection_method",
     "match_threshold",
     "match_margin",
     "wire_bytes",
     "elapsed_s"
    ],
    "properties": {
     "source": {
      "type": "string"
     },
     "matches": {
      "type": "integer"
     },
     "selection_method": {
      "type": "string"
     },
     "match_threshold": {
      "type": "number"
     },
     "match_margin": {
      "type": "number"
     },
     "wire_bytes": {
      "type": "integer"
     },
     "elapsed_s": {
      "type": "number"
     }
    }
   },
   "BookingSearchMatch": {
    "type": "object",
    "required": [
     "pagename",
     "country",
     "name",
     "url",
     "rank",
     "name_score",
     "identity_score",
     "match_score",
     "confidence"
    ],
    "properties": {
     "pagename": {
      "type": "string",
      "description": "URL slug; pass as `pagename`."
     },
     "country": {
      "type": "string",
      "description": "Two-letter URL segment; pass as `country`."
     },
     "name": {
      "type": "string"
     },
     "url": {
      "type": "string"
     },
     "rank": {
      "type": "integer"
     },
     "name_score": {
      "type": "number"
     },
     "identity_score": {
      "type": "number"
     },
     "match_score": {
      "type": "number"
     },
     "confidence": {
      "type": "string",
      "enum": [
       "high",
       "medium",
       "low"
      ]
     }
    }
   },
   "BookingSearchResponse": {
    "type": "object",
    "description": "Response of `POST /v1/ota/booking/search`.",
    "required": [
     "search_parameters",
     "search_status",
     "recommended_match",
     "warnings",
     "matches",
     "meta"
    ],
    "properties": {
     "search_parameters": {
      "type": "object",
      "required": [
       "engine",
       "name",
       "city",
       "limit"
      ],
      "properties": {
       "engine": {
        "type": "string",
        "enum": [
         "booking_search"
        ]
       },
       "name": {
        "type": "string"
       },
       "city": {
        "type": "string"
       },
       "limit": {
        "type": "integer"
       }
      }
     },
     "search_status": {
      "type": "string",
      "description": "`matched` only when the top candidate clears the identity threshold and margin.",
      "enum": [
       "matched",
       "ambiguous",
       "not_found"
      ]
     },
     "recommended_match": {
      "anyOf": [
       {
        "$ref": "#/components/schemas/BookingSearchMatch"
       },
       {
        "type": "null"
       }
      ],
      "description": "Safe to store; null unless `search_status` is `matched`."
     },
     "warnings": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "matches": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/BookingSearchMatch"
      },
      "description": "Candidates, best first, for manual review."
     },
     "meta": {
      "$ref": "#/components/schemas/OtaSearchMeta"
     }
    }
   },
   "HotelsSearchMatch": {
    "type": "object",
    "required": [
     "property_id",
     "name",
     "city",
     "address",
     "country",
     "url",
     "rank",
     "score",
     "name_score",
     "identity_score",
     "match_score",
     "confidence",
     "winner_reason"
    ],
    "properties": {
     "property_id": {
      "type": "string",
      "description": "Numeric Hotels.com id (digits); pass as `property_id`."
     },
     "name": {
      "type": "string"
     },
     "city": {
      "type": "string"
     },
     "address": {
      "type": "string"
     },
     "country": {
      "type": "string"
     },
     "url": {
      "type": "string"
     },
     "rank": {
      "type": "integer"
     },
     "score": {
      "type": "number"
     },
     "name_score": {
      "type": "number"
     },
     "identity_score": {
      "type": "number"
     },
     "match_score": {
      "type": "number"
     },
     "confidence": {
      "type": "string",
      "enum": [
       "high",
       "medium",
       "low"
      ]
     },
     "winner_reason": {
      "type": "string"
     },
     "city_score": {
      "type": "number",
      "description": "Present only when `city` was supplied."
     },
     "coordinates": {
      "type": "object",
      "description": "Present only when the source returned coordinates.",
      "required": [
       "latitude",
       "longitude"
      ],
      "properties": {
       "latitude": {
        "type": "number"
       },
       "longitude": {
        "type": "number"
       }
      }
     }
    }
   },
   "HotelsSearchResponse": {
    "type": "object",
    "description": "Response of `POST /v1/ota/hotels/search`.",
    "required": [
     "search_parameters",
     "search_status",
     "recommended_match",
     "warnings",
     "matches",
     "meta"
    ],
    "properties": {
     "search_parameters": {
      "type": "object",
      "required": [
       "engine",
       "name",
       "city",
       "market",
       "limit"
      ],
      "properties": {
       "engine": {
        "type": "string",
        "enum": [
         "hotels_search"
        ]
       },
       "name": {
        "type": "string"
       },
       "city": {
        "type": "string"
       },
       "market": {
        "type": "string"
       },
       "limit": {
        "type": "integer"
       }
      }
     },
     "search_status": {
      "type": "string",
      "description": "`matched` only when the top candidate clears the identity threshold and margin.",
      "enum": [
       "matched",
       "ambiguous",
       "not_found"
      ]
     },
     "recommended_match": {
      "anyOf": [
       {
        "$ref": "#/components/schemas/HotelsSearchMatch"
       },
       {
        "type": "null"
       }
      ],
      "description": "Safe to store; null unless `search_status` is `matched`."
     },
     "warnings": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "matches": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/HotelsSearchMatch"
      },
      "description": "Candidates, best first, for manual review."
     },
     "meta": {
      "$ref": "#/components/schemas/OtaSearchMeta"
     }
    }
   },
   "AgodaSearchMatch": {
    "type": "object",
    "required": [
     "property_id",
     "name",
     "city",
     "country",
     "location",
     "rank",
     "score",
     "name_score",
     "identity_score",
     "match_score",
     "confidence"
    ],
    "properties": {
     "property_id": {
      "type": "string",
      "description": "Numeric Agoda id; pass as `property_id`."
     },
     "name": {
      "type": "string"
     },
     "city": {
      "type": "string"
     },
     "country": {
      "type": "string"
     },
     "location": {
      "type": "string"
     },
     "rank": {
      "type": "integer"
     },
     "score": {
      "type": "number"
     },
     "name_score": {
      "type": "number"
     },
     "identity_score": {
      "type": "number"
     },
     "match_score": {
      "type": "number"
     },
     "confidence": {
      "type": "string",
      "enum": [
       "high",
       "medium",
       "low"
      ]
     },
     "city_score": {
      "type": "number",
      "description": "Present only when `city` was supplied."
     }
    }
   },
   "AgodaSearchResponse": {
    "type": "object",
    "description": "Response of `POST /v1/ota/agoda/search`.",
    "required": [
     "search_parameters",
     "search_status",
     "recommended_match",
     "warnings",
     "matches",
     "meta"
    ],
    "properties": {
     "search_parameters": {
      "type": "object",
      "required": [
       "engine",
       "name",
       "city",
       "origin",
       "limit"
      ],
      "properties": {
       "engine": {
        "type": "string",
        "enum": [
         "agoda_search"
        ]
       },
       "name": {
        "type": "string"
       },
       "city": {
        "type": "string"
       },
       "origin": {
        "type": "string"
       },
       "limit": {
        "type": "integer"
       }
      }
     },
     "search_status": {
      "type": "string",
      "description": "`matched` only when the top candidate clears the identity threshold and margin.",
      "enum": [
       "matched",
       "ambiguous",
       "not_found"
      ]
     },
     "recommended_match": {
      "anyOf": [
       {
        "$ref": "#/components/schemas/AgodaSearchMatch"
       },
       {
        "type": "null"
       }
      ],
      "description": "Safe to store; null unless `search_status` is `matched`."
     },
     "warnings": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "matches": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/AgodaSearchMatch"
      },
      "description": "Candidates, best first, for manual review."
     },
     "meta": {
      "$ref": "#/components/schemas/OtaSearchMeta"
     }
    }
   },
   "BookingCalendarNight": {
    "type": "object",
    "required": [
     "stay_date",
     "available",
     "price",
     "currency",
     "min_length_of_stay",
     "provenance"
    ],
    "properties": {
     "stay_date": {
      "type": "string",
      "format": "date"
     },
     "available": {
      "type": "boolean"
     },
     "price": {
      "type": [
       "number",
       "null"
      ],
      "description": "Null for unsellable dates."
     },
     "currency": {
      "type": "string"
     },
     "min_length_of_stay": {
      "type": [
       "integer",
       "null"
      ]
     },
     "provenance": {
      "$ref": "#/components/schemas/RateProvenance"
     }
    }
   },
   "BookingCalendarResponse": {
    "type": "object",
    "description": "Response of `POST /v1/ota/booking`.",
    "required": [
     "search_parameters",
     "property",
     "calendar",
     "unavailable_dates",
     "meta"
    ],
    "properties": {
     "search_parameters": {
      "type": "object",
      "required": [
       "engine",
       "pagename",
       "country",
       "start_date",
       "days",
       "currency",
       "adults",
       "rooms"
      ],
      "properties": {
       "engine": {
        "type": "string",
        "enum": [
         "booking_calendar"
        ]
       },
       "pagename": {
        "type": "string"
       },
       "country": {
        "type": "string"
       },
       "start_date": {
        "type": "string",
        "format": "date"
       },
       "days": {
        "type": "integer"
       },
       "currency": {
        "type": "string"
       },
       "adults": {
        "type": "integer"
       },
       "rooms": {
        "type": "integer"
       }
      }
     },
     "property": {
      "type": "object",
      "required": [
       "pagename",
       "hotel_id"
      ],
      "properties": {
       "pagename": {
        "type": "string"
       },
       "hotel_id": {
        "type": [
         "integer",
         "null"
        ],
        "description": "Booking.com's numeric hotel id as returned upstream."
       }
      }
     },
     "calendar": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/BookingCalendarNight"
      }
     },
     "unavailable_dates": {
      "type": "array",
      "items": {
       "type": "string",
       "format": "date"
      }
     },
     "meta": {
      "type": "object",
      "required": [
       "source",
       "collection_id",
       "observed_at",
       "calls",
       "wire_bytes",
       "elapsed_s",
       "dates",
       "priced"
      ],
      "properties": {
       "source": {
        "type": "string",
        "enum": [
         "booking"
        ]
       },
       "collection_id": {
        "type": "string"
       },
       "observed_at": {
        "type": "string"
       },
       "calls": {
        "type": "integer"
       },
       "wire_bytes": {
        "type": "integer"
       },
       "elapsed_s": {
        "type": "number"
       },
       "dates": {
        "type": "integer"
       },
       "priced": {
        "type": "integer"
       }
      }
     }
    }
   },
   "BookingRoomRatePlan": {
    "type": "object",
    "required": [
     "block_id",
     "price",
     "currency",
     "guests",
     "free_cancellation",
     "no_prepayment",
     "breakfast_included",
     "provenance"
    ],
    "properties": {
     "block_id": {
      "type": "string"
     },
     "price": {
      "type": [
       "number",
       "null"
      ]
     },
     "currency": {
      "type": "string"
     },
     "guests": {
      "type": [
       "integer",
       "null"
      ]
     },
     "free_cancellation": {
      "type": "boolean"
     },
     "no_prepayment": {
      "type": "boolean"
     },
     "breakfast_included": {
      "type": "boolean"
     },
     "provenance": {
      "$ref": "#/components/schemas/RateProvenance"
     }
    }
   },
   "BookingRoomsResponse": {
    "type": "object",
    "description": "Response of `POST /v1/ota/booking/rooms`.",
    "required": [
     "pagename",
     "hotel_id",
     "property_name",
     "check_in",
     "check_out",
     "nights",
     "currency",
     "sold_out",
     "rendered",
     "catalogue_from_graphql",
     "cheapest_rate",
     "wire_bytes",
     "collection_id",
     "observed_at",
     "rooms"
    ],
    "properties": {
     "pagename": {
      "type": "string"
     },
     "hotel_id": {
      "type": "string",
      "description": "Empty string when the room catalogue was unavailable."
     },
     "property_name": {
      "type": "string"
     },
     "check_in": {
      "type": "string",
      "format": "date"
     },
     "check_out": {
      "type": "string",
      "format": "date"
     },
     "nights": {
      "type": "integer"
     },
     "currency": {
      "type": "string"
     },
     "sold_out": {
      "type": [
       "boolean",
       "null"
      ]
     },
     "rendered": {
      "type": "boolean"
     },
     "catalogue_from_graphql": {
      "type": "boolean",
      "description": "Whether room size / occupancy enrichment was available."
     },
     "cheapest_rate": {
      "type": [
       "number",
       "null"
      ]
     },
     "wire_bytes": {
      "type": "integer"
     },
     "collection_id": {
      "type": "string"
     },
     "observed_at": {
      "type": "string"
     },
     "rooms": {
      "type": "array",
      "items": {
       "type": "object",
       "required": [
        "name",
        "room_id",
        "beds",
        "room_size",
        "max_persons",
        "cheapest_rate",
        "rate_plans"
       ],
       "properties": {
        "name": {
         "type": "string"
        },
        "room_id": {
         "type": "string"
        },
        "beds": {
         "type": "string"
        },
        "room_size": {
         "type": [
          "number",
          "null"
         ]
        },
        "max_persons": {
         "type": [
          "integer",
          "null"
         ]
        },
        "cheapest_rate": {
         "type": [
          "number",
          "null"
         ]
        },
        "rate_plans": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/BookingRoomRatePlan"
         }
        }
       }
      }
     }
    }
   },
   "HotelsPriceResponse": {
    "type": "object",
    "description": "Response of `POST /v1/ota/hotels`.",
    "required": [
     "search_parameters",
     "property",
     "meta"
    ],
    "properties": {
     "search_parameters": {
      "type": "object",
      "required": [
       "engine",
       "property_id",
       "check_in_date",
       "check_out_date",
       "adults",
       "market",
       "currency"
      ],
      "properties": {
       "engine": {
        "type": "string",
        "enum": [
         "hotels_property"
        ]
       },
       "property_id": {
        "type": "string"
       },
       "check_in_date": {
        "type": "string",
        "format": "date"
       },
       "check_out_date": {
        "type": "string",
        "format": "date"
       },
       "adults": {
        "type": "integer"
       },
       "market": {
        "type": "string"
       },
       "currency": {
        "type": "string",
        "description": "The market's currency."
       }
      }
     },
     "property": {
      "type": "object",
      "required": [
       "property_id",
       "price_per_night",
       "currency",
       "currency_verified",
       "available",
       "provenance"
      ],
      "properties": {
       "property_id": {
        "type": "string"
       },
       "price_per_night": {
        "type": [
         "number",
         "null"
        ]
       },
       "currency": {
        "type": "string",
        "description": "Currency the point-of-sale actually priced in."
       },
       "currency_verified": {
        "type": "boolean"
       },
       "available": {
        "type": "boolean"
       },
       "provenance": {
        "$ref": "#/components/schemas/RateProvenance"
       }
      }
     },
     "meta": {
      "type": "object",
      "required": [
       "source",
       "collection_id",
       "observed_at",
       "nights",
       "elapsed_s",
       "comparable_across_markets"
      ],
      "properties": {
       "source": {
        "type": "string",
        "enum": [
         "hotels"
        ]
       },
       "collection_id": {
        "type": "string"
       },
       "observed_at": {
        "type": "string"
       },
       "nights": {
        "type": "integer"
       },
       "elapsed_s": {
        "type": "number"
       },
       "comparable_across_markets": {
        "type": "boolean",
        "description": "Always false."
       }
      }
     }
    }
   },
   "HotelsRoomRatePlan": {
    "type": "object",
    "required": [
     "plan_id",
     "price",
     "price_text",
     "currency",
     "refundable",
     "refundable_until",
     "pay_now",
     "provenance"
    ],
    "properties": {
     "plan_id": {
      "type": "string"
     },
     "price": {
      "type": [
       "number",
       "null"
      ]
     },
     "price_text": {
      "type": "string"
     },
     "currency": {
      "type": "string"
     },
     "refundable": {
      "type": [
       "boolean",
       "null"
      ],
      "description": "Tri-state: null means the source stated nothing, which is not the same as non-refundable."
     },
     "refundable_until": {
      "type": "string"
     },
     "pay_now": {
      "type": "boolean"
     },
     "provenance": {
      "$ref": "#/components/schemas/RateProvenance"
     }
    }
   },
   "HotelsRoomsResponse": {
    "type": "object",
    "description": "Response of `POST /v1/ota/hotels/rooms`.",
    "required": [
     "property_id",
     "market",
     "check_in",
     "check_out",
     "nights",
     "currency",
     "sold_out",
     "cheapest_rate",
     "wire_bytes",
     "collection_id",
     "observed_at",
     "rooms"
    ],
    "properties": {
     "property_id": {
      "type": "string"
     },
     "market": {
      "type": "string"
     },
     "check_in": {
      "type": "string",
      "format": "date"
     },
     "check_out": {
      "type": "string",
      "format": "date"
     },
     "nights": {
      "type": "integer"
     },
     "currency": {
      "type": "string"
     },
     "sold_out": {
      "type": "boolean"
     },
     "cheapest_rate": {
      "type": [
       "number",
       "null"
      ]
     },
     "wire_bytes": {
      "type": "integer"
     },
     "collection_id": {
      "type": "string"
     },
     "observed_at": {
      "type": "string"
     },
     "rooms": {
      "type": "array",
      "items": {
       "type": "object",
       "required": [
        "name",
        "unit_id",
        "cheapest_rate",
        "rate_plans"
       ],
       "properties": {
        "name": {
         "type": "string"
        },
        "unit_id": {
         "type": "string"
        },
        "cheapest_rate": {
         "type": [
          "number",
          "null"
         ]
        },
        "rate_plans": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/HotelsRoomRatePlan"
         }
        }
       }
      }
     }
    }
   },
   "AgodaOffer": {
    "type": "object",
    "required": [
     "price",
     "currency",
     "currency_code",
     "price_text",
     "tax_inclusive",
     "discount",
     "free_cancellation",
     "provenance"
    ],
    "properties": {
     "price": {
      "type": [
       "number",
       "null"
      ]
     },
     "currency": {
      "type": "string",
      "description": "Agoda's display token (may be a symbol such as `€`)."
     },
     "currency_code": {
      "type": "string",
      "description": "ISO 4217 code."
     },
     "price_text": {
      "type": "string"
     },
     "tax_inclusive": {
      "type": [
       "boolean",
       "null"
      ]
     },
     "discount": {
      "type": [
       "string",
       "null"
      ],
      "description": "e.g. `-29%`"
     },
     "free_cancellation": {
      "type": "boolean"
     },
     "provenance": {
      "$ref": "#/components/schemas/RateProvenance"
     }
    }
   },
   "AgodaRoomsResponse": {
    "type": "object",
    "description": "Response of `POST /v1/ota/agoda`.",
    "required": [
     "search_parameters",
     "property",
     "meta"
    ],
    "properties": {
     "search_parameters": {
      "type": "object",
      "required": [
       "engine",
       "property_id",
       "check_in_date",
       "check_out_date",
       "adults",
       "rooms",
       "currency"
      ],
      "properties": {
       "engine": {
        "type": "string",
        "enum": [
         "agoda_property"
        ]
       },
       "property_id": {
        "type": "string"
       },
       "check_in_date": {
        "type": "string",
        "format": "date"
       },
       "check_out_date": {
        "type": "string",
        "format": "date"
       },
       "adults": {
        "type": "integer"
       },
       "rooms": {
        "type": "integer"
       },
       "currency": {
        "type": "string"
       }
      }
     },
     "property": {
      "type": "object",
      "required": [
       "property_id",
       "name",
       "price_per_night",
       "currency",
       "currency_display",
       "tax_inclusive",
       "sold_out",
       "provenance",
       "rooms"
      ],
      "properties": {
       "property_id": {
        "type": "string"
       },
       "name": {
        "type": "string"
       },
       "price_per_night": {
        "type": [
         "number",
         "null"
        ],
        "description": "Cheapest priced offer."
       },
       "currency": {
        "type": "string",
        "description": "ISO code of the cheapest offer (the requested currency when nothing priced)."
       },
       "currency_display": {
        "type": [
         "string",
         "null"
        ]
       },
       "tax_inclusive": {
        "type": [
         "boolean",
         "null"
        ]
       },
       "sold_out": {
        "type": "boolean"
       },
       "provenance": {
        "anyOf": [
         {
          "$ref": "#/components/schemas/RateProvenance"
         },
         {
          "type": "null"
         }
        ],
        "description": "Provenance of the cheapest priced row; null when nothing priced."
       },
       "rooms": {
        "type": "array",
        "items": {
         "type": "object",
         "required": [
          "name",
          "offers"
         ],
         "properties": {
          "name": {
           "type": "string"
          },
          "offers": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/AgodaOffer"
           }
          }
         }
        }
       }
      }
     },
     "meta": {
      "type": "object",
      "required": [
       "source",
       "collection_id",
       "observed_at",
       "nights",
       "wire_bytes",
       "elapsed_s",
       "room_types",
       "offers",
       "comparable_across_markets"
      ],
      "properties": {
       "source": {
        "type": "string",
        "enum": [
         "agoda"
        ]
       },
       "collection_id": {
        "type": "string"
       },
       "observed_at": {
        "type": "string"
       },
       "nights": {
        "type": "integer"
       },
       "wire_bytes": {
        "type": "integer"
       },
       "elapsed_s": {
        "type": "number"
       },
       "room_types": {
        "type": "integer"
       },
       "offers": {
        "type": "integer"
       },
       "comparable_across_markets": {
        "type": "boolean",
        "description": "Always true."
       }
      }
     }
    }
   },
   "TripadvisorOffer": {
    "type": "object",
    "required": [
     "provider",
     "provider_name",
     "location_id",
     "check_in",
     "check_out",
     "price",
     "price_value",
     "currency",
     "price_currency",
     "room_plan",
     "offer_type",
     "provenance"
    ],
    "properties": {
     "provider": {
      "type": "string"
     },
     "provider_name": {
      "type": "string",
      "description": "Same value as `provider`."
     },
     "location_id": {
      "type": "string"
     },
     "check_in": {
      "type": "string",
      "format": "date"
     },
     "check_out": {
      "type": "string",
      "format": "date"
     },
     "price": {
      "type": "number"
     },
     "price_value": {
      "type": "number",
      "description": "Same value as `price`."
     },
     "currency": {
      "type": "string"
     },
     "price_currency": {
      "type": "string",
      "description": "Same value as `currency`."
     },
     "room_plan": {
      "type": "string",
      "enum": [
       "",
       "CP",
       "EP",
       "MAP",
       "AP"
      ]
     },
     "offer_type": {
      "type": "string",
      "enum": [
       "chevron",
       "hidden"
      ]
     },
     "provenance": {
      "$ref": "#/components/schemas/RateProvenance"
     }
    }
   },
   "TripadvisorPricesResponse": {
    "type": "object",
    "description": "Response of `POST /v1/ota/tripadvisor`.",
    "required": [
     "search_parameters",
     "property",
     "offers",
     "meta"
    ],
    "properties": {
     "search_parameters": {
      "type": "object",
      "required": [
       "engine",
       "location_id",
       "check_in_date",
       "check_out_date",
       "nights",
       "adults",
       "rooms",
       "currency"
      ],
      "properties": {
       "engine": {
        "type": "string",
        "enum": [
         "tripadvisor_property"
        ]
       },
       "location_id": {
        "type": "string"
       },
       "check_in_date": {
        "type": "string",
        "format": "date"
       },
       "check_out_date": {
        "type": "string",
        "format": "date"
       },
       "nights": {
        "type": "integer"
       },
       "adults": {
        "type": "integer"
       },
       "rooms": {
        "type": "integer"
       },
       "currency": {
        "type": "string"
       }
      }
     },
     "property": {
      "type": "object",
      "required": [
       "location_id",
       "hotel_id",
       "price_per_night",
       "currency",
       "provenance"
      ],
      "properties": {
       "location_id": {
        "type": "string"
       },
       "hotel_id": {
        "type": "string"
       },
       "price_per_night": {
        "type": [
         "number",
         "null"
        ],
        "description": "Cheapest provider offer."
       },
       "currency": {
        "type": "string",
        "description": "The requested currency."
       },
       "provenance": {
        "anyOf": [
         {
          "$ref": "#/components/schemas/RateProvenance"
         },
         {
          "type": "null"
         }
        ],
        "description": "Provenance of the cheapest priced row; null when nothing priced."
       }
      }
     },
     "offers": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/TripadvisorOffer"
      }
     },
     "meta": {
      "type": "object",
      "required": [
       "source",
       "collection_id",
       "observed_at",
       "nights",
       "wire_bytes",
       "elapsed_s",
       "offers"
      ],
      "properties": {
       "source": {
        "type": "string",
        "enum": [
         "tripadvisor"
        ]
       },
       "collection_id": {
        "type": "string"
       },
       "observed_at": {
        "type": "string"
       },
       "nights": {
        "type": "integer"
       },
       "wire_bytes": {
        "type": "integer",
        "description": "Estimated."
       },
       "elapsed_s": {
        "type": "number"
       },
       "offers": {
        "type": "integer"
       }
      }
     }
    }
   },
   "HostelworldRatePlan": {
    "type": "object",
    "required": [
     "rate_plan_id",
     "rate_plan_type",
     "payment_procedure",
     "payment_label",
     "is_default",
     "price",
     "original_price",
     "currency",
     "min_nights",
     "restrictions",
     "promotions",
     "provenance"
    ],
    "properties": {
     "rate_plan_id": {
      "type": "integer"
     },
     "rate_plan_type": {
      "type": "string"
     },
     "payment_procedure": {
      "type": "string"
     },
     "payment_label": {
      "type": "string"
     },
     "is_default": {
      "type": "boolean"
     },
     "price": {
      "type": [
       "number",
       "null"
      ]
     },
     "original_price": {
      "type": [
       "number",
       "null"
      ]
     },
     "currency": {
      "type": "string"
     },
     "min_nights": {
      "type": [
       "integer",
       "null"
      ]
     },
     "restrictions": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "promotions": {
      "anyOf": [
       {
        "type": "object",
        "required": [
         "discount",
         "promotion_ids"
        ],
        "properties": {
         "discount": {
          "type": "string",
          "description": "e.g. `20.00`"
         },
         "promotion_ids": {
          "type": "array",
          "items": {}
         }
        }
       },
       {
        "type": "null"
       }
      ]
     },
     "provenance": {
      "$ref": "#/components/schemas/RateProvenance"
     }
    }
   },
   "HostelworldRoom": {
    "type": "object",
    "required": [
     "room_id",
     "name",
     "room_type",
     "basic_type",
     "capacity",
     "ensuite",
     "description",
     "label_description",
     "beds_available",
     "rooms_available",
     "available",
     "rate_plans"
    ],
    "properties": {
     "room_id": {
      "type": "integer"
     },
     "name": {
      "type": "string"
     },
     "room_type": {
      "type": "string",
      "enum": [
       "dorm",
       "private"
      ]
     },
     "basic_type": {
      "type": "string"
     },
     "capacity": {
      "type": "integer"
     },
     "ensuite": {
      "type": "boolean"
     },
     "description": {
      "type": "string"
     },
     "label_description": {
      "type": "string"
     },
     "beds_available": {
      "type": [
       "integer",
       "null"
      ]
     },
     "rooms_available": {
      "type": [
       "integer",
       "null"
      ]
     },
     "available": {
      "type": "boolean"
     },
     "rate_plans": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/HostelworldRatePlan"
      }
     }
    }
   },
   "HostelworldResponse": {
    "type": "object",
    "description": "Response of `POST /v1/ota/hostelworld`.",
    "required": [
     "search_parameters",
     "property",
     "meta"
    ],
    "properties": {
     "search_parameters": {
      "type": "object",
      "required": [
       "engine",
       "property_id",
       "check_in_date",
       "check_out_date",
       "guests"
      ],
      "properties": {
       "engine": {
        "type": "string",
        "enum": [
         "hostelworld_property"
        ]
       },
       "property_id": {
        "type": "string"
       },
       "check_in_date": {
        "type": "string",
        "format": "date"
       },
       "check_out_date": {
        "type": "string",
        "format": "date"
       },
       "guests": {
        "type": "integer"
       }
      }
     },
     "property": {
      "type": "object",
      "required": [
       "property_id",
       "price_per_night",
       "currency",
       "sold_out",
       "deposit_percentage",
       "free_cancellation_available",
       "vat",
       "provenance",
       "rooms"
      ],
      "properties": {
       "property_id": {
        "type": "string"
       },
       "price_per_night": {
        "type": [
         "number",
         "null"
        ]
       },
       "currency": {
        "type": "string",
        "description": "The property's native currency."
       },
       "sold_out": {
        "type": "boolean"
       },
       "deposit_percentage": {
        "type": [
         "number",
         "null"
        ]
       },
       "free_cancellation_available": {
        "type": "boolean"
       },
       "vat": {
        "type": "number"
       },
       "provenance": {
        "anyOf": [
         {
          "$ref": "#/components/schemas/RateProvenance"
         },
         {
          "type": "null"
         }
        ],
        "description": "Provenance of the cheapest priced row; null when nothing priced."
       },
       "rooms": {
        "type": "array",
        "items": {
         "$ref": "#/components/schemas/HostelworldRoom"
        }
       }
      }
     },
     "meta": {
      "type": "object",
      "required": [
       "source",
       "collection_id",
       "observed_at",
       "nights",
       "wire_bytes",
       "elapsed_s",
       "dorms_count",
       "privates_count",
       "total_rate_plans",
       "comparable_across_markets",
       "notes"
      ],
      "properties": {
       "source": {
        "type": "string",
        "enum": [
         "hostelworld"
        ]
       },
       "collection_id": {
        "type": "string"
       },
       "observed_at": {
        "type": "string"
       },
       "nights": {
        "type": "integer"
       },
       "wire_bytes": {
        "type": "integer"
       },
       "elapsed_s": {
        "type": "number"
       },
       "dorms_count": {
        "type": "integer"
       },
       "privates_count": {
        "type": "integer"
       },
       "total_rate_plans": {
        "type": "integer"
       },
       "comparable_across_markets": {
        "type": "boolean",
        "description": "Always false."
       },
       "notes": {
        "type": "string"
       }
      }
     }
    }
   },
   "CompareResponse": {
    "type": "object",
    "description": "Response of `POST /v1/ota/compare`.",
    "required": [
     "search_parameters",
     "comparison",
     "sources",
     "meta"
    ],
    "properties": {
     "search_parameters": {
      "type": "object",
      "required": [
       "engine",
       "check_in_date",
       "check_out_date",
       "adults",
       "currency"
      ],
      "properties": {
       "engine": {
        "type": "string",
        "enum": [
         "ota_compare"
        ]
       },
       "check_in_date": {
        "type": "string",
        "format": "date"
       },
       "check_out_date": {
        "type": "string",
        "format": "date"
       },
       "adults": {
        "type": "integer"
       },
       "currency": {
        "type": "string",
        "description": "Requested currency; used by Booking.com and Agoda. Hotels.com and Expedia price in their market's currency."
       },
       "booking_pagename": {
        "type": "string",
        "description": "Present only when supplied."
       },
       "hotels_property_id": {
        "type": "string",
        "description": "Present only when supplied."
       },
       "agoda_property_id": {
        "type": "string",
        "description": "Present only when supplied."
       },
       "expedia_property_id": {
        "type": "string",
        "description": "Present only when supplied."
       }
      }
     },
     "comparison": {
      "type": "object",
      "required": [
       "status",
       "comparable",
       "reason",
       "identifiers",
       "lowest_price",
       "lowest_source",
       "spread",
       "prices",
       "currencies",
       "price_basis_consistent",
       "by_price_basis",
       "price_provenance"
      ],
      "properties": {
       "status": {
        "type": "string",
        "enum": [
         "no_prices",
         "single_source",
         "mixed_currency",
         "comparable"
        ]
       },
       "comparable": {
        "type": "boolean",
        "description": "True when at least two sources priced in one currency."
       },
       "reason": {
        "type": [
         "string",
         "null"
        ],
        "description": "Why the prices are not (fully) comparable. Null only when `status` is `comparable` and every price shares one basis; when bases differ it says the headline minimum mixes them."
       },
       "identifiers": {
        "type": "object",
        "description": "Echo of the identifiers used, keyed `booking` / `hotels` / `agoda` / `expedia` (supplied ones only).",
        "additionalProperties": {
         "type": "string"
        }
       },
       "lowest_price": {
        "type": [
         "number",
         "null"
        ],
        "description": "Null when nothing priced or currencies are mixed. May span different price bases; see `price_basis_consistent`."
       },
       "lowest_source": {
        "type": [
         "string",
         "null"
        ]
       },
       "spread": {
        "type": [
         "number",
         "null"
        ],
        "description": "Highest minus lowest price per night; non-null only when `comparable` is true."
       },
       "prices": {
        "type": "object",
        "description": "Source -> price per night (priced sources only).",
        "additionalProperties": {
         "type": "number"
        }
       },
       "currencies": {
        "type": "object",
        "description": "Source -> upper-case currency code (priced sources only).",
        "additionalProperties": {
         "type": "string"
        }
       },
       "price_basis_consistent": {
        "type": "boolean",
        "description": "True when every priced source shares one price basis (also true when at most one priced)."
       },
       "by_price_basis": {
        "type": "object",
        "description": "Priced sources grouped by price basis (keys as in `sources.<name>.price_basis`), so like is compared with like. Empty when nothing priced.",
        "additionalProperties": {
         "type": "object",
         "required": [
          "sources",
          "currencies",
          "lowest_source",
          "lowest_price_per_night"
         ],
         "properties": {
          "sources": {
           "type": "array",
           "items": {
            "type": "string"
           }
          },
          "currencies": {
           "type": "array",
           "items": {
            "type": "string"
           }
          },
          "lowest_source": {
           "type": [
            "string",
            "null"
           ],
           "description": "Null when the group mixes currencies."
          },
          "lowest_price_per_night": {
           "type": [
            "number",
            "null"
           ],
           "description": "Null when the group mixes currencies."
          }
         }
        }
       },
       "price_provenance": {
        "type": "object",
        "description": "Source -> provenance of the compared price (priced sources only).",
        "additionalProperties": {
         "$ref": "#/components/schemas/RateProvenance"
        }
       }
      }
     },
     "sources": {
      "type": "object",
      "description": "One entry per requested source (`booking`, `hotels`, `agoda`, `expedia`). Fail-soft: a failed source is an entry with `status: error`, not a failed request.",
      "additionalProperties": {
       "anyOf": [
        {
         "type": "object",
         "required": [
          "status",
          "price_per_night",
          "currency",
          "price_basis",
          "payload"
         ],
         "properties": {
          "status": {
           "type": "string",
           "enum": [
            "ok"
           ]
          },
          "price_per_night": {
           "type": "number",
           "description": "Expedia: its headline stay total divided by nights (its nightly figure is before taxes)."
          },
          "currency": {
           "type": "string"
          },
          "price_basis": {
           "type": "string",
           "description": "Basis of `price_per_night`. Expedia: `total_including_taxes_and_fees`, `total_fees_included` or `stay_total_per_night`, from its own labels; other sources: `provenance.price_basis` of the compared price; `unknown` when not stated."
          },
          "payload": {
           "description": "The full response of that source's endpoint (Expedia's is the headline-only form, with empty `rooms`).",
           "anyOf": [
            {
             "$ref": "#/components/schemas/BookingCalendarResponse"
            },
            {
             "$ref": "#/components/schemas/HotelsPriceResponse"
            },
            {
             "$ref": "#/components/schemas/AgodaRoomsResponse"
            },
            {
             "$ref": "#/components/schemas/ExpediaRatesResponse"
            }
           ]
          }
         }
        },
        {
         "type": "object",
         "required": [
          "status",
          "price_per_night",
          "currency",
          "payload"
         ],
         "properties": {
          "status": {
           "type": "string",
           "description": "The source answered but returned no price (sold out or unpriced).",
           "enum": [
            "no_price"
           ]
          },
          "price_per_night": {
           "type": "null"
          },
          "currency": {
           "type": "string"
          },
          "payload": {
           "description": "The full response of that source's endpoint.",
           "anyOf": [
            {
             "$ref": "#/components/schemas/BookingCalendarResponse"
            },
            {
             "$ref": "#/components/schemas/HotelsPriceResponse"
            },
            {
             "$ref": "#/components/schemas/AgodaRoomsResponse"
            },
            {
             "$ref": "#/components/schemas/ExpediaRatesResponse"
            }
           ]
          }
         }
        },
        {
         "type": "object",
         "required": [
          "status",
          "error"
         ],
         "properties": {
          "status": {
           "type": "string",
           "enum": [
            "error"
           ]
          },
          "error": {
           "type": "string",
           "description": "`ExceptionName: message`."
          }
         }
        }
       ]
      }
     },
     "meta": {
      "type": "object",
      "required": [
       "requested",
       "ok",
       "elapsed_s"
      ],
      "properties": {
       "requested": {
        "type": "integer"
       },
       "ok": {
        "type": "integer",
        "description": "Sources that returned a price."
       },
       "elapsed_s": {
        "type": "number"
       }
      }
     }
    }
   },
   "OtaSourceCapability": {
    "type": "object",
    "required": [
     "engine",
     "primary_operation",
     "identifier",
     "granularity",
     "multi_date",
     "max_dates_per_call",
     "per_room",
     "currency_selectable",
     "needs_browser_token",
     "operations",
     "notes",
     "available"
    ],
    "properties": {
     "engine": {
      "type": "string"
     },
     "primary_operation": {
      "type": "string"
     },
     "identifier": {
      "type": "string"
     },
     "granularity": {
      "type": "string"
     },
     "multi_date": {
      "type": "boolean"
     },
     "max_dates_per_call": {
      "type": "integer"
     },
     "per_room": {
      "type": "boolean"
     },
     "currency_selectable": {
      "type": "boolean"
     },
     "needs_browser_token": {
      "type": "boolean"
     },
     "operations": {
      "type": "object",
      "required": [
       "search",
       "rates",
       "rooms",
       "calendar"
      ],
      "properties": {
       "search": {
        "type": "object",
        "required": [
         "supported",
         "needs_browser_token",
         "available"
        ],
        "properties": {
         "supported": {
          "type": "boolean"
         },
         "needs_browser_token": {
          "type": "boolean"
         },
         "available": {
          "type": "boolean"
         },
         "unavailable_reason": {
          "type": "string",
          "description": "Present only when `available` is false."
         }
        }
       },
       "rates": {
        "type": "object",
        "required": [
         "supported",
         "needs_browser_token",
         "available"
        ],
        "properties": {
         "supported": {
          "type": "boolean"
         },
         "needs_browser_token": {
          "type": "boolean"
         },
         "available": {
          "type": "boolean"
         },
         "unavailable_reason": {
          "type": "string",
          "description": "Present only when `available` is false."
         }
        }
       },
       "rooms": {
        "type": "object",
        "required": [
         "supported",
         "needs_browser_token",
         "available"
        ],
        "properties": {
         "supported": {
          "type": "boolean"
         },
         "needs_browser_token": {
          "type": "boolean"
         },
         "available": {
          "type": "boolean"
         },
         "unavailable_reason": {
          "type": "string",
          "description": "Present only when `available` is false."
         }
        }
       },
       "calendar": {
        "type": "object",
        "required": [
         "supported",
         "needs_browser_token",
         "available"
        ],
        "properties": {
         "supported": {
          "type": "boolean"
         },
         "needs_browser_token": {
          "type": "boolean"
         },
         "available": {
          "type": "boolean"
         },
         "unavailable_reason": {
          "type": "string",
          "description": "Present only when `available` is false."
         }
        }
       }
      }
     },
     "notes": {
      "type": "string"
     },
     "available": {
      "type": "boolean"
     },
     "unavailable_reason": {
      "type": "string",
      "description": "Present only when `available` is false."
     },
     "currency_mechanism": {
      "type": "string",
      "description": "`point-of-sale`: currency follows the market. Hotels.com, Expedia and Vrbo only."
     },
     "markets": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Supported point-of-sale codes. Hotels.com, Expedia and Vrbo only."
     },
     "currencies": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Selectable currencies. Agoda, Tripadvisor and Hostelworld only (empty for Hostelworld)."
     }
    }
   },
   "OtaSourcesResponse": {
    "type": "object",
    "required": [
     "sources"
    ],
    "properties": {
     "sources": {
      "type": "object",
      "required": [
       "booking",
       "hotels",
       "agoda",
       "tripadvisor",
       "hostelworld",
       "expedia",
       "vrbo"
      ],
      "properties": {
       "booking": {
        "$ref": "#/components/schemas/OtaSourceCapability"
       },
       "hotels": {
        "$ref": "#/components/schemas/OtaSourceCapability"
       },
       "agoda": {
        "$ref": "#/components/schemas/OtaSourceCapability"
       },
       "tripadvisor": {
        "$ref": "#/components/schemas/OtaSourceCapability"
       },
       "hostelworld": {
        "$ref": "#/components/schemas/OtaSourceCapability"
       },
       "expedia": {
        "$ref": "#/components/schemas/OtaSourceCapability"
       },
       "vrbo": {
        "$ref": "#/components/schemas/OtaSourceCapability"
       }
      }
     }
    }
   },
   "OfficialEnginesResponse": {
    "type": "object",
    "description": "Response of `GET /v1/official/engines`.",
    "required": [
     "extractable",
     "identified_only",
     "retired"
    ],
    "properties": {
     "extractable": {
      "type": "object",
      "description": "Booking engines rates can be extracted from, keyed by engine id (31 today).",
      "additionalProperties": {
       "type": "object",
       "required": [
        "cost_s",
        "browser"
       ],
       "properties": {
        "cost_s": {
         "type": "number",
         "description": "Typical seconds per query."
        },
        "browser": {
         "type": [
          "string",
          "null"
         ],
         "description": "When a headless browser is needed: `every query`, `once per session`, `once per token (hours)`, or null when never."
        }
       }
      }
     },
     "identified_only": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Engines that are detected but not yet extractable."
     },
     "retired": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Historical engines with no live booking flow."
     }
    }
   },
   "OfficialRate": {
    "type": "object",
    "required": [
     "price",
     "price_total",
     "reference_price",
     "tax",
     "fees",
     "original_price",
     "currency",
     "rate_plan",
     "tax_inclusive",
     "access_type",
     "loyalty_points",
     "loyalty_cash",
     "is_discounted",
     "provenance"
    ],
    "properties": {
     "price": {
      "type": [
       "number",
       "null"
      ],
      "description": "Headline price for the stay on the engine's own basis."
     },
     "price_total": {
      "type": [
       "number",
       "null"
      ]
     },
     "reference_price": {
      "type": [
       "number",
       "null"
      ]
     },
     "tax": {
      "type": [
       "number",
       "null"
      ]
     },
     "fees": {
      "type": [
       "number",
       "null"
      ]
     },
     "original_price": {
      "type": [
       "number",
       "null"
      ]
     },
     "currency": {
      "type": "string"
     },
     "rate_plan": {
      "type": "string"
     },
     "tax_inclusive": {
      "type": [
       "boolean",
       "null"
      ],
      "description": "Null means the engine did not state a basis, not that tax is excluded."
     },
     "access_type": {
      "type": "string",
      "description": "`public`, `member`, `points_and_cash` or `points`."
     },
     "loyalty_points": {
      "type": [
       "integer",
       "null"
      ]
     },
     "loyalty_cash": {
      "type": [
       "number",
       "null"
      ]
     },
     "is_discounted": {
      "type": "boolean"
     },
     "provenance": {
      "$ref": "#/components/schemas/RateProvenance"
     }
    }
   },
   "OfficialRoom": {
    "type": "object",
    "required": [
     "name",
     "code",
     "max_occupancy",
     "quantity",
     "available",
     "cheapest_rate",
     "rates"
    ],
    "properties": {
     "name": {
      "type": "string"
     },
     "code": {
      "type": "string"
     },
     "max_occupancy": {
      "type": [
       "integer",
       "null"
      ]
     },
     "quantity": {
      "type": [
       "integer",
       "null"
      ]
     },
     "available": {
      "type": "boolean"
     },
     "cheapest_rate": {
      "type": [
       "number",
       "null"
      ],
      "description": "Cheapest PUBLIC rate in `rates`."
     },
     "rates": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/OfficialRate"
      }
     }
    }
   },
   "OfficialResponse": {
    "type": "object",
    "description": "Response of `POST /v1/official`.",
    "required": [
     "search_parameters",
     "engine",
     "source_url",
     "booking_url",
     "detected_by",
     "discovery_pages",
     "wrapper_resolutions",
     "discovery_cache_hit",
     "discovery_elapsed_s",
     "collection_id",
     "observed_at",
     "property_ref",
     "check_in",
     "check_out",
     "nights",
     "currency",
     "sold_out",
     "cheapest_rate",
     "cheapest_member_rate",
     "member_rates_returned",
     "rooms_returned",
     "used_browser",
     "elapsed_s",
     "rooms"
    ],
    "properties": {
     "search_parameters": {
      "type": "object",
      "required": [
       "engine",
       "source_url",
       "booking_url",
       "check_in_date",
       "check_out_date",
       "adults",
       "currency"
      ],
      "properties": {
       "engine": {
        "type": "string",
        "description": "`official_` + engine id."
       },
       "source_url": {
        "type": "string"
       },
       "booking_url": {
        "type": "string"
       },
       "check_in_date": {
        "type": "string",
        "format": "date"
       },
       "check_out_date": {
        "type": "string",
        "format": "date"
       },
       "adults": {
        "type": "integer"
       },
       "currency": {
        "type": "string"
       }
      }
     },
     "engine": {
      "type": "string",
      "description": "Detected engine id."
     },
     "source_url": {
      "type": "string"
     },
     "booking_url": {
      "type": "string"
     },
     "detected_by": {
      "type": "string",
      "description": "How the engine was detected, e.g. `url`, `redirect`, `booking_link`, `html_fingerprint`."
     },
     "discovery_pages": {
      "type": "integer"
     },
     "wrapper_resolutions": {
      "type": "integer"
     },
     "discovery_cache_hit": {
      "type": "boolean"
     },
     "discovery_elapsed_s": {
      "type": "number"
     },
     "collection_id": {
      "type": "string"
     },
     "observed_at": {
      "type": "string"
     },
     "property_ref": {
      "type": "string",
      "description": "Engine-native property id (may be empty)."
     },
     "check_in": {
      "type": "string",
      "format": "date"
     },
     "check_out": {
      "type": "string",
      "format": "date"
     },
     "nights": {
      "type": "integer"
     },
     "currency": {
      "type": "string"
     },
     "sold_out": {
      "type": "boolean"
     },
     "cheapest_rate": {
      "type": [
       "number",
       "null"
      ],
      "description": "Cheapest public rate across available rooms."
     },
     "cheapest_member_rate": {
      "type": [
       "number",
       "null"
      ]
     },
     "member_rates_returned": {
      "type": "integer"
     },
     "rooms_returned": {
      "type": "integer"
     },
     "used_browser": {
      "type": "boolean"
     },
     "elapsed_s": {
      "type": "number"
     },
     "rooms": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/OfficialRoom"
      }
     }
    }
   },
   "AirbnbPrice": {
    "type": "object",
    "required": [
     "total_price",
     "extracted_total_price",
     "provenance"
    ],
    "properties": {
     "total_price": {
      "type": "string",
      "description": "As displayed."
     },
     "extracted_total_price": {
      "type": [
       "number",
       "null"
      ]
     },
     "qualifier": {
      "type": "string",
      "description": "e.g. `for 2 nights`"
     },
     "extracted_qualifier": {
      "type": "integer"
     },
     "price_per_qualifier": {
      "type": "string"
     },
     "extracted_price_per_qualifier": {
      "type": [
       "number",
       "null"
      ]
     },
     "original_price": {
      "type": "string"
     },
     "extracted_original_price": {
      "type": "number"
     },
     "discount": {
      "type": "string"
     },
     "extracted_discount": {
      "type": "number"
     },
     "breakdown": {
      "type": "array",
      "items": {
       "type": "object",
       "required": [
        "description",
        "price",
        "extracted_price"
       ],
       "properties": {
        "description": {
         "type": "string"
        },
        "price": {
         "type": "string"
        },
        "extracted_price": {
         "type": [
          "number",
          "null"
         ]
        }
       }
      }
     },
     "total_with_taxes": {
      "type": "string",
      "description": "Only with `include_taxes` and a tax line."
     },
     "extracted_total_with_taxes": {
      "type": [
       "number",
       "null"
      ]
     },
     "provenance": {
      "$ref": "#/components/schemas/RateProvenance"
     }
    }
   },
   "AirbnbProperty": {
    "type": "object",
    "description": "One listing. Keys whose value would be null are omitted.",
    "required": [
     "position",
     "id",
     "link",
     "booking_link",
     "booking_token"
    ],
    "properties": {
     "position": {
      "type": "integer"
     },
     "id": {
      "type": "string"
     },
     "title": {
      "type": "string"
     },
     "description": {
      "type": "string"
     },
     "link": {
      "type": "string"
     },
     "booking_link": {
      "type": "string"
     },
     "booking_token": {
      "type": "string"
     },
     "rating": {
      "type": "number"
     },
     "reviews": {
      "type": "integer"
     },
     "price": {
      "$ref": "#/components/schemas/AirbnbPrice"
     },
     "check_in_date": {
      "type": "string"
     },
     "check_out_date": {
      "type": "string"
     },
     "time_period": {
      "type": "string"
     },
     "accommodations": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "gps_coordinates": {
      "type": "object",
      "required": [
       "latitude",
       "longitude"
      ],
      "properties": {
       "latitude": {
        "type": "number"
       },
       "longitude": {
        "type": "number"
       }
      }
     },
     "has_free_cancellation": {
      "type": "boolean",
      "description": "Only present (as true) when advertised."
     },
     "badges": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "images": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "distance": {
      "type": "string"
     },
     "extracted_distance": {
      "type": "number"
     }
    }
   },
   "AirbnbSearchResponse": {
    "type": "object",
    "description": "SearchAPI-compatible Airbnb search response.",
    "required": [
     "search_metadata",
     "search_parameters",
     "search_information",
     "properties"
    ],
    "properties": {
     "search_metadata": {
      "type": "object",
      "required": [
       "id",
       "status",
       "created_at",
       "collection_id",
       "observed_at",
       "request_time_taken",
       "parsing_time_taken",
       "total_time_taken",
       "request_url",
       "wire_bytes"
      ],
      "properties": {
       "id": {
        "type": "string"
       },
       "status": {
        "type": "string"
       },
       "created_at": {
        "type": "string"
       },
       "collection_id": {
        "type": "string"
       },
       "observed_at": {
        "type": "string"
       },
       "request_time_taken": {
        "type": "number"
       },
       "parsing_time_taken": {
        "type": "number"
       },
       "total_time_taken": {
        "type": "number"
       },
       "request_url": {
        "type": "string"
       },
       "wire_bytes": {
        "type": "integer"
       }
      }
     },
     "search_parameters": {
      "type": "object",
      "required": [
       "engine",
       "airbnb_domain"
      ],
      "description": "Echo of the effective request. Every value is a string; parameters that were not set are omitted.",
      "properties": {
       "engine": {
        "type": "string",
        "enum": [
         "airbnb"
        ]
       },
       "airbnb_domain": {
        "type": "string"
       }
      },
      "additionalProperties": {
       "type": "string"
      }
     },
     "search_information": {
      "type": "object",
      "required": [
       "query_displayed",
       "results",
       "guests"
      ],
      "properties": {
       "query_displayed": {
        "type": "string"
       },
       "results": {
        "type": "string"
       },
       "check_in_date": {
        "type": "string"
       },
       "check_out_date": {
        "type": "string"
       },
       "time_period": {
        "type": "string"
       },
       "adults": {
        "type": "integer"
       },
       "children": {
        "type": "integer"
       },
       "infants": {
        "type": "integer"
       },
       "pets": {
        "type": "integer"
       },
       "guests": {
        "type": "string",
        "description": "e.g. `2 guests` or `Add guests`."
       }
      }
     },
     "properties": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/AirbnbProperty"
      }
     },
     "pagination": {
      "type": "object",
      "description": "Present only when another page exists.",
      "required": [
       "next_page_token"
      ],
      "properties": {
       "next_page_token": {
        "type": "string"
       }
      }
     }
    }
   },
   "SerpMoney": {
    "type": "object",
    "required": [
     "extracted_price_before_taxes",
     "currency"
    ],
    "properties": {
     "price": {
      "type": "string",
      "description": "Display string, e.g. `$2,907`. Omitted when unknown."
     },
     "extracted_price": {
      "type": "number",
      "description": "Omitted when unknown."
     },
     "extracted_price_before_taxes": {
      "type": [
       "number",
       "null"
      ]
     },
     "currency": {
      "type": "string"
     }
    }
   },
   "SerpOfferRoom": {
    "type": "object",
    "required": [
     "name",
     "link",
     "num_guests",
     "price_per_night",
     "total_price",
     "is_suite",
     "beds",
     "free_cancellation_until",
     "thumbnail",
     "provenance"
    ],
    "properties": {
     "name": {
      "type": "string"
     },
     "link": {
      "type": [
       "string",
       "null"
      ]
     },
     "num_guests": {
      "type": "integer"
     },
     "price_per_night": {
      "$ref": "#/components/schemas/SerpMoney"
     },
     "total_price": {
      "$ref": "#/components/schemas/SerpMoney"
     },
     "is_suite": {
      "type": "boolean"
     },
     "beds": {
      "type": [
       "integer",
       "null"
      ]
     },
     "free_cancellation_until": {
      "type": [
       "string",
       "null"
      ]
     },
     "thumbnail": {
      "type": [
       "string",
       "null"
      ]
     },
     "provenance": {
      "$ref": "#/components/schemas/RateProvenance"
     }
    }
   },
   "SerpOffer": {
    "type": "object",
    "required": [
     "source",
     "raw_source",
     "is_official",
     "num_guests",
     "room_id",
     "price_per_night",
     "total_price",
     "tax_basis",
     "is_outlier",
     "rooms",
     "is_featured",
     "has_free_cancellation",
     "free_cancellation_until",
     "free_cancellation_time",
     "price_derived_from_room",
     "headline_price_total",
     "headline_price_before_taxes",
     "provenance"
    ],
    "properties": {
     "source": {
      "type": "string",
      "description": "Seller label (official offers use the hotel's rendered name)."
     },
     "raw_source": {
      "type": "string"
     },
     "is_official": {
      "type": "boolean"
     },
     "num_guests": {
      "type": "integer"
     },
     "room_id": {
      "type": [
       "string",
       "null"
      ]
     },
     "price_per_night": {
      "$ref": "#/components/schemas/SerpMoney"
     },
     "total_price": {
      "$ref": "#/components/schemas/SerpMoney"
     },
     "tax_basis": {
      "type": "string",
      "enum": [
       "deeplink",
       "derived",
       "unknown"
      ]
     },
     "is_outlier": {
      "type": "boolean"
     },
     "rooms": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/SerpOfferRoom"
      }
     },
     "is_featured": {
      "type": "boolean"
     },
     "has_free_cancellation": {
      "type": "boolean"
     },
     "free_cancellation_until": {
      "type": [
       "string",
       "null"
      ]
     },
     "free_cancellation_time": {
      "type": [
       "string",
       "null"
      ]
     },
     "price_derived_from_room": {
      "type": "boolean"
     },
     "headline_price_total": {
      "type": [
       "number",
       "null"
      ]
     },
     "headline_price_before_taxes": {
      "type": [
       "number",
       "null"
      ]
     },
     "provenance": {
      "$ref": "#/components/schemas/RateProvenance"
     }
    }
   },
   "SerpPropertyResponse": {
    "type": "object",
    "description": "SearchAPI-compatible `google_hotels_property` response.",
    "required": [
     "search_parameters",
     "property",
     "meta"
    ],
    "properties": {
     "search_parameters": {
      "type": "object",
      "required": [
       "engine",
       "property_token",
       "check_in_date",
       "check_out_date",
       "adults",
       "currency",
       "gl",
       "nights"
      ],
      "properties": {
       "engine": {
        "type": "string",
        "enum": [
         "google_hotels_property"
        ]
       },
       "property_token": {
        "type": "string"
       },
       "check_in_date": {
        "type": "string",
        "format": "date"
       },
       "check_out_date": {
        "type": "string",
        "format": "date"
       },
       "adults": {
        "type": "integer"
       },
       "currency": {
        "type": "string"
       },
       "gl": {
        "type": "string"
       },
       "nights": {
        "type": "integer"
       },
       "sources": {
        "type": "array",
        "items": {
         "type": "string"
        },
        "description": "Present only when `sources` was requested."
       },
       "source_coverage": {
        "type": "string",
        "description": "Present only when `sources` was requested."
       }
      }
     },
     "property": {
      "type": "object",
      "required": [
       "property_token",
       "name",
       "hotel_class",
       "hotel_class_stars",
       "rating",
       "reviews",
       "deal",
       "deal_description",
       "has_deal",
       "price_insights",
       "all_offers",
       "featured_offers",
       "price_per_night",
       "provenance",
       "currency_verified",
       "requested_market",
       "egress_market",
       "egress_geo_locked_ok",
       "price_insights_market_verified",
       "tax_profile"
      ],
      "properties": {
       "property_token": {
        "type": "string"
       },
       "name": {
        "type": "string"
       },
       "hotel_class": {
        "type": "string"
       },
       "hotel_class_stars": {
        "type": [
         "integer",
         "null"
        ]
       },
       "rating": {
        "type": [
         "number",
         "null"
        ]
       },
       "reviews": {
        "type": [
         "integer",
         "null"
        ]
       },
       "deal": {
        "type": [
         "string",
         "null"
        ]
       },
       "deal_description": {
        "type": [
         "string",
         "null"
        ]
       },
       "has_deal": {
        "type": "boolean"
       },
       "price_insights": {
        "$ref": "#/components/schemas/PriceInsights"
       },
       "all_offers": {
        "type": "array",
        "items": {
         "$ref": "#/components/schemas/SerpOffer"
        }
       },
       "featured_offers": {
        "type": "array",
        "items": {
         "$ref": "#/components/schemas/SerpOffer"
        },
        "description": "Offers Google rendered as featured cards."
       },
       "price_per_night": {
        "anyOf": [
         {
          "type": "object",
          "required": [
           "price",
           "extracted_price"
          ],
          "properties": {
           "price": {
            "type": "string"
           },
           "extracted_price": {
            "type": "number"
           }
          }
         },
         {
          "type": "null"
         }
        ],
        "description": "Lowest all-in nightly price across offers."
       },
       "provenance": {
        "anyOf": [
         {
          "$ref": "#/components/schemas/RateProvenance"
         },
         {
          "type": "null"
         }
        ],
        "description": "Provenance of the lowest-priced offer."
       },
       "currency_verified": {
        "type": "boolean"
       },
       "requested_market": {
        "type": "string"
       },
       "egress_market": {
        "type": [
         "string",
         "null"
        ]
       },
       "egress_geo_locked_ok": {
        "type": "boolean"
       },
       "price_insights_market_verified": {
        "type": "boolean"
       },
       "tax_profile": {
        "anyOf": [
         {
          "type": "object",
          "required": [
           "rate",
           "confidence"
          ],
          "properties": {
           "rate": {
            "type": "number"
           },
           "confidence": {
            "type": "string",
            "enum": [
             "high",
             "low",
             "none"
            ]
           }
          }
         },
         {
          "type": "null"
         }
        ]
       }
      }
     },
     "meta": {
      "type": "object",
      "required": [
       "wire_bytes",
       "elapsed_s",
       "offers",
       "priced",
       "property_fetch",
       "tax_profile_cache"
      ],
      "properties": {
       "wire_bytes": {
        "type": "integer"
       },
       "elapsed_s": {
        "type": "number"
       },
       "offers": {
        "type": "integer"
       },
       "priced": {
        "type": "integer"
       },
       "property_fetch": {
        "type": "string"
       },
       "tax_profile_cache": {
        "type": "string"
       }
      }
     }
    }
   },
   "SerpCalendarDay": {
    "type": "object",
    "required": [
     "date",
     "price",
     "extracted_price_before_taxes",
     "extracted_price_base",
     "extracted_price_total",
     "tax",
     "fees",
     "currency",
     "rates_include_tax",
     "provenance"
    ],
    "properties": {
     "date": {
      "type": "string",
      "format": "date"
     },
     "price": {
      "type": "object",
      "description": "The market-correct nightly figure (same as `rate` on `/v1/calendar`).",
      "required": [
       "price",
       "extracted_price"
      ],
      "properties": {
       "price": {
        "type": "string"
       },
       "extracted_price": {
        "type": "number"
       }
      }
     },
     "extracted_price_before_taxes": {
      "type": [
       "number",
       "null"
      ],
      "description": "Base + mandatory fees (SearchAPI basis)."
     },
     "extracted_price_base": {
      "type": [
       "number",
       "null"
      ]
     },
     "extracted_price_total": {
      "type": [
       "number",
       "null"
      ]
     },
     "tax": {
      "type": [
       "number",
       "null"
      ]
     },
     "fees": {
      "type": [
       "number",
       "null"
      ]
     },
     "currency": {
      "type": "string"
     },
     "rates_include_tax": {
      "type": "boolean"
     },
     "provenance": {
      "$ref": "#/components/schemas/CalendarRateProvenance"
     }
    }
   },
   "SerpCalendarResponse": {
    "type": "object",
    "description": "Response of `POST /v1/serp/google_hotels_calendar`.",
    "required": [
     "search_parameters",
     "calendar",
     "unavailable_dates",
     "tax_profile",
     "meta"
    ],
    "properties": {
     "search_parameters": {
      "type": "object",
      "required": [
       "engine",
       "property_token",
       "days",
       "adults",
       "currency",
       "gl",
       "los"
      ],
      "properties": {
       "engine": {
        "type": "string",
        "enum": [
         "google_hotels_calendar"
        ]
       },
       "property_token": {
        "type": "string"
       },
       "days": {
        "type": "integer"
       },
       "adults": {
        "type": "integer"
       },
       "currency": {
        "type": "string"
       },
       "gl": {
        "type": "string"
       },
       "los": {
        "type": "integer"
       }
      }
     },
     "calendar": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/SerpCalendarDay"
      },
      "description": "One row per priced night."
     },
     "unavailable_dates": {
      "type": "array",
      "items": {
       "type": "string",
       "format": "date"
      }
     },
     "tax_profile": {
      "anyOf": [
       {
        "type": "object",
        "required": [
         "rate",
         "confidence"
        ],
        "properties": {
         "rate": {
          "type": "number"
         },
         "confidence": {
          "type": "string",
          "enum": [
           "high",
           "low",
           "none"
          ]
         }
        }
       },
       {
        "type": "null"
       }
      ]
     },
     "meta": {
      "type": "object",
      "required": [
       "coverage",
       "collection_id",
       "observed_at",
       "wire_bytes",
       "elapsed_s",
       "retries"
      ],
      "properties": {
       "coverage": {
        "type": "number",
        "description": "Share of requested nights priced, 0-1."
       },
       "collection_id": {
        "type": "string"
       },
       "observed_at": {
        "type": "string"
       },
       "wire_bytes": {
        "type": "integer"
       },
       "elapsed_s": {
        "type": "number"
       },
       "retries": {
        "type": "integer"
       }
      }
     }
    }
   },
   "FlightSegment": {
    "type": "object",
    "description": "One flight: a single takeoff and landing.",
    "required": [
     "departure_airport",
     "arrival_airport",
     "departure_time",
     "arrival_time",
     "airline",
     "airline_code",
     "flight_number",
     "duration_minutes",
     "aircraft",
     "cabin_class",
     "departure_airport_name",
     "arrival_airport_name",
     "operated_by",
     "ticket_also_sold_by",
     "legroom",
     "legroom_category",
     "overnight",
     "red_eye",
     "often_delayed_by_over_30_min",
     "carbon_emissions_kg",
     "extensions",
     "airline_logo"
    ],
    "properties": {
     "departure_airport": {
      "type": "string",
      "description": "IATA code."
     },
     "arrival_airport": {
      "type": "string",
      "description": "IATA code."
     },
     "departure_time": {
      "type": [
       "string",
       "null"
      ],
      "description": "Airport-local wall-clock time as Google shows it, ISO 8601 without a UTC offset, e.g. `2026-11-04T18:10:00`. Null when unknown."
     },
     "arrival_time": {
      "type": [
       "string",
       "null"
      ],
      "description": "Airport-local wall-clock time as Google shows it, ISO 8601 without a UTC offset, e.g. `2026-11-04T18:10:00`. Null when unknown."
     },
     "airline": {
      "type": "string",
      "description": "Marketing airline name (empty string when Google gives none)."
     },
     "airline_code": {
      "type": [
       "string",
       "null"
      ],
      "description": "IATA code of the marketing airline."
     },
     "flight_number": {
      "type": [
       "string",
       "null"
      ],
      "description": "Marketing carrier and number, e.g. `AC 874`."
     },
     "duration_minutes": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Flight time, minutes."
     },
     "aircraft": {
      "type": [
       "string",
       "null"
      ],
      "description": "e.g. `Airbus A330`."
     },
     "cabin_class": {
      "type": [
       "string",
       "null"
      ],
      "enum": [
       "economy",
       "premium_economy",
       "business",
       "first",
       null
      ]
     },
     "departure_airport_name": {
      "type": [
       "string",
       "null"
      ]
     },
     "arrival_airport_name": {
      "type": [
       "string",
       "null"
      ]
     },
     "operated_by": {
      "type": [
       "string",
       "null"
      ],
      "description": "The airline actually flying it when Google names one other than the marketing carrier, e.g. `Endeavor Air DBA Delta Connection`."
     },
     "ticket_also_sold_by": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Codeshare flight numbers the same flight is also sold under, e.g. `LH 6809`."
     },
     "legroom": {
      "type": [
       "string",
       "null"
      ],
      "description": "Seat pitch as Google shows it, e.g. `31 in`."
     },
     "legroom_category": {
      "type": [
       "string",
       "null"
      ],
      "enum": [
       "average",
       "below_average",
       "above_average",
       null
      ]
     },
     "overnight": {
      "type": "boolean",
      "description": "Lands on a later calendar day than it departs (local times)."
     },
     "red_eye": {
      "type": "boolean",
      "description": "Heuristic: departs 20:00-02:59 and lands 04:00-10:59 after the night (local times). `overnight` is exact; this is not."
     },
     "often_delayed_by_over_30_min": {
      "type": "boolean",
      "description": "Google's flag that this flight is often delayed by more than 30 minutes."
     },
     "carbon_emissions_kg": {
      "type": [
       "integer",
       "null"
      ],
      "description": "CO2e estimate for this flight, kilograms (rounded)."
     },
     "extensions": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Google's amenity lines, e.g. `Average legroom (31 in)`, `Free Wi-Fi`, `Wi-Fi for a fee`, `In-seat power & USB outlets`, `Live TV`, `On-demand video`, `Stream media to your device`, `Carbon emissions estimate: 325 kg`."
     },
     "airline_logo": {
      "type": [
       "string",
       "null"
      ],
      "description": "Logo URL of the marketing airline."
     }
    }
   },
   "FlightLeg": {
    "type": "object",
    "description": "One direction of travel, possibly with connections.",
    "required": [
     "segments",
     "departure_airport",
     "arrival_airport",
     "duration_minutes",
     "stops",
     "layover_airports",
     "is_direct",
     "layovers",
     "airlines"
    ],
    "properties": {
     "segments": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/FlightSegment"
      },
      "description": "Flights in order."
     },
     "departure_airport": {
      "type": "string",
      "description": "IATA code."
     },
     "arrival_airport": {
      "type": "string",
      "description": "IATA code."
     },
     "departure_time": {
      "type": "string",
      "description": "Airport-local wall-clock time as Google shows it, ISO 8601 without a UTC offset, e.g. `2026-11-04T18:10:00`. Present only when known."
     },
     "arrival_time": {
      "type": "string",
      "description": "Airport-local wall-clock time as Google shows it, ISO 8601 without a UTC offset, e.g. `2026-11-04T18:10:00`. Present only when known."
     },
     "duration_minutes": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Door-to-door travel time including layovers, minutes."
     },
     "stops": {
      "type": "integer"
     },
     "layover_airports": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "IATA codes of the connection airports."
     },
     "is_direct": {
      "type": "boolean",
      "description": "`stops` is 0."
     },
     "layovers": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/FlightLayover"
      }
     },
     "airlines": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Airline names Google lists for this leg."
     }
    }
   },
   "FlightItinerary": {
    "type": "object",
    "description": "One option for the leg being chosen. A one-way option is the whole trip; on a round trip or multi-city trip each option is priced for the whole trip and carries `departure_token` (more legs to choose) or `booking_token` (last leg).",
    "required": [
     "legs",
     "price",
     "currency",
     "display_price",
     "booking_token",
     "booking_url",
     "carbon_emissions_kg",
     "carbon_emissions_comparison",
     "trip_type",
     "total_stops",
     "is_direct",
     "departure_token",
     "google_flights_url",
     "group",
     "price_exact",
     "price_token",
     "priced_in",
     "carbon_emissions",
     "total_duration_minutes",
     "carry_on_bags_included",
     "checked_bags_included",
     "airline_logo"
    ],
    "properties": {
     "legs": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/FlightLeg"
      },
      "description": "The leg chosen in this call (one entry). Earlier legs are not repeated; `/v1/serp/google_flights_booking` returns every leg."
     },
     "price": {
      "type": [
       "number",
       "null"
      ],
      "description": "Google's displayed whole amount for the whole trip (every leg, all passengers), in `currency`. Google rounds up (527 where the exact fare is 526.19; see `price_exact`). When `priced_in` is set, the amount is in that currency instead."
     },
     "currency": {
      "type": "string",
      "description": "The requested currency."
     },
     "display_price": {
      "type": [
       "string",
       "null"
      ],
      "description": "`price` with its currency symbol, e.g. `$527`. Null when `price` is null or `priced_in` is set."
     },
     "booking_token": {
      "type": [
       "string",
       "null"
      ],
      "description": "Pass to `POST /v1/serp/google_flights_booking` for sellers, prices and booking links. Set only on complete itineraries (one-way options, and the options of a trip's last leg); null when `departure_token` is set. Compatibility: until 2026-09-30 this field held Google's raw price token on every itinerary; that value is now `price_token`."
     },
     "booking_url": {
      "type": [
       "string",
       "null"
      ],
      "description": "Google Flights booking page for the complete itinerary. Set together with `booking_token`."
     },
     "carbon_emissions_kg": {
      "type": [
       "integer",
       "null"
      ],
      "description": "CO2e estimate for this itinerary, kilograms (rounded). `carbon_emissions` has the same figure in grams."
     },
     "carbon_emissions_comparison": {
      "type": [
       "string",
       "null"
      ],
      "description": "e.g. `19% lower than typical` or `typical for this route`."
     },
     "trip_type": {
      "type": "string",
      "description": "`one_way`, `round_trip` or `multi_city`.",
      "enum": [
       "one_way",
       "round_trip",
       "multi_city"
      ]
     },
     "total_stops": {
      "type": "integer",
      "description": "Stops across `legs`."
     },
     "is_direct": {
      "type": "boolean",
      "description": "`total_stops` is 0."
     },
     "departure_token": {
      "type": [
       "string",
       "null"
      ],
      "description": "Pass to `POST /v1/serp/google_flights_return` for the next leg's options after choosing this one. Set while legs remain to choose (round-trip outbound, multi-city legs before the last); null when `booking_token` is set. Self-contained: nothing else is needed with it."
     },
     "google_flights_url": {
      "type": [
       "string",
       "null"
      ],
      "description": "Google Flights page for this option: the search page with the earlier legs chosen, or the booking page once every leg is chosen."
     },
     "group": {
      "type": "string",
      "description": "`best` (Google's top flights) or `other`. Every option is `other` when `sort_by` is not `top_flights`.",
      "enum": [
       "best",
       "other"
      ]
     },
     "price_exact": {
      "type": [
       "number",
       "null"
      ],
      "description": "Price with minor units, from Google's price token (526.19 where `price` is 527). Null when the token has no amount or is in another currency."
     },
     "price_token": {
      "type": [
       "string",
       "null"
      ],
      "description": "Google's own opaque price token for this option, on every itinerary (returned as `booking_token` until 2026-09-30). Usable as an itinerary key; no endpoint takes it."
     },
     "priced_in": {
      "type": [
       "string",
       "null"
      ],
      "description": "Set only when Google priced this option in another currency than requested: that ISO 4217 code. `price` is then in this currency and `warnings` says so."
     },
     "carbon_emissions": {
      "anyOf": [
       {
        "$ref": "#/components/schemas/FlightCarbonEmissions"
       },
       {
        "type": "null"
       }
      ],
      "description": "Null when Google gives no estimate."
     },
     "total_duration_minutes": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Sum of the legs' door-to-door durations, minutes; null when one is unknown."
     },
     "carry_on_bags_included": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Carry-on bags included in the fare, as Google states it; null when not stated."
     },
     "checked_bags_included": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Checked bags included in the fare, as Google states it; null when not stated."
     },
     "airline_logo": {
      "type": [
       "string",
       "null"
      ],
      "description": "Logo URL of the main airline; null when several airlines share the itinerary."
     }
    }
   },
   "FlightsSearchResponse": {
    "type": "object",
    "description": "Response of `POST /v1/serp/google_flights`.",
    "required": [
     "departure_airport",
     "arrival_airport",
     "departure_date",
     "currency",
     "adults",
     "itineraries",
     "wire_bytes",
     "elapsed_s",
     "cheapest_price",
     "trip_type",
     "leg_index",
     "legs_total",
     "itinerary_count",
     "best_count",
     "airlines_available",
     "google_flights_url",
     "source",
     "warnings"
    ],
    "properties": {
     "departure_airport": {
      "type": "string",
      "description": "Echo of the request's `departure`."
     },
     "arrival_airport": {
      "type": "string",
      "description": "Echo of the request's `arrival`."
     },
     "departure_date": {
      "type": "string",
      "description": "Date of the leg these options are for.",
      "format": "date"
     },
     "return_date": {
      "type": "string",
      "description": "Present only for round trips.",
      "format": "date"
     },
     "currency": {
      "type": "string",
      "description": "The requested currency."
     },
     "adults": {
      "type": "integer"
     },
     "itineraries": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/FlightItinerary"
      },
      "description": "Options for the leg being chosen: Google's best flights first, then the others."
     },
     "wire_bytes": {
      "type": "integer",
      "description": "Size of Google's response, bytes."
     },
     "elapsed_s": {
      "type": "number",
      "description": "Time Google took to answer, seconds."
     },
     "cheapest_price": {
      "type": [
       "number",
       "null"
      ],
      "description": "Lowest `price` in `itineraries`; null when none is priced."
     },
     "trip_type": {
      "type": "string",
      "description": "`one_way`, `round_trip` or `multi_city`.",
      "enum": [
       "one_way",
       "round_trip",
       "multi_city"
      ]
     },
     "leg_index": {
      "type": "integer",
      "description": "Which leg these options are for: 0 = first (outbound), 1 = return or second multi-city leg, and so on."
     },
     "legs_total": {
      "type": "integer",
      "description": "Legs in the trip: 1 one-way, 2 round trip, 2-5 multi-city."
     },
     "itinerary_count": {
      "type": "integer",
      "description": "Number of entries in `itineraries`."
     },
     "best_count": {
      "type": "integer",
      "description": "How many `itineraries` have `group: best`."
     },
     "price_insights": {
      "anyOf": [
       {
        "$ref": "#/components/schemas/FlightPriceInsights"
       },
       {
        "type": "null"
       }
      ],
      "description": "Null when Google gives none (some filtered searches). Omitted when `itineraries` is empty; that answer is not billed."
     },
     "airlines_available": {
      "type": "array",
      "items": {
       "type": "object",
       "required": [
        "code",
        "name",
        "type"
       ],
       "properties": {
        "code": {
         "type": "string",
         "description": "IATA airline code, or `STAR_ALLIANCE` / `SKYTEAM` / `ONEWORLD`."
        },
        "name": {
         "type": [
          "string",
          "null"
         ]
        },
        "type": {
         "type": "string",
         "enum": [
          "alliance",
          "airline"
         ]
        }
       }
      },
      "description": "Airlines and alliances Google offers as filters for this search; the codes work in `include_airlines`."
     },
     "google_flights_url": {
      "type": "string",
      "description": "Google Flights search page for this trip."
     },
     "source": {
      "type": "string",
      "description": "`rpc` normally; `html` when the results came from Google's server-rendered page fallback, which holds only Google's first screen of results (about 8-10 itineraries).",
      "enum": [
       "rpc",
       "html"
      ]
     },
     "warnings": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Notices about this answer, e.g. that Google priced some options in another currency (see each itinerary's `priced_in`). Empty when none."
     }
    }
   },
   "FlightsCalendarPrice": {
    "type": "object",
    "required": [
     "departure_date",
     "price",
     "currency",
     "display_price",
     "is_priced"
    ],
    "properties": {
     "departure_date": {
      "type": "string",
      "format": "date"
     },
     "return_date": {
      "type": "string",
      "description": "Present only for round trips.",
      "format": "date"
     },
     "price": {
      "type": [
       "number",
       "null"
      ],
      "description": "Cheapest fare Google shows for this date combination (whole trip), in `currency`; null when unpriced."
     },
     "currency": {
      "type": "string"
     },
     "display_price": {
      "type": [
       "string",
       "null"
      ],
      "description": "`price` with its currency symbol, e.g. `$245`."
     },
     "is_priced": {
      "type": "boolean",
      "description": "`price` is not null."
     }
    }
   },
   "FlightsCalendarResponse": {
    "type": "object",
    "description": "Response of `POST /v1/serp/google_flights_calendar`.",
    "required": [
     "departure_airport",
     "arrival_airport",
     "currency",
     "adults",
     "trip_type",
     "prices",
     "wire_bytes",
     "elapsed_s",
     "cheapest_price",
     "coverage"
    ],
    "properties": {
     "departure_airport": {
      "type": "string",
      "description": "Echo of the request's `departure`."
     },
     "arrival_airport": {
      "type": "string",
      "description": "Echo of the request's `arrival`."
     },
     "currency": {
      "type": "string"
     },
     "adults": {
      "type": "integer"
     },
     "trip_type": {
      "type": "string",
      "enum": [
       "one_way",
       "round_trip"
      ]
     },
     "prices": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/FlightsCalendarPrice"
      },
      "description": "One row per date combination in the window."
     },
     "wire_bytes": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Size of Google's response, bytes; null when the grid was assembled from several searches."
     },
     "elapsed_s": {
      "type": "number",
      "description": "Seconds."
     },
     "cheapest_price": {
      "type": [
       "number",
       "null"
      ],
      "description": "Lowest `price` in `prices`."
     },
     "coverage": {
      "type": "string",
      "description": "`priced/total`, e.g. `14/15` (a string here)."
     }
    }
   },
   "AirbnbCalendarPriceStatus": {
    "type": "string",
    "description": "Why a date is or isn't priced. `priced`: quoted; see `price`. `not_sampled`: a valid check-in that `sample` mode didn't pick. `quote_cap_reached`: a valid check-in past `max_price_quotes` in `all` mode. `not_requested`: a valid check-in while pricing is off (seen only in summary counts with `price_nights: none`). `unavailable`: the night is booked or blocked. `past`: before today (UTC). `check_in_not_allowed`: Airbnb doesn't allow arrival on this date. `check_out_not_allowed`: the stay's departure day doesn't allow check-out. `stay_blocked`: a later night of the stay is unavailable. `stay_exceeds_max_nights`: the stay is longer than the date's `max_nights`. `quote_refused`: the calendar allowed the stay but Airbnb's quote refused it. `no_price`: the quote came back without a nightly price line. `quote_failed`: the quote request failed; the rest of the calendar is still returned. `quote_skipped`: the quote was never sent (time budget ran out, or three quotes in a row failed) and isn't charged.",
    "enum": [
     "priced",
     "not_sampled",
     "quote_cap_reached",
     "not_requested",
     "unavailable",
     "past",
     "check_in_not_allowed",
     "check_out_not_allowed",
     "stay_blocked",
     "stay_exceeds_max_nights",
     "quote_refused",
     "no_price",
     "quote_failed",
     "quote_skipped"
    ]
   },
   "AirbnbCalendarSummary": {
    "type": "object",
    "description": "Counts over the returned days, and the spread of quoted nightly prices.",
    "required": [
     "days",
     "available",
     "available_for_checkin",
     "bookable",
     "priced",
     "price_status"
    ],
    "properties": {
     "days": {
      "type": "integer",
      "description": "Days returned."
     },
     "available": {
      "type": "integer",
      "description": "Days whose night is open."
     },
     "available_for_checkin": {
      "type": "integer",
      "description": "Days Airbnb allows arriving on."
     },
     "bookable": {
      "type": "integer",
      "description": "Days Airbnb marks bookable."
     },
     "priced": {
      "type": "integer",
      "description": "Days with a quoted price (each is charged 1 credit)."
     },
     "min_price_per_night": {
      "type": "number",
      "description": "Lowest `price_per_night` among priced days. Present only when at least one day was priced."
     },
     "max_price_per_night": {
      "type": "number",
      "description": "Highest `price_per_night` among priced days. Present only when at least one day was priced."
     },
     "median_price_per_night": {
      "type": "number",
      "description": "Median `price_per_night` among priced days, 2 decimals. Present only when at least one day was priced."
     },
     "price_status": {
      "type": "object",
      "description": "Number of days per `price_status` value, keys sorted; only statuses that occur are present.",
      "properties": {
       "priced": {
        "type": "integer"
       },
       "not_sampled": {
        "type": "integer"
       },
       "quote_cap_reached": {
        "type": "integer"
       },
       "not_requested": {
        "type": "integer"
       },
       "unavailable": {
        "type": "integer"
       },
       "past": {
        "type": "integer"
       },
       "check_in_not_allowed": {
        "type": "integer"
       },
       "check_out_not_allowed": {
        "type": "integer"
       },
       "stay_blocked": {
        "type": "integer"
       },
       "stay_exceeds_max_nights": {
        "type": "integer"
       },
       "quote_refused": {
        "type": "integer"
       },
       "no_price": {
        "type": "integer"
       },
       "quote_failed": {
        "type": "integer"
       },
       "quote_skipped": {
        "type": "integer"
       }
      }
     }
    }
   },
   "AirbnbCalendarPriceLine": {
    "type": "object",
    "description": "One line of Airbnb's price breakdown.",
    "required": [
     "description",
     "price",
     "kind"
    ],
    "properties": {
     "description": {
      "type": "string",
      "description": "Line label as Airbnb shows it, e.g. `2 nights x $178.00 CAD`, `Long stay discount`, `Taxes`, `Total`."
     },
     "price": {
      "type": "string",
      "description": "Amount as displayed, e.g. `$356.00 CAD`."
     },
     "extracted_price": {
      "type": "number",
      "description": "Signed amount (discounts are negative). Omitted when the amount can't be read."
     },
     "kind": {
      "type": "string",
      "description": "Line type.",
      "enum": [
       "nights",
       "discount",
       "fee",
       "tax",
       "total",
       "other"
      ]
     }
    }
   },
   "AirbnbCalendarPrice": {
    "type": "object",
    "description": "Airbnb's quote for one stay checking in on this date, as the listing page's booking sidebar shows it.",
    "required": [
     "price_per_night",
     "check_in",
     "check_out",
     "nights",
     "price_per_night_text",
     "price_basis",
     "breakdown",
     "provenance"
    ],
    "properties": {
     "price_per_night": {
      "type": "number",
      "description": "Airbnb's own nightly figure for the quoted stay (the `N nights x $X` line): all-in, with cleaning and service fees folded in, before taxes. It depends on the stay length, so read it with `check_in`, `check_out` and `nights`."
     },
     "currency": {
      "type": "string",
      "description": "Currency Airbnb priced the quote in (ISO 4217). Omitted when it can't be read from the price text."
     },
     "check_in": {
      "type": "string",
      "description": "Check-in of the quoted stay (this date).",
      "format": "date"
     },
     "check_out": {
      "type": "string",
      "description": "Check-out of the quoted stay.",
      "format": "date"
     },
     "nights": {
      "type": "integer",
      "description": "Nights in the quoted stay: `stay_nights`, or the date's minimum stay when that is longer or `stay_nights` was omitted."
     },
     "accommodation": {
      "type": "number",
      "description": "Exact subtotal of the nightly line (`nights` x nightly rate). Omitted when the amount can't be read."
     },
     "discount": {
      "type": "number",
      "description": "Total discount as a positive amount (e.g. a long-stay discount). Present only when the quote has a discount line."
     },
     "fees": {
      "type": "number",
      "description": "Sum of separately listed fee lines. Present only when Airbnb itemizes fees; `price_basis` is then `nightly_before_listed_fees_and_taxes`."
     },
     "taxes": {
      "type": "number",
      "description": "Sum of tax lines. Present only when Airbnb itemizes taxes."
     },
     "total": {
      "type": "number",
      "description": "Stay total including taxes, from the quote's Total line. Present only when the quote has one."
     },
     "price_per_night_text": {
      "type": "string",
      "description": "Nightly figure as displayed, e.g. `$178.00 CAD`."
     },
     "total_text": {
      "type": "string",
      "description": "Total line as displayed. Present only when the quote has one."
     },
     "display_total": {
      "type": "string",
      "description": "Headline price Airbnb shows for the stay, rounded as displayed (e.g. `$424 CAD`). Present only when shown."
     },
     "price_basis": {
      "type": "string",
      "description": "What `price_per_night` includes. `nightly_all_in_before_taxes`: fees folded in, taxes separate. `nightly_before_listed_fees_and_taxes`: the quote itemized a fee line, so those fees are in `fees`, not in the nightly figure.",
      "enum": [
       "nightly_all_in_before_taxes",
       "nightly_before_listed_fees_and_taxes"
      ]
     },
     "display_style": {
      "type": "string",
      "description": "Airbnb's price display style for the quote, e.g. `REGULATED_TOTAL`. Present only when Airbnb returns one."
     },
     "breakdown": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/AirbnbCalendarPriceLine"
      },
      "description": "Airbnb's price lines in display order."
     },
     "provenance": {
      "$ref": "#/components/schemas/RateProvenance"
     }
    }
   },
   "AirbnbCalendarDay": {
    "type": "object",
    "description": "One calendar date with Airbnb's rules and, when priced, the quoted stay.",
    "required": [
     "date",
     "available",
     "available_for_checkin",
     "available_for_checkout",
     "bookable"
    ],
    "properties": {
     "date": {
      "type": "string",
      "description": "Calendar date; the night starts on this date.",
      "format": "date"
     },
     "available": {
      "type": "boolean",
      "description": "The night is open (not booked or blocked)."
     },
     "available_for_checkin": {
      "type": "boolean",
      "description": "Airbnb allows arriving on this date."
     },
     "available_for_checkout": {
      "type": "boolean",
      "description": "Airbnb allows departing on this date."
     },
     "bookable": {
      "type": "boolean",
      "description": "Airbnb's bookable flag for this date."
     },
     "min_nights": {
      "type": "integer",
      "description": "Minimum stay for a check-in on this date. Present only when Airbnb reports it."
     },
     "max_nights": {
      "type": "integer",
      "description": "Maximum stay for a check-in on this date. Present only when Airbnb reports it."
     },
     "closed_to_arrival": {
      "type": "boolean",
      "description": "Arrival restriction for this date. Present only when Airbnb returns arrival/departure rules for it."
     },
     "closed_to_departure": {
      "type": "boolean",
      "description": "Departure restriction for this date. Present only when Airbnb returns arrival/departure rules for it."
     },
     "price_status": {
      "allOf": [
       {
        "$ref": "#/components/schemas/AirbnbCalendarPriceStatus"
       }
      ],
      "description": "Present unless `price_nights` is `none`."
     },
     "price_error": {
      "type": "string",
      "description": "Reason behind `quote_refused` (Airbnb's message), `no_price`, `quote_failed` or `quote_skipped` (`deadline_exceeded` or `stopped_after_failures`). Present only when there is one."
     },
     "price": {
      "allOf": [
       {
        "$ref": "#/components/schemas/AirbnbCalendarPrice"
       }
      ],
      "description": "Present only when `price_status` is `priced`."
     }
    }
   },
   "AirbnbCalendarListing": {
    "type": "object",
    "description": "Listing facts gathered along the way: `constant_min_nights` from the calendar, capacity and guest policy from the price quotes, and the rest from one extra request with `include_listing: true`. Unknown keys are omitted.",
    "properties": {
     "constant_min_nights": {
      "type": "integer",
      "description": "Minimum stay that applies to every date, when Airbnb reports one."
     },
     "max_guests": {
      "type": "integer",
      "description": "Guest capacity."
     },
     "pets_allowed": {
      "type": "boolean"
     },
     "children_allowed": {
      "type": "boolean"
     },
     "infants_allowed": {
      "type": "boolean"
     },
     "guest_policy": {
      "type": "string",
      "description": "Airbnb's guest-policy sentence, e.g. `This place has a maximum of 2 guests, not including infants.`"
     },
     "title": {
      "type": "string",
      "description": "Listing title. Only with `include_listing`."
     },
     "property_type": {
      "type": "string",
      "description": "Airbnb property type, e.g. `PRIVATE_SUITE`. Only with `include_listing`."
     },
     "room_type": {
      "type": "string",
      "description": "Airbnb space type, e.g. `ENTIRE_HOME`. Only with `include_listing`."
     },
     "location": {
      "type": "string",
      "description": "Displayed location, e.g. `Toronto`. Only with `include_listing`."
     },
     "overview": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Summary items, e.g. `Entire guest suite`, `1 bed`, `1 bath`. Only with `include_listing`."
     },
     "rating": {
      "type": "number",
      "description": "Average rating. Only with `include_listing`."
     },
     "reviews": {
      "type": "integer",
      "description": "Review count. Only with `include_listing`."
     },
     "is_guest_favorite": {
      "type": "boolean",
      "description": "Only with `include_listing`."
     },
     "is_luxe": {
      "type": "boolean",
      "description": "Only with `include_listing`."
     },
     "gps_coordinates": {
      "type": "object",
      "description": "Only with `include_listing`.",
      "required": [
       "latitude",
       "longitude"
      ],
      "properties": {
       "latitude": {
        "type": "number"
       },
       "longitude": {
        "type": "number"
       }
      }
     }
    }
   },
   "AirbnbCalendarMetadata": {
    "type": "object",
    "required": [
     "collection_id",
     "observed_at",
     "calendar_operation",
     "upstream_requests",
     "price_quotes",
     "wire_bytes",
     "request_time_taken",
     "parsing_time_taken",
     "total_time_taken",
     "egress"
    ],
    "properties": {
     "collection_id": {
      "type": "string",
      "description": "Shared by every price in this response (`ratecol_...`)."
     },
     "observed_at": {
      "type": "string",
      "description": "UTC observation time, ISO-8601."
     },
     "calendar_operation": {
      "type": "string",
      "description": "Upstream operation used."
     },
     "upstream_requests": {
      "type": "integer",
      "description": "Upstream requests made, including retried attempts."
     },
     "price_quotes": {
      "type": "integer",
      "description": "Stays planned for quoting (skipped quotes included)."
     },
     "wire_bytes": {
      "type": "integer",
      "description": "Bytes received from upstream, compressed."
     },
     "request_time_taken": {
      "type": "number",
      "description": "Seconds spent in upstream requests, summed. Quotes run in parallel, so this can exceed `total_time_taken`."
     },
     "parsing_time_taken": {
      "type": "number",
      "description": "Seconds spent parsing the calendar."
     },
     "total_time_taken": {
      "type": "number",
      "description": "End-to-end seconds for this request."
     },
     "egress": {
      "type": "array",
      "items": {
       "type": "string",
       "enum": [
        "direct",
        "proxy"
       ]
      },
      "description": "How upstream requests were routed: `direct`, `proxy`, or both."
     }
    }
   },
   "AirbnbCalendarResponse": {
    "type": "object",
    "description": "Response of `POST /v1/airbnb/calendar`.",
    "required": [
     "listing_id",
     "link",
     "airbnb_domain",
     "guests",
     "start_month",
     "start_year",
     "months",
     "price_nights",
     "max_price_quotes",
     "summary",
     "days",
     "metadata"
    ],
    "properties": {
     "listing_id": {
      "type": "string",
      "description": "Airbnb listing id."
     },
     "link": {
      "type": "string",
      "description": "Listing URL on `airbnb_domain`."
     },
     "airbnb_domain": {
      "type": "string"
     },
     "currency": {
      "type": "string",
      "description": "Currency of the quoted prices: the one Airbnb priced in, else the requested `currency`. Omitted when neither is known (no `currency` sent and no day priced)."
     },
     "requested_currency": {
      "type": "string",
      "description": "Present only when `currency` was sent."
     },
     "guests": {
      "type": "object",
      "description": "Party the quotes were priced for.",
      "required": [
       "adults",
       "children",
       "infants",
       "pets"
      ],
      "properties": {
       "adults": {
        "type": "integer"
       },
       "children": {
        "type": "integer"
       },
       "infants": {
        "type": "integer"
       },
       "pets": {
        "type": "integer"
       }
      }
     },
     "start_month": {
      "type": "integer",
      "description": "Effective first month (defaults to the current UTC month)."
     },
     "start_year": {
      "type": "integer",
      "description": "Effective year of `start_month`."
     },
     "months": {
      "type": "integer"
     },
     "price_nights": {
      "type": "string",
      "enum": [
       "none",
       "sample",
       "all"
      ]
     },
     "stay_nights": {
      "type": "integer",
      "description": "Present only when `stay_nights` was sent."
     },
     "max_price_quotes": {
      "type": "integer",
      "description": "Quote budget that applied: the requested `max_price_quotes` or the mode default (12 for `sample`, 92 for `all`), capped at 92 and at 31 x `months`; 0 with `price_nights: none`."
     },
     "listing": {
      "allOf": [
       {
        "$ref": "#/components/schemas/AirbnbCalendarListing"
       }
      ],
      "description": "Present only when at least one listing fact is known."
     },
     "summary": {
      "$ref": "#/components/schemas/AirbnbCalendarSummary"
     },
     "days": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/AirbnbCalendarDay"
      },
      "description": "One row per date of the requested months, in date order."
     },
     "metadata": {
      "$ref": "#/components/schemas/AirbnbCalendarMetadata"
     },
     "warnings": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Things worth checking: refused, failed or skipped quotes, a currency other than the one asked for, stays quoted longer than `stay_nights`, missing listing details. Present only when there is at least one."
     }
    }
   },
   "AirbnbAvailabilityPrice": {
    "type": "object",
    "description": "Airbnb's quote for one stay checking in on this date, in SearchAPI's Airbnb search price vocabulary.",
    "required": [
     "check_in_date",
     "check_out_date",
     "price_per_night",
     "extracted_price_per_night",
     "qualifier",
     "extracted_qualifier",
     "price_per_qualifier",
     "extracted_price_per_qualifier",
     "breakdown",
     "provenance"
    ],
    "properties": {
     "check_in_date": {
      "type": "string",
      "description": "Check-in of the quoted stay (this date).",
      "format": "date"
     },
     "check_out_date": {
      "type": "string",
      "description": "Check-out of the quoted stay.",
      "format": "date"
     },
     "currency": {
      "type": "string",
      "description": "Currency Airbnb priced the quote in. Omitted when it can't be read from the price text."
     },
     "price_per_night": {
      "type": "string",
      "description": "Airbnb's nightly figure for the quoted stay as displayed, e.g. `$178.00 CAD`: all-in, with cleaning and service fees folded in, before taxes."
     },
     "extracted_price_per_night": {
      "type": "number",
      "description": "`price_per_night` as a number."
     },
     "total_price": {
      "type": "string",
      "description": "Headline price Airbnb shows for the stay, e.g. `$424 CAD`; falls back to the Total line. Omitted when neither exists."
     },
     "extracted_total_price": {
      "type": "number",
      "description": "`total_price` as a number (rounded as displayed); falls back to `extracted_total_with_taxes`. Omitted when neither exists."
     },
     "qualifier": {
      "type": "string",
      "description": "e.g. `for 2 nights`."
     },
     "extracted_qualifier": {
      "type": "integer",
      "description": "Nights in the quoted stay."
     },
     "price_per_qualifier": {
      "type": "string",
      "description": "Airbnb's nightly line, e.g. `2 nights x $178.00 CAD`."
     },
     "extracted_price_per_qualifier": {
      "type": "number",
      "description": "Nightly figure; same as `extracted_price_per_night`."
     },
     "total_with_taxes": {
      "type": "string",
      "description": "Total line as displayed, taxes included. Present only when the quote has one."
     },
     "extracted_total_with_taxes": {
      "type": "number",
      "description": "`total_with_taxes` as a number. Present only when the quote has one."
     },
     "breakdown": {
      "type": "array",
      "items": {
       "type": "object",
       "required": [
        "description",
        "price",
        "extracted_price"
       ],
       "properties": {
        "description": {
         "type": "string"
        },
        "price": {
         "type": "string",
         "description": "As displayed."
        },
        "extracted_price": {
         "type": [
          "number",
          "null"
         ],
         "description": "Signed amount (discounts are negative); null when it can't be read."
        }
       }
      },
      "description": "Airbnb's price lines in display order."
     },
     "provenance": {
      "$ref": "#/components/schemas/RateProvenance"
     }
    }
   },
   "AirbnbAvailabilityDay": {
    "type": "object",
    "description": "One calendar date. SearchAPI's fields, plus `price_status` and `price` when prices were requested.",
    "required": [
     "date",
     "is_available",
     "is_available_for_checkin",
     "is_available_for_checkout",
     "is_bookable"
    ],
    "properties": {
     "date": {
      "type": "string",
      "description": "Calendar date; the night starts on this date.",
      "format": "date"
     },
     "is_available": {
      "type": "boolean",
      "description": "The night is open (not booked or blocked)."
     },
     "is_available_for_checkin": {
      "type": "boolean",
      "description": "Airbnb allows arriving on this date."
     },
     "is_available_for_checkout": {
      "type": "boolean",
      "description": "Airbnb allows departing on this date."
     },
     "is_bookable": {
      "type": "boolean"
     },
     "min_nights": {
      "type": "integer",
      "description": "Minimum stay for a check-in on this date. Present only when Airbnb reports it."
     },
     "max_nights": {
      "type": "integer",
      "description": "Maximum stay for a check-in on this date. Present only when Airbnb reports it."
     },
     "price_status": {
      "allOf": [
       {
        "$ref": "#/components/schemas/AirbnbCalendarPriceStatus"
       }
      ],
      "description": "Present only when `price_nights` isn't `none`."
     },
     "price": {
      "allOf": [
       {
        "$ref": "#/components/schemas/AirbnbAvailabilityPrice"
       }
      ],
      "description": "Present only when `price_status` is `priced`."
     }
    }
   },
   "AirbnbAvailabilityMonth": {
    "type": "object",
    "required": [
     "year",
     "month",
     "days"
    ],
    "properties": {
     "year": {
      "type": "integer"
     },
     "month": {
      "type": "integer",
      "description": "1-12."
     },
     "days": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/AirbnbAvailabilityDay"
      },
      "description": "In date order."
     }
    }
   },
   "AirbnbAvailabilityCalendarResponse": {
    "type": "object",
    "description": "Response of `POST /v1/serp/airbnb_property_availability_calendar`.",
    "required": [
     "search_metadata",
     "search_parameters",
     "months"
    ],
    "properties": {
     "search_metadata": {
      "type": "object",
      "required": [
       "id",
       "status",
       "created_at",
       "request_time_taken",
       "parsing_time_taken",
       "total_time_taken",
       "request_url",
       "collection_id",
       "observed_at",
       "wire_bytes",
       "upstream_requests"
      ],
      "properties": {
       "id": {
        "type": "string"
       },
       "status": {
        "type": "string",
        "enum": [
         "Success"
        ]
       },
       "created_at": {
        "type": "string",
        "description": "UTC, ISO-8601."
       },
       "request_time_taken": {
        "type": "number",
        "description": "Seconds spent in upstream requests, summed; can exceed `total_time_taken` because quotes run in parallel."
       },
       "parsing_time_taken": {
        "type": "number"
       },
       "total_time_taken": {
        "type": "number"
       },
       "request_url": {
        "type": "string",
        "description": "Listing URL."
       },
       "collection_id": {
        "type": "string",
        "description": "Shared by every price in this response (`ratecol_...`)."
       },
       "observed_at": {
        "type": "string",
        "description": "UTC observation time, ISO-8601."
       },
       "wire_bytes": {
        "type": "integer",
        "description": "Bytes received from upstream, compressed."
       },
       "upstream_requests": {
        "type": "integer",
        "description": "Upstream requests made: 1 for the calendar plus one per quote attempt."
       }
      }
     },
     "search_parameters": {
      "type": "object",
      "description": "Echo of the effective request.",
      "required": [
       "engine",
       "airbnb_domain",
       "property_id",
       "start_month",
       "start_year",
       "months"
      ],
      "properties": {
       "engine": {
        "type": "string",
        "enum": [
         "airbnb_property_availability_calendar"
        ]
       },
       "airbnb_domain": {
        "type": "string"
       },
       "property_id": {
        "type": "string"
       },
       "start_month": {
        "type": "integer",
        "description": "Effective first month (defaults resolved)."
       },
       "start_year": {
        "type": "integer"
       },
       "months": {
        "type": "integer"
       },
       "currency": {
        "type": "string",
        "description": "Present only when sent."
       },
       "adults": {
        "type": "integer",
        "description": "Present only when `price_nights` isn't `none`."
       },
       "children": {
        "type": "integer",
        "description": "Present only when non-zero and `price_nights` isn't `none`."
       },
       "infants": {
        "type": "integer",
        "description": "Present only when non-zero and `price_nights` isn't `none`."
       },
       "pets": {
        "type": "integer",
        "description": "Present only when non-zero and `price_nights` isn't `none`."
       },
       "price_nights": {
        "type": "string",
        "description": "Present only when not `none`.",
        "enum": [
         "sample",
         "all"
        ]
       },
       "max_price_quotes": {
        "type": "integer",
        "description": "As sent. Present only when sent and `price_nights` isn't `none`."
       },
       "stay_nights": {
        "type": "integer",
        "description": "Present only when sent and `price_nights` isn't `none`."
       }
      }
     },
     "months": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/AirbnbAvailabilityMonth"
      },
      "description": "One entry per requested month, in order."
     },
     "price_summary": {
      "allOf": [
       {
        "$ref": "#/components/schemas/AirbnbCalendarSummary"
       }
      ],
      "description": "Present only when `price_nights` isn't `none`."
     },
     "warnings": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Things worth checking: refused, failed or skipped quotes, a currency other than the one asked for, stays quoted longer than `stay_nights`. Present only when there is at least one."
     }
    }
   },
   "ExpediaSearchMatch": {
    "type": "object",
    "required": [
     "property_id",
     "name",
     "city",
     "address",
     "country",
     "url",
     "rank",
     "score",
     "name_score",
     "identity_score",
     "match_score",
     "confidence",
     "winner_reason"
    ],
    "properties": {
     "property_id": {
      "type": "string",
      "description": "Numeric Expedia id (digits); pass as `property_id` to `POST /v1/ota/expedia` or as `expedia_property_id` to `POST /v1/ota/compare`. Matches the Hotels.com id only for newer properties."
     },
     "name": {
      "type": "string"
     },
     "city": {
      "type": "string"
     },
     "address": {
      "type": "string"
     },
     "country": {
      "type": "string"
     },
     "url": {
      "type": "string",
      "description": "Expedia property page, `https://<host>/h<property_id>.Hotel-Information`."
     },
     "rank": {
      "type": "integer"
     },
     "score": {
      "type": "number"
     },
     "name_score": {
      "type": "number"
     },
     "identity_score": {
      "type": "number"
     },
     "match_score": {
      "type": "number"
     },
     "confidence": {
      "type": "string",
      "enum": [
       "high",
       "medium",
       "low"
      ]
     },
     "winner_reason": {
      "type": "string"
     },
     "city_score": {
      "type": "number",
      "description": "Present only when `city` was supplied."
     },
     "coordinates": {
      "type": "object",
      "description": "Present only when the source returned coordinates.",
      "required": [
       "latitude",
       "longitude"
      ],
      "properties": {
       "latitude": {
        "type": "number"
       },
       "longitude": {
        "type": "number"
       }
      }
     }
    }
   },
   "ExpediaSearchResponse": {
    "type": "object",
    "description": "Response of `POST /v1/ota/expedia/search`.",
    "required": [
     "search_parameters",
     "search_status",
     "recommended_match",
     "warnings",
     "matches",
     "meta"
    ],
    "properties": {
     "search_parameters": {
      "type": "object",
      "required": [
       "engine",
       "name",
       "city",
       "market",
       "limit"
      ],
      "properties": {
       "engine": {
        "type": "string",
        "enum": [
         "expedia_search"
        ]
       },
       "name": {
        "type": "string"
       },
       "city": {
        "type": "string"
       },
       "market": {
        "type": "string",
        "description": "Point-of-sale searched: `US` (www.expedia.com) or `CA` (www.expedia.ca)."
       },
       "limit": {
        "type": "integer"
       }
      }
     },
     "search_status": {
      "type": "string",
      "description": "`matched` only when the top candidate clears the identity threshold and margin.",
      "enum": [
       "matched",
       "ambiguous",
       "not_found"
      ]
     },
     "recommended_match": {
      "anyOf": [
       {
        "$ref": "#/components/schemas/ExpediaSearchMatch"
       },
       {
        "type": "null"
       }
      ],
      "description": "Safe to store; null unless `search_status` is `matched`."
     },
     "warnings": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "matches": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/ExpediaSearchMatch"
      },
      "description": "Candidates, best first, for manual review."
     },
     "meta": {
      "type": "object",
      "required": [
       "source",
       "matches",
       "selection_method",
       "match_threshold",
       "match_margin",
       "wire_bytes",
       "elapsed_s",
       "egress_mode"
      ],
      "properties": {
       "source": {
        "type": "string",
        "enum": [
         "expedia"
        ]
       },
       "matches": {
        "type": "integer"
       },
       "selection_method": {
        "type": "string"
       },
       "match_threshold": {
        "type": "number"
       },
       "match_margin": {
        "type": "number"
       },
       "wire_bytes": {
        "type": "integer"
       },
       "elapsed_s": {
        "type": "number"
       },
       "egress_mode": {
        "type": "string",
        "description": "How the request was routed: `direct` or `proxy`.",
        "enum": [
         "direct",
         "proxy"
        ]
       }
      }
     }
    }
   },
   "ExpediaOffer": {
    "type": "object",
    "description": "One bookable price: a rate plan under one payment model. `provenance.price_basis` is `stay_total_including_taxes_and_fees`, `stay_total_fees_included` or `stay_total`.",
    "required": [
     "plan_id",
     "room_type_id",
     "total",
     "nightly",
     "taxes_and_fees",
     "currency",
     "total_text",
     "nightly_text",
     "taxes_and_fees_included",
     "fees_included",
     "payment_model",
     "hotel_collect",
     "member_only",
     "refundable",
     "cancellation_text",
     "extras",
     "extras_text",
     "strikeout_text",
     "inventory_type",
     "business_model",
     "messages",
     "provenance",
     "taxes_and_fees_provenance"
    ],
    "properties": {
     "plan_id": {
      "type": "string",
      "description": "Expedia rate-plan id."
     },
     "room_type_id": {
      "type": "string"
     },
     "total": {
      "type": [
       "number",
       "null"
      ],
      "description": "Stay total for all nights, as the source states it; `taxes_and_fees_included` / `fees_included` repeat its label. Null when the plan carried no price."
     },
     "nightly": {
      "type": [
       "number",
       "null"
      ],
      "description": "Average nightly price before taxes and fees; Expedia rounds it to whole units."
     },
     "taxes_and_fees": {
      "type": [
       "number",
       "null"
      ],
      "description": "Derived, not read from the source: `total - nightly × nights`, set only when `taxes_and_fees_included` is true. Accurate to within `nights` currency units because `nightly` is rounded; taxes and fees are not itemised. See `taxes_and_fees_provenance`."
     },
     "currency": {
      "type": "string",
      "description": "ISO 4217 code read back from the reply."
     },
     "total_text": {
      "type": "string",
      "description": "Total as displayed, e.g. `$635 total`."
     },
     "nightly_text": {
      "type": "string",
      "description": "Nightly price as displayed, e.g. `$509 nightly`."
     },
     "taxes_and_fees_included": {
      "type": [
       "boolean",
       "null"
      ],
      "description": "True when the source labels the total \"Total with taxes and fees\". Null means no such label was shown, not that taxes are excluded."
     },
     "fees_included": {
      "type": [
       "boolean",
       "null"
      ],
      "description": "True when the source labels the total \"All fees included\". Null means no such label was shown."
     },
     "payment_model": {
      "type": "string",
      "description": "`PAY_NOW`, `PAY_LATER` or `PAY_LATER_WITH_DEPOSIT`; empty when not stated. A plan sold both ways is two offers.",
      "enum": [
       "PAY_NOW",
       "PAY_LATER",
       "PAY_LATER_WITH_DEPOSIT",
       ""
      ]
     },
     "hotel_collect": {
      "type": [
       "boolean",
       "null"
      ],
      "description": "True when the property collects payment; null when not stated."
     },
     "member_only": {
      "type": "boolean",
      "description": "True when booking the plan requires signing in as a member."
     },
     "refundable": {
      "type": [
       "boolean",
       "null"
      ],
      "description": "Tri-state, from the room card's cancellation option: true = refundable / free cancellation, false = non-refundable, null = not stated (not the same as non-refundable)."
     },
     "cancellation_text": {
      "type": "string",
      "description": "Cancellation option as displayed, e.g. `Fully refundable before Nov 14`; for display only, use `refundable`. Empty when not stated."
     },
     "extras": {
      "type": [
       "string",
       "null"
      ],
      "description": "Add-on code, e.g. `breakfast`, `breakfast-for-two`; null for no extras or when not stated."
     },
     "extras_text": {
      "type": "string",
      "description": "Add-on as displayed, e.g. `No extras`; empty when not stated."
     },
     "strikeout_text": {
      "type": "string",
      "description": "Struck-through comparison price as displayed; empty when none."
     },
     "inventory_type": {
      "type": "string",
      "description": "Source inventory type, e.g. `MERCHANT`, `TRIPCOM`, `DIRECT_AGENCY`, `VRBO`; empty when not stated."
     },
     "business_model": {
      "type": "string",
      "description": "`EXPEDIA_COLLECT` or `HOTEL_COLLECT`; empty when not stated."
     },
     "messages": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Highlighted plan messages, e.g. `Reserve now, pay deposit`; usually empty for hotel rooms."
     },
     "provenance": {
      "$ref": "#/components/schemas/RateProvenance"
     },
     "taxes_and_fees_provenance": {
      "anyOf": [
       {
        "$ref": "#/components/schemas/RateProvenance"
       },
       {
        "type": "null"
       }
      ],
      "description": "Provenance of `taxes_and_fees` (`price_basis: taxes_and_fees_combined`, `derivation: total_minus_nightly_times_nights`); null when `taxes_and_fees` is null."
     }
    }
   },
   "ExpediaRoom": {
    "type": "object",
    "required": [
     "unit_id",
     "name",
     "cheapest_total",
     "offers"
    ],
    "properties": {
     "unit_id": {
      "type": "string",
      "description": "Room type id. A vacation rental listed on Expedia is one room with `unit_id` = `property_id` and name `entire unit`."
     },
     "name": {
      "type": "string",
      "description": "Room name as displayed, e.g. `Room, 1 King Bed`."
     },
     "cheapest_total": {
      "type": [
       "number",
       "null"
      ],
      "description": "Lowest `total` among this room's offers; null when none priced."
     },
     "offers": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/ExpediaOffer"
      }
     }
    }
   },
   "ExpediaRatesResponse": {
    "type": "object",
    "description": "Response of `POST /v1/ota/expedia`.",
    "required": [
     "search_parameters",
     "property",
     "rooms",
     "meta"
    ],
    "properties": {
     "search_parameters": {
      "type": "object",
      "required": [
       "engine",
       "property_id",
       "check_in_date",
       "check_out_date",
       "adults",
       "market",
       "currency",
       "rooms"
      ],
      "properties": {
       "engine": {
        "type": "string",
        "enum": [
         "expedia_property"
        ]
       },
       "property_id": {
        "type": "string"
       },
       "check_in_date": {
        "type": "string",
        "format": "date"
       },
       "check_out_date": {
        "type": "string",
        "format": "date"
       },
       "adults": {
        "type": "integer"
       },
       "market": {
        "type": "string",
        "description": "`US` or `CA`."
       },
       "currency": {
        "type": "string",
        "description": "The market's currency (`USD` for `US`, `CAD` for `CA`)."
       },
       "rooms": {
        "type": "boolean",
        "description": "Whether room types and rate plans were requested."
       }
      }
     },
     "property": {
      "type": "object",
      "required": [
       "property_id",
       "total",
       "price_per_night",
       "basis",
       "total_text",
       "nightly_text",
       "taxes_and_fees_included",
       "fees_included",
       "currency",
       "currency_verified",
       "available",
       "unavailable_reason",
       "cheapest_total",
       "provenance"
      ],
      "properties": {
       "property_id": {
        "type": "string"
       },
       "total": {
        "type": [
         "number",
         "null"
        ],
        "description": "Headline stay total for all nights; see `basis` and `taxes_and_fees_included`. Null when nothing priced."
       },
       "price_per_night": {
        "type": [
         "number",
         "null"
        ],
        "description": "Headline nightly price, before taxes and fees (Expedia rounds it to whole units)."
       },
       "basis": {
        "type": [
         "string",
         "null"
        ],
        "description": "Where the headline comes from: `sticky_bar` (the page's own headline price, read by its labels) or `cheapest_offer` (the cheapest priced offer). Null when nothing priced.",
        "enum": [
         "sticky_bar",
         "cheapest_offer",
         null
        ]
       },
       "total_text": {
        "type": "string",
        "description": "Headline total as displayed; empty when not shown."
       },
       "nightly_text": {
        "type": "string",
        "description": "Headline nightly price as displayed; empty when not shown."
       },
       "taxes_and_fees_included": {
        "type": [
         "boolean",
         "null"
        ],
        "description": "True when the headline total is labelled \"with taxes and fees\"; null when no such label was shown."
       },
       "fees_included": {
        "type": [
         "boolean",
         "null"
        ],
        "description": "True when the headline total is labelled \"All fees included\"; null when no such label was shown."
       },
       "currency": {
        "type": "string",
        "description": "Currency the point-of-sale actually priced in."
       },
       "currency_verified": {
        "type": "boolean",
        "description": "Whether `currency` equals the market's currency."
       },
       "available": {
        "type": "boolean",
        "description": "False when nothing is bookable for this stay as asked."
       },
       "unavailable_reason": {
        "type": [
         "string",
         "null"
        ],
        "description": "Expedia's own message when it says why the stay cannot be booked, e.g. `This property requires you to stay at least 4 nights`. Null otherwise; `available` can be false with a null reason when nothing priced."
       },
       "cheapest_total": {
        "type": [
         "number",
         "null"
        ],
        "description": "Lowest offer `total` across `rooms`; null when `rooms` was false or no offer priced."
       },
       "provenance": {
        "$ref": "#/components/schemas/RateProvenance"
       }
      }
     },
     "rooms": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/ExpediaRoom"
      },
      "description": "Every room type with its offers. Empty when the request set `rooms: false`."
     },
     "meta": {
      "type": "object",
      "required": [
       "source",
       "collection_id",
       "observed_at",
       "nights",
       "wire_bytes",
       "elapsed_s",
       "egress_mode",
       "room_types",
       "offers",
       "comparable_across_markets"
      ],
      "properties": {
       "source": {
        "type": "string",
        "enum": [
         "expedia"
        ]
       },
       "collection_id": {
        "type": "string"
       },
       "observed_at": {
        "type": "string"
       },
       "nights": {
        "type": "integer"
       },
       "wire_bytes": {
        "type": "integer",
        "description": "Bytes received from the source."
       },
       "elapsed_s": {
        "type": "number"
       },
       "egress_mode": {
        "type": "string",
        "description": "How the request was routed: `direct` or `proxy`.",
        "enum": [
         "direct",
         "proxy"
        ]
       },
       "room_types": {
        "type": "integer",
        "description": "0 when `rooms` was false."
       },
       "offers": {
        "type": "integer",
        "description": "Offers across all rooms; 0 when `rooms` was false."
       },
       "comparable_across_markets": {
        "type": "boolean",
        "description": "Always false: the display basis differs by market."
       }
      }
     }
    }
   },
   "VrboListing": {
    "type": "object",
    "required": [
     "property_id",
     "listing_id",
     "name",
     "summary",
     "url",
     "nightly",
     "total",
     "currency",
     "nightly_text",
     "total_text",
     "fees_included",
     "taxes_and_fees_included",
     "rank",
     "provenance"
    ],
    "properties": {
     "property_id": {
      "type": "string",
      "description": "Numeric Vrbo property id; pass as `property_id` to `POST /v1/ota/vrbo`."
     },
     "listing_id": {
      "type": "string",
      "description": "Id in the listing's Vrbo URL, e.g. `20218736ha`; empty when the card carried no listing link."
     },
     "name": {
      "type": "string"
     },
     "summary": {
      "type": "string",
      "description": "Card details joined with ` · `, e.g. `House · 4 bedrooms · 4 Queen Beds`."
     },
     "url": {
      "type": "string",
      "description": "`https://www.vrbo.com/<listing_id>`; empty when `listing_id` is empty."
     },
     "nightly": {
      "type": [
       "number",
       "null"
      ],
      "description": "Vrbo's nightly price, to the cent. Null when the card's price carried no recognised label."
     },
     "total": {
      "type": [
       "number",
       "null"
      ],
      "description": "Stay total for all nights; null when the card did not state one."
     },
     "currency": {
      "type": "string"
     },
     "nightly_text": {
      "type": "string",
      "description": "As displayed, e.g. `$462`."
     },
     "total_text": {
      "type": "string",
      "description": "As displayed, e.g. `$1,386 for 3 nights`."
     },
     "fees_included": {
      "type": [
       "boolean",
       "null"
      ],
      "description": "True when Vrbo labels the price \"All fees included\"; null when no such label was shown."
     },
     "taxes_and_fees_included": {
      "type": [
       "boolean",
       "null"
      ],
      "description": "True when labelled as including taxes and fees; null when no such label was shown."
     },
     "rank": {
      "type": "integer",
      "description": "0-based position in Vrbo's recommended order."
     },
     "provenance": {
      "$ref": "#/components/schemas/RateProvenance"
     }
    }
   },
   "VrboSearchResponse": {
    "type": "object",
    "description": "Response of `POST /v1/ota/vrbo/search`.",
    "required": [
     "search_parameters",
     "summary",
     "listings",
     "meta"
    ],
    "properties": {
     "search_parameters": {
      "type": "object",
      "required": [
       "engine",
       "destination",
       "check_in_date",
       "check_out_date",
       "adults",
       "market",
       "currency",
       "limit"
      ],
      "properties": {
       "engine": {
        "type": "string",
        "enum": [
         "vrbo_search"
        ]
       },
       "destination": {
        "type": "string"
       },
       "check_in_date": {
        "type": "string",
        "format": "date"
       },
       "check_out_date": {
        "type": "string",
        "format": "date"
       },
       "adults": {
        "type": "integer"
       },
       "market": {
        "type": "string",
        "description": "`US`."
       },
       "currency": {
        "type": "string",
        "description": "The market's currency (`USD`)."
       },
       "limit": {
        "type": "integer"
       }
      }
     },
     "summary": {
      "type": "object",
      "required": [
       "matched_properties",
       "results_heading"
      ],
      "properties": {
       "matched_properties": {
        "type": [
         "integer",
         "null"
        ],
        "description": "Total listings Vrbo matched for the destination and dates."
       },
       "results_heading": {
        "type": [
         "string",
         "null"
        ],
        "description": "Vrbo's heading, e.g. `Search results showing 359 properties in ...`."
       }
      }
     },
     "listings": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/VrboListing"
      },
      "description": "At most `limit` listings, in Vrbo's recommended order; sponsored placements are skipped."
     },
     "meta": {
      "type": "object",
      "required": [
       "source",
       "listings",
       "collection_id",
       "observed_at",
       "wire_bytes",
       "elapsed_s",
       "egress_mode"
      ],
      "properties": {
       "source": {
        "type": "string",
        "enum": [
         "vrbo"
        ]
       },
       "listings": {
        "type": "integer"
       },
       "collection_id": {
        "type": "string"
       },
       "observed_at": {
        "type": "string"
       },
       "wire_bytes": {
        "type": "integer",
        "description": "Bytes received from the source."
       },
       "elapsed_s": {
        "type": "number"
       },
       "egress_mode": {
        "type": "string",
        "description": "How the request was routed: `direct` or `proxy`.",
        "enum": [
         "direct",
         "proxy"
        ]
       }
      }
     }
    }
   },
   "VrboOffer": {
    "type": "object",
    "description": "One bookable price for the rental: a rate plan under one payment model.",
    "required": [
     "plan_id",
     "room_type_id",
     "total",
     "nightly",
     "taxes_and_fees",
     "currency",
     "total_text",
     "nightly_text",
     "taxes_and_fees_included",
     "fees_included",
     "payment_model",
     "hotel_collect",
     "member_only",
     "refundable",
     "cancellation_text",
     "extras",
     "extras_text",
     "strikeout_text",
     "inventory_type",
     "business_model",
     "messages",
     "provenance",
     "taxes_and_fees_provenance"
    ],
    "properties": {
     "plan_id": {
      "type": "string",
      "description": "Vrbo rate-plan id."
     },
     "room_type_id": {
      "type": "string"
     },
     "total": {
      "type": [
       "number",
       "null"
      ],
      "description": "Stay total for all nights, Vrbo's own figure; `fees_included` repeats its \"All fees included\" label. Cleaning and service fees and taxes are not itemised."
     },
     "nightly": {
      "type": [
       "number",
       "null"
      ],
      "description": "Vrbo's nightly price."
     },
     "taxes_and_fees": {
      "type": [
       "number",
       "null"
      ],
      "description": "Derived, not read from the source: `total - nightly × nights`, set only when `taxes_and_fees_included` is true. Accurate to within `nights` currency units because `nightly` is rounded; taxes and fees are not itemised. See `taxes_and_fees_provenance`."
     },
     "currency": {
      "type": "string",
      "description": "ISO 4217 code read back from the reply."
     },
     "total_text": {
      "type": "string",
      "description": "Total as displayed, e.g. `$635 total`."
     },
     "nightly_text": {
      "type": "string",
      "description": "Nightly price as displayed, e.g. `$509 nightly`."
     },
     "taxes_and_fees_included": {
      "type": [
       "boolean",
       "null"
      ],
      "description": "True when the source labels the total \"Total with taxes and fees\". Null means no such label was shown, not that taxes are excluded."
     },
     "fees_included": {
      "type": [
       "boolean",
       "null"
      ],
      "description": "True when the source labels the total \"All fees included\". Null means no such label was shown."
     },
     "payment_model": {
      "type": "string",
      "description": "`PAY_NOW`, `PAY_LATER` or `PAY_LATER_WITH_DEPOSIT`; empty when not stated. A plan sold both ways is two offers.",
      "enum": [
       "PAY_NOW",
       "PAY_LATER",
       "PAY_LATER_WITH_DEPOSIT",
       ""
      ]
     },
     "hotel_collect": {
      "type": [
       "boolean",
       "null"
      ],
      "description": "True when the property collects payment; null when not stated."
     },
     "member_only": {
      "type": "boolean",
      "description": "True when booking the plan requires signing in as a member."
     },
     "refundable": {
      "type": [
       "boolean",
       "null"
      ],
      "description": "Always null on Vrbo: refundability is not read, rather than guessed."
     },
     "cancellation_text": {
      "type": "string",
      "description": "Always empty on Vrbo."
     },
     "extras": {
      "type": [
       "string",
       "null"
      ],
      "description": "Always null on Vrbo."
     },
     "extras_text": {
      "type": "string",
      "description": "Always empty on Vrbo."
     },
     "strikeout_text": {
      "type": "string",
      "description": "Struck-through comparison price as displayed; empty when none."
     },
     "inventory_type": {
      "type": "string",
      "description": "Source inventory type, e.g. `MERCHANT`, `TRIPCOM`, `DIRECT_AGENCY`, `VRBO`; empty when not stated."
     },
     "business_model": {
      "type": "string",
      "description": "`EXPEDIA_COLLECT` or `HOTEL_COLLECT`; empty when not stated."
     },
     "messages": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Vrbo's highlighted messages for the plan, e.g. `Reserve now, pay deposit`, `Your dates are available`."
     },
     "provenance": {
      "$ref": "#/components/schemas/RateProvenance"
     },
     "taxes_and_fees_provenance": {
      "anyOf": [
       {
        "$ref": "#/components/schemas/RateProvenance"
       },
       {
        "type": "null"
       }
      ],
      "description": "Provenance of `taxes_and_fees` (`price_basis: taxes_and_fees_combined`, `derivation: total_minus_nightly_times_nights`); null when `taxes_and_fees` is null."
     }
    }
   },
   "VrboQuoteResponse": {
    "type": "object",
    "description": "Response of `POST /v1/ota/vrbo`.",
    "required": [
     "search_parameters",
     "property",
     "offers",
     "meta"
    ],
    "properties": {
     "search_parameters": {
      "type": "object",
      "required": [
       "engine",
       "property_id",
       "check_in_date",
       "check_out_date",
       "adults",
       "market",
       "currency"
      ],
      "properties": {
       "engine": {
        "type": "string",
        "enum": [
         "vrbo_property"
        ]
       },
       "property_id": {
        "type": "string",
        "description": "The property id quoted (resolved from `listing_id` when only that was sent)."
       },
       "listing_id": {
        "type": "string",
        "description": "Present only when `listing_id` was supplied."
       },
       "check_in_date": {
        "type": "string",
        "format": "date"
       },
       "check_out_date": {
        "type": "string",
        "format": "date"
       },
       "adults": {
        "type": "integer"
       },
       "market": {
        "type": "string",
        "description": "`US`."
       },
       "currency": {
        "type": "string",
        "description": "The market's currency (`USD`)."
       }
      }
     },
     "property": {
      "type": "object",
      "required": [
       "property_id",
       "listing_id",
       "total",
       "price_per_night",
       "basis",
       "total_text",
       "nightly_text",
       "taxes_and_fees_included",
       "fees_included",
       "currency",
       "currency_verified",
       "available",
       "unavailable_reason",
       "payment_model",
       "provenance"
      ],
      "properties": {
       "property_id": {
        "type": "string",
        "description": "Numeric Vrbo property id; store it to skip listing resolution next time."
       },
       "listing_id": {
        "type": [
         "string",
         "null"
        ],
        "description": "The `listing_id` you sent, echoed; null when you sent only `property_id`. When both are sent, `property_id` is used and the two are not cross-checked."
       },
       "total": {
        "type": [
         "number",
         "null"
        ],
        "description": "Headline stay total for all nights (Vrbo's own figure); see `basis`. Null when nothing priced."
       },
       "price_per_night": {
        "type": [
         "number",
         "null"
        ],
        "description": "Headline nightly price."
       },
       "basis": {
        "type": [
         "string",
         "null"
        ],
        "description": "Where the headline comes from: `sticky_bar` (the page's own headline price, read by its labels) or `cheapest_offer` (the cheapest priced offer). Null when nothing priced.",
        "enum": [
         "sticky_bar",
         "cheapest_offer",
         null
        ]
       },
       "total_text": {
        "type": "string",
        "description": "Headline total as displayed; empty when not shown."
       },
       "nightly_text": {
        "type": "string",
        "description": "Headline nightly price as displayed; empty when not shown."
       },
       "taxes_and_fees_included": {
        "type": [
         "boolean",
         "null"
        ],
        "description": "True when the headline total is labelled \"with taxes and fees\"; null when no such label was shown."
       },
       "fees_included": {
        "type": [
         "boolean",
         "null"
        ],
        "description": "True when the headline total is labelled \"All fees included\"; null when no such label was shown."
       },
       "currency": {
        "type": "string",
        "description": "Currency the point-of-sale actually priced in."
       },
       "currency_verified": {
        "type": "boolean",
        "description": "Whether `currency` equals the market's currency."
       },
       "available": {
        "type": "boolean",
        "description": "False when Vrbo will not sell the stay as asked."
       },
       "unavailable_reason": {
        "type": [
         "string",
         "null"
        ],
        "description": "Vrbo's own message when the stay cannot be booked (minimum stay, dates taken). Null otherwise; `available` can be false with a null reason when nothing priced."
       },
       "payment_model": {
        "type": [
         "string",
         "null"
        ],
        "description": "`payment_model` of the cheapest offer; null when nothing priced.",
        "enum": [
         "PAY_NOW",
         "PAY_LATER",
         "PAY_LATER_WITH_DEPOSIT",
         "",
         null
        ]
       },
       "provenance": {
        "$ref": "#/components/schemas/RateProvenance"
       }
      }
     },
     "offers": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/VrboOffer"
      },
      "description": "Every rate plan for the rental."
     },
     "meta": {
      "type": "object",
      "required": [
       "source",
       "collection_id",
       "observed_at",
       "nights",
       "wire_bytes",
       "elapsed_s",
       "egress_mode",
       "listing_resolved"
      ],
      "properties": {
       "source": {
        "type": "string",
        "enum": [
         "vrbo"
        ]
       },
       "collection_id": {
        "type": "string"
       },
       "observed_at": {
        "type": "string"
       },
       "nights": {
        "type": "integer"
       },
       "wire_bytes": {
        "type": "integer",
        "description": "Bytes received from the source, including the listing page when `listing_id` was resolved."
       },
       "elapsed_s": {
        "type": "number"
       },
       "egress_mode": {
        "type": "string",
        "description": "How the request was routed: `direct` or `proxy`.",
        "enum": [
         "direct",
         "proxy"
        ]
       },
       "listing_resolved": {
        "type": "boolean",
        "description": "True when `listing_id` was resolved to `property_id` in this call."
       }
      }
     }
    }
   },
   "FlightLayover": {
    "type": "object",
    "description": "A connection between two segments of a leg.",
    "required": [
     "duration_minutes",
     "airport",
     "airport_name",
     "city",
     "departure_airport",
     "change_of_airport",
     "overnight"
    ],
    "properties": {
     "duration_minutes": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Connection time, minutes."
     },
     "airport": {
      "type": "string",
      "description": "IATA code of the airport the traveller lands at."
     },
     "airport_name": {
      "type": [
       "string",
       "null"
      ]
     },
     "city": {
      "type": [
       "string",
       "null"
      ]
     },
     "departure_airport": {
      "type": "string",
      "description": "Airport the next flight leaves from; equals `airport` unless the connection changes airports."
     },
     "change_of_airport": {
      "type": "boolean",
      "description": "The next flight leaves from a different airport."
     },
     "overnight": {
      "type": "boolean",
      "description": "The next flight leaves on a later calendar day than the previous one lands."
     }
    }
   },
   "FlightCarbonEmissions": {
    "type": "object",
    "description": "Emissions in grams of CO2e (SerpApi's `carbon_emissions` shape).",
    "required": [
     "this_flight",
     "typical_for_this_route",
     "difference_percent"
    ],
    "properties": {
     "this_flight": {
      "type": "integer",
      "description": "Estimate for this itinerary, grams of CO2e."
     },
     "typical_for_this_route": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Typical estimate for this route, grams of CO2e."
     },
     "difference_percent": {
      "type": [
       "integer",
       "null"
      ],
      "description": "This itinerary vs typical, percent (negative = lower)."
     }
    }
   },
   "FlightPriceInsights": {
    "type": "object",
    "description": "Google Flights price insights.",
    "required": [
     "lowest_price",
     "price_level",
     "typical_price_range",
     "price_history"
    ],
    "properties": {
     "lowest_price": {
      "type": [
       "number",
       "null"
      ],
      "description": "Lowest price Google shows for this search, in `currency`."
     },
     "price_level": {
      "type": [
       "string",
       "null"
      ],
      "description": "Google's verdict on today's price: `low` (below its typical range), `typical` (inside it) or `high` (above it).",
      "enum": [
       "low",
       "typical",
       "high",
       null
      ]
     },
     "typical_price_range": {
      "anyOf": [
       {
        "type": "array",
        "items": {
         "type": "number"
        },
        "minItems": 2,
        "maxItems": 2
       },
       {
        "type": "null"
       }
      ],
      "description": "`[low, high]`: Google's typical price range for this trip."
     },
     "price_history": {
      "type": "array",
      "items": {
       "type": "array",
       "items": {
        "type": "number"
       },
       "minItems": 2,
       "maxItems": 2
      },
      "description": "`[[unix_seconds, price], ...]`: Google's price history for this trip, about 60 days. Empty when Google gives none."
     }
    }
   },
   "FlightsReturnResponse": {
    "type": "object",
    "description": "Response of `POST /v1/serp/google_flights_return`. Same shape as the `/v1/serp/google_flights` response, for the leg after the one the `departure_token` chose. Options of the trip's last leg carry `booking_token`; earlier ones carry `departure_token`.",
    "required": [
     "departure_airport",
     "arrival_airport",
     "departure_date",
     "currency",
     "adults",
     "itineraries",
     "wire_bytes",
     "elapsed_s",
     "cheapest_price",
     "trip_type",
     "leg_index",
     "legs_total",
     "itinerary_count",
     "best_count",
     "airlines_available",
     "google_flights_url",
     "source",
     "warnings"
    ],
    "properties": {
     "departure_airport": {
      "type": "string",
      "description": "Origin of the leg these options are for: airport codes or Google city ids, comma-separated."
     },
     "arrival_airport": {
      "type": "string",
      "description": "Destination of the leg these options are for: airport codes or Google city ids, comma-separated."
     },
     "departure_date": {
      "type": "string",
      "description": "Date of the leg these options are for (the return date of a round trip).",
      "format": "date"
     },
     "return_date": {
      "type": "string",
      "description": "Present only for round trips (the same date as `departure_date`).",
      "format": "date"
     },
     "currency": {
      "type": "string",
      "description": "The requested currency."
     },
     "adults": {
      "type": "integer"
     },
     "itineraries": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/FlightItinerary"
      },
      "description": "Options for the leg being chosen: Google's best flights first, then the others."
     },
     "wire_bytes": {
      "type": "integer",
      "description": "Size of Google's response, bytes."
     },
     "elapsed_s": {
      "type": "number",
      "description": "Time Google took to answer, seconds."
     },
     "cheapest_price": {
      "type": [
       "number",
       "null"
      ],
      "description": "Lowest `price` in `itineraries`; null when none is priced."
     },
     "trip_type": {
      "type": "string",
      "description": "`one_way`, `round_trip` or `multi_city`.",
      "enum": [
       "one_way",
       "round_trip",
       "multi_city"
      ]
     },
     "leg_index": {
      "type": "integer",
      "description": "Which leg these options are for: 1 = return or second multi-city leg, and so on."
     },
     "legs_total": {
      "type": "integer",
      "description": "Legs in the trip: 1 one-way, 2 round trip, 2-5 multi-city."
     },
     "itinerary_count": {
      "type": "integer",
      "description": "Number of entries in `itineraries`."
     },
     "best_count": {
      "type": "integer",
      "description": "How many `itineraries` have `group: best`."
     },
     "price_insights": {
      "anyOf": [
       {
        "$ref": "#/components/schemas/FlightPriceInsights"
       },
       {
        "type": "null"
       }
      ],
      "description": "Usually null: Google rarely gives insights for a return or later leg. Omitted when `itineraries` is empty; that answer is not billed."
     },
     "airlines_available": {
      "type": "array",
      "items": {
       "type": "object",
       "required": [
        "code",
        "name",
        "type"
       ],
       "properties": {
        "code": {
         "type": "string",
         "description": "IATA airline code, or `STAR_ALLIANCE` / `SKYTEAM` / `ONEWORLD`."
        },
        "name": {
         "type": [
          "string",
          "null"
         ]
        },
        "type": {
         "type": "string",
         "enum": [
          "alliance",
          "airline"
         ]
        }
       }
      },
      "description": "Airlines and alliances Google offers as filters for this search; the codes work in `include_airlines`."
     },
     "google_flights_url": {
      "type": "string",
      "description": "Google Flights search page for this trip."
     },
     "source": {
      "type": "string",
      "description": "Always `rpc` for this call.",
      "enum": [
       "rpc",
       "html"
      ]
     },
     "warnings": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Notices about this answer, e.g. that Google priced some options in another currency (see each itinerary's `priced_in`). Empty when none."
     }
    }
   },
   "FlightBookingOption": {
    "type": "object",
    "description": "One way to buy the itinerary (SerpApi's `booking_options`).",
    "required": [
     "book_with",
     "seller_code",
     "is_airline",
     "price",
     "currency",
     "display_price",
     "local_prices",
     "marketed_as",
     "booking_request",
     "booking_url",
     "seller_domain",
     "booking_phone",
     "separate_tickets",
     "sellers",
     "option_title",
     "extensions",
     "baggage_prices"
    ],
    "properties": {
     "book_with": {
      "type": "string",
      "description": "Seller name; several sellers are joined with ` and ` when the option is separate tickets."
     },
     "seller_code": {
      "type": [
       "string",
       "null"
      ],
      "description": "Google's code for the (first) seller: the IATA code for an airline, e.g. `LX`."
     },
     "is_airline": {
      "type": "boolean",
      "description": "Every seller is an airline (airline direct)."
     },
     "price": {
      "type": [
       "number",
       "null"
      ],
      "description": "This seller's price for the whole trip, in `currency`, as Google shows it."
     },
     "currency": {
      "type": "string",
      "description": "Currency of the original search."
     },
     "display_price": {
      "type": [
       "string",
       "null"
      ],
      "description": "`price` with its currency symbol, e.g. `$527`."
     },
     "local_prices": {
      "type": "array",
      "items": {
       "type": "object",
       "required": [
        "currency",
        "price"
       ],
       "properties": {
        "currency": {
         "type": "string"
        },
        "price": {
         "type": "number"
        }
       }
      },
      "description": "The seller's own price when it charges in another currency, e.g. CAD 749."
     },
     "marketed_as": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Flight numbers this seller sells the itinerary under, e.g. `LX 647`."
     },
     "booking_request": {
      "anyOf": [
       {
        "type": "object",
        "required": [
         "url",
         "post_data"
        ],
        "properties": {
         "url": {
          "type": "string",
          "description": "Google's click-through URL."
         },
         "post_data": {
          "type": "string",
          "description": "URL-encoded form body."
         }
        }
       },
       {
        "type": "null"
       }
      ],
      "description": "Google's click-through as a form (SerpApi's shape): POST `post_data` as `application/x-www-form-urlencoded` to `url`. Null when the seller has no link (e.g. call to book)."
     },
     "booking_url": {
      "type": [
       "string",
       "null"
      ],
      "description": "The same click-through as a GET link; Google answers it with a redirect to the seller's page. Null when `booking_request` is."
     },
     "seller_domain": {
      "type": [
       "string",
       "null"
      ],
      "description": "The seller's site as Google shows it, e.g. `www.swiss.com/...`."
     },
     "booking_phone": {
      "type": [
       "string",
       "null"
      ],
      "description": "Phone number of a call-to-book seller (which has no link)."
     },
     "separate_tickets": {
      "type": "boolean",
      "description": "The option is several tickets bought from different sellers (see `sellers`)."
     },
     "sellers": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Every seller of this option."
     },
     "option_title": {
      "type": [
       "string",
       "null"
      ],
      "description": "Fare family when Google names one, e.g. `Delta Main Basic`."
     },
     "extensions": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Fare rules Google lists, e.g. `No refunds`, `Free seat selection`, `Ticket changes for a fee`. Mostly shown for airline-direct sellers."
     },
     "baggage_prices": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Bag fees as Google words them, e.g. `1st checked bag: $45`, `1 free carry-on`."
     }
    }
   },
   "FlightsBookingResponse": {
    "type": "object",
    "description": "Response of `POST /v1/serp/google_flights_booking`.",
    "required": [
     "currency",
     "trip_type",
     "legs",
     "booking_options",
     "option_count",
     "cheapest_price",
     "google_flights_url",
     "wire_bytes",
     "elapsed_s"
    ],
    "properties": {
     "currency": {
      "type": "string",
      "description": "Currency of the original search."
     },
     "trip_type": {
      "type": "string",
      "description": "`one_way`, `round_trip` or `multi_city`.",
      "enum": [
       "one_way",
       "round_trip",
       "multi_city"
      ]
     },
     "legs": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/FlightLeg"
      },
      "description": "Every leg of the chosen itinerary, in order."
     },
     "booking_options": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/FlightBookingOption"
      },
      "description": "Airline-direct and online travel agency sellers."
     },
     "option_count": {
      "type": "integer",
      "description": "Number of entries in `booking_options`."
     },
     "cheapest_price": {
      "type": [
       "number",
       "null"
      ],
      "description": "Lowest `price` in `booking_options`; null when none is priced."
     },
     "price_insights": {
      "anyOf": [
       {
        "$ref": "#/components/schemas/FlightPriceInsights"
       },
       {
        "type": "null"
       }
      ],
      "description": "Null when Google gives none. Omitted when `booking_options` is empty; that answer is not billed."
     },
     "google_flights_url": {
      "type": "string",
      "description": "Google Flights booking page for this itinerary."
     },
     "wire_bytes": {
      "type": "integer",
      "description": "Size of Google's response, bytes."
     },
     "elapsed_s": {
      "type": "number",
      "description": "Time Google took to answer, seconds (typically 3-12 s: Google checks seller prices while the request is open)."
     }
    }
   },
   "FlightLocation": {
    "type": "object",
    "description": "One autocomplete result.",
    "required": [
     "type",
     "name",
     "iata",
     "id",
     "city",
     "description",
     "airports"
    ],
    "properties": {
     "type": {
      "type": "string",
      "enum": [
       "airport",
       "city",
       "region",
       "train_station"
      ]
     },
     "name": {
      "type": "string",
      "description": "e.g. `Paris, France`."
     },
     "iata": {
      "type": [
       "string",
       "null"
      ],
      "description": "IATA code of an airport or train station; null for cities and regions."
     },
     "id": {
      "type": [
       "string",
       "null"
      ],
      "description": "Google entity id, e.g. `/m/05qtj`. A city's id can be passed as `departure_id`/`arrival_id` (or a `multi_city` leg's `departure`/`arrival`) of `/v1/serp/google_flights` to search all of its airports."
     },
     "city": {
      "type": [
       "string",
       "null"
      ]
     },
     "description": {
      "type": [
       "string",
       "null"
      ],
      "description": "e.g. `Capital of France`, `Airport in France`."
     },
     "airports": {
      "type": "array",
      "items": {
       "type": "object",
       "required": [
        "iata",
        "name",
        "city",
        "type",
        "distance"
       ],
       "properties": {
        "iata": {
         "type": "string"
        },
        "name": {
         "type": [
          "string",
          "null"
         ]
        },
        "city": {
         "type": [
          "string",
          "null"
         ]
        },
        "type": {
         "type": "string",
         "enum": [
          "airport",
          "city",
          "region",
          "train_station"
         ]
        },
        "distance": {
         "type": [
          "string",
          "null"
         ],
         "description": "Distance from the city as Google shows it, e.g. `14 mi`."
        }
       }
      },
      "description": "For a city: its airports and train stations. Empty otherwise."
     }
    }
   },
   "FlightsLocationSearchResponse": {
    "type": "object",
    "description": "Response of `POST /v1/serp/google_flights_location_search`.",
    "required": [
     "q",
     "locations",
     "count",
     "wire_bytes",
     "elapsed_s",
     "cached"
    ],
    "properties": {
     "q": {
      "type": "string",
      "description": "Echo of the request's `q`."
     },
     "locations": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/FlightLocation"
      },
      "description": "Google's autocomplete results, in its order. An empty list is not billed."
     },
     "count": {
      "type": "integer",
      "description": "Number of entries in `locations`."
     },
     "wire_bytes": {
      "type": "integer",
      "description": "Size of Google's response, bytes; 0 when served from cache."
     },
     "elapsed_s": {
      "type": "number",
      "description": "Time Google took to answer, seconds; 0 when served from cache."
     },
     "cached": {
      "type": "boolean",
      "description": "Served from the 6-hour cache of repeated queries."
     }
    }
   },
   "GoogleHotelsSearchImage": {
    "type": "object",
    "required": [
     "thumbnail",
     "original"
    ],
    "properties": {
     "thumbnail": {
      "type": "string",
      "description": "Image URL as Google sent it (card size)."
     },
     "original": {
      "type": "string",
      "description": "Largest rendition of the same image; equals `thumbnail` when no larger size is available."
     }
    }
   },
   "GoogleHotelsSearchReviewCategory": {
    "type": "object",
    "required": [
     "name",
     "description",
     "total",
     "positive",
     "neutral",
     "negative"
    ],
    "properties": {
     "name": {
      "type": "string",
      "description": "Review topic, e.g. `Fitness`."
     },
     "description": {
      "type": "string"
     },
     "total": {
      "type": "integer",
      "description": "Reviews that mention the topic."
     },
     "positive": {
      "type": "integer"
     },
     "neutral": {
      "type": "integer",
      "description": "`total - positive - negative`, never below 0."
     },
     "negative": {
      "type": "integer"
     }
    }
   },
   "GoogleHotelsSearchNearbyPlace": {
    "type": "object",
    "required": [
     "name",
     "category_code",
     "transportations"
    ],
    "properties": {
     "name": {
      "type": "string"
     },
     "category_code": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Google's place category code, as sent."
     },
     "transportations": {
      "type": "array",
      "items": {
       "type": "object",
       "required": [
        "type",
        "type_code",
        "duration"
       ],
       "properties": {
        "type": {
         "type": [
          "string",
          "null"
         ],
         "description": "`Taxi`, `Walking` or `Public transport`; null for an unmapped `type_code`."
        },
        "type_code": {
         "type": [
          "integer",
          "null"
         ],
         "description": "Google's code: 0 taxi, 2 walking, 3 public transport."
        },
        "duration": {
         "type": "string",
         "description": "As displayed, e.g. `35 min`."
        }
       }
      }
     }
    }
   },
   "GoogleHotelsSearchSellerPrice": {
    "type": "object",
    "description": "One seller row Google attached to a result card; mostly on vacation rentals. All prices are in the property's currency.",
    "required": [
     "source",
     "raw_source",
     "displayed_prices",
     "partner_id",
     "logo",
     "price_per_night",
     "price_per_night_before_taxes",
     "extracted_price_per_night",
     "extracted_price_per_night_before_taxes",
     "has_free_cancellation",
     "free_cancellation_until",
     "free_cancellation_time",
     "is_featured"
    ],
    "properties": {
     "source": {
      "type": "string",
      "description": "Seller name, with country-domain variants merged (e.g. `Booking.com`)."
     },
     "raw_source": {
      "type": "string",
      "description": "Seller name as displayed."
     },
     "displayed_prices": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Every price string on the row, as displayed, including a lone one whose basis Google does not label."
     },
     "partner_id": {
      "type": [
       "string",
       "null"
      ],
      "description": "Google's partner id for the seller."
     },
     "logo": {
      "type": [
       "string",
       "null"
      ],
      "description": "Logo URL; may be protocol-relative (`//...`)."
     },
     "price_per_night": {
      "type": [
       "string",
       "null"
      ],
      "description": "Nightly display string including taxes and fees. Null unless the row shows a before-taxes / all-in pair."
     },
     "price_per_night_before_taxes": {
      "type": [
       "string",
       "null"
      ],
      "description": "Nightly display string before taxes. Null unless the row shows a pair."
     },
     "extracted_price_per_night": {
      "type": [
       "number",
       "null"
      ],
      "description": "Nightly price including taxes and fees."
     },
     "extracted_price_per_night_before_taxes": {
      "type": [
       "number",
       "null"
      ],
      "description": "Nightly price before taxes."
     },
     "has_free_cancellation": {
      "type": "boolean"
     },
     "free_cancellation_until": {
      "type": [
       "string",
       "null"
      ],
      "description": "Last free-cancellation date as displayed, e.g. `Oct 16`."
     },
     "free_cancellation_time": {
      "type": [
       "string",
       "null"
      ],
      "description": "e.g. `4:00 PM`."
     },
     "is_featured": {
      "type": "boolean",
      "description": "True for rows from Google's featured list."
     }
    }
   },
   "GoogleHotelsSearchBrand": {
    "type": "object",
    "description": "A brand family Google offers as a filter for this destination. Informational only: brand filtering is not supported.",
    "required": [
     "id",
     "title",
     "children"
    ],
    "properties": {
     "id": {
      "type": "integer",
      "description": "Google brand id."
     },
     "title": {
      "type": "string",
      "description": "Brand name; empty string when Google did not name it."
     },
     "children": {
      "type": "array",
      "items": {
       "type": "object",
       "required": [
        "id",
        "title"
       ],
       "properties": {
        "id": {
         "type": "integer"
        },
        "title": {
         "type": "string"
        }
       }
      },
      "description": "Sub-brands."
     }
    }
   },
   "GoogleHotelsSearchPagination": {
    "type": "object",
    "description": "Pages overlap by a few results (page 2 starts before page 1 ends); de-duplicate by `property_token`.",
    "required": [
     "records_from",
     "records_to",
     "next_page_token"
    ],
    "properties": {
     "records_from": {
      "type": [
       "integer",
       "null"
      ],
      "description": "1-based position of the first result on this page."
     },
     "records_to": {
      "type": [
       "integer",
       "null"
      ],
      "description": "1-based position of the last result on this page."
     },
     "next_page_token": {
      "type": [
       "string",
       "null"
      ],
      "description": "Send it back (as `page_token` on `/v1/hotels/search`, `next_page_token` on `/v1/serp/google_hotels`) with the same query, stay, party and filters for the next page. Null on the last page."
     }
    }
   },
   "GoogleHotelsSearchRate": {
    "type": "object",
    "description": "Lowest price Google shows for the stay, itemised. Every figure is in `currency`.",
    "required": [
     "currency",
     "check_in",
     "check_out",
     "nights",
     "price_per_night",
     "price_per_night_before_taxes",
     "extracted_price_per_night",
     "extracted_price_per_night_before_taxes",
     "total_price",
     "total_price_before_taxes",
     "base",
     "taxes",
     "fees",
     "total",
     "before_taxes",
     "from_display_text"
    ],
    "properties": {
     "currency": {
      "type": [
       "string",
       "null"
      ],
      "description": "ISO 4217 code every figure in `rate` is in."
     },
     "check_in": {
      "type": [
       "string",
       "null"
      ],
      "description": "Stay Google priced (equals the requested stay whenever `total` is set).",
      "format": "date"
     },
     "check_out": {
      "type": [
       "string",
       "null"
      ],
      "format": "date"
     },
     "nights": {
      "type": [
       "integer",
       "null"
      ]
     },
     "price_per_night": {
      "type": [
       "string",
       "null"
      ],
      "description": "Nightly display string including taxes and fees, e.g. `$121`."
     },
     "price_per_night_before_taxes": {
      "type": [
       "string",
       "null"
      ],
      "description": "Nightly display string before taxes (base + mandatory fees); the price Google's card shows."
     },
     "extracted_price_per_night": {
      "type": [
       "number",
       "null"
      ],
      "description": "`total / nights`, rounded to 2 decimals: nightly price including taxes and fees."
     },
     "extracted_price_per_night_before_taxes": {
      "type": [
       "number",
       "null"
      ],
      "description": "Google's exact nightly figure before taxes: `(base + fees) / nights`."
     },
     "total_price": {
      "type": [
       "string",
       "null"
      ],
      "description": "Whole-stay display string including taxes and fees."
     },
     "total_price_before_taxes": {
      "type": [
       "string",
       "null"
      ],
      "description": "Whole-stay display string before taxes."
     },
     "base": {
      "type": [
       "number",
       "null"
      ],
      "description": "Whole-stay room price before taxes and fees."
     },
     "taxes": {
      "type": [
       "number",
       "null"
      ],
      "description": "Whole-stay taxes."
     },
     "fees": {
      "type": [
       "number",
       "null"
      ],
      "description": "Whole-stay mandatory fees (e.g. a rental's cleaning fee), kept separate from taxes."
     },
     "total": {
      "type": [
       "number",
       "null"
      ],
      "description": "Whole-stay price: `base + taxes + fees`. Null when Google showed only a nightly display price."
     },
     "before_taxes": {
      "type": [
       "number",
       "null"
      ],
      "description": "Whole-stay `base + fees`, rounded to 2 decimals (SearchAPI's before-taxes basis)."
     },
     "from_display_text": {
      "type": "boolean",
      "description": "True when Google sent no itemised amounts and `total`/`base` were parsed from the display strings; `taxes` and `fees` are then null and `base` is the displayed before-taxes total."
     }
    }
   },
   "GoogleHotelsSearchProperty": {
    "type": "object",
    "description": "One result card. Every key is always present; unknown values are null.",
    "required": [
     "type",
     "property_token",
     "name",
     "data_id",
     "description",
     "link",
     "gps_coordinates",
     "country",
     "check_in_time",
     "check_out_time",
     "hotel_class",
     "extracted_hotel_class",
     "rating",
     "reviews",
     "reviews_histogram",
     "location_rating",
     "proximity_to_things_to_do_rating",
     "proximity_to_restaurants_rating",
     "proximity_to_transit_rating",
     "airport_access_rating",
     "reviews_breakdown",
     "amenities",
     "amenity_codes",
     "excluded_amenities",
     "essential_info",
     "thumbnail",
     "images",
     "nearby_places",
     "deal",
     "deal_description",
     "deal_kind",
     "rate",
     "sources",
     "provenance"
    ],
    "properties": {
     "type": {
      "type": "string",
      "description": "Google blends vacation rentals into the default list; this says which each result is.",
      "enum": [
       "hotel",
       "vacation_rental"
      ]
     },
     "property_token": {
      "type": "string",
      "description": "Google property token; pass it to `/v1/calendar` or `/v1/offers`."
     },
     "name": {
      "type": "string"
     },
     "data_id": {
      "type": [
       "string",
       "null"
      ],
      "description": "Google Maps data id (`0x...:0x...`)."
     },
     "description": {
      "type": [
       "string",
       "null"
      ]
     },
     "link": {
      "type": [
       "string",
       "null"
      ],
      "description": "The property's own website, when Google lists one."
     },
     "gps_coordinates": {
      "anyOf": [
       {
        "type": "object",
        "required": [
         "latitude",
         "longitude"
        ],
        "properties": {
         "latitude": {
          "type": "number"
         },
         "longitude": {
          "type": "number"
         }
        }
       },
       {
        "type": "null"
       }
      ]
     },
     "country": {
      "type": [
       "string",
       "null"
      ],
      "description": "ISO 3166-1 alpha-2 country code."
     },
     "check_in_time": {
      "type": [
       "string",
       "null"
      ],
      "description": "As displayed, e.g. `3:00 PM`."
     },
     "check_out_time": {
      "type": [
       "string",
       "null"
      ],
      "description": "As displayed, e.g. `11:00 AM`."
     },
     "hotel_class": {
      "type": [
       "string",
       "null"
      ],
      "description": "As displayed, e.g. `4-star hotel`."
     },
     "extracted_hotel_class": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Star class, 1-5."
     },
     "rating": {
      "type": [
       "number",
       "null"
      ],
      "description": "Guest rating out of 5."
     },
     "reviews": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Number of reviews."
     },
     "reviews_histogram": {
      "anyOf": [
       {
        "type": "object",
        "properties": {
         "1": {
          "type": "integer"
         },
         "2": {
          "type": "integer"
         },
         "3": {
          "type": "integer"
         },
         "4": {
          "type": "integer"
         },
         "5": {
          "type": "integer"
         }
        }
       },
       {
        "type": "null"
       }
      ],
      "description": "Review count per star rating, keyed `1`-`5` (only the stars Google reported). Null when Google gave none."
     },
     "location_rating": {
      "type": [
       "number",
       "null"
      ],
      "description": "Overall location score, out of 5. Null when Google has no score."
     },
     "proximity_to_things_to_do_rating": {
      "type": [
       "number",
       "null"
      ],
      "description": "Score for proximity to things to do, out of 5. Null when Google has no score."
     },
     "proximity_to_restaurants_rating": {
      "type": [
       "number",
       "null"
      ],
      "description": "Score for proximity to restaurants, out of 5. Null when Google has no score."
     },
     "proximity_to_transit_rating": {
      "type": [
       "number",
       "null"
      ],
      "description": "Score for proximity to public transit, out of 5. Null when Google has no score."
     },
     "airport_access_rating": {
      "type": [
       "number",
       "null"
      ],
      "description": "Score for airport access, out of 5. Null when Google has no score."
     },
     "reviews_breakdown": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/GoogleHotelsSearchReviewCategory"
      },
      "description": "Review topics with mention counts; empty when Google gave none."
     },
     "amenities": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Amenity names. Hotel amenity names are always English; rentals use Google's own labels."
     },
     "amenity_codes": {
      "type": "array",
      "items": {
       "type": "array",
       "items": {
        "type": "integer"
       },
       "minItems": 2,
       "maxItems": 2
      },
      "description": "Raw `[flag, code]` pairs from the card. Codes are not the `amenities` filter ids; codes without a known name appear only here. The flag does not mark an amenity as absent."
     },
     "excluded_amenities": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Amenities a rental states it lacks, e.g. `No balcony`; usually empty for hotels."
     },
     "essential_info": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Rental basics such as `Entire apartment` or `Sleeps 2`; usually empty for hotels."
     },
     "thumbnail": {
      "type": [
       "string",
       "null"
      ]
     },
     "images": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/GoogleHotelsSearchImage"
      }
     },
     "nearby_places": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/GoogleHotelsSearchNearbyPlace"
      }
     },
     "deal": {
      "type": [
       "string",
       "null"
      ],
      "description": "Deal text, e.g. `27% less than usual` or `Great price for a 4-star hotel`. Null when there is no deal."
     },
     "deal_description": {
      "type": [
       "string",
       "null"
      ],
      "description": "Badge Google renders: `Deal`, `Great Deal`, `Great Price`, or another label."
     },
     "deal_kind": {
      "type": [
       "string",
       "null"
      ],
      "description": "`below_usual_price`, `great_price`, or `code_<n>` for a deal type not yet mapped. Null when there is no deal."
     },
     "rate": {
      "anyOf": [
       {
        "$ref": "#/components/schemas/GoogleHotelsSearchRate"
       },
       {
        "type": "null"
       }
      ],
      "description": "Lowest price for the stay. Null when the card carried no price, or Google priced other dates and the price was removed (see `warnings`)."
     },
     "sources": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/GoogleHotelsSearchSellerPrice"
      },
      "description": "Seller rows Google attached to the card; mostly vacation rentals, usually empty for hotels."
     },
     "provenance": {
      "anyOf": [
       {
        "$ref": "#/components/schemas/RateProvenance"
       },
       {
        "type": "null"
       }
      ],
      "description": "Provenance of `rate`; null unless `rate.total` is known."
     }
    }
   },
   "GoogleHotelsSearchResponse": {
    "type": "object",
    "description": "Response of `POST /v1/hotels/search`.",
    "required": [
     "search_parameters",
     "search_information",
     "properties",
     "brands",
     "pagination",
     "warnings",
     "meta"
    ],
    "properties": {
     "search_parameters": {
      "type": "object",
      "description": "Echo of the effective request. Optional filters appear only when set.",
      "required": [
       "engine",
       "q",
       "check_in_date",
       "check_out_date",
       "adults",
       "children_ages",
       "currency",
       "gl",
       "hl",
       "sort_by"
      ],
      "properties": {
       "engine": {
        "type": "string",
        "enum": [
         "google_hotels_search"
        ]
       },
       "q": {
        "type": "string"
       },
       "check_in_date": {
        "type": "string",
        "format": "date"
       },
       "check_out_date": {
        "type": "string",
        "format": "date"
       },
       "adults": {
        "type": "integer"
       },
       "children_ages": {
        "type": "array",
        "items": {
         "type": "integer"
        },
        "description": "One age per child; empty when none."
       },
       "currency": {
        "type": "string",
        "description": "Requested currency, upper-case."
       },
       "gl": {
        "type": "string",
        "description": "Market country code, lower-case."
       },
       "hl": {
        "type": "string"
       },
       "sort_by": {
        "type": "string",
        "enum": [
         "relevance",
         "lowest_price",
         "highest_rating",
         "most_reviewed"
        ]
       },
       "price_min": {
        "type": "integer",
        "description": "Present only when set in the request."
       },
       "price_max": {
        "type": "integer",
        "description": "Present only when set in the request."
       },
       "min_rating": {
        "type": "number",
        "description": "3.5, 4.0 or 4.5. Present only when set in the request."
       },
       "hotel_class": {
        "type": "array",
        "items": {
         "type": "integer"
        },
        "description": "Present only when set in the request."
       },
       "amenities": {
        "type": "array",
        "items": {
         "type": "integer"
        },
        "description": "Present only when set in the request."
       },
       "property_types": {
        "type": "array",
        "items": {
         "type": "integer"
        },
        "description": "Present only when set in the request."
       },
       "free_cancellation": {
        "type": "boolean",
        "description": "Present only when true."
       },
       "special_offers": {
        "type": "boolean",
        "description": "Present only when true."
       },
       "eco_certified": {
        "type": "boolean",
        "description": "Present only when true."
       },
       "next_page_token": {
        "type": "string",
        "description": "Page token this page was fetched with. Present only when one was sent."
       }
      }
     },
     "search_information": {
      "type": "object",
      "required": [
       "total_results",
       "location",
       "location_data_id",
       "nights",
       "returned",
       "priced",
       "requested_currency",
       "returned_currency",
       "currency_matches_request",
       "requested_market",
       "available_property_types"
      ],
      "properties": {
       "total_results": {
        "type": [
         "integer",
         "null"
        ],
        "description": "Total properties Google reports for the search."
       },
       "location": {
        "type": [
         "string",
         "null"
        ],
        "description": "Place Google resolved `q` to."
       },
       "location_data_id": {
        "type": [
         "string",
         "null"
        ],
        "description": "Google's place id for `location`."
       },
       "nights": {
        "type": "integer"
       },
       "returned": {
        "type": "integer",
        "description": "Properties on this page."
       },
       "priced": {
        "type": "integer",
        "description": "Properties on this page with a known stay total."
       },
       "requested_currency": {
        "type": "string"
       },
       "returned_currency": {
        "type": [
         "string",
         "null"
        ],
        "description": "Currency the prices came back in; `MIXED` when properties differ; null when no property carried a currency."
       },
       "currency_matches_request": {
        "type": "boolean",
        "description": "False when Google returned another currency (also reported in `warnings`)."
       },
       "requested_market": {
        "type": "string",
        "description": "`gl`, upper-cased."
       },
       "available_property_types": {
        "type": "array",
        "items": {
         "type": "object",
         "required": [
          "id",
          "name"
         ],
         "properties": {
          "id": {
           "type": "integer",
           "description": "Pass in `property_types` to filter."
          },
          "name": {
           "type": [
            "string",
            "null"
           ],
           "description": "Null for an id without a known name."
          }
         }
        },
        "description": "Property-type filters Google offers for this destination."
       }
      }
     },
     "properties": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/GoogleHotelsSearchProperty"
      },
      "description": "About 20 per page."
     },
     "brands": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/GoogleHotelsSearchBrand"
      }
     },
     "pagination": {
      "$ref": "#/components/schemas/GoogleHotelsSearchPagination"
     },
     "warnings": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Notices about this page: prices removed because Google priced other dates, a currency other than the one requested, results outside a requested `hotel_class`, `min_rating` or `price_max`, or prices not verified for the requested market."
     },
     "meta": {
      "type": "object",
      "required": [
       "wire_bytes",
       "elapsed_s",
       "egress",
       "skipped_records"
      ],
      "properties": {
       "wire_bytes": {
        "type": "integer",
        "description": "Bytes received from Google."
       },
       "elapsed_s": {
        "type": "number",
        "description": "Seconds spent fetching from Google."
       },
       "egress": {
        "type": "object",
        "description": "How the request reached Google.",
        "required": [
         "mode",
         "class",
         "pool",
         "attempts",
         "path"
        ],
        "properties": {
         "mode": {
          "type": "string",
          "enum": [
           "direct",
           "proxy"
          ]
         },
         "class": {
          "type": "string",
          "description": "Route class: `direct`, `dc`, `isp`, `resi`, `mobile` or `unblocker`.",
          "enum": [
           "direct",
           "dc",
           "isp",
           "resi",
           "mobile",
           "unblocker"
          ]
         },
         "pool": {
          "type": "string",
          "description": "Route pool that served the request."
         },
         "attempts": {
          "type": "integer",
          "description": "Routes tried, including the successful one."
         },
         "path": {
          "type": "array",
          "items": {
           "type": "string"
          },
          "description": "Each attempt as `<class>/<pool>:<outcome>`, in order."
         }
        }
       },
       "skipped_records": {
        "type": "integer",
        "description": "Result cards that could not be read and were left out."
       }
      }
     }
    }
   },
   "GoogleHotelsSearchSerpProperty": {
    "type": "object",
    "description": "One result card, SearchAPI field names. Keys whose value would be null are omitted, so every key outside `required` is present only when Google supplied it.",
    "required": [
     "type",
     "property_token",
     "name",
     "nearby_places",
     "reviews_breakdown",
     "amenities",
     "images"
    ],
    "properties": {
     "type": {
      "type": "string",
      "description": "Google blends vacation rentals into the default list; this says which each result is.",
      "enum": [
       "hotel",
       "vacation_rental"
      ]
     },
     "property_token": {
      "type": "string",
      "description": "Google property token; pass it to `/v1/serp/google_hotels_property` or `/v1/calendar`."
     },
     "data_id": {
      "type": "string",
      "description": "Google Maps data id (`0x...:0x...`)."
     },
     "name": {
      "type": "string"
     },
     "link": {
      "type": "string",
      "description": "The property's own website."
     },
     "description": {
      "type": "string"
     },
     "gps_coordinates": {
      "type": "object",
      "required": [
       "latitude",
       "longitude"
      ],
      "properties": {
       "latitude": {
        "type": "number"
       },
       "longitude": {
        "type": "number"
       }
      }
     },
     "city": {
      "type": "string",
      "description": "The place Google resolved `q` to (same as `search_information.location`), not a per-property city."
     },
     "country": {
      "type": "string",
      "description": "ISO 3166-1 alpha-2 country code."
     },
     "check_in_time": {
      "type": "string",
      "description": "As displayed, e.g. `3:00 PM`."
     },
     "check_out_time": {
      "type": "string"
     },
     "price_per_night": {
      "type": "object",
      "description": "Present only when the stay total is known.",
      "required": [
       "price",
       "extracted_price",
       "price_before_taxes",
       "extracted_price_before_taxes"
      ],
      "properties": {
       "price": {
        "type": [
         "string",
         "null"
        ],
        "description": "Display string including taxes and fees."
       },
       "extracted_price": {
        "type": [
         "number",
         "null"
        ],
        "description": "Stay total / nights: nightly price including taxes and fees."
       },
       "price_before_taxes": {
        "type": [
         "string",
         "null"
        ],
        "description": "Display string before taxes; the price Google's card shows."
       },
       "extracted_price_before_taxes": {
        "type": [
         "number",
         "null"
        ],
        "description": "Google's exact nightly figure before taxes (base + mandatory fees)."
       }
      }
     },
     "total_price": {
      "type": "object",
      "description": "Present only when the stay total is known.",
      "required": [
       "price",
       "extracted_price",
       "price_before_taxes",
       "extracted_price_before_taxes"
      ],
      "properties": {
       "price": {
        "type": [
         "string",
         "null"
        ],
        "description": "Whole-stay display string including taxes and fees."
       },
       "extracted_price": {
        "type": "number",
        "description": "Whole-stay price including taxes and fees."
       },
       "price_before_taxes": {
        "type": [
         "string",
         "null"
        ],
        "description": "Whole-stay display string before taxes."
       },
       "extracted_price_before_taxes": {
        "type": [
         "number",
         "null"
        ],
        "description": "Whole-stay base + mandatory fees."
       }
      }
     },
     "deal": {
      "type": "string",
      "description": "Deal text, e.g. `27% less than usual`."
     },
     "deal_description": {
      "type": "string",
      "description": "Badge Google renders: `Deal`, `Great Deal`, `Great Price`, or another label."
     },
     "nearby_places": {
      "type": "array",
      "items": {
       "type": "object",
       "required": [
        "name",
        "transportations"
       ],
       "properties": {
        "name": {
         "type": "string"
        },
        "transportations": {
         "type": "array",
         "items": {
          "type": "object",
          "required": [
           "type",
           "duration"
          ],
          "properties": {
           "type": {
            "type": [
             "string",
             "null"
            ],
            "description": "`Taxi`, `Walking` or `Public transport`; null for an unmapped mode."
           },
           "duration": {
            "type": "string",
            "description": "As displayed, e.g. `35 min`."
           }
          }
         }
        }
       }
      }
     },
     "hotel_class": {
      "type": "string",
      "description": "As displayed, e.g. `4-star hotel`."
     },
     "extracted_hotel_class": {
      "type": "integer",
      "description": "Star class, 1-5."
     },
     "rating": {
      "type": "number",
      "description": "Guest rating out of 5."
     },
     "reviews": {
      "type": "integer"
     },
     "reviews_histogram": {
      "type": "object",
      "properties": {
       "1": {
        "type": "integer"
       },
       "2": {
        "type": "integer"
       },
       "3": {
        "type": "integer"
       },
       "4": {
        "type": "integer"
       },
       "5": {
        "type": "integer"
       }
      },
      "description": "Review count per star rating, keyed `1`-`5`."
     },
     "location_rating": {
      "type": "number",
      "description": "Overall location score, out of 5."
     },
     "proximity_to_things_to_do_rating": {
      "type": "number",
      "description": "Score for proximity to things to do, out of 5."
     },
     "proximity_to_restaurants_rating": {
      "type": "number",
      "description": "Score for proximity to restaurants, out of 5."
     },
     "proximity_to_transit_rating": {
      "type": "number",
      "description": "Score for proximity to public transit, out of 5."
     },
     "airport_access_rating": {
      "type": "number",
      "description": "Score for airport access, out of 5."
     },
     "reviews_breakdown": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/GoogleHotelsSearchReviewCategory"
      },
      "description": "Empty when Google gave none."
     },
     "amenities": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Hotel amenity names are always English; rentals use Google's own labels."
     },
     "excluded_amenities": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Amenities a rental states it lacks, e.g. `No balcony`."
     },
     "essential_info": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Rental basics such as `Entire apartment` or `Sleeps 2`."
     },
     "images": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/GoogleHotelsSearchImage"
      }
     },
     "thumbnail": {
      "type": "string"
     },
     "prices": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/GoogleHotelsSearchSellerPrice"
      },
      "description": "Seller rows Google attached to the card (an addition to SearchAPI's shape); mostly vacation rentals."
     },
     "currency": {
      "type": "string",
      "description": "ISO 4217 code of every price on the property."
     }
    }
   },
   "SerpGoogleHotelsResponse": {
    "type": "object",
    "description": "Response of `POST /v1/serp/google_hotels`.",
    "required": [
     "search_metadata",
     "search_parameters",
     "search_information",
     "properties",
     "brands",
     "pagination"
    ],
    "properties": {
     "search_metadata": {
      "type": "object",
      "required": [
       "status",
       "created_at",
       "request_time_taken",
       "total_time_taken"
      ],
      "properties": {
       "status": {
        "type": "string",
        "enum": [
         "Success"
        ]
       },
       "created_at": {
        "type": "string",
        "description": "UTC, ISO-8601 with `Z`.",
        "format": "date-time"
       },
       "request_time_taken": {
        "type": "number",
        "description": "Seconds."
       },
       "total_time_taken": {
        "type": "number",
        "description": "Seconds."
       }
      }
     },
     "search_parameters": {
      "type": "object",
      "description": "Echo of the effective request. Optional filters appear only when set.",
      "required": [
       "engine",
       "q",
       "check_in_date",
       "check_out_date",
       "adults",
       "children_ages",
       "currency",
       "gl",
       "hl",
       "sort_by",
       "property_type"
      ],
      "properties": {
       "engine": {
        "type": "string",
        "enum": [
         "google_hotels"
        ]
       },
       "q": {
        "type": "string"
       },
       "check_in_date": {
        "type": "string",
        "format": "date"
       },
       "check_out_date": {
        "type": "string",
        "format": "date"
       },
       "adults": {
        "type": "integer"
       },
       "children_ages": {
        "type": "array",
        "items": {
         "type": "integer"
        },
        "description": "One age per child; empty when none."
       },
       "currency": {
        "type": "string",
        "description": "Requested currency, upper-case."
       },
       "gl": {
        "type": "string",
        "description": "Market country code, lower-case."
       },
       "hl": {
        "type": "string"
       },
       "sort_by": {
        "type": "string",
        "enum": [
         "relevance",
         "lowest_price",
         "highest_rating",
         "most_reviewed"
        ]
       },
       "price_min": {
        "type": "integer",
        "description": "Present only when set in the request."
       },
       "price_max": {
        "type": "integer",
        "description": "Present only when set in the request."
       },
       "min_rating": {
        "type": "number",
        "description": "3.5, 4.0 or 4.5. Present only when set in the request. Converted from the `rating` code (7, 8, 9)."
       },
       "hotel_class": {
        "type": "array",
        "items": {
         "type": "integer"
        },
        "description": "Present only when set in the request."
       },
       "amenities": {
        "type": "array",
        "items": {
         "type": "integer"
        },
        "description": "Present only when set in the request."
       },
       "property_types": {
        "type": "array",
        "items": {
         "type": "integer"
        },
        "description": "Present only when set in the request."
       },
       "free_cancellation": {
        "type": "boolean",
        "description": "Present only when true."
       },
       "special_offers": {
        "type": "boolean",
        "description": "Present only when true."
       },
       "eco_certified": {
        "type": "boolean",
        "description": "Present only when true."
       },
       "next_page_token": {
        "type": "string",
        "description": "Page token this page was fetched with. Present only when one was sent."
       },
       "property_type": {
        "type": "string",
        "description": "Always `hotel`.",
        "enum": [
         "hotel"
        ]
       }
      }
     },
     "search_information": {
      "type": "object",
      "required": [
       "total_results",
       "location",
       "currency_matches_request"
      ],
      "properties": {
       "total_results": {
        "type": [
         "integer",
         "null"
        ],
        "description": "Total properties Google reports for the search."
       },
       "location": {
        "type": [
         "string",
         "null"
        ],
        "description": "Place Google resolved `q` to."
       },
       "currency_matches_request": {
        "type": "boolean",
        "description": "False when Google returned a currency other than the one requested."
       }
      }
     },
     "properties": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/GoogleHotelsSearchSerpProperty"
      },
      "description": "About 20 per page."
     },
     "brands": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/GoogleHotelsSearchBrand"
      }
     },
     "pagination": {
      "$ref": "#/components/schemas/GoogleHotelsSearchPagination"
     }
    }
   }
  }
 }
}
