openapi: 3.1.0
info:
  title: Botzi Public API
  summary: Catálogo público de los negocios que usan Botzi.
  description: >-
    API pública de **Botzi**, la plataforma de WhatsApp con IA y mini-ERP para pymes de LATAM
    (https://botzi.co).


    ## Qué se puede hacer con esta API


    Leer la **vitrina pública** de un negocio que usa Botzi: los datos de la tienda y

    su catálogo activo, con precios ya rebajados si hay promociones vigentes. Es la

    misma información que sirve la página `https://botzi.co/t/{slug}`, en JSON.


    Sirve para: mostrar el catálogo de un negocio dentro de otra aplicación,

    construir un agente que responda "¿qué vende X y a qué precio?", o sincronizar

    precios y stock hacia un tercero.


    ## Autenticación


    **Ninguna.** Estos endpoints son públicos por diseño: el `slug` de una tienda

    lo comparte el propio dueño con sus clientes. No hay API key, no hay OAuth, no

    hay cabeceras que mandar.


    Consecuencia importante: la API es de **sólo lectura** y sólo alcanza lo que el

    negocio decidió publicar. No hay forma de leer pedidos, conversaciones, clientes

    ni caja desde acá — eso vive detrás de la sesión del panel y no tiene API

    pública. Ver https://botzi.co/desarrolladores.


    ## Límite de uso


    **30 peticiones por minuto** por combinación de `slug` e

    IP, en ventana deslizante de 60 segundos. Al pasarse, la respuesta es

    `429` y basta con esperar un minuto. No hay cuota diaria ni costo por llamada.


    ## Estabilidad


    Los campos existentes no se quitan ni cambian de tipo sin subir la versión de

    este documento. Se pueden **agregar** campos nuevos en cualquier momento: un

    cliente correcto ignora los que no conoce.
  version: 1.0.0
  termsOfService: https://botzi.co/terminos
  contact:
    name: Botzi
    url: https://botzi.co/desarrolladores
    email: legal@botzi.co
  x-whatsapp: https://wa.me/573239261083
externalDocs:
  description: Documentación para desarrolladores y agentes de IA
  url: https://botzi.co/desarrolladores
servers:
  - url: https://botzi.co/api
    description: Producción
tags:
  - name: Vitrina pública
    description: Lectura del catálogo que un negocio publicó en su tienda de Botzi. Sin autenticación.
paths:
  /public/store/{slug}:
    get:
      operationId: getPublicStore
      summary: Obtener la vitrina pública de un negocio
      description: >-
        Devuelve los datos públicos del negocio (nombre, mensaje de bienvenida, WhatsApp si está
        conectado) y su catálogo activo. Los precios ya vienen con las promociones vigentes
        aplicadas: cuando hay descuento, el producto trae además `original_price` y
        `discount_label`. Las propiedades inmobiliarias reservadas, arrendadas o vendidas no se
        incluyen. No requiere autenticación.
      tags:
        - Vitrina pública
      security: []
      parameters:
        - name: slug
          in: path
          required: true
          description: >-
            Identificador público de la tienda, el mismo de la URL `botzi.co/t/{slug}`. Lo comparte
            el dueño del negocio.
          schema:
            type: string
            minLength: 1
            maxLength: 120
            examples:
              - mi-negocio-a1b2
      responses:
        '200':
          description: La vitrina del negocio con su catálogo activo.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicStore'
        '404':
          description: No existe una tienda activa con ese `slug`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
  /public/store/{slug}/products/{productId}/variants:
    get:
      operationId: getPublicStoreProductVariants
      summary: Listar las variantes de un producto
      description: >-
        Devuelve las variantes activas de un producto del catálogo público (tallas, colores,
        presentaciones). Se incluyen también las agotadas, con `stock_quantity` en 0, para que se
        puedan mostrar deshabilitadas en vez de desaparecer. El producto debe pertenecer al negocio
        del `slug`, así que este endpoint no sirve para enumerar productos ajenos. No requiere
        autenticación.
      tags:
        - Vitrina pública
      security: []
      parameters:
        - name: slug
          in: path
          required: true
          description: Identificador público de la tienda.
          schema:
            type: string
            minLength: 1
            maxLength: 120
            examples:
              - mi-negocio-a1b2
        - name: productId
          in: path
          required: true
          description: UUID del producto, tal como viene en el campo `id` de `getPublicStore`.
          schema:
            type: string
            format: uuid
            examples:
              - 00000000-0000-4000-8000-000000000000
      responses:
        '200':
          description: El producto y sus variantes activas.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProductVariants'
        '404':
          description: No existe la tienda, o el producto no pertenece a esa tienda o no está activo.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
components:
  responses:
    RateLimited:
      description: >-
        Se superaron las 30 peticiones por minuto para ese `slug` desde esa IP. Reintentar después
        de 60 segundos.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  schemas:
    PublicStore:
      type: object
      description: Datos públicos de un negocio y su catálogo activo.
      required:
        - agent
        - products
      properties:
        agent:
          $ref: '#/components/schemas/StoreProfile'
        products:
          type: array
          description: >-
            Catálogo activo, en el orden en que el negocio lo ordenó. Puede venir vacío si todavía
            no cargó nada.
          items:
            $ref: '#/components/schemas/Product'
    StoreProfile:
      type: object
      description: >-
        Ficha pública del negocio. No incluye datos del dueño de la cuenta (ni correo, ni
        identificadores internos).
      required:
        - name
        - slug
        - business_name
      properties:
        name:
          type: string
          description: Nombre del asistente de Botzi del negocio.
        slug:
          type: string
          description: Identificador público de la tienda.
        business_name:
          type: string
          description: Nombre comercial que se muestra al cliente.
        whatsapp_phone:
          type:
            - string
            - 'null'
          description: >-
            Número de WhatsApp del negocio en formato internacional. Es `null` si el negocio todavía
            no conectó su WhatsApp.
          examples:
            - '573001234567'
        welcome_message:
          type:
            - string
            - 'null'
          description: Mensaje con el que el asistente saluda a un cliente nuevo.
        business_type:
          type:
            - string
            - 'null'
          description: >-
            Rubro del negocio, cuando está configurado. Determina qué campos del catálogo tienen
            sentido (por ejemplo `bedrooms` sólo aplica a inmobiliarias).
          examples:
            - veterinaria
    Product:
      type: object
      description: >-
        Un producto, servicio o inmueble publicado. Los campos específicos de un rubro vienen en
        `null` para los demás.
      required:
        - id
        - name
        - resource_type
        - has_variants
      properties:
        id:
          type: string
          format: uuid
          description: Identificador del producto.
        name:
          type: string
          description: Nombre visible.
        description:
          type:
            - string
            - 'null'
          description: Descripción larga.
        short_description:
          type:
            - string
            - 'null'
          description: Descripción corta para listados.
        price:
          type:
            - number
            - 'null'
          description: >-
            Precio vigente, con la promoción ya aplicada si hay alguna activa. Moneda: la del
            negocio (COP en Colombia). `null` cuando el negocio no publica precio.
          examples:
            - 1850000
        original_price:
          type:
            - number
            - 'null'
          description: >-
            Precio antes del descuento. Sólo aparece cuando hay una promoción vigente aplicada sobre
            `price`.
        discount_label:
          type:
            - string
            - 'null'
          description: Etiqueta legible del descuento aplicado. Sólo aparece junto a `original_price`.
          examples:
            - 20% OFF
        category:
          type:
            - string
            - 'null'
          description: Categoría dentro del catálogo del negocio.
        image_url:
          type:
            - string
            - 'null'
          format: uri
          description: Imagen principal.
        gallery_urls:
          type:
            - array
            - 'null'
          description: Galería adicional de imágenes.
          items:
            type: string
            format: uri
        stock:
          type:
            - integer
            - 'null'
          description: >-
            Unidades disponibles. `null` cuando el negocio no lleva inventario de ese ítem (por
            ejemplo, un servicio).
        resource_type:
          type: string
          description: Qué clase de ítem es.
          examples:
            - product
        has_variants:
          type: boolean
          description: >-
            Si es `true`, pedir las opciones con `getPublicStoreProductVariants` antes de mostrar
            precio o stock.
        operation:
          type:
            - string
            - 'null'
          description: 'Inmobiliarias: si el inmueble se vende o se arrienda.'
          examples:
            - venta
        zone:
          type:
            - string
            - 'null'
          description: 'Inmobiliarias: zona o barrio.'
        bedrooms:
          type:
            - integer
            - 'null'
          description: 'Inmobiliarias: número de habitaciones.'
        bathrooms:
          type:
            - integer
            - 'null'
          description: 'Inmobiliarias: número de baños.'
        area_m2:
          type:
            - number
            - 'null'
          description: 'Inmobiliarias: área construida en m².'
        rent_price:
          type:
            - number
            - 'null'
          description: 'Inmobiliarias: canon de arriendo, cuando la operación lo incluye.'
        property_status:
          type:
            - string
            - 'null'
          description: >-
            Inmobiliarias: estado del inmueble. Los reservados, arrendados y vendidos no se
            devuelven.
          examples:
            - disponible
    ProductVariants:
      type: object
      description: Un producto con sus variantes activas.
      required:
        - product
        - variants
      properties:
        product:
          $ref: '#/components/schemas/ProductSummary'
        variants:
          type: array
          description: Variantes activas, en el orden en que se crearon. Incluye las agotadas.
          items:
            $ref: '#/components/schemas/ProductVariant'
    ProductSummary:
      type: object
      description: Datos mínimos del producto al que pertenecen las variantes.
      required:
        - id
        - has_variants
      properties:
        id:
          type: string
          format: uuid
          description: Identificador del producto.
        name:
          type:
            - string
            - 'null'
          description: Nombre visible del producto.
        price:
          type:
            - number
            - 'null'
          description: Precio base del producto.
        has_variants:
          type: boolean
          description: Si el producto se vende por variantes.
    ProductVariant:
      type: object
      description: Una combinación concreta de atributos con su propio precio y stock.
      required:
        - id
        - attributes
        - stock_quantity
      properties:
        id:
          type: string
          format: uuid
          description: Identificador de la variante.
        attributes:
          type: object
          description: Atributos que definen la variante, como pares clave/valor.
          additionalProperties:
            type: string
          examples:
            - color: Negro
              talla: M
        stock_quantity:
          type: integer
          description: Unidades disponibles de esta variante. `0` significa agotada.
        price:
          type:
            - number
            - 'null'
          description: Precio de esta variante. Si es `null`, aplica el precio base del producto.
        image_url:
          type:
            - string
            - 'null'
          format: uri
          description: Imagen propia de esta variante, si tiene una distinta a la del producto.
    Error:
      type: object
      description: Formato de error de la API.
      required:
        - detail
      properties:
        detail:
          type: string
          description: Explicación legible de qué salió mal.
          examples:
            - Tienda no encontrada
security: []
