{
  "openapi": "3.1.0",
  "info": {
    "title": "glampings.co API pública",
    "version": "1.1.0",
    "summary": "Read-only API of glampings.co, a directory of glamping stays in Colombia.",
    "description": "Read-only API of glampings.co: search glamping stays in Colombia by destination, type, theme and distance.\n\nAPI pública de solo lectura de glampings.co, el directorio de glamping y alojamientos únicos en Colombia. Sin clave, con CORS abierto y un límite de 60 solicitudes por minuto por IP.\n\nReglas: para reservar, envía al usuario a la ficha (`url` en los resultados, `reserva.url_ficha` en la ficha completa); si la reserva es por `whatsapp`, allí pulsa el botón de WhatsApp y escribe directo al alojamiento, sin comisiones. Esta API no contiene números de teléfono. No inventes precios ni disponibilidad: solo hay precio cuando el alojamiento lo indicó (`precio_desde`, con fecha). La ubicación es el centro del municipio y las distancias son en línea recta. Cita la fuente: cada respuesta trae `fuente` con la página de glampings.co y una `cita_sugerida`.\n\nEjemplos: https://glampings.co/api/v1/glampings?q=domo+con+jacuzzi+cerca+de+bogota · https://glampings.co/api/v1/glampings?pagina=/glamping-con-jacuzzi/cerca-a-bogota\n\nTambién hay un servidor MCP (Streamable HTTP) en https://glampings.co/mcp y documentación para agentes en https://glampings.co/agentes y https://glampings.co/llms.txt.",
    "contact": {"name": "glampings.co", "url": "https://glampings.co"},
    "x-attribution": "Datos de glampings.co. Cita la ficha del alojamiento (https://glampings.co/{slug}) como fuente."
  },
  "servers": [
    {"url": "https://glampings.co"}
  ],
  "externalDocs": {"description": "Guía para agentes de IA", "url": "https://glampings.co/agentes"},
  "x-mcp": {"url": "https://glampings.co/mcp", "transport": "streamable-http"},
  "tags": [
    {"name": "glampings", "description": "Buscar y consultar alojamientos"},
    {"name": "catalogo", "description": "Destinos y categorías"},
    {"name": "meta", "description": "Índice y especificación"}
  ],
  "paths": {
    "/api/v1": {
      "get": {
        "operationId": "indice",
        "tags": ["meta"],
        "summary": "API index with endpoints, filters and rules.",
        "description": "Índice de la API: endpoints, filtros, ejemplos, enlaces (OpenAPI, MCP, llms.txt, /agentes) y reglas de reserva y citación.",
        "responses": {
          "200": {
            "description": "Índice de la API",
            "content": {
              "application/json": {
                "schema": {"type": "object"}
              }
            }
          },
          "429": {"$ref": "#/components/responses/TooManyRequests"}
        }
      }
    },
    "/api/v1/glampings": {
      "get": {
        "operationId": "buscarGlampings",
        "tags": ["glampings"],
        "summary": "Search glamping stays with filters and pagination.",
        "description": "Busca alojamientos del catálogo de glampings.co. Sin pagina: solo fichas indexadas. Con pagina: los alojamientos de esa página, también los no indexables (indexable = false). Todos los filtros se combinan (Y). Orden: como en glampings.co, o por distancia cuando hay cerca_a. Un valor de filtro desconocido devuelve 400 con los valores válidos. Para la página siguiente de resultados abre siguiente_url.\n\nLa forma más simple es q, una pregunta en texto libre: https://glampings.co/api/v1/glampings?q=domo+con+jacuzzi+cerca+de+bogota. Con pagina se obtienen los alojamientos de una página de glampings.co: https://glampings.co/api/v1/glampings?pagina=/glamping-con-jacuzzi/cerca-a-bogota.\n\nCada resultado es un resumen (la ficha completa está en url_api). La respuesta trae fuente (página de glampings.co para citar) y pagina_recomendada.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Pregunta en texto libre, en español o inglés, p. ej. \"domo con jacuzzi cerca de bogota\" o \"glamping pet friendly en antioquia\". Se traduce sin IA a los filtros de abajo; la respuesta muestra lo aplicado en interpretacion y las palabras sin entender en no_entendido. Los demás parámetros tienen prioridad sobre q.",
            "schema": {"type": "string", "maxLength": 200},
            "examples": {
              "ejemplo1": {"summary": "Domos con jacuzzi cerca de Bogotá", "value": "domo con jacuzzi cerca de bogota"},
              "ejemplo2": {"summary": "Glamping pet friendly en Antioquia", "value": "glamping pet friendly en antioquia"},
              "ejemplo3": {"summary": "Glamping near Cartagena with a pool", "value": "glamping near cartagena with pool"}
            }
          },
          {
            "name": "pagina",
            "in": "query",
            "required": false,
            "description": "Ruta de una página de categoría de glampings.co, p. ej. \"/glamping-con-jacuzzi/cerca-a-bogota\", \"/colombia/glamping-boyaca\" o \"/colombia\": devuelve los mismos alojamientos y en el mismo orden que esa página (también fichas no indexables, con indexable = false). Solo se combina con limit y offset.",
            "schema": {"type": "string"},
            "examples": {
              "ejemplo1": {
                "summary": "Lo que muestra la página Glamping con jacuzzi cerca a Bogotá",
                "value": "/glamping-con-jacuzzi/cerca-a-bogota"
              },
              "ejemplo2": {"summary": "Lo que muestra la página Glamping en Boyacá", "value": "/colombia/glamping-boyaca"}
            }
          },
          {
            "name": "destino",
            "in": "query",
            "required": false,
            "description": "Texto libre como en el buscador de glampings.co: municipio, zona, departamento, región o paisaje (p. ej. \"Guatavita\", \"Eje Cafetero\", \"Cañón del Chicamocha\") o ciudad (\"Bogotá\" = Bogotá y alrededores). Si no se reconoce, se busca el texto en nombre, municipio, zona y departamento.",
            "schema": {"type": "string"},
            "example": "Guatavita"
          },
          {
            "name": "departamento",
            "in": "query",
            "required": false,
            "description": "Nombre o slug del departamento, p. ej. \"Cundinamarca\" o \"boyaca\".",
            "schema": {"type": "string"},
            "example": "Cundinamarca"
          },
          {
            "name": "municipio",
            "in": "query",
            "required": false,
            "description": "Nombre del municipio, p. ej. \"Guatavita\". Combínalo con departamento si el nombre se repite.",
            "schema": {"type": "string"},
            "example": "Guatavita"
          },
          {
            "name": "cerca_a",
            "in": "query",
            "required": false,
            "description": "Ciudad de referencia (slug o nombre): bogota, medellin, cali, bucaramanga, pereira, manizales, armenia, villavicencio, ibague, santa-marta, cartagena, tunja, popayan. Sin max_km: dentro del radio que usa glampings.co para esa ciudad. Ordena por distancia.",
            "schema": {
              "type": "string",
              "enum": [
                "bogota",
                "medellin",
                "cali",
                "bucaramanga",
                "pereira",
                "manizales",
                "armenia",
                "villavicencio",
                "ibague",
                "santa-marta",
                "cartagena",
                "tunja",
                "popayan"
              ]
            },
            "example": "bogota"
          },
          {
            "name": "max_km",
            "in": "query",
            "required": false,
            "description": "Distancia máxima en km, en línea recta desde el centro del municipio del alojamiento hasta la ciudad de cerca_a (1 a 500). Requiere cerca_a.",
            "schema": {"type": "number", "minimum": 1, "maximum": 500},
            "example": 60
          },
          {
            "name": "tipo",
            "in": "query",
            "required": false,
            "description": "Uno o varios tipos de alojamiento, separados por coma; basta con que cumpla uno: domos, burbujas, tipis, casas-del-arbol, cabanas-alpinas, tiny-houses, yurtas, carpas-safari, contenedores, casas-hobbit, iglus, malocas, palafitos, casas-flotantes, capsulas, cuevas, chalets, cabanas, ecolodges, glamping.",
            "schema": {"type": "string"},
            "example": "domos,burbujas"
          },
          {
            "name": "tema",
            "in": "query",
            "required": false,
            "description": "Uno o varios temas, separados por coma; deben cumplirse todos: con-jacuzzi, para-parejas, con-vista, con-chimenea, con-piscina, junto-al-rio, en-el-lago, en-la-playa, pet-friendly.",
            "schema": {"type": "string"},
            "example": "con-jacuzzi"
          },
          {
            "name": "caracteristica",
            "in": "query",
            "required": false,
            "description": "Una o varias características, separadas por coma; deben cumplirse todas: jacuzzi, piscina, mascotas, parejas, vista, lago, playa, rio, chimenea, familias, sauna-spa, malla-catamaran, desayuno.",
            "schema": {"type": "string"},
            "example": "sauna-spa"
          },
          {
            "name": "mascotas",
            "in": "query",
            "required": false,
            "description": "true = solo alojamientos que aceptan mascotas (tema pet-friendly).",
            "schema": {"type": "boolean"}
          },
          {
            "name": "solo_whatsapp",
            "in": "query",
            "required": false,
            "description": "true = solo alojamientos que reciben la reserva directa por WhatsApp desde la ficha.",
            "schema": {"type": "boolean"}
          },
          {
            "name": "con_precio",
            "in": "query",
            "required": false,
            "description": "true = solo alojamientos con precio desde indicado por el propio alojamiento.",
            "schema": {"type": "boolean"}
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Resultados por página, 1 a 50 (por defecto 10).",
            "schema": {"type": "integer", "minimum": 1, "maximum": 50, "default": 10}
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Resultados que se saltan, para paginar (desde 0).",
            "schema": {"type": "integer", "minimum": 0, "default": 0}
          }
        ],
        "responses": {
          "200": {
            "description": "Resultados",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/SearchResult"}
              }
            }
          },
          "400": {
            "description": "Parámetro o valor no válido (incluye valid_values cuando aplica); pagina combinada con otros filtros",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/Error"}
              }
            }
          },
          "404": {
            "description": "pagina vacía o no es una página de categoría de glampings.co (valid_values trae URLs de ejemplo que funcionan)",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/Error"}
              }
            }
          },
          "429": {"$ref": "#/components/responses/TooManyRequests"}
        }
      }
    },
    "/api/v1/glampings/{slug}": {
      "get": {
        "operationId": "obtenerGlamping",
        "tags": ["glampings"],
        "summary": "Get one stay by slug.",
        "description": "Ficha completa de un alojamiento por su slug (también acepta la URL de la ficha). Funciona para cualquier ficha no retirada e indica si es indexable.",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "Slug de la ficha, p. ej. ecolodge-el-almejal",
            "schema": {"type": "string"}
          }
        ],
        "responses": {
          "200": {
            "description": "Ficha",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/GlampingDetail"}
              }
            }
          },
          "404": {
            "description": "No existe (el mensaje indica la nueva dirección si la ficha cambió de slug)",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/Error"}
              }
            }
          },
          "410": {
            "description": "Ficha retirada de glampings.co",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/Error"}
              }
            }
          },
          "429": {"$ref": "#/components/responses/TooManyRequests"}
        }
      }
    },
    "/api/v1/destinos": {
      "get": {
        "operationId": "listarDestinos",
        "tags": ["catalogo"],
        "summary": "List destinations (departments, cities, regions, municipalities) with counts.",
        "description": "Departamentos, ciudades de referencia, regiones y paisajes, y los municipios con más glampings, con número de alojamientos y la URL de su página (HTML y Markdown).",
        "responses": {
          "200": {
            "description": "Destinos",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/Destinos"}
              }
            }
          },
          "429": {"$ref": "#/components/responses/TooManyRequests"}
        }
      }
    },
    "/api/v1/categorias": {
      "get": {
        "operationId": "listarCategorias",
        "tags": ["catalogo"],
        "summary": "List stay types, themes and features with counts.",
        "description": "Tipos de alojamiento, temas y características con su slug (valor de filtro), etiqueta en español, número de glampings y página de categoría cuando existe.",
        "responses": {
          "200": {
            "description": "Categorías",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/Categorias"}
              }
            }
          },
          "429": {"$ref": "#/components/responses/TooManyRequests"}
        }
      }
    },
    "/api/v1/openapi.json": {
      "get": {
        "operationId": "openapi",
        "tags": ["meta"],
        "summary": "This OpenAPI 3.1 document.",
        "description": "Este documento OpenAPI 3.1 (también en https://glampings.co/openapi.json).",
        "responses": {
          "200": {
            "description": "Documento OpenAPI",
            "content": {
              "application/json": {
                "schema": {"type": "object"}
              }
            }
          },
          "429": {"$ref": "#/components/responses/TooManyRequests"}
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Fuente": {
        "type": "object",
        "description": "Fuente para citar: glampings.co y la página que respalda esta respuesta",
        "required": ["sitio", "url", "cita_sugerida"],
        "properties": {
          "sitio": {
            "type": "string",
            "enum": ["glampings.co"]
          },
          "url": {
            "type": "string",
            "description": "Página de glampings.co más específica para esta respuesta (la de pagina, la página recomendada, la ficha o el inicio) (URL)"
          },
          "cita_sugerida": {"type": "string", "description": "Texto para citar: \"Fuente: glampings.co, {título de la página} ({url})\""}
        }
      },
      "GlampingResumen": {
        "type": "object",
        "description": "Resumen de un alojamiento (resultado de búsqueda); la ficha completa está en url_api",
        "required": [
          "slug",
          "nombre",
          "tipo",
          "tipos",
          "municipio",
          "departamento",
          "distancia",
          "caracteristicas",
          "rnt",
          "reserva",
          "precio_desde",
          "verificado_por_propietario",
          "indexable",
          "url",
          "url_markdown",
          "url_api"
        ],
        "properties": {
          "slug": {"type": "string", "description": "Identificador de la ficha"},
          "nombre": {"type": "string", "description": "Nombre del alojamiento"},
          "tipo": {"type": "string", "description": "Tipo principal (etiqueta en español)"},
          "tipos": {
            "type": "array",
            "items": {"type": "string"},
            "description": "Todos los tipos que ofrece (etiquetas), el principal primero"
          },
          "municipio": {
            "type": ["string", "null"]
          },
          "departamento": {
            "type": ["string", "null"]
          },
          "distancia": {
            "type": ["object", "null"],
            "description": "Distancia a la ciudad de cerca_a o, sin cerca_a, a la ciudad de referencia más cercana",
            "required": ["ciudad", "km_linea_recta"],
            "properties": {
              "ciudad": {"type": "string"},
              "km_linea_recta": {"type": "integer", "description": "Km en línea recta desde el centro del municipio, redondeado"}
            }
          },
          "caracteristicas": {
            "type": "array",
            "items": {"type": "string"},
            "description": "Lo que ofrece según la información pública del alojamiento (etiquetas)"
          },
          "rnt": {
            "type": ["string", "null"],
            "description": "Número de Registro Nacional de Turismo, si está publicado"
          },
          "reserva": {
            "type": "string",
            "description": "whatsapp = botón de WhatsApp en la ficha (reserva directa, sin comisiones); web = enlaces del alojamiento en la ficha; consulta = sin canal publicado",
            "enum": ["whatsapp", "web", "consulta"]
          },
          "precio_desde": {
            "type": ["object", "null"],
            "description": "Precio desde por noche indicado por el alojamiento (máximo 183 días de antigüedad); null si no lo indicó",
            "required": ["cop", "moneda", "fin_de_semana_cop", "incluye_desayuno", "fecha_confirmacion", "fuente", "etiqueta"],
            "properties": {
              "cop": {"type": "integer", "description": "Precio desde por noche en pesos colombianos"},
              "moneda": {
                "type": "string",
                "enum": ["COP"]
              },
              "fin_de_semana_cop": {
                "type": ["integer", "null"],
                "description": "Precio desde para fines de semana y puentes"
              },
              "incluye_desayuno": {"type": "boolean"},
              "fecha_confirmacion": {"type": "string", "description": "Fecha en que el alojamiento indicó o confirmó el precio (AAAA-MM-DD)"},
              "fuente": {
                "type": "string",
                "enum": ["alojamiento"]
              },
              "etiqueta": {"type": "string"}
            }
          },
          "verificado_por_propietario": {"type": "boolean", "description": "El propietario verificó la ficha"},
          "indexable": {
            "type": "boolean",
            "description": "La ficha está en el catálogo indexado; con pagina también salen fichas no indexables de esa página"
          },
          "url": {"type": "string", "description": "Ficha en glampings.co: cítala y envía allí al usuario para reservar (URL)"},
          "url_markdown": {"type": "string", "description": "Versión Markdown de la ficha (URL)"},
          "url_api": {"type": "string", "description": "Ficha completa en JSON (GET) (URL)"}
        }
      },
      "GlampingItem": {
        "type": "object",
        "description": "Alojamiento en el catálogo de glampings.co",
        "required": [
          "slug",
          "nombre",
          "tipo",
          "tipos",
          "ubicacion",
          "cerca_de",
          "temas",
          "caracteristicas",
          "unidades",
          "rnt",
          "reserva",
          "enlaces",
          "precio_desde",
          "verificado_por_propietario",
          "url",
          "url_markdown"
        ],
        "properties": {
          "slug": {"type": "string", "description": "Identificador de la ficha"},
          "nombre": {"type": "string", "description": "Nombre del alojamiento"},
          "tipo": {
            "type": "object",
            "required": ["slug", "label"],
            "properties": {
              "slug": {"type": "string", "description": "Slug del tipo principal (valor de filtro)"},
              "label": {"type": "string", "description": "Etiqueta en español de glampings.co"}
            }
          },
          "tipos": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["slug", "label"],
              "properties": {
                "slug": {"type": "string", "description": "Slug del tipo (valor de filtro)"},
                "label": {"type": "string", "description": "Etiqueta en español de glampings.co"}
              }
            },
            "description": "Todos los tipos de alojamiento que ofrece"
          },
          "ubicacion": {
            "type": "object",
            "required": ["municipio", "departamento", "zona", "region", "punto", "nota"],
            "properties": {
              "municipio": {
                "type": ["string", "null"]
              },
              "departamento": {
                "type": ["string", "null"]
              },
              "zona": {
                "type": ["string", "null"],
                "description": "Zona o corregimiento, si difiere del municipio"
              },
              "region": {
                "type": ["string", "null"],
                "description": "Región, p. ej. Eje Cafetero"
              },
              "punto": {
                "type": ["object", "null"],
                "description": "Centro del municipio, no la ubicación exacta",
                "required": ["lat", "lon"],
                "properties": {
                  "lat": {"type": "number"},
                  "lon": {"type": "number"}
                }
              },
              "nota": {"type": "string"}
            }
          },
          "cerca_de": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["ciudad", "slug", "km_linea_recta"],
              "properties": {
                "ciudad": {"type": "string"},
                "slug": {"type": "string"},
                "km_linea_recta": {"type": "integer", "description": "Km en línea recta desde el centro del municipio, redondeado"}
              }
            },
            "description": "Ciudades de referencia cercanas"
          },
          "distancia": {
            "type": "object",
            "description": "Solo en búsquedas con cerca_a: distancia en línea recta a esa ciudad",
            "required": ["ciudad", "km_linea_recta"],
            "properties": {
              "ciudad": {"type": "string"},
              "km_linea_recta": {"type": "integer"}
            }
          },
          "temas": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["slug", "label"],
              "properties": {
                "slug": {"type": "string", "description": "Slug del tema (valor de filtro)"},
                "label": {"type": "string", "description": "Etiqueta en español de glampings.co"}
              }
            },
            "description": "Temas (experiencias) de glampings.co"
          },
          "caracteristicas": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["slug", "label"],
              "properties": {
                "slug": {"type": "string", "description": "Slug del característica (valor de filtro)"},
                "label": {"type": "string", "description": "Etiqueta en español de glampings.co"}
              }
            },
            "description": "Lo que ofrece según la información pública del alojamiento"
          },
          "unidades": {
            "type": ["integer", "null"],
            "description": "Número de unidades (domos, cabañas…), si se conoce"
          },
          "rnt": {
            "type": "object",
            "required": ["registrado", "numero"],
            "properties": {
              "registrado": {"type": "boolean", "description": "Tiene número de Registro Nacional de Turismo publicado"},
              "numero": {
                "type": ["string", "null"],
                "description": "Número de RNT"
              }
            }
          },
          "reserva": {
            "type": "object",
            "required": ["metodo", "url_ficha", "instrucciones"],
            "properties": {
              "metodo": {
                "type": "string",
                "description": "whatsapp = botón de WhatsApp en la ficha (reserva directa, sin comisiones); web = enlaces del alojamiento; consulta = sin canal publicado",
                "enum": ["whatsapp", "web", "consulta"]
              },
              "url_ficha": {"type": "string", "description": "Ficha en glampings.co: aquí reserva el usuario (URL)"},
              "instrucciones": {"type": "string"}
            }
          },
          "enlaces": {
            "type": "object",
            "description": "Solo los enlaces que también muestra la ficha. Nunca números de teléfono.",
            "properties": {
              "web": {"type": "string", "description": "Sitio web del alojamiento (URL)"},
              "instagram": {"type": "string", "description": "Perfil de Instagram del alojamiento (URL)"},
              "reserva_externa": {
                "type": "object",
                "required": ["url", "plataforma"],
                "properties": {
                  "url": {"type": "string", "description": "Anuncio en otra plataforma (URL)"},
                  "plataforma": {"type": "string", "description": "Nombre de la plataforma, p. ej. Airbnb"}
                }
              }
            }
          },
          "precio_desde": {
            "type": ["object", "null"],
            "description": "Precio desde por noche indicado por el alojamiento (máximo 183 días de antigüedad); null si no lo indicó",
            "required": ["cop", "moneda", "fin_de_semana_cop", "incluye_desayuno", "fecha_confirmacion", "fuente", "etiqueta"],
            "properties": {
              "cop": {"type": "integer", "description": "Precio desde por noche en pesos colombianos"},
              "moneda": {
                "type": "string",
                "enum": ["COP"]
              },
              "fin_de_semana_cop": {
                "type": ["integer", "null"],
                "description": "Precio desde para fines de semana y puentes"
              },
              "incluye_desayuno": {"type": "boolean"},
              "fecha_confirmacion": {"type": "string", "description": "Fecha en que el alojamiento indicó o confirmó el precio (AAAA-MM-DD)"},
              "fuente": {
                "type": "string",
                "enum": ["alojamiento"]
              },
              "etiqueta": {"type": "string"}
            }
          },
          "verificado_por_propietario": {"type": "boolean", "description": "El propietario verificó la ficha"},
          "url": {"type": "string", "description": "Ficha en glampings.co (cítala como fuente) (URL)"},
          "url_markdown": {"type": "string", "description": "Versión Markdown de la ficha (URL)"}
        }
      },
      "GlampingDetail": {
        "type": "object",
        "description": "Ficha completa de un alojamiento",
        "required": [
          "slug",
          "nombre",
          "tipo",
          "tipos",
          "ubicacion",
          "cerca_de",
          "temas",
          "caracteristicas",
          "unidades",
          "rnt",
          "reserva",
          "enlaces",
          "precio_desde",
          "verificado_por_propietario",
          "url",
          "url_markdown",
          "indexable",
          "descripcion",
          "cercanos",
          "fuente"
        ],
        "properties": {
          "slug": {"type": "string", "description": "Identificador de la ficha"},
          "nombre": {"type": "string", "description": "Nombre del alojamiento"},
          "tipo": {
            "type": "object",
            "required": ["slug", "label"],
            "properties": {
              "slug": {"type": "string", "description": "Slug del tipo principal (valor de filtro)"},
              "label": {"type": "string", "description": "Etiqueta en español de glampings.co"}
            }
          },
          "tipos": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["slug", "label"],
              "properties": {
                "slug": {"type": "string", "description": "Slug del tipo (valor de filtro)"},
                "label": {"type": "string", "description": "Etiqueta en español de glampings.co"}
              }
            },
            "description": "Todos los tipos de alojamiento que ofrece"
          },
          "ubicacion": {
            "type": "object",
            "required": ["municipio", "departamento", "zona", "region", "punto", "nota"],
            "properties": {
              "municipio": {
                "type": ["string", "null"]
              },
              "departamento": {
                "type": ["string", "null"]
              },
              "zona": {
                "type": ["string", "null"],
                "description": "Zona o corregimiento, si difiere del municipio"
              },
              "region": {
                "type": ["string", "null"],
                "description": "Región, p. ej. Eje Cafetero"
              },
              "punto": {
                "type": ["object", "null"],
                "description": "Centro del municipio, no la ubicación exacta",
                "required": ["lat", "lon"],
                "properties": {
                  "lat": {"type": "number"},
                  "lon": {"type": "number"}
                }
              },
              "nota": {"type": "string"}
            }
          },
          "cerca_de": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["ciudad", "slug", "km_linea_recta"],
              "properties": {
                "ciudad": {"type": "string"},
                "slug": {"type": "string"},
                "km_linea_recta": {"type": "integer", "description": "Km en línea recta desde el centro del municipio, redondeado"}
              }
            },
            "description": "Ciudades de referencia cercanas"
          },
          "distancia": {
            "type": "object",
            "description": "Solo en búsquedas con cerca_a: distancia en línea recta a esa ciudad",
            "required": ["ciudad", "km_linea_recta"],
            "properties": {
              "ciudad": {"type": "string"},
              "km_linea_recta": {"type": "integer"}
            }
          },
          "temas": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["slug", "label"],
              "properties": {
                "slug": {"type": "string", "description": "Slug del tema (valor de filtro)"},
                "label": {"type": "string", "description": "Etiqueta en español de glampings.co"}
              }
            },
            "description": "Temas (experiencias) de glampings.co"
          },
          "caracteristicas": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["slug", "label"],
              "properties": {
                "slug": {"type": "string", "description": "Slug del característica (valor de filtro)"},
                "label": {"type": "string", "description": "Etiqueta en español de glampings.co"}
              }
            },
            "description": "Lo que ofrece según la información pública del alojamiento"
          },
          "unidades": {
            "type": ["integer", "null"],
            "description": "Número de unidades (domos, cabañas…), si se conoce"
          },
          "rnt": {
            "type": "object",
            "required": ["registrado", "numero"],
            "properties": {
              "registrado": {"type": "boolean", "description": "Tiene número de Registro Nacional de Turismo publicado"},
              "numero": {
                "type": ["string", "null"],
                "description": "Número de RNT"
              }
            }
          },
          "reserva": {
            "type": "object",
            "required": ["metodo", "url_ficha", "instrucciones"],
            "properties": {
              "metodo": {
                "type": "string",
                "description": "whatsapp = botón de WhatsApp en la ficha (reserva directa, sin comisiones); web = enlaces del alojamiento; consulta = sin canal publicado",
                "enum": ["whatsapp", "web", "consulta"]
              },
              "url_ficha": {"type": "string", "description": "Ficha en glampings.co: aquí reserva el usuario (URL)"},
              "instrucciones": {"type": "string"}
            }
          },
          "enlaces": {
            "type": "object",
            "description": "Solo los enlaces que también muestra la ficha. Nunca números de teléfono.",
            "properties": {
              "web": {"type": "string", "description": "Sitio web del alojamiento (URL)"},
              "instagram": {"type": "string", "description": "Perfil de Instagram del alojamiento (URL)"},
              "reserva_externa": {
                "type": "object",
                "required": ["url", "plataforma"],
                "properties": {
                  "url": {"type": "string", "description": "Anuncio en otra plataforma (URL)"},
                  "plataforma": {"type": "string", "description": "Nombre de la plataforma, p. ej. Airbnb"}
                }
              }
            }
          },
          "precio_desde": {
            "type": ["object", "null"],
            "description": "Precio desde por noche indicado por el alojamiento (máximo 183 días de antigüedad); null si no lo indicó",
            "required": ["cop", "moneda", "fin_de_semana_cop", "incluye_desayuno", "fecha_confirmacion", "fuente", "etiqueta"],
            "properties": {
              "cop": {"type": "integer", "description": "Precio desde por noche en pesos colombianos"},
              "moneda": {
                "type": "string",
                "enum": ["COP"]
              },
              "fin_de_semana_cop": {
                "type": ["integer", "null"],
                "description": "Precio desde para fines de semana y puentes"
              },
              "incluye_desayuno": {"type": "boolean"},
              "fecha_confirmacion": {"type": "string", "description": "Fecha en que el alojamiento indicó o confirmó el precio (AAAA-MM-DD)"},
              "fuente": {
                "type": "string",
                "enum": ["alojamiento"]
              },
              "etiqueta": {"type": "string"}
            }
          },
          "verificado_por_propietario": {"type": "boolean", "description": "El propietario verificó la ficha"},
          "url": {"type": "string", "description": "Ficha en glampings.co (cítala como fuente) (URL)"},
          "url_markdown": {"type": "string", "description": "Versión Markdown de la ficha (URL)"},
          "indexable": {
            "type": "boolean",
            "description": "La ficha está en el catálogo indexado (los resultados de búsqueda solo incluyen fichas indexables)"
          },
          "descripcion": {
            "type": "array",
            "items": {"type": "string"},
            "description": "Párrafos de la sección Sobre de la ficha"
          },
          "cercanos": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["slug", "nombre", "url", "url_markdown"],
              "properties": {
                "slug": {"type": "string"},
                "nombre": {"type": "string"},
                "url": {"type": "string", "description": "URL"},
                "url_markdown": {"type": "string", "description": "URL"}
              }
            },
            "description": "Alojamientos cerca"
          },
          "fuente": {
            "type": "object",
            "description": "Fuente para citar: glampings.co y la página que respalda esta respuesta",
            "required": ["sitio", "url", "cita_sugerida"],
            "properties": {
              "sitio": {
                "type": "string",
                "enum": ["glampings.co"]
              },
              "url": {
                "type": "string",
                "description": "Página de glampings.co más específica para esta respuesta (la de pagina, la página recomendada, la ficha o el inicio) (URL)"
              },
              "cita_sugerida": {"type": "string", "description": "Texto para citar: \"Fuente: glampings.co, {título de la página} ({url})\""}
            }
          }
        }
      },
      "SearchResult": {
        "type": "object",
        "description": "Resultado de búsqueda",
        "required": [
          "total",
          "limit",
          "offset",
          "siguiente_offset",
          "siguiente_url",
          "orden",
          "fuente",
          "pagina_recomendada",
          "interpretacion",
          "no_entendido",
          "pagina",
          "filtros",
          "aviso",
          "nota",
          "items"
        ],
        "properties": {
          "total": {"type": "integer", "description": "Resultados en total"},
          "limit": {"type": "integer"},
          "offset": {"type": "integer"},
          "siguiente_offset": {
            "type": ["integer", "null"],
            "description": "offset de la página siguiente, o null"
          },
          "siguiente_url": {
            "type": ["string", "null"],
            "description": "La misma búsqueda con offset = siguiente_offset, lista para abrir con GET; null si no hay más (URL)"
          },
          "orden": {
            "type": "string",
            "description": "relevancia = como en glampings.co; distancia = con cerca_a",
            "enum": ["relevancia", "distancia"]
          },
          "fuente": {
            "type": "object",
            "description": "Fuente para citar: glampings.co y la página que respalda esta respuesta",
            "required": ["sitio", "url", "cita_sugerida"],
            "properties": {
              "sitio": {
                "type": "string",
                "enum": ["glampings.co"]
              },
              "url": {
                "type": "string",
                "description": "Página de glampings.co más específica para esta respuesta (la de pagina, la página recomendada, la ficha o el inicio) (URL)"
              },
              "cita_sugerida": {"type": "string", "description": "Texto para citar: \"Fuente: glampings.co, {título de la página} ({url})\""}
            }
          },
          "pagina_recomendada": {
            "type": ["string", "null"],
            "description": "Página de categoría de glampings.co más específica para estos filtros (o la de pagina) (URL)"
          },
          "interpretacion": {
            "type": ["object", "null"],
            "description": "Filtros que se sacaron de q y se aplicaron; null sin q",
            "properties": {
              "destino": {"type": "string"},
              "departamento": {"type": "string"},
              "municipio": {"type": "string"},
              "cerca_a": {"type": "string"},
              "max_km": {"type": "number"},
              "tipo": {
                "type": "array",
                "items": {"type": "string"}
              },
              "tema": {
                "type": "array",
                "items": {"type": "string"}
              },
              "caracteristica": {
                "type": "array",
                "items": {"type": "string"}
              },
              "mascotas": {"type": "boolean"},
              "solo_whatsapp": {"type": "boolean"}
            }
          },
          "no_entendido": {
            "type": "array",
            "items": {"type": "string"},
            "description": "Palabras de q que no se reconocieron como filtro"
          },
          "pagina": {
            "type": ["object", "null"],
            "description": "La página de categoría pedida con pagina; null sin pagina",
            "required": ["url", "url_markdown", "titulo", "indexable"],
            "properties": {
              "url": {"type": "string", "description": "Página de glampings.co (URL)"},
              "url_markdown": {"type": "string", "description": "Versión Markdown de la página (URL)"},
              "titulo": {"type": "string", "description": "Título (H1) de la página"},
              "indexable": {"type": "boolean", "description": "La página está en el índice de buscadores"}
            }
          },
          "filtros": {
            "type": "object",
            "required": [
              "destino",
              "departamento",
              "municipio",
              "cerca_a",
              "max_km",
              "tipo",
              "tema",
              "caracteristica",
              "solo_whatsapp",
              "con_precio"
            ],
            "properties": {
              "destino": {
                "type": ["object", "null"],
                "required": ["consulta", "interpretado_como", "modo", "url", "url_markdown"],
                "properties": {
                  "consulta": {"type": "string"},
                  "interpretado_como": {"type": "string"},
                  "modo": {
                    "type": "string",
                    "description": "lugar = destino reconocido; texto = búsqueda de texto",
                    "enum": ["lugar", "texto"]
                  },
                  "url": {
                    "type": ["string", "null"],
                    "description": "Página de categoría en glampings.co, si existe (URL)"
                  },
                  "url_markdown": {
                    "type": ["string", "null"],
                    "description": "Versión Markdown de esa página (URL)"
                  }
                }
              },
              "departamento": {
                "type": ["string", "null"]
              },
              "municipio": {
                "type": ["string", "null"]
              },
              "cerca_a": {
                "type": ["string", "null"]
              },
              "max_km": {
                "type": ["number", "null"]
              },
              "tipo": {
                "type": "array",
                "items": {"type": "string"}
              },
              "tema": {
                "type": "array",
                "items": {"type": "string"}
              },
              "caracteristica": {
                "type": "array",
                "items": {"type": "string"}
              },
              "solo_whatsapp": {"type": "boolean"},
              "con_precio": {"type": "boolean"}
            }
          },
          "aviso": {
            "type": ["string", "null"],
            "description": "Aviso cuando hay palabras de q sin entender, no se reconoció el destino, no hay resultados o una página de glampings.co muestra más alojamientos que coinciden y aún no están en el catálogo publicado (con su URL)"
          },
          "nota": {"type": "string"},
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "Resumen de un alojamiento (resultado de búsqueda); la ficha completa está en url_api",
              "required": [
                "slug",
                "nombre",
                "tipo",
                "tipos",
                "municipio",
                "departamento",
                "distancia",
                "caracteristicas",
                "rnt",
                "reserva",
                "precio_desde",
                "verificado_por_propietario",
                "indexable",
                "url",
                "url_markdown",
                "url_api"
              ],
              "properties": {
                "slug": {"type": "string", "description": "Identificador de la ficha"},
                "nombre": {"type": "string", "description": "Nombre del alojamiento"},
                "tipo": {"type": "string", "description": "Tipo principal (etiqueta en español)"},
                "tipos": {
                  "type": "array",
                  "items": {"type": "string"},
                  "description": "Todos los tipos que ofrece (etiquetas), el principal primero"
                },
                "municipio": {
                  "type": ["string", "null"]
                },
                "departamento": {
                  "type": ["string", "null"]
                },
                "distancia": {
                  "type": ["object", "null"],
                  "description": "Distancia a la ciudad de cerca_a o, sin cerca_a, a la ciudad de referencia más cercana",
                  "required": ["ciudad", "km_linea_recta"],
                  "properties": {
                    "ciudad": {"type": "string"},
                    "km_linea_recta": {"type": "integer", "description": "Km en línea recta desde el centro del municipio, redondeado"}
                  }
                },
                "caracteristicas": {
                  "type": "array",
                  "items": {"type": "string"},
                  "description": "Lo que ofrece según la información pública del alojamiento (etiquetas)"
                },
                "rnt": {
                  "type": ["string", "null"],
                  "description": "Número de Registro Nacional de Turismo, si está publicado"
                },
                "reserva": {
                  "type": "string",
                  "description": "whatsapp = botón de WhatsApp en la ficha (reserva directa, sin comisiones); web = enlaces del alojamiento en la ficha; consulta = sin canal publicado",
                  "enum": ["whatsapp", "web", "consulta"]
                },
                "precio_desde": {
                  "type": ["object", "null"],
                  "description": "Precio desde por noche indicado por el alojamiento (máximo 183 días de antigüedad); null si no lo indicó",
                  "required": ["cop", "moneda", "fin_de_semana_cop", "incluye_desayuno", "fecha_confirmacion", "fuente", "etiqueta"],
                  "properties": {
                    "cop": {"type": "integer", "description": "Precio desde por noche en pesos colombianos"},
                    "moneda": {
                      "type": "string",
                      "enum": ["COP"]
                    },
                    "fin_de_semana_cop": {
                      "type": ["integer", "null"],
                      "description": "Precio desde para fines de semana y puentes"
                    },
                    "incluye_desayuno": {"type": "boolean"},
                    "fecha_confirmacion": {"type": "string", "description": "Fecha en que el alojamiento indicó o confirmó el precio (AAAA-MM-DD)"},
                    "fuente": {
                      "type": "string",
                      "enum": ["alojamiento"]
                    },
                    "etiqueta": {"type": "string"}
                  }
                },
                "verificado_por_propietario": {"type": "boolean", "description": "El propietario verificó la ficha"},
                "indexable": {
                  "type": "boolean",
                  "description": "La ficha está en el catálogo indexado; con pagina también salen fichas no indexables de esa página"
                },
                "url": {"type": "string", "description": "Ficha en glampings.co: cítala y envía allí al usuario para reservar (URL)"},
                "url_markdown": {"type": "string", "description": "Versión Markdown de la ficha (URL)"},
                "url_api": {"type": "string", "description": "Ficha completa en JSON (GET) (URL)"}
              }
            }
          }
        }
      },
      "Destinos": {
        "type": "object",
        "description": "Destinos con número de glampings en el catálogo",
        "required": ["total_glampings", "departamentos", "ciudades", "regiones", "municipios", "nota", "fuente"],
        "properties": {
          "total_glampings": {"type": "integer"},
          "departamentos": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["nombre", "slug", "glampings", "url", "url_markdown"],
              "properties": {
                "nombre": {"type": "string"},
                "slug": {"type": "string"},
                "glampings": {"type": "integer"},
                "url": {
                  "type": ["string", "null"],
                  "description": "Página de categoría en glampings.co, si existe (URL)"
                },
                "url_markdown": {
                  "type": ["string", "null"],
                  "description": "Versión Markdown de esa página (URL)"
                }
              }
            }
          },
          "ciudades": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["nombre", "slug", "radio_km", "glampings", "url", "url_markdown"],
              "properties": {
                "nombre": {"type": "string"},
                "slug": {"type": "string"},
                "radio_km": {"type": "integer"},
                "glampings": {"type": "integer"},
                "url": {
                  "type": ["string", "null"],
                  "description": "Página de categoría en glampings.co, si existe (URL)"
                },
                "url_markdown": {
                  "type": ["string", "null"],
                  "description": "Versión Markdown de esa página (URL)"
                }
              }
            }
          },
          "regiones": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["nombre", "glampings", "url", "url_markdown"],
              "properties": {
                "nombre": {"type": "string"},
                "glampings": {"type": "integer"},
                "url": {
                  "type": ["string", "null"],
                  "description": "Página de categoría en glampings.co, si existe (URL)"
                },
                "url_markdown": {
                  "type": ["string", "null"],
                  "description": "Versión Markdown de esa página (URL)"
                }
              }
            }
          },
          "municipios": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["nombre", "departamento", "glampings", "url", "url_markdown"],
              "properties": {
                "nombre": {"type": "string"},
                "departamento": {"type": "string"},
                "glampings": {"type": "integer"},
                "url": {
                  "type": ["string", "null"],
                  "description": "Página de categoría en glampings.co, si existe (URL)"
                },
                "url_markdown": {
                  "type": ["string", "null"],
                  "description": "Versión Markdown de esa página (URL)"
                }
              }
            }
          },
          "nota": {"type": "string"},
          "fuente": {
            "type": "object",
            "description": "Fuente para citar: glampings.co y la página que respalda esta respuesta",
            "required": ["sitio", "url", "cita_sugerida"],
            "properties": {
              "sitio": {
                "type": "string",
                "enum": ["glampings.co"]
              },
              "url": {
                "type": "string",
                "description": "Página de glampings.co más específica para esta respuesta (la de pagina, la página recomendada, la ficha o el inicio) (URL)"
              },
              "cita_sugerida": {"type": "string", "description": "Texto para citar: \"Fuente: glampings.co, {título de la página} ({url})\""}
            }
          }
        }
      },
      "Categorias": {
        "type": "object",
        "description": "Tipos, temas y características con número de glampings",
        "required": ["tipos", "temas", "caracteristicas", "nota", "fuente"],
        "properties": {
          "tipos": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["slug", "label", "plural", "descripcion", "glampings", "url", "url_markdown"],
              "properties": {
                "slug": {"type": "string"},
                "label": {"type": "string"},
                "plural": {"type": "string"},
                "descripcion": {"type": "string"},
                "glampings": {"type": "integer"},
                "url": {
                  "type": ["string", "null"],
                  "description": "Página de categoría en glampings.co, si existe (URL)"
                },
                "url_markdown": {
                  "type": ["string", "null"],
                  "description": "Versión Markdown de esa página (URL)"
                }
              }
            }
          },
          "temas": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["slug", "label", "glampings", "url", "url_markdown"],
              "properties": {
                "slug": {"type": "string"},
                "label": {"type": "string"},
                "glampings": {"type": "integer"},
                "url": {
                  "type": ["string", "null"],
                  "description": "Página de categoría en glampings.co, si existe (URL)"
                },
                "url_markdown": {
                  "type": ["string", "null"],
                  "description": "Versión Markdown de esa página (URL)"
                }
              }
            }
          },
          "caracteristicas": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["slug", "label", "glampings", "url", "url_markdown"],
              "properties": {
                "slug": {"type": "string"},
                "label": {"type": "string"},
                "glampings": {"type": "integer"},
                "url": {
                  "type": ["string", "null"],
                  "description": "Página de categoría en glampings.co, si existe (URL)"
                },
                "url_markdown": {
                  "type": ["string", "null"],
                  "description": "Versión Markdown de esa página (URL)"
                }
              }
            }
          },
          "nota": {"type": "string"},
          "fuente": {
            "type": "object",
            "description": "Fuente para citar: glampings.co y la página que respalda esta respuesta",
            "required": ["sitio", "url", "cita_sugerida"],
            "properties": {
              "sitio": {
                "type": "string",
                "enum": ["glampings.co"]
              },
              "url": {
                "type": "string",
                "description": "Página de glampings.co más específica para esta respuesta (la de pagina, la página recomendada, la ficha o el inicio) (URL)"
              },
              "cita_sugerida": {"type": "string", "description": "Texto para citar: \"Fuente: glampings.co, {título de la página} ({url})\""}
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "description": "Error",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "required": ["code", "message"],
            "properties": {
              "code": {
                "type": "string",
                "description": "invalid_parameter, unknown_parameter, invalid_value, not_found, gone, rate_limited, internal_error"
              },
              "message": {"type": "string", "description": "Mensaje en español"},
              "valid_values": {
                "type": "array",
                "items": {"type": "string"},
                "description": "Valores válidos, cuando aplica"
              }
            }
          }
        }
      }
    },
    "responses": {
      "TooManyRequests": {
        "description": "Límite de solicitudes superado (60 por minuto por IP)",
        "headers": {
          "Retry-After": {
            "description": "Segundos de espera",
            "schema": {"type": "integer"}
          }
        },
        "content": {
          "application/json": {
            "schema": {"$ref": "#/components/schemas/Error"}
          }
        }
      }
    }
  }
}
