{
  "openapi": "3.1.0",
  "info": {
    "title": "Vita Delta availability API",
    "version": "1.0.0",
    "description": "Live availability and prices of the five cabins of Vita Delta (Tigre Delta, Buenos Aires, Argentina). Free, no API key, read-only.\n\nFor AI assistants:\n- Quote a stay with quoteStay; check_out is the departure day (nights = check_out - check_in), or pass nights instead.\n- Dates: YYYY-MM-DD preferred; DD/MM/YYYY, DD-MM-YYYY (day first) and YYYY/MM/DD are accepted too. Without guests the quote is for 2 (stay.assumed_guests = true): tell the guest.\n- Present each cabin's price and status, then give the guest its booking_url (or whatsapp_url) to book.\n- This API never books: never claim a booking is made, held or confirmed. Dates are only held once the guest pays the 50% deposit.\n- Prices are in Argentine pesos (ARS), total for the whole stay and group.\n- Human text is Spanish by default; pass lang=en for English.\n- Rate limit: 30 requests per minute per client (429 with Retry-After). Responses may be cached for 60 seconds.\n- Browsing-only agents can open https://vitadelta.com.ar/disponibilidad/?llegada=YYYY-MM-DD&salida=YYYY-MM-DD&personas=N for the same answer as an HTML page. That page answers 200 even for unusable input, explaining what to fix with a corrected URL.",
    "contact": {
      "name": "Vita Delta",
      "email": "reservas@vitadelta.com.ar",
      "url": "https://vitadelta.com.ar/"
    }
  },
  "servers": [
    {
      "url": "https://vitadelta.com.ar/api/v1"
    }
  ],
  "externalDocs": {
    "description": "Site map for AI assistants (llms.txt)",
    "url": "https://vitadelta.com.ar/llms.txt"
  },
  "paths": {
    "/quote": {
      "get": {
        "operationId": "quoteStay",
        "summary": "Price and availability of every cabin for a stay",
        "description": "Quotes the stay in every cabin that fits the group, bookable cabins first. Present booking_url / whatsapp_url to the guest; never say the booking is confirmed.",
        "parameters": [
          {
            "name": "check_in",
            "in": "query",
            "required": true,
            "description": "Arrival date, from today. Formats: YYYY-MM-DD (preferred), DD/MM/YYYY, DD-MM-YYYY (day first) or YYYY/MM/DD; responses always use YYYY-MM-DD. Alias: llegada.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2027-01-15"
          },
          {
            "name": "check_out",
            "in": "query",
            "required": false,
            "description": "Departure date (the day the guest leaves), after check_in, at most 30 nights. Formats: YYYY-MM-DD (preferred), DD/MM/YYYY, DD-MM-YYYY (day first) or YYYY/MM/DD; responses always use YYYY-MM-DD. Required unless nights is given. Alias: salida.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2027-01-17"
          },
          {
            "name": "nights",
            "in": "query",
            "required": false,
            "description": "Number of nights, instead of check_out (check_out = check_in + nights). If both are given they must agree. Alias: noches.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 30
            },
            "example": 2
          },
          {
            "name": "guests",
            "in": "query",
            "required": false,
            "description": "Number of guests (1 to 5); a leading number like \"2 adults\" is read as 2. Default 2 when omitted: the response then has stay.assumed_guests = true and the summary says so. Alias: personas.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 5,
              "default": 2
            },
            "example": 2
          },
          {
            "name": "lang",
            "in": "query",
            "required": false,
            "description": "Language of the human-readable text (summary, notes, error messages). Field names are always English.",
            "schema": {
              "type": "string",
              "enum": [
                "es",
                "en"
              ],
              "default": "es"
            },
            "example": "en"
          }
        ],
        "responses": {
          "200": {
            "description": "Quote.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string"
                },
                "description": "public, s-maxage=60"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Quote"
                },
                "example": {
                  "stay": {
                    "check_in": "2027-01-15",
                    "check_out": "2027-01-17",
                    "nights": 2,
                    "guests": 2,
                    "assumed_guests": false
                  },
                  "currency": "ARS",
                  "summary": "Stay from 2027-01-15 to 2027-01-17 (2 nights) for 2 guests: 1 bookable on the website, 1 not available. Total price from ARS 240,000.",
                  "cabins": [
                    {
                      "id": 1,
                      "slug": "bamboo",
                      "name": "Bamboo",
                      "max_guests": 5,
                      "url": "https://vitadelta.com.ar/en/cabanas/bamboo/",
                      "status": "bookable",
                      "price_total": 240000,
                      "deposit": 120000,
                      "balance": 120000,
                      "check_in_time": "13:00",
                      "check_out_time": "10:00",
                      "required_package": null,
                      "booking_url": "https://vitadelta.com.ar/en/cabanas/bamboo/?llegada=2027-01-15&salida=2027-01-17&personas=2",
                      "whatsapp_url": "https://wa.me/5491132937979?text=Hi%2C%20I%27d%20like%20to%20book%20Bamboo%20from%2015%2F01%2F2027%20to%2017%2F01%2F2027"
                    }
                  ],
                  "notes": [
                    "Dates are not held until the deposit is paid: availability and price may change until then.",
                    "This API does not book. To book, open booking_url (the cabin page with the stay filled in) or message on WhatsApp (whatsapp_url)."
                  ],
                  "generated_at": "2026-12-01T12:00:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters (payload_invalido, fechas_invalidas, personas_invalidas, cabana_invalida).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "fechas_invalidas",
                    "message": "Invalid dates: check-in must be from today and within 2 years, check-out after check-in (at most 30 nights per quote, 62 per calendar)."
                  }
                }
              }
            }
          },
          "414": {
            "description": "Query string longer than 512 bytes (consulta_muy_larga).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "consulta_muy_larga",
                    "message": "The query string is too long."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached (demasiadas_solicitudes). Wait for Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "demasiadas_solicitudes",
                    "message": "Too many requests. Please try again in a minute."
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait (60)."
              }
            }
          },
          "502": {
            "description": "Upstream failure (error_servicio).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "error_servicio",
                    "message": "The service is not available right now."
                  }
                }
              }
            }
          },
          "503": {
            "description": "Service not configured (servicio_no_configurado).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "servicio_no_configurado",
                    "message": "The service is not available right now."
                  }
                }
              }
            }
          },
          "504": {
            "description": "Upstream timeout (tiempo_agotado).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "tiempo_agotado",
                    "message": "The service took too long to answer. Please try again."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/calendar": {
      "get": {
        "operationId": "getAvailabilityCalendar",
        "summary": "Occupied nights and event packages per cabin",
        "description": "Nights that cannot be booked, per cabin, in [from, to). A stay may end (check_out) on an occupied night. A stay touching an event package must contain it whole. Use quoteStay for prices.",
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "First night (YYYY-MM-DD). Default: today.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2027-01-01"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "End of the window, exclusive (YYYY-MM-DD), at most 62 nights after from. Default: from + 30.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2027-01-31"
          },
          {
            "name": "cabin",
            "in": "query",
            "required": false,
            "description": "Only this cabin: slug (e.g. bamboo) or id.",
            "schema": {
              "type": "string"
            },
            "example": "bamboo"
          },
          {
            "name": "lang",
            "in": "query",
            "required": false,
            "description": "Language of the human-readable text (summary, notes, error messages). Field names are always English.",
            "schema": {
              "type": "string",
              "enum": [
                "es",
                "en"
              ],
              "default": "es"
            },
            "example": "en"
          }
        ],
        "responses": {
          "200": {
            "description": "Calendar.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Calendar"
                },
                "example": {
                  "from": "2027-01-01",
                  "to": "2027-01-31",
                  "cabins": [
                    {
                      "id": 1,
                      "slug": "bamboo",
                      "name": "Bamboo",
                      "occupied_nights": [
                        "2027-01-09",
                        "2027-01-10"
                      ],
                      "event_packages": [
                        {
                          "check_in": "2027-01-22",
                          "check_out": "2027-01-25"
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters (payload_invalido, fechas_invalidas, personas_invalidas, cabana_invalida).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "fechas_invalidas",
                    "message": "Invalid dates: check-in must be from today and within 2 years, check-out after check-in (at most 30 nights per quote, 62 per calendar)."
                  }
                }
              }
            }
          },
          "414": {
            "description": "Query string longer than 512 bytes (consulta_muy_larga).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "consulta_muy_larga",
                    "message": "The query string is too long."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached (demasiadas_solicitudes). Wait for Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "demasiadas_solicitudes",
                    "message": "Too many requests. Please try again in a minute."
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait (60)."
              }
            }
          },
          "502": {
            "description": "Upstream failure (error_servicio).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "error_servicio",
                    "message": "The service is not available right now."
                  }
                }
              }
            }
          },
          "503": {
            "description": "Service not configured (servicio_no_configurado).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "servicio_no_configurado",
                    "message": "The service is not available right now."
                  }
                }
              }
            }
          },
          "504": {
            "description": "Upstream timeout (tiempo_agotado).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "tiempo_agotado",
                    "message": "The service took too long to answer. Please try again."
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Quote": {
        "type": "object",
        "required": [
          "stay",
          "currency",
          "summary",
          "cabins",
          "notes",
          "generated_at"
        ],
        "properties": {
          "stay": {
            "type": "object",
            "description": "The stay as understood from the parameters (dates normalized to YYYY-MM-DD).",
            "required": [
              "check_in",
              "check_out",
              "nights",
              "guests",
              "assumed_guests"
            ],
            "properties": {
              "check_in": {
                "type": "string",
                "format": "date"
              },
              "check_out": {
                "type": "string",
                "format": "date"
              },
              "nights": {
                "type": "integer"
              },
              "guests": {
                "type": "integer"
              },
              "assumed_guests": {
                "type": "boolean",
                "description": "True when guests was not given and 2 was assumed."
              }
            }
          },
          "currency": {
            "type": "string",
            "const": "ARS"
          },
          "summary": {
            "type": "string",
            "description": "One-paragraph answer to read to the guest."
          },
          "cabins": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/QuoteCabin"
            }
          },
          "notes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Conditions to relay (deposit, nothing held until paid)."
          },
          "generated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "QuoteCabin": {
        "type": "object",
        "required": [
          "id",
          "slug",
          "name",
          "max_guests",
          "url",
          "status",
          "price_total",
          "deposit",
          "balance",
          "check_in_time",
          "check_out_time",
          "required_package",
          "booking_url",
          "whatsapp_url"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "description": "Cabin id."
          },
          "slug": {
            "type": "string",
            "description": "Cabin slug, usable as `cabin` in /calendar."
          },
          "name": {
            "type": "string"
          },
          "max_guests": {
            "type": "integer"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Cabin page (photos, details)."
          },
          "status": {
            "type": "string",
            "enum": [
              "bookable",
              "on_request",
              "package_required",
              "unavailable"
            ],
            "description": "bookable: can be booked on the website. on_request: available, booking is arranged on WhatsApp. package_required: the stay covers part of an event sold only as a full package (see required_package). unavailable: taken."
          },
          "price_total": {
            "type": [
              "number",
              "null"
            ],
            "description": "Total for the whole stay and group, ARS. Null without a price."
          },
          "deposit": {
            "type": [
              "number",
              "null"
            ],
            "description": "Deposit (50%) that confirms the booking, ARS."
          },
          "balance": {
            "type": [
              "number",
              "null"
            ],
            "description": "Rest of the price, ARS."
          },
          "check_in_time": {
            "type": [
              "string",
              "null"
            ],
            "description": "HH:MM on the arrival day."
          },
          "check_out_time": {
            "type": [
              "string",
              "null"
            ],
            "description": "HH:MM on the departure day."
          },
          "required_package": {
            "type": [
              "object",
              "null"
            ],
            "description": "Dates of the full event package to book instead (check_out = departure day).",
            "required": [
              "check_in",
              "check_out"
            ],
            "properties": {
              "check_in": {
                "type": "string",
                "format": "date"
              },
              "check_out": {
                "type": "string",
                "format": "date"
              }
            }
          },
          "booking_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Where the guest books: the cabin page with the stay filled in (for package_required, the package dates). Null when unavailable."
          },
          "whatsapp_url": {
            "type": "string",
            "format": "uri",
            "description": "WhatsApp chat with the stay prefilled."
          }
        }
      },
      "Calendar": {
        "type": "object",
        "required": [
          "from",
          "to",
          "cabins"
        ],
        "properties": {
          "from": {
            "type": "string",
            "format": "date"
          },
          "to": {
            "type": "string",
            "format": "date"
          },
          "cabins": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CalendarCabin"
            }
          }
        }
      },
      "CalendarCabin": {
        "type": "object",
        "required": [
          "id",
          "slug",
          "name",
          "occupied_nights",
          "event_packages"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "slug": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "occupied_nights": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "date"
            }
          },
          "event_packages": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "check_in",
                "check_out"
              ],
              "properties": {
                "check_in": {
                  "type": "string",
                  "format": "date"
                },
                "check_out": {
                  "type": "string",
                  "format": "date"
                }
              }
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            }
          }
        }
      }
    }
  }
}