{"openapi":"3.1.0","info":{"title":"City of Trees House public agent API","version":"1.0.0","description":"Public facts, bounded availability, and anonymous quotes. Feature availability is controlled at runtime; disabled endpoints return 503 AGENT_API_DISABLED. Quotes expire after five minutes and do not reserve dates. Inventory is based on confirmed direct bookings and synchronized channel calendars; channel updates may be delayed. Payment and booking require the guest-facing checkout, fresh review, payment authorization, and identity verification. No API credential grants booking, guest-data, cancellation, or refund authority."},"servers":[{"url":"/"}],"paths":{"/api/agent/v1/property":{"get":{"operationId":"getProperty","summary":"Read public property facts","responses":{"200":{"description":"Public facts; cache at most five minutes. Supports ETag and If-None-Match.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Property"}}}},"304":{"description":"Unchanged; no body."},"400":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"404":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"409":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"410":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"413":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"415":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"422":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"429":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"500":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"503":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}}}}},"/api/agent/v1/availability":{"get":{"operationId":"getAvailability","summary":"Check dates; does not check price or minimum stay","parameters":[{"name":"checkIn","in":"query","required":true,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"name":"checkOut","in":"query","required":true,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"name":"guests","in":"query","required":true,"schema":{"type":"integer","minimum":1,"maximum":10}},{"name":"petCount","in":"query","required":true,"schema":{"type":"integer","minimum":0,"maximum":2}}],"responses":{"200":{"description":"A live date check, no-store. No inventory hold.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Availability"}}}},"400":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"404":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"409":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"410":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"413":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"415":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"422":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"429":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"500":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"503":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}}}}},"/api/agent/v1/quotes":{"post":{"operationId":"createQuote","summary":"Quote a stay and return a booking handoff","description":"Dates use the America/Los_Angeles calendar, check-out is exclusive. Check-in must be today through 548 days ahead, and stay length must be 1 through 27 nights. PriceLabs may require a longer minimum stay. JSON body at most 4 KiB; no unknown fields or guest information. Maximum 10 quotes per minute per IP and 60 per minute for the property. All money is integer USD cents. Only enabled payment methods are returned. Follow bookingUrl and requiredGuestActions; checkoutEnabled is false on preview.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Stay"}}}},"responses":{"200":{"description":"Five-minute quote snapshot, no-store. Not a reservation or price guarantee.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Quote"}}}},"400":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"404":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"409":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"410":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"413":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"415":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"422":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"429":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"500":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"503":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}}}}},"/api/agent/v1/quotes/{quoteId}":{"get":{"operationId":"getQuote","summary":"Read an unexpired snapshot; does not recheck inventory","parameters":[{"name":"quoteId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Snapshot, no-store. 410 after expiry; 404 after retention cleanup.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Quote"}}}},"400":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"404":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"409":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"410":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"413":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"415":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"422":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"429":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"500":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}},"503":{"description":"Typed error. Honor retryable and Retry-After; never infer availability from an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait when rate limited or temporarily unavailable."}}}}}}},"components":{"schemas":{"Stay":{"type":"object","properties":{"checkIn":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"checkOut":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"guests":{"type":"integer","minimum":1,"maximum":10},"petCount":{"type":"integer","minimum":0,"maximum":2}},"required":["checkIn","checkOut","guests","petCount"],"additionalProperties":false},"Property":{"type":"object","properties":{"propertySlug":{"type":"string","const":"city-of-trees-house"},"name":{"type":"string","const":"City of Trees House"},"entityId":{"type":"string","const":"https://cityoftrees.house/#vacation-rental"},"url":{"type":"string","const":"https://cityoftrees.house/"},"bookingUrl":{"type":"string","const":"https://cityoftrees.house/#book"},"operator":{"type":"object","properties":{"name":{"type":"string","const":"Good Reviews Only"},"url":{"type":"string","const":"https://www.goodreviewsonly.com"}},"required":["name","url"],"additionalProperties":false},"timezone":{"type":"string","const":"America/Los_Angeles"},"currency":{"type":"string","const":"USD"},"location":{"type":"object","properties":{"locality":{"type":"string","const":"West Sacramento"},"region":{"type":"string","const":"California"},"country":{"type":"string","const":"US"}},"required":["locality","region","country"],"additionalProperties":false},"occupancyMax":{"type":"number","const":10},"bedrooms":{"type":"number","const":3},"bathrooms":{"type":"number","const":2},"bookingType":{"type":"string","const":"whole"},"petsMax":{"type":"number","const":2},"maxStayNights":{"type":"number","const":27},"bookingHorizonDays":{"type":"number","const":548},"amenities":{"type":"array","items":{"type":"string"}},"policyUrl":{"type":"string","const":"https://cityoftrees.house/terms"},"factsUpdatedAt":{"type":"string","const":"2026-10-12T00:00:00Z"},"apiVersion":{"type":"string","const":"1"},"apiDocumentationUrl":{"type":"string","const":"https://cityoftrees.house/agents"}},"required":["propertySlug","name","entityId","url","bookingUrl","operator","timezone","currency","location","occupancyMax","bedrooms","bathrooms","bookingType","petsMax","maxStayNights","bookingHorizonDays","amenities","policyUrl","factsUpdatedAt","apiVersion","apiDocumentationUrl"],"additionalProperties":false},"Availability":{"type":"object","properties":{"propertySlug":{"type":"string","const":"city-of-trees-house"},"stay":{"type":"object","properties":{"checkIn":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"checkOut":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"guests":{"type":"integer","minimum":1,"maximum":10},"petCount":{"type":"integer","minimum":0,"maximum":2}},"required":["checkIn","checkOut","guests","petCount"],"additionalProperties":false},"inventoryAvailable":{"type":"boolean"},"reservesInventory":{"type":"boolean","const":false},"checkedAt":{"type":"string","format":"date-time"},"calendarObservedAt":{"type":"string","format":"date-time"},"availabilityBasis":{"type":"string","const":"confirmed_bookings_and_calendar_hub"},"requiresQuoteForPriceAndMinStay":{"type":"boolean","const":true}},"required":["propertySlug","stay","inventoryAvailable","reservesInventory","checkedAt","calendarObservedAt","availabilityBasis","requiresQuoteForPriceAndMinStay"],"additionalProperties":false},"PaymentOption":{"type":"object","properties":{"method":{"type":"string","enum":["zelle","stripe_ach","venmo","stripe_card","paypal","cash_app"]},"label":{"type":"string","minLength":1},"confirmationMode":{"type":"string","enum":["automatic","host_verified"]},"taxableSubtotalCents":{"type":"integer","minimum":0,"maximum":10000000000},"taxCents":{"type":"integer","minimum":0,"maximum":10000000000},"totalCents":{"type":"integer","minimum":0,"maximum":10000000000}},"required":["method","label","confirmationMode","taxableSubtotalCents","taxCents","totalCents"],"additionalProperties":false},"Quote":{"type":"object","properties":{"quoteId":{"type":"string","format":"uuid"},"propertySlug":{"type":"string","const":"city-of-trees-house"},"stay":{"type":"object","properties":{"checkIn":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"checkOut":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"guests":{"type":"integer","minimum":1,"maximum":10},"petCount":{"type":"integer","minimum":0,"maximum":2}},"required":["checkIn","checkOut","guests","petCount"],"additionalProperties":false},"currency":{"type":"string","const":"USD"},"timezone":{"type":"string","const":"America/Los_Angeles"},"generatedAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"},"quoteCheckedAt":{"type":"string","format":"date-time"},"calendarObservedAt":{"type":"string","format":"date-time"},"pricingAuthoritative":{"type":"boolean","const":true},"inventoryAvailable":{"type":"boolean","const":true},"reservesInventory":{"type":"boolean","const":false},"checkoutEnabled":{"type":"boolean"},"minStayNights":{"type":"integer","minimum":1,"maximum":27},"stayValueCents":{"type":"integer","minimum":0,"maximum":10000000000},"petFeeCents":{"type":"integer","minimum":0,"maximum":10000000000},"nightlyPrices":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"amountCents":{"type":"integer","minimum":0,"maximum":10000000000}},"required":["date","amountCents"],"additionalProperties":false},"minItems":1,"maxItems":27},"paymentOptions":{"type":"array","items":{"type":"object","properties":{"method":{"type":"string","enum":["zelle","stripe_ach","venmo","stripe_card","paypal","cash_app"]},"label":{"type":"string","minLength":1},"confirmationMode":{"type":"string","enum":["automatic","host_verified"]},"taxableSubtotalCents":{"type":"integer","minimum":0,"maximum":10000000000},"taxCents":{"type":"integer","minimum":0,"maximum":10000000000},"totalCents":{"type":"integer","minimum":0,"maximum":10000000000}},"required":["method","label","confirmationMode","taxableSubtotalCents","taxCents","totalCents"],"additionalProperties":false},"minItems":1,"maxItems":6},"cancellationPolicy":{"type":"object","properties":{"version":{"type":"string","minLength":1,"maxLength":80},"url":{"type":"string","format":"uri"},"summary":{"type":"string","minLength":1}},"required":["version","url","summary"],"additionalProperties":false},"requiredGuestActions":{"type":"array","items":{"type":"string","enum":["review_total_and_terms","confirm_primary_renter_age","authorize_payment","verify_identity"]},"minItems":4,"maxItems":4},"bookingUrl":{"type":"string","format":"uri"}},"required":["quoteId","propertySlug","stay","currency","timezone","generatedAt","expiresAt","quoteCheckedAt","calendarObservedAt","pricingAuthoritative","inventoryAvailable","reservesInventory","checkoutEnabled","minStayNights","stayValueCents","petFeeCents","nightlyPrices","paymentOptions","cancellationPolicy","requiredGuestActions","bookingUrl"],"additionalProperties":false},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["INVALID_REQUEST","NOT_FOUND","DATES_UNAVAILABLE","QUOTE_EXPIRED","MIN_STAY_NOT_MET","RATE_LIMITED","CALENDAR_UNVERIFIED","PRICING_UNAVAILABLE","NO_PAYMENT_METHODS","AGENT_API_DISABLED","SERVICE_UNAVAILABLE","INTERNAL_ERROR"]},"message":{"type":"string"},"retryable":{"type":"boolean"},"requestId":{"type":"string"},"details":{"type":"object","properties":{"fields":{"type":"array","items":{"type":"string"}},"minStayNights":{"type":"integer"}},"additionalProperties":false}},"required":["code","message","retryable","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}