{
  "openapi": "3.0.3",
  "info": {
    "title": "Walk On Valley Properties Public Property Agent API",
    "version": "1.0.0",
    "description": "Safe public endpoints for AI agents to discover properties, check availability, get quotes, and start booking workflows.",
    "contact": {
      "email": "Info@walkonvalley.com"
    }
  },
  "servers": [
    {
      "url": "https://www.walkonvalley.com"
    }
  ],
  "tags": [
    {
      "name": "PublicProperties",
      "description": "Public property discovery, details, availability, and quotes."
    },
    {
      "name": "PublicBookings",
      "description": "Public booking request and checkout preparation flows."
    }
  ],
  "paths": {
    "/api/public/properties": {
      "get": {
        "tags": [
          "PublicProperties"
        ],
        "operationId": "listPublicProperties",
        "summary": "List compact public property cards.",
        "responses": {
          "200": {
            "description": "Compact public property cards; fetch a property detail for full listing data.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PublicPropertyCard"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/public/properties/search": {
      "get": {
        "tags": [
          "PublicProperties"
        ],
        "operationId": "searchPublicProperties",
        "summary": "Search public properties by fit, dates, and booking mode.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 120
            }
          },
          {
            "name": "region",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "Bitterroot Valley",
                "Missoula Valley",
                "Sun Valley"
              ]
            }
          },
          {
            "name": "guests",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 99
            }
          },
          {
            "name": "guestCount",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 99
            }
          },
          {
            "name": "bookingMode",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "instant",
                "request",
                "inquiry"
              ]
            }
          },
          {
            "name": "startDate",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "availableOnly",
            "in": "query",
            "description": "Exclude only listings with available=false; listings with available=null remain because availability is unknown.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Filtered public property cards with search metadata.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicPropertySearchResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/public/properties/{slugOrId}": {
      "get": {
        "tags": [
          "PublicProperties"
        ],
        "operationId": "getPublicProperty",
        "summary": "Get one public property listing.",
        "parameters": [
          {
            "name": "slugOrId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Public property slug or numeric property id."
          }
        ],
        "responses": {
          "200": {
            "description": "Public property listing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicPropertyListing"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/public/properties/{slugOrId}/availability": {
      "get": {
        "tags": [
          "PublicProperties"
        ],
        "operationId": "checkPublicPropertyAvailability",
        "summary": "Check availability for one public property.",
        "parameters": [
          {
            "name": "slugOrId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Public property slug or numeric property id."
          },
          {
            "name": "startDate",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "guests",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 99
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Availability result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicPropertyAvailability"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/public/properties/{slugOrId}/quote": {
      "get": {
        "tags": [
          "PublicProperties"
        ],
        "operationId": "getPublicPropertyQuote",
        "summary": "Get a current quote for one public property.",
        "parameters": [
          {
            "name": "slugOrId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Public property slug or numeric property id."
          },
          {
            "name": "arrivalDate",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "departureDate",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "guestCount",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 99
            }
          },
          {
            "name": "promoCode",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 80
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Quote result or clear not-configured response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicPropertyQuote"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "409": {
            "$ref": "#/components/responses/PublicBookingError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/public/properties/{slugOrId}/booking-locks": {
      "post": {
        "tags": [
          "PublicBookings"
        ],
        "operationId": "createPublicBookingLock",
        "summary": "Request or hold dates for a public property.",
        "parameters": [
          {
            "name": "slugOrId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Public property slug or numeric property id."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicBookingLockRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Booking request created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicBookingLockResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "409": {
            "$ref": "#/components/responses/PublicBookingError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/public/properties/{slugOrId}/booking-checkouts/prepare": {
      "post": {
        "tags": [
          "PublicBookings"
        ],
        "operationId": "preparePublicBookingCheckout",
        "summary": "Prepare checkout from a valid public quote token.",
        "parameters": [
          {
            "name": "slugOrId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Public property slug or numeric property id."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 120
            },
            "description": "Stable retry key for agent/browser checkout preparation retries."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicBookingCheckoutPrepareRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Checkout prepared.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicBookingCheckoutPrepareResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "409": {
            "$ref": "#/components/responses/PublicBookingError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/public/booking-checkouts/{checkoutId}/finalize": {
      "post": {
        "tags": [
          "PublicBookings"
        ],
        "operationId": "finalizePublicBookingCheckout",
        "summary": "Finalize a prepared public checkout with its guest access token after payment confirmation.",
        "description": "Requires the checkout-bound accessToken returned by preparation. Unknown, mismatched, expired and revoked tokens receive the same generic denial before payment reconciliation.",
        "parameters": [
          {
            "name": "checkoutId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicBookingCheckoutFinalizeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Checkout finalized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicBookingCheckoutFinalizeResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/PublicBookingError"
          }
        }
      }
    }
  },
  "components": {
    "responses": {
      "BadRequest": {
        "description": "Invalid request.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/PublicApiError"
            }
          }
        }
      },
      "NotFound": {
        "description": "Public resource not found.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/PublicApiError"
            }
          }
        }
      },
      "PublicBookingError": {
        "description": "Clear public booking error with a machine-readable code.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/PublicApiError"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Public endpoint rate limit exceeded.",
        "headers": {
          "Retry-After": {
            "schema": {
              "type": "integer"
            },
            "description": "Seconds to wait before retrying."
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/PublicApiError"
            }
          }
        }
      }
    },
    "schemas": {
      "PublicPropertyListing": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "slug",
          "name",
          "region",
          "location",
          "maxGuestCount",
          "bookingMode",
          "cohort",
          "publishedRevisionNumber",
          "paymentReadiness"
        ],
        "properties": {
          "propertyId": {
            "type": "integer",
            "nullable": true
          },
          "slug": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "headline": {
            "type": "string"
          },
          "subheadline": {
            "type": "string"
          },
          "region": {
            "type": "string",
            "enum": [
              "Bitterroot Valley",
              "Missoula Valley",
              "Sun Valley"
            ]
          },
          "location": {
            "type": "string"
          },
          "imageUrl": {
            "type": "string"
          },
          "galleryImages": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sleepsLabel": {
            "type": "string",
            "nullable": true
          },
          "bedroomsLabel": {
            "type": "string",
            "nullable": true
          },
          "bathroomsLabel": {
            "type": "string",
            "nullable": true
          },
          "maxGuestCount": {
            "type": "integer"
          },
          "nightlyRateLabel": {
            "type": "string",
            "nullable": true
          },
          "summary": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "highlights": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "amenities": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "bookingMode": {
            "type": "string",
            "enum": [
              "instant",
              "request",
              "inquiry"
            ]
          },
          "cohort": {
            "type": "string",
            "enum": [
              "request_to_book_launch"
            ]
          },
          "publishedRevisionNumber": {
            "type": "integer",
            "minimum": 0,
            "description": "Published snapshot revision. Zero identifies an enabled listing served from current public fields."
          },
          "paymentReadiness": {
            "$ref": "#/components/schemas/PublicPropertyPaymentReadiness"
          },
          "propertyType": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "PublicPropertyCard": {
        "type": "object",
        "required": [
          "propertyId",
          "slug",
          "name",
          "region",
          "location",
          "imageUrl",
          "stats",
          "nightlyRateLabel",
          "summary",
          "petFriendly",
          "bookingMode",
          "featured",
          "pricingSource",
          "cohort",
          "publishedRevisionNumber"
        ],
        "properties": {
          "propertyId": {
            "type": "integer",
            "nullable": true
          },
          "slug": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "region": {
            "type": "string",
            "enum": [
              "Bitterroot Valley",
              "Missoula Valley",
              "Sun Valley"
            ]
          },
          "destinationPath": {
            "type": "string",
            "nullable": true
          },
          "location": {
            "type": "string"
          },
          "imageUrl": {
            "type": "string"
          },
          "stats": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "key",
                "label",
                "value"
              ],
              "properties": {
                "key": {
                  "type": "string",
                  "enum": [
                    "sleeps",
                    "bedrooms",
                    "bathrooms"
                  ]
                },
                "label": {
                  "type": "string"
                },
                "value": {
                  "type": "string"
                }
              }
            }
          },
          "nightlyRateLabel": {
            "type": "string",
            "nullable": true
          },
          "summary": {
            "type": "string"
          },
          "petFriendly": {
            "type": "boolean"
          },
          "bookingMode": {
            "type": "string",
            "enum": [
              "instant",
              "request",
              "inquiry"
            ]
          },
          "featured": {
            "type": "boolean"
          },
          "pricingSource": {
            "type": "string",
            "enum": [
              "hostaway",
              "manual",
              "fallback",
              "unavailable"
            ],
            "nullable": true
          },
          "cohort": {
            "type": "string",
            "enum": [
              "request_to_book_launch"
            ]
          },
          "publishedRevisionNumber": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "PublicPropertySearchResponse": {
        "type": "object",
        "required": [
          "ok",
          "count",
          "data",
          "filters",
          "summary"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "count": {
            "type": "integer"
          },
          "filters": {
            "type": "object",
            "additionalProperties": true
          },
          "summary": {
            "type": "object",
            "required": [
              "matched",
              "checked",
              "available",
              "unavailable",
              "unknown",
              "partial"
            ],
            "properties": {
              "matched": {
                "type": "integer"
              },
              "checked": {
                "type": "integer"
              },
              "available": {
                "type": "integer"
              },
              "unavailable": {
                "type": "integer"
              },
              "unknown": {
                "type": "integer"
              },
              "partial": {
                "type": "boolean"
              }
            }
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicPropertySearchResult"
            }
          }
        }
      },
      "PublicPropertySearchResult": {
        "allOf": [
          {
            "$ref": "#/components/schemas/PublicPropertyCard"
          },
          {
            "type": "object",
            "properties": {
              "search": {
                "type": "object",
                "properties": {
                  "publicPath": {
                    "type": "string"
                  },
                  "publicUrl": {
                    "type": "string",
                    "format": "uri"
                  },
                  "matched": {
                    "type": "boolean"
                  },
                  "availabilityChecked": {
                    "type": "boolean"
                  },
                  "availabilityStatus": {
                    "type": "string",
                    "enum": [
                      "available",
                      "unavailable",
                      "unknown"
                    ]
                  },
                  "available": {
                    "type": "boolean",
                    "nullable": true,
                    "description": "Tri-state availability: true is confirmed available, false is confirmed unavailable, and null is unknown."
                  },
                  "availabilitySource": {
                    "type": "string",
                    "nullable": true
                  },
                  "availabilityMessage": {
                    "type": "string",
                    "nullable": true
                  }
                }
              }
            }
          }
        ]
      },
      "PublicPropertyPaymentReadiness": {
        "type": "object",
        "required": [
          "quoteConfigured",
          "stripeReady",
          "checkoutEnabled",
          "missingRequirements"
        ],
        "properties": {
          "quoteConfigured": {
            "type": "boolean"
          },
          "stripeReady": {
            "type": "boolean"
          },
          "checkoutEnabled": {
            "type": "boolean"
          },
          "missingRequirements": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "PublicPropertyAvailability": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "slug",
          "startDate",
          "endDate",
          "checkedAt",
          "source",
          "available",
          "message"
        ],
        "properties": {
          "propertyId": {
            "type": "integer",
            "nullable": true
          },
          "slug": {
            "type": "string"
          },
          "startDate": {
            "type": "string",
            "format": "date"
          },
          "endDate": {
            "type": "string",
            "format": "date"
          },
          "checkedAt": {
            "type": "string",
            "format": "date-time"
          },
          "live": {
            "type": "boolean"
          },
          "source": {
            "type": "string",
            "enum": [
              "hostaway",
              "local",
              "unavailable"
            ]
          },
          "freshness": {
            "type": "string",
            "enum": [
              "fresh",
              "stale",
              "too_stale",
              "unavailable"
            ]
          },
          "lastRefreshedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "onlineBookingEnabled": {
            "type": "boolean"
          },
          "available": {
            "type": "boolean",
            "nullable": true,
            "description": "Tri-state availability: true is confirmed available, false is confirmed unavailable, and null is unknown."
          },
          "unavailableDates": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "date"
            }
          },
          "message": {
            "type": "string"
          }
        }
      },
      "PublicPropertyQuote": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "ok",
          "configured",
          "checkoutEnabled",
          "quoteToken",
          "slug",
          "arrivalDate",
          "departureDate",
          "total",
          "message"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "configured": {
            "type": "boolean"
          },
          "checkoutEnabled": {
            "type": "boolean"
          },
          "quoteToken": {
            "type": "string",
            "nullable": true
          },
          "slug": {
            "type": "string"
          },
          "arrivalDate": {
            "type": "string",
            "format": "date"
          },
          "departureDate": {
            "type": "string",
            "format": "date"
          },
          "guestCount": {
            "type": "integer",
            "nullable": true
          },
          "nights": {
            "type": "integer"
          },
          "currency": {
            "type": "string"
          },
          "rent": {
            "type": "string"
          },
          "total": {
            "type": "string"
          },
          "dueNow": {
            "type": "string"
          },
          "expiresAt": {
            "type": "string",
            "nullable": true
          },
          "message": {
            "type": "string"
          },
          "missingRequirements": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "PublicBookingLockRequest": {
        "type": "object",
        "required": [
          "arrivalDate",
          "departureDate",
          "guestCount",
          "name",
          "email"
        ],
        "properties": {
          "arrivalDate": {
            "type": "string",
            "format": "date"
          },
          "departureDate": {
            "type": "string",
            "format": "date"
          },
          "guestCount": {
            "type": "integer",
            "minimum": 1,
            "maximum": 99
          },
          "name": {
            "type": "string",
            "minLength": 2,
            "maxLength": 120
          },
          "email": {
            "type": "string",
            "format": "email",
            "maxLength": 180
          },
          "phone": {
            "type": "string",
            "maxLength": 60
          },
          "message": {
            "type": "string",
            "maxLength": 1000
          },
          "sourcePath": {
            "type": "string",
            "maxLength": 300
          }
        }
      },
      "PublicBookingCheckoutPrepareRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/PublicBookingLockRequest"
          },
          {
            "type": "object",
            "required": [
              "quoteToken"
            ],
            "properties": {
              "quoteToken": {
                "type": "string",
                "minLength": 16,
                "maxLength": 1024
              },
              "promoCode": {
                "type": "string",
                "maxLength": 80
              },
              "idempotencyKey": {
                "type": "string",
                "maxLength": 120
              }
            }
          }
        ]
      },
      "PublicBookingCheckoutFinalizeRequest": {
        "type": "object",
        "required": [
          "accessToken"
        ],
        "properties": {
          "accessToken": {
            "type": "string",
            "minLength": 32,
            "maxLength": 256,
            "description": "Checkout-bound guest capability; must be unexpired and unrevoked."
          },
          "paymentIntentId": {
            "type": "string",
            "maxLength": 160
          }
        }
      },
      "PublicBookingLockResponse": {
        "type": "object",
        "required": [
          "ok",
          "bookingId",
          "reservationId",
          "status",
          "message"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "bookingId": {
            "type": "integer"
          },
          "inquiryId": {
            "type": "integer",
            "nullable": true
          },
          "reservationId": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending"
            ]
          },
          "message": {
            "type": "string"
          }
        }
      },
      "PublicBookingCheckoutPrepareResponse": {
        "type": "object",
        "required": [
          "ok",
          "checkoutId",
          "bookingId",
          "accessToken",
          "paymentIntentId",
          "clientSecret",
          "publishableKey",
          "amountTotal",
          "currency",
          "expiresAt"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "checkoutId": {
            "type": "integer"
          },
          "bookingId": {
            "type": "integer"
          },
          "reservationId": {
            "type": "string"
          },
          "accessToken": {
            "type": "string"
          },
          "paymentIntentId": {
            "type": "string"
          },
          "clientSecret": {
            "type": "string"
          },
          "publishableKey": {
            "type": "string"
          },
          "amountTotal": {
            "type": "string"
          },
          "currency": {
            "type": "string"
          },
          "merchantDisplayName": {
            "type": "string"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PublicBookingCheckoutFinalizeResponse": {
        "type": "object",
        "required": [
          "ok",
          "checkoutId",
          "bookingId",
          "status",
          "message"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "checkoutId": {
            "type": "integer"
          },
          "bookingId": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "enum": [
              "paid"
            ]
          },
          "message": {
            "type": "string"
          }
        }
      },
      "PublicApiError": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "error": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "retryAfterSec": {
            "type": "integer"
          },
          "issues": {}
        }
      }
    }
  }
}