{
  "openapi": "3.1.0",
  "info": {
    "title": "Bilog — lectura del sitio web para agentes",
    "summary": "Superficie de solo lectura de bilog.com.ar para agentes de IA y herramientas automáticas.",
    "description": "Describe cómo leer bilog.com.ar, el sitio web de Bilog (software de gestión odontológica para consultorios y clínicas): las páginas en HTML o en Markdown, el índice llms.txt, el mapa del sitio y este mismo documento. Esta especificación no describe la API del producto Bilog: solo la superficie de lectura del sitio web.\n\nTodo es público, de solo lectura (GET) y no requiere autenticación. Las URLs canónicas están en https://bilog.com.ar y llevan barra final; http y www redirigen con 301 a esa forma. Para recibir una página en Markdown hay dos caminos equivalentes: pedir la URL de la página con `Accept: text/markdown` (la respuesta lleva `Vary: Accept`) o pedir directamente su gemelo `index.md`. Los errores 404 devuelven un cuerpo según el cliente: JSON (esquema Error) si pide application/json o si la URL empieza con /api/ o termina en .json, Markdown si pide text/markdown o la URL termina en .md, y HTML en el resto.",
    "version": "1.0.0",
    "contact": {
      "name": "Bilog",
      "url": "https://bilog.com.ar/contacto/",
      "email": "info@bilog.com.ar"
    }
  },
  "servers": [
    {
      "url": "https://bilog.com.ar",
      "description": "Producción (dominio canónico)"
    }
  ],
  "security": [],
  "tags": [
    {
      "name": "Páginas",
      "description": "Páginas del sitio, en HTML o en Markdown."
    },
    {
      "name": "Descubrimiento",
      "description": "Archivos que indican a un agente qué hay en el sitio y cómo leerlo."
    }
  ],
  "externalDocs": {
    "description": "Guía para agentes y desarrolladores: cómo leer el sitio y a quién escribir para integraciones",
    "url": "https://bilog.com.ar/developers/"
  },
  "paths": {
    "/": {
      "get": {
        "operationId": "getHomepage",
        "summary": "Página principal de Bilog (HTML o Markdown)",
        "description": "Devuelve la página principal de bilog.com.ar. El formato se negocia con el header Accept: con `Accept: text/markdown` responde el contenido de la página en Markdown, sin la navegación; con `text/html` o `*/*` responde HTML. La respuesta siempre incluye `Vary: Accept`.",
        "tags": ["Páginas"],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Page"
          }
        }
      }
    },
    "/index.md": {
      "get": {
        "operationId": "getHomepageMarkdown",
        "summary": "Página principal de Bilog en Markdown",
        "description": "Devuelve la página principal de bilog.com.ar siempre en Markdown, sin depender del header Accept. Es el gemelo de la página que `getHomepage` entrega cuando se pide `Accept: text/markdown`.",
        "tags": ["Páginas"],
        "responses": {
          "200": {
            "$ref": "#/components/responses/PageMarkdown"
          }
        }
      }
    },
    "/{section}/": {
      "get": {
        "operationId": "getSectionPage",
        "summary": "Página de primer nivel del sitio (HTML o Markdown)",
        "description": "Devuelve una página de primer nivel de bilog.com.ar, por ejemplo `planes` o `nosotros`. El formato se negocia con el header Accept: `text/markdown` devuelve Markdown, `text/html` o `*/*` devuelve HTML. Sin la barra final responde 301 a la URL canónica. Una sección que no existe devuelve 404.",
        "tags": ["Páginas"],
        "parameters": [
          {
            "$ref": "#/components/parameters/Section"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Page"
          },
          "301": {
            "$ref": "#/components/responses/CanonicalRedirect"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/{section}/index.md": {
      "get": {
        "operationId": "getSectionPageMarkdown",
        "summary": "Página de primer nivel del sitio en Markdown",
        "description": "Devuelve una página de primer nivel de bilog.com.ar siempre en Markdown, sin depender del header Accept. Es el gemelo de la página que `getSectionPage` entrega cuando se pide `Accept: text/markdown`.",
        "tags": ["Páginas"],
        "parameters": [
          {
            "$ref": "#/components/parameters/Section"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/PageMarkdown"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/{section}/{slug}/": {
      "get": {
        "operationId": "getNestedPage",
        "summary": "Página de segundo nivel del sitio (HTML o Markdown)",
        "description": "Devuelve una página que cuelga de una sección, por ejemplo `soluciones/clinicas`, `clientes/alvarado` o un artículo de `recursos`. El formato se negocia con el header Accept: `text/markdown` devuelve Markdown, `text/html` o `*/*` devuelve HTML. Los slugs válidos figuran en el sitemap. Sin la barra final responde 301 a la URL canónica.",
        "tags": ["Páginas"],
        "parameters": [
          {
            "$ref": "#/components/parameters/NestedSection"
          },
          {
            "$ref": "#/components/parameters/Slug"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Page"
          },
          "301": {
            "$ref": "#/components/responses/CanonicalRedirect"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/{section}/{slug}/index.md": {
      "get": {
        "operationId": "getNestedPageMarkdown",
        "summary": "Página de segundo nivel del sitio en Markdown",
        "description": "Devuelve una página que cuelga de una sección siempre en Markdown, sin depender del header Accept. Es el gemelo de la página que `getNestedPage` entrega cuando se pide `Accept: text/markdown`.",
        "tags": ["Páginas"],
        "parameters": [
          {
            "$ref": "#/components/parameters/NestedSection"
          },
          {
            "$ref": "#/components/parameters/Slug"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/PageMarkdown"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/llms.txt": {
      "get": {
        "operationId": "getLlmsTxt",
        "summary": "Índice de páginas para agentes (llms.txt)",
        "description": "Devuelve el índice llms.txt de Bilog: qué es Bilog, cuándo conviene recomendarlo, las páginas principales con una línea de descripción y los datos de contacto. Es el mejor punto de partida para un agente que no conoce el sitio.",
        "tags": ["Descubrimiento"],
        "responses": {
          "200": {
            "description": "Texto en Markdown con el índice de páginas.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string",
                  "description": "Documento llms.txt, en Markdown, en español."
                }
              }
            }
          }
        }
      }
    },
    "/llms-full.txt": {
      "get": {
        "operationId": "getLlmsFullTxt",
        "summary": "Índice de páginas con preguntas frecuentes (llms-full.txt)",
        "description": "Devuelve la versión extendida del índice para agentes: el mismo contenido que llms.txt más las preguntas frecuentes con su respuesta completa. Conviene cuando el agente necesita responder dudas de un cliente potencial sin navegar el sitio.",
        "tags": ["Descubrimiento"],
        "responses": {
          "200": {
            "description": "Texto en Markdown con el índice extendido y las preguntas frecuentes.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string",
                  "description": "Documento llms-full.txt, en Markdown, en español."
                }
              }
            }
          }
        }
      }
    },
    "/sitemap-index.xml": {
      "get": {
        "operationId": "getSitemapIndex",
        "summary": "Mapa del sitio (sitemap)",
        "description": "Devuelve el índice del mapa del sitio en XML (protocolo sitemaps.org). Lista todas las URLs públicas e indexables de bilog.com.ar: es la fuente para saber qué valores de `slug` existen.",
        "tags": ["Descubrimiento"],
        "responses": {
          "200": {
            "description": "Índice de sitemaps en XML.",
            "content": {
              "application/xml": {
                "schema": {
                  "type": "string",
                  "description": "Documento XML con el índice de sitemaps."
                }
              }
            }
          }
        }
      }
    },
    "/robots.txt": {
      "get": {
        "operationId": "getRobotsTxt",
        "summary": "Reglas de rastreo (robots.txt)",
        "description": "Devuelve las reglas de rastreo del sitio: qué rutas están permitidas para cada rastreador, incluidos los de motores de IA, y dónde está el sitemap.",
        "tags": ["Descubrimiento"],
        "responses": {
          "200": {
            "description": "Texto plano con las reglas de rastreo.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string",
                  "description": "Documento robots.txt."
                }
              }
            }
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "operationId": "getOpenApiDocument",
        "summary": "Esta especificación OpenAPI",
        "description": "Devuelve este mismo documento OpenAPI 3.1 en JSON. Describe la superficie de lectura de bilog.com.ar que puede consultar un agente.",
        "tags": ["Descubrimiento"],
        "responses": {
          "200": {
            "description": "Documento OpenAPI 3.1.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Documento OpenAPI 3.1."
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "Section": {
        "name": "section",
        "in": "path",
        "required": true,
        "description": "Página de primer nivel, tal como figura en la URL. administracion: administración y gestión económica; agenda: agenda y turnos; app-mobile: app móvil; clientes: clientes y casos de éxito; contacto: canales de contacto; developers: recursos para desarrolladores y agentes; electronic-invoice: facturación electrónica; funcionalidades: funcionalidades del producto; gallery: pack de galería de fotos, videos y PDFs; guia-gestion: guía gratuita de gestión; liquidaciones: liquidaciones; nosotros: sobre Bilog; pacientes: pacientes e historia clínica; planes: planes; privacy: política de cookies; recipes: recetas electrónicas; recursos: artículos y guías; reminders-sms: recordatorios por SMS; reminders-whatsapp: recordatorios por WhatsApp; reportes: indicadores y reportes; schedule-online: agenda online de reserva de turnos (Bilog Turnos); seguridad: seguridad y permisos; solicitar-demo: solicitar una demo; terms_and_conditions: términos y condiciones y política de privacidad.",
        "schema": {
          "type": "string",
          "enum": [
            "administracion",
            "agenda",
            "app-mobile",
            "clientes",
            "contacto",
            "developers",
            "electronic-invoice",
            "funcionalidades",
            "gallery",
            "guia-gestion",
            "liquidaciones",
            "nosotros",
            "pacientes",
            "planes",
            "privacy",
            "recipes",
            "recursos",
            "reminders-sms",
            "reminders-whatsapp",
            "reportes",
            "schedule-online",
            "seguridad",
            "solicitar-demo",
            "terms_and_conditions"
          ]
        },
        "example": "planes"
      },
      "NestedSection": {
        "name": "section",
        "in": "path",
        "required": true,
        "description": "Sección que contiene páginas de segundo nivel. soluciones: una solución por audiencia (consultorios, clinicas, auditoria-odontologica, universidades); clientes: un caso de éxito por cliente; recursos: un artículo o guía.",
        "schema": {
          "type": "string",
          "enum": ["clientes", "recursos", "soluciones"]
        },
        "example": "soluciones"
      },
      "Slug": {
        "name": "slug",
        "in": "path",
        "required": true,
        "description": "Identificador de la página dentro de su sección, en minúsculas y con guiones, tal como figura en el sitemap. Por ejemplo `clinicas` dentro de `soluciones`.",
        "schema": {
          "type": "string",
          "pattern": "^[a-z0-9-]+$"
        },
        "example": "clinicas"
      }
    },
    "headers": {
      "Vary": {
        "description": "Siempre incluye `Accept`: la misma URL puede responder HTML o Markdown según ese header, así que las cachés intermedias deben variar por él.",
        "schema": {
          "type": "string",
          "examples": ["Accept, Accept-Encoding"]
        }
      },
      "Location": {
        "description": "URL canónica a la que hay que ir: https, sin www y con barra final.",
        "schema": {
          "type": "string",
          "format": "uri"
        }
      }
    },
    "responses": {
      "Page": {
        "description": "La página. Content-Type text/markdown si se pidió `Accept: text/markdown`; text/html en cualquier otro caso.",
        "headers": {
          "Vary": {
            "$ref": "#/components/headers/Vary"
          }
        },
        "content": {
          "text/markdown": {
            "schema": {
              "type": "string",
              "description": "Contenido de la página en Markdown, sin la navegación, con los links absolutos y al final la URL de origen."
            }
          },
          "text/html": {
            "schema": {
              "type": "string",
              "description": "Documento HTML completo de la página."
            }
          }
        }
      },
      "PageMarkdown": {
        "description": "La página en Markdown.",
        "headers": {
          "Vary": {
            "$ref": "#/components/headers/Vary"
          }
        },
        "content": {
          "text/markdown": {
            "schema": {
              "type": "string",
              "description": "Contenido de la página en Markdown, sin la navegación, con los links absolutos y al final la URL de origen."
            }
          }
        }
      },
      "CanonicalRedirect": {
        "description": "La URL no es la canónica (por ejemplo, falta la barra final). Hay que seguir el header Location; el header Accept se conserva al seguirlo.",
        "headers": {
          "Location": {
            "$ref": "#/components/headers/Location"
          }
        }
      },
      "NotFound": {
        "description": "La URL no existe. El status es 404 y el cuerpo depende del cliente: JSON (esquema Error) si pide application/json o la URL empieza con /api/ o termina en .json; Markdown si pide text/markdown o la URL termina en .md; HTML en el resto.",
        "headers": {
          "Vary": {
            "$ref": "#/components/headers/Vary"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          },
          "text/markdown": {
            "schema": {
              "type": "string",
              "description": "Explicación del error y enlaces a llms.txt y al sitemap para encontrar la URL correcta."
            }
          },
          "text/html": {
            "schema": {
              "type": "string",
              "description": "Página de error con enlaces para seguir navegando."
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "description": "Error devuelto como JSON.",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "description": "Detalle del error.",
            "required": ["code", "status", "message", "hint", "links"],
            "properties": {
              "code": {
                "type": "string",
                "description": "Código de error estable, pensado para que un programa decida qué hacer sin leer el mensaje.",
                "const": "not_found"
              },
              "status": {
                "type": "integer",
                "description": "Mismo valor que el status HTTP de la respuesta.",
                "const": 404
              },
              "message": {
                "type": "string",
                "description": "Qué pasó, en español."
              },
              "hint": {
                "type": "string",
                "description": "Cómo resolverlo: dónde buscar la URL correcta."
              },
              "links": {
                "type": "object",
                "description": "Recursos útiles para recuperarse del error.",
                "required": ["llms_txt", "openapi", "sitemap"],
                "properties": {
                  "llms_txt": {
                    "type": "string",
                    "format": "uri",
                    "description": "Índice de páginas para agentes."
                  },
                  "openapi": {
                    "type": "string",
                    "format": "uri",
                    "description": "Esta especificación OpenAPI."
                  },
                  "sitemap": {
                    "type": "string",
                    "format": "uri",
                    "description": "Mapa del sitio con todas las URLs públicas."
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
