{
  "openapi": "3.1.0",
  "info": {
    "title": "Five Star Guest Agent API",
    "version": "1.0.0",
    "description": "A narrow public API for searching published Five Star listings, checking selected-listing availability, handing guests to direct booking, and submitting enquiry-only listing enquiries."
  },
  "servers": [
    {
      "url": "https://fivestar.ie/accounts/api/agent/v1"
    }
  ],
  "tags": [
    {
      "name": "Listings"
    },
    {
      "name": "Enquiries"
    }
  ],
  "paths": {
    "/listings.php": {
      "get": {
        "operationId": "searchListings",
        "tags": [
          "Listings"
        ],
        "summary": "Search published listings",
        "description": "Searches only active public listings. Dates are optional for browsing; when supplied, only listings whose authoritative availability check succeeds are returned.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CheckIn"
          },
          {
            "$ref": "#/components/parameters/CheckOut"
          },
          {
            "name": "country_id",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "region_id",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "area_id",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "location",
            "in": "query",
            "description": "A bounded free-text country, region, area, or location search.",
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          },
          {
            "name": "keywords",
            "in": "query",
            "description": "Up to eight terms searched against approved public listing content and feature fields, for example sea view beach.",
            "schema": {
              "type": "string",
              "maxLength": 120
            }
          },
          {
            "name": "category",
            "in": "query",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9-]{1,50}$"
            }
          },
          {
            "name": "beach",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "guests",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 40
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 20,
              "default": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Matching public listings.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListingSearchResponse"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/availability.php": {
      "get": {
        "operationId": "checkListingAvailability",
        "tags": [
          "Listings"
        ],
        "summary": "Check one listing's availability",
        "description": "Runs a fresh authoritative availability and minimum-stay check. It never returns bookings, blocked-date details, guest data, or owner data.",
        "parameters": [
          {
            "name": "listing_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "$ref": "#/components/parameters/RequiredCheckIn"
          },
          {
            "$ref": "#/components/parameters/RequiredCheckOut"
          },
          {
            "name": "party_size",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 40
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Availability result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AvailabilityResponse"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/InvalidRequest"
          }
        }
      }
    },
    "/enquiries.php": {
      "post": {
        "operationId": "submitListingEnquiry",
        "tags": [
          "Enquiries"
        ],
        "summary": "Submit an enquiry for an enquiry-only listing",
        "description": "Creates a guest enquiry through the existing CRM enquiry and notification workflow. Direct-booking listings reject this operation and return their booking handoff instead. A unique Idempotency-Key is required.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "16-128 letters, numbers, underscores, or hyphens. Retrying the same key and payload returns the same reference without creating another enquiry.",
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9_-]{16,128}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EnquiryRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Enquiry submitted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnquiryResponse"
                }
              }
            }
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "CheckIn": {
        "name": "check_in",
        "in": "query",
        "schema": {
          "type": "string",
          "format": "date"
        }
      },
      "CheckOut": {
        "name": "check_out",
        "in": "query",
        "schema": {
          "type": "string",
          "format": "date"
        }
      },
      "RequiredCheckIn": {
        "name": "check_in",
        "in": "query",
        "required": true,
        "schema": {
          "type": "string",
          "format": "date"
        }
      },
      "RequiredCheckOut": {
        "name": "check_out",
        "in": "query",
        "required": true,
        "schema": {
          "type": "string",
          "format": "date"
        }
      }
    },
    "schemas": {
      "Location": {
        "type": "object",
        "required": [
          "country",
          "country_alias",
          "region",
          "region_alias",
          "area",
          "area_alias"
        ],
        "properties": {
          "country": {
            "type": [
              "string",
              "null"
            ]
          },
          "country_alias": {
            "type": [
              "string",
              "null"
            ]
          },
          "region": {
            "type": [
              "string",
              "null"
            ]
          },
          "region_alias": {
            "type": [
              "string",
              "null"
            ]
          },
          "area": {
            "type": [
              "string",
              "null"
            ]
          },
          "area_alias": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "BookingHandoff": {
        "type": "object",
        "required": [
          "mode",
          "url",
          "enquiry_endpoint"
        ],
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "direct",
              "enquiry",
              "none"
            ]
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "enquiry_endpoint": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          }
        }
      },
      "Listing": {
        "type": "object",
        "required": [
          "id",
          "name",
          "url",
          "category",
          "location",
          "summary",
          "image_url",
          "max_guests",
          "bedrooms",
          "features",
          "availability",
          "booking"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "category": {
            "type": "string"
          },
          "location": {
            "$ref": "#/components/schemas/Location"
          },
          "summary": {
            "type": "string"
          },
          "image_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "max_guests": {
            "type": "integer"
          },
          "bedrooms": {
            "type": "integer"
          },
          "features": {
            "type": "object",
            "required": [
              "beach",
              "amenities",
              "key_features"
            ],
            "properties": {
              "beach": {
                "type": "boolean"
              },
              "amenities": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "key_features": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "availability": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "type": "object",
                "required": [
                  "available"
                ],
                "properties": {
                  "available": {
                    "type": "boolean"
                  }
                }
              }
            ]
          },
          "booking": {
            "$ref": "#/components/schemas/BookingHandoff"
          }
        }
      },
      "ListingSearchResponse": {
        "type": "object",
        "required": [
          "data",
          "pagination",
          "checked_at"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Listing"
            }
          },
          "pagination": {
            "type": "object",
            "required": [
              "page",
              "limit",
              "next_page"
            ],
            "properties": {
              "page": {
                "type": "integer"
              },
              "limit": {
                "type": "integer"
              },
              "next_page": {
                "type": [
                  "integer",
                  "null"
                ]
              }
            }
          },
          "checked_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AvailabilityResponse": {
        "type": "object",
        "required": [
          "listing_id",
          "check_in",
          "check_out",
          "party_size",
          "available",
          "minimum_stay",
          "reason",
          "booking",
          "checked_at"
        ],
        "properties": {
          "listing_id": {
            "type": "integer"
          },
          "check_in": {
            "type": "string",
            "format": "date"
          },
          "check_out": {
            "type": "string",
            "format": "date"
          },
          "party_size": {
            "type": [
              "integer",
              "null"
            ]
          },
          "available": {
            "type": "boolean"
          },
          "minimum_stay": {
            "type": [
              "integer",
              "null"
            ]
          },
          "reason": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "not_bookable",
              "party_size_exceeds_capacity",
              "minimum_stay",
              "unavailable",
              null
            ]
          },
          "booking": {
            "$ref": "#/components/schemas/BookingHandoff"
          },
          "checked_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "EnquiryRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "listing_id",
          "name",
          "email",
          "phone",
          "check_in",
          "check_out",
          "adults",
          "consent"
        ],
        "properties": {
          "listing_id": {
            "type": "integer",
            "minimum": 1
          },
          "name": {
            "type": "string",
            "minLength": 2,
            "maxLength": 100
          },
          "email": {
            "type": "string",
            "format": "email",
            "maxLength": 254
          },
          "phone": {
            "type": "string",
            "minLength": 3,
            "maxLength": 50
          },
          "check_in": {
            "type": "string",
            "format": "date"
          },
          "check_out": {
            "type": "string",
            "format": "date"
          },
          "adults": {
            "type": "integer",
            "minimum": 1,
            "maximum": 40
          },
          "children": {
            "type": "integer",
            "minimum": 0,
            "maximum": 40,
            "default": 0
          },
          "message": {
            "type": "string",
            "maxLength": 2000
          },
          "consent": {
            "type": "boolean",
            "const": true
          }
        }
      },
      "EnquiryResponse": {
        "type": "object",
        "required": [
          "status",
          "replayed",
          "reference",
          "listing_id",
          "submitted_at"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "submitted"
            ]
          },
          "replayed": {
            "type": "boolean"
          },
          "reference": {
            "type": "string"
          },
          "listing_id": {
            "type": "integer"
          },
          "submitted_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "message",
              "details"
            ],
            "properties": {
              "message": {
                "type": "string"
              },
              "details": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        }
      }
    },
    "responses": {
      "InvalidRequest": {
        "description": "The request failed validation.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "The public listing was not found.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Conflict": {
        "description": "The listing does not support this operation or the idempotency key was reused with different data.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "The caller is rate limited.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  }
}
