{
  "openapi": "3.1.0",
  "info": {
    "title": "RentRemote Marketplace API",
    "version": "1.0.0",
    "summary": "Read-only search over RentRemote's furnished, work-ready apartments for stays of one month or longer.",
    "description": "Unauthenticated JSON API for AI agents and other clients that want to search the RentRemote marketplace on behalf of a person. Returns only publicly listable inventory, at the address precision each operator allows. Booking happens on the listing `url` returned with every property; this API does not create bookings. Rate limited to 60 requests per minute per IP. Human-readable guide: https://rentremote.com/llms.txt",
    "contact": {
      "name": "RentRemote",
      "url": "https://rentremote.com/contact-us"
    }
  },
  "servers": [
    { "url": "https://rentremote.com/api", "description": "Production" }
  ],
  "tags": [
    { "name": "Marketplace", "description": "Public, read-only inventory search. No API key." }
  ],
  "paths": {
    "/marketplace/v1/locations": {
      "get": {
        "tags": ["Marketplace"],
        "operationId": "listMarketplaceLocations",
        "summary": "Cities that currently have bookable listings",
        "description": "Call this first to learn which `city` values are worth searching. Ordered by inventory size, largest first.",
        "responses": {
          "200": {
            "description": "Cities with at least one listed property",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/MarketplaceLocation" } }
                  }
                }
              }
            }
          },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/marketplace/v1/properties": {
      "get": {
        "tags": ["Marketplace"],
        "operationId": "searchMarketplaceProperties",
        "summary": "Search listed properties in a city",
        "description": "Paginated. Follow `links.next` until it is null. Prices in the results are in each listing's own `currency`; `min_price` and `max_price` are interpreted in the `currency` query parameter (default USD) and converted before filtering.",
        "parameters": [
          { "name": "city", "in": "query", "required": true, "description": "City slug from the locations endpoint, or a plain city name.", "schema": { "type": "string" }, "example": "lisbon" },
          { "name": "bedrooms", "in": "query", "description": "Exact number of bedrooms. 0 is a studio.", "schema": { "type": "integer", "minimum": 0 } },
          { "name": "min_bedrooms", "in": "query", "description": "At least this many bedrooms.", "schema": { "type": "integer", "minimum": 0 } },
          { "name": "min_price", "in": "query", "description": "Minimum monthly rent, in `currency`.", "schema": { "type": "number", "minimum": 0 } },
          { "name": "max_price", "in": "query", "description": "Maximum monthly rent, in `currency`.", "schema": { "type": "number", "minimum": 0 } },
          { "name": "currency", "in": "query", "description": "ISO 4217 code the price band is expressed in. Default USD.", "schema": { "type": "string", "minLength": 3, "maxLength": 3 }, "example": "EUR" },
          { "name": "pet_friendly", "in": "query", "description": "Only pet-friendly units when true.", "schema": { "type": "string", "enum": ["true", "false"] } },
          { "name": "has_workstation", "in": "query", "description": "Only units with a dedicated workstation when true.", "schema": { "type": "string", "enum": ["true", "false"] } },
          { "name": "move_in", "in": "query", "description": "Only units whose advertised availability starts on or before this date (YYYY-MM-DD). Confirm with the availability endpoint.", "schema": { "type": "string", "format": "date" } },
          { "name": "sort", "in": "query", "schema": { "type": "string", "enum": ["relevance", "price_asc", "price_desc"], "default": "relevance" } },
          { "name": "page", "in": "query", "schema": { "type": "integer", "minimum": 1, "default": 1 } },
          { "name": "per_page", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 50, "default": 20 } }
        ],
        "responses": {
          "200": {
            "description": "A page of listed properties",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/MarketplaceProperty" } },
                    "links": {
                      "type": "object",
                      "properties": {
                        "first": { "type": ["string", "null"] },
                        "last": { "type": ["string", "null"] },
                        "prev": { "type": ["string", "null"] },
                        "next": { "type": ["string", "null"], "description": "Null on the last page." }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "current_page": { "type": "integer" },
                        "last_page": { "type": "integer" },
                        "per_page": { "type": "integer" },
                        "total": { "type": "integer" }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/marketplace/v1/properties/{id}": {
      "get": {
        "tags": ["Marketplace"],
        "operationId": "getMarketplaceProperty",
        "summary": "Full details of one listed property",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }
        ],
        "responses": {
          "200": {
            "description": "The property, with the full description, amenities and house rules",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": { "data": { "$ref": "#/components/schemas/MarketplacePropertyDetail" } }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/marketplace/v1/properties/{id}/availability": {
      "get": {
        "tags": ["Marketplace"],
        "operationId": "getMarketplacePropertyAvailability",
        "summary": "Blocked dates and first bookable move-in date",
        "description": "Covers the next 24 months. A stay is possible when none of its nights (check-in inclusive, check-out exclusive) appear in `unavailable_dates` and it lasts at least `minimum_stay_nights`. Cached for up to 6 hours.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }
        ],
        "responses": {
          "200": {
            "description": "Availability for the property",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "move_in": { "type": ["string", "null"], "format": "date", "description": "First date a stay of at least the minimum length can start. Null when the operator has not published availability." },
                    "unavailable_dates": { "type": "array", "items": { "type": "string", "format": "date" } },
                    "minimum_stay_nights": { "type": "integer" }
                  }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "MarketplaceLocation": {
        "type": "object",
        "properties": {
          "slug": { "type": "string", "description": "Pass this as `city` when searching.", "example": "lisbon" },
          "city": { "type": "string", "example": "Lisbon" },
          "country": { "type": ["string", "null"], "example": "Portugal" },
          "country_code": { "type": ["string", "null"], "example": "PT" },
          "listed_properties": { "type": "integer" },
          "search_url": { "type": "string", "format": "uri" },
          "web_url": { "type": "string", "format": "uri", "description": "The server-rendered city page a person can browse." }
        }
      },
      "MarketplaceProperty": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "url": { "type": "string", "format": "uri", "description": "The listing and booking page. The only place a person can book." },
          "availability_url": { "type": "string", "format": "uri" },
          "title": { "type": "string" },
          "summary": { "type": "string", "description": "First 300 characters of the description." },
          "city": { "type": ["string", "null"] },
          "country": { "type": ["string", "null"] },
          "country_code": { "type": ["string", "null"] },
          "neighborhood": { "type": ["string", "null"] },
          "address": { "type": "string", "description": "At the precision the operator publishes; see address_is_approximate." },
          "address_is_approximate": { "type": "boolean", "description": "True when the address is neighbourhood-level and the pin is offset by a few hundred metres." },
          "lat": { "type": ["number", "null"] },
          "lng": { "type": ["number", "null"] },
          "bedrooms": { "type": ["integer", "null"], "description": "0 is a studio." },
          "bathrooms": { "type": ["integer", "null"] },
          "beds": { "type": ["integer", "null"] },
          "surface_m2": { "type": ["number", "null"] },
          "price_per_month": { "type": ["number", "null"], "description": "Monthly rent in `currency`." },
          "currency": { "type": ["string", "null"], "description": "ISO 4217 code of price_per_month." },
          "price_per_month_usd": { "type": ["number", "null"], "description": "Daily-refreshed conversion for cross-city comparison. Not the quoted price." },
          "minimum_stay_nights": { "type": "integer" },
          "available_from": { "type": ["string", "null"], "format": "date", "description": "First move-in date honouring the minimum stay. Null when unknown." },
          "pet_friendly": { "type": "boolean" },
          "workstations_count": { "type": "integer" },
          "dedicated_office_space": { "type": "boolean" },
          "fast_internet": { "type": "boolean" },
          "images": { "type": "array", "items": { "type": "string", "format": "uri" }, "description": "Main photo first. Up to 5 in search results, all on the detail endpoint." }
        }
      },
      "MarketplacePropertyDetail": {
        "allOf": [
          { "$ref": "#/components/schemas/MarketplaceProperty" },
          {
            "type": "object",
            "properties": {
              "description": { "type": "string" },
              "amenities": { "type": "array", "items": { "type": "string" } },
              "house_rules": { "type": ["string", "null"] }
            }
          }
        ]
      },
      "Error": {
        "type": "object",
        "properties": { "error": { "type": "string" } }
      }
    },
    "responses": {
      "NotFound": {
        "description": "Unknown city, or a property that is not currently listed",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "ValidationError": {
        "description": "A query parameter is invalid; the messages say what is accepted",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "message": { "type": "string" },
                "errors": { "type": "object", "additionalProperties": { "type": "array", "items": { "type": "string" } } }
              }
            }
          }
        }
      },
      "RateLimited": {
        "description": "More than 60 requests in a minute from this IP. Wait for the Retry-After header."
      }
    }
  }
}
