{
  "openapi": "3.1.0",
  "info": {
    "title": "API de Qubo",
    "version": "1.0.0",
    "description": "Crea y descarga códigos QR con el diseño del Studio, gestiona enlaces cortos y links de WhatsApp, trae las estadísticas y los contactos de tus BioLinks, maneja tus tarjetas de lealtad, cupones, tarjetas de regalo, eventos, catálogos y tu lista de clientes. Guía completa: https://qubo.click/docs/api",
    "contact": {
      "name": "Qubo",
      "url": "https://qubo.click",
      "email": "info@cibergenios.com"
    },
    "license": {
      "name": "Propietaria: uso según los Términos de Servicio de Qubo"
    }
  },
  "servers": [
    {
      "url": "https://qubo.click/api/v1"
    }
  ],
  "security": [
    {
      "ApiKey": []
    },
    {
      "Bearer": []
    }
  ],
  "tags": [
    {
      "name": "QR",
      "description": "Códigos QR estáticos y dinámicos: crear, descargar, editar y escaneos."
    },
    {
      "name": "Enlaces",
      "description": "Enlaces cortos y links de WhatsApp (comparten el cupo del plan)."
    },
    {
      "name": "BioLinks",
      "description": "Solo lectura: tus BioLinks, sus estadísticas y los contactos de sus formularios."
    },
    {
      "name": "Tarjetas de lealtad",
      "description": "Programas de sellos, las tarjetas de tus clientes (sellar y entregar premios desde tu punto de venta), cupones, tarjetas de regalo y eventos con entradas."
    },
    {
      "name": "Catálogos",
      "description": "Catálogos y menús con sus productos. Los pedidos llegan solo por WhatsApp."
    },
    {
      "name": "Clientes",
      "description": "Tu lista de clientes unida: consultarla, traer contactos de otro sistema y borrar a quien lo pida."
    }
  ],
  "paths": {
    "/qr": {
      "get": {
        "tags": [
          "QR"
        ],
        "summary": "Listar tus QR",
        "operationId": "listQr",
        "parameters": [
          {
            "name": "type",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "static",
                "dynamic"
              ]
            }
          },
          {
            "name": "content_type",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tag",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Busca en el nombre.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "is_active",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Una página de resultados",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Qr"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PageMeta"
                    },
                    "links": {
                      "type": "object",
                      "properties": {
                        "next": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "prev": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      },
      "post": {
        "tags": [
          "QR"
        ],
        "summary": "Crear un QR",
        "operationId": "createQr",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QrCreate"
              },
              "example": {
                "title": "Mesa 4 - Menú",
                "type": "dynamic",
                "url": "https://turestaurante.com/menu",
                "design": {
                  "dots_style": "rounded"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Creado",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Qr"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/qr/generate": {
      "post": {
        "tags": [
          "QR"
        ],
        "summary": "Crear un QR dinámico (versión anterior)",
        "operationId": "generateQr",
        "deprecated": false,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "title",
                  "redirect_url"
                ],
                "properties": {
                  "title": {
                    "type": "string"
                  },
                  "redirect_url": {
                    "type": "string",
                    "format": "uri"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Creado",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/LegacyQr"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/qr/render": {
      "post": {
        "tags": [
          "QR"
        ],
        "summary": "Generar la imagen sin guardar",
        "operationId": "renderQr",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QrRender"
              },
              "example": {
                "content_type": "wifi",
                "payload": {
                  "ssid": "Cafe_Invitados",
                  "password": "cafe2026"
                },
                "format": "svg"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "La imagen",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/svg+xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/qr/{id}": {
      "get": {
        "tags": [
          "QR"
        ],
        "summary": "Consultar un QR",
        "operationId": "getQr",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Qr"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "tags": [
          "QR"
        ],
        "summary": "Editar un QR (destino, pausa, diseño, etiquetas)",
        "operationId": "updateQr",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QrUpdate"
              },
              "example": {
                "url": "https://turestaurante.com/menu-navidad"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Qr"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      },
      "delete": {
        "tags": [
          "QR"
        ],
        "summary": "Borrar un QR",
        "operationId": "deleteQr",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Deleted"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/qr/{id}/image": {
      "get": {
        "tags": [
          "QR"
        ],
        "summary": "Descargar la imagen de un QR",
        "operationId": "getQrImage",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "format",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "png",
                "svg"
              ],
              "default": "png"
            }
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 128,
              "maximum": 4096,
              "default": 1024
            }
          }
        ],
        "responses": {
          "200": {
            "description": "La imagen",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/svg+xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/qr/{id}/stats": {
      "get": {
        "tags": [
          "QR"
        ],
        "summary": "Escaneos de un QR",
        "operationId": "getQrStats",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "days",
            "in": "query",
            "description": "Días hacia atrás. Se recorta al historial de tu plan.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 30
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/QrStats"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/links": {
      "get": {
        "tags": [
          "Enlaces"
        ],
        "summary": "Listar enlaces cortos y links de WhatsApp",
        "operationId": "listLinks",
        "parameters": [
          {
            "name": "type",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "url",
                "whatsapp"
              ]
            }
          },
          {
            "name": "tag",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Busca en el nombre.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "is_active",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Una página de resultados",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Link"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PageMeta"
                    },
                    "links": {
                      "type": "object",
                      "properties": {
                        "next": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "prev": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      },
      "post": {
        "tags": [
          "Enlaces"
        ],
        "summary": "Crear un enlace corto",
        "operationId": "createLink",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LinkCreate"
              },
              "example": {
                "destination_url": "https://tutienda.com/promo",
                "alias": "promo-oct"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Creado",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Link"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/whatsapp": {
      "post": {
        "tags": [
          "Enlaces"
        ],
        "summary": "Crear un link de WhatsApp",
        "operationId": "createWhatsappLink",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WhatsappCreate"
              },
              "example": {
                "phone": "+57 300 123 4567",
                "message": "Hola, quiero hacer un pedido"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Creado",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Link"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/links/{id}": {
      "get": {
        "tags": [
          "Enlaces"
        ],
        "summary": "Consultar un enlace",
        "operationId": "getLink",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Link"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "tags": [
          "Enlaces"
        ],
        "summary": "Editar un enlace (destino o número, pausa, etiquetas)",
        "operationId": "updateLink",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LinkUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Link"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      },
      "delete": {
        "tags": [
          "Enlaces"
        ],
        "summary": "Borrar un enlace",
        "operationId": "deleteLink",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Deleted"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/links/{id}/stats": {
      "get": {
        "tags": [
          "Enlaces"
        ],
        "summary": "Clics de un enlace",
        "operationId": "getLinkStats",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "days",
            "in": "query",
            "description": "Días hacia atrás. Se recorta al historial de tu plan.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 30
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/LinkStats"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/biolinks": {
      "get": {
        "tags": [
          "BioLinks"
        ],
        "summary": "Listar tus BioLinks",
        "operationId": "listBioLinks",
        "parameters": [
          {
            "name": "per_page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Una página de resultados",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BioLink"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PageMeta"
                    },
                    "links": {
                      "type": "object",
                      "properties": {
                        "next": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "prev": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/biolinks/{id}": {
      "get": {
        "tags": [
          "BioLinks"
        ],
        "summary": "Consultar un BioLink con sus bloques",
        "operationId": "getBioLink",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/BioLinkDetail"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/biolinks/{id}/leads": {
      "get": {
        "tags": [
          "BioLinks"
        ],
        "summary": "Contactos de los formularios",
        "operationId": "listBioLinkLeads",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "since",
            "in": "query",
            "description": "Solo los recibidos desde esta fecha (ISO 8601).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Una página de resultados",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Lead"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PageMeta"
                    },
                    "links": {
                      "type": "object",
                      "properties": {
                        "next": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "prev": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/biolinks/{id}/stats": {
      "get": {
        "tags": [
          "BioLinks"
        ],
        "summary": "Visitas y clics de un BioLink",
        "operationId": "getBioLinkStats",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "days",
            "in": "query",
            "description": "Días hacia atrás. Se recorta al historial de tu plan.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 30
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/BioLinkStats"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/loyalty-programs": {
      "get": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Listar tus tarjetas de lealtad",
        "operationId": "listLoyaltyPrograms",
        "parameters": [
          {
            "name": "per_page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Una página de resultados",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/LoyaltyProgram"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PageMeta"
                    },
                    "links": {
                      "type": "object",
                      "properties": {
                        "next": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "prev": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      },
      "post": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Crear una tarjeta de lealtad",
        "operationId": "createLoyaltyProgram",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LoyaltyProgramInput"
              },
              "example": {
                "slug": "cafe-rosa",
                "title": "Café Rosa",
                "reward": "Un café gratis",
                "stamps_required": 10
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Creada",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/LoyaltyProgram"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/loyalty-programs/{id}": {
      "get": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Consultar una tarjeta de lealtad",
        "operationId": "getLoyaltyProgram",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/LoyaltyProgram"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Editar una tarjeta de lealtad",
        "operationId": "updateLoyaltyProgram",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LoyaltyProgramInput"
              },
              "example": {
                "reward": "Un combo grande"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/LoyaltyProgram"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      },
      "delete": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Borrar una tarjeta de lealtad con sus clientes y cupones",
        "operationId": "deleteLoyaltyProgram",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Deleted"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/loyalty-programs/{id}/stats": {
      "get": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Inscripciones, sellos y premios",
        "operationId": "getLoyaltyProgramStats",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "days",
            "in": "query",
            "description": "Días hacia atrás. Se recorta al historial de tu plan.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 30
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/LoyaltyStats"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/loyalty-programs/{id}/cards": {
      "get": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Tarjetas de tus clientes",
        "operationId": "listLoyaltyCards",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "since",
            "in": "query",
            "description": "Solo las creadas desde esta fecha (ISO 8601).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Una página de resultados",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/LoyaltyCard"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PageMeta"
                    },
                    "links": {
                      "type": "object",
                      "properties": {
                        "next": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "prev": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/loyalty-programs/{id}/cards/{code}/stamp": {
      "post": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Sumar un sello (desde tu punto de venta)",
        "operationId": "stampLoyaltyCard",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/CardAction"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/loyalty-programs/{id}/cards/{code}/redeem": {
      "post": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Entregar un premio ganado",
        "operationId": "redeemLoyaltyReward",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/CardAction"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/loyalty-programs/{id}/coupons": {
      "get": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Cupones del negocio",
        "operationId": "listCoupons",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Coupon"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "post": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Crear un cupón",
        "operationId": "createCoupon",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CouponInput"
              },
              "example": {
                "title": "2x1 en boletas 2D",
                "details": "De lunes a jueves",
                "expires_on": "2026-11-30",
                "max_claims": 200
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Creado",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Coupon"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/loyalty-programs/{id}/coupons/{couponId}": {
      "patch": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Editar o pausar un cupón",
        "operationId": "updateCoupon",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "couponId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CouponInput"
              },
              "example": {
                "is_active": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Coupon"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      },
      "delete": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Borrar un cupón",
        "operationId": "deleteCoupon",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "couponId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Deleted"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/loyalty-programs/{id}/coupons/{couponId}/claims": {
      "post": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Darle el cupón a un cliente con tarjeta",
        "operationId": "giveCoupon",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "couponId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "description": "Devuelve el enlace de su cupón para mandárselo. Si ya lo tenía, devuelve el mismo (200) sin gastar cupo.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "card_code"
                ],
                "properties": {
                  "card_code": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Entregado",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/CouponClaim"
                    }
                  }
                }
              }
            }
          },
          "200": {
            "description": "Ya lo tenía",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/CouponClaim"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/loyalty-programs/{id}/coupon-claims/{code}/redeem": {
      "post": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Canjear el cupón de un cliente",
        "operationId": "redeemCoupon",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "description": "Una sola vez. 422 coupon_not_redeemable si ya se usó o venció.",
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/CouponClaim"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/loyalty-programs/{id}/gift-cards": {
      "get": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Tarjetas de regalo vendidas",
        "operationId": "listGiftCards",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Una página de resultados",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/GiftCard"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PageMeta"
                    },
                    "links": {
                      "type": "object",
                      "properties": {
                        "next": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "prev": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      },
      "post": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Emitir una tarjeta de regalo",
        "operationId": "issueGiftCard",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "description": "El negocio ya cobró con su forma de pago: Qubo la emite y lleva el saldo.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GiftCardInput"
              },
              "example": {
                "amount": 50000,
                "recipient_name": "Ana",
                "message": "¡Feliz cumpleaños!"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Emitida",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/GiftCard"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/loyalty-programs/{id}/gift-cards/{code}": {
      "get": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Saldo y movimientos de una tarjeta de regalo",
        "operationId": "getGiftCard",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/GiftCard"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/loyalty-programs/{id}/gift-cards/{code}/charge": {
      "post": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Cobrar una compra contra el saldo",
        "operationId": "chargeGiftCard",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "description": "Nunca deja el saldo en negativo: si no alcanza responde 422 gift_not_chargeable y no descuenta nada.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "amount"
                ],
                "properties": {
                  "amount": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "note": {
                    "type": "string",
                    "maxLength": 120
                  }
                }
              },
              "example": {
                "amount": 18000,
                "note": "Factura 1234"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/GiftCard"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/loyalty-programs/{id}/gift-cards/{code}/void": {
      "post": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Anular una tarjeta de regalo",
        "operationId": "voidGiftCard",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "description": "Su saldo queda en cero. Para cuando el negocio devolvió el dinero.",
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/GiftCard"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/loyalty-programs/{id}/events": {
      "get": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Eventos del negocio",
        "operationId": "listEvents",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Event"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "post": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Crear un evento",
        "operationId": "createEvent",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EventInput"
              },
              "example": {
                "title": "Preestreno: Avengers",
                "starts_at": "2026-11-20T19:30",
                "venue": "Sala 3",
                "mode": "counter",
                "tiers": [
                  {
                    "name": "General",
                    "price": 18000
                  },
                  {
                    "name": "VIP",
                    "price": 30000,
                    "capacity": 20
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Creado",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Event"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/loyalty-programs/{id}/events/{eventId}": {
      "get": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Consultar un evento",
        "operationId": "getEvent",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "eventId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Event"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Editar o pausar un evento",
        "operationId": "updateEvent",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "eventId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EventInput"
              },
              "example": {
                "venue": "Sala 5"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Event"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      },
      "delete": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Borrar un evento con sus entradas",
        "operationId": "deleteEvent",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "eventId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Deleted"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/loyalty-programs/{id}/events/{eventId}/tickets": {
      "get": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Entradas de un evento",
        "operationId": "listTickets",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "eventId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Una página de resultados",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Ticket"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PageMeta"
                    },
                    "links": {
                      "type": "object",
                      "properties": {
                        "next": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "prev": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      },
      "post": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Emitir entradas (venta en el mostrador)",
        "operationId": "issueTickets",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "eventId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "description": "El negocio ya cobró: Qubo emite las entradas. order_url abre todas las de la venta. 422 sold_out si no hay cupo.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "tier_id": {
                    "type": "integer",
                    "description": "Sin tier_id, la primera localidad."
                  },
                  "quantity": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 20,
                    "default": 1
                  },
                  "holder_name": {
                    "type": "string",
                    "maxLength": 120
                  }
                }
              },
              "example": {
                "tier_id": 12,
                "quantity": 2,
                "holder_name": "Familia Ríos"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Emitidas",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "order_url": {
                          "type": "string"
                        },
                        "tickets": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Ticket"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/loyalty-programs/{id}/tickets/{code}/check-in": {
      "post": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Registrar la entrada en la puerta",
        "operationId": "checkInTicket",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "description": "Una sola vez. 422 ticket_not_valid si ya entró (dice cuándo), fue anulada o el evento pasó.",
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Ticket"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/loyalty-programs/{id}/tickets/{code}/void": {
      "post": {
        "tags": [
          "Tarjetas de lealtad"
        ],
        "summary": "Anular una entrada y devolver su cupo",
        "operationId": "voidTicket",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Ticket"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/catalogs": {
      "get": {
        "tags": [
          "Catálogos"
        ],
        "summary": "Listar tus catálogos y menús",
        "operationId": "listCatalogs",
        "parameters": [
          {
            "name": "per_page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Una página de resultados",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Catalog"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PageMeta"
                    },
                    "links": {
                      "type": "object",
                      "properties": {
                        "next": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "prev": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      },
      "post": {
        "tags": [
          "Catálogos"
        ],
        "summary": "Crear un catálogo o menú",
        "operationId": "createCatalog",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CatalogInput"
              },
              "example": {
                "slug": "menu-rosa",
                "kind": "menu",
                "title": "Menú Café Rosa",
                "whatsapp": "57 300 123 4567"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Creado",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Catalog"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/catalogs/{id}": {
      "get": {
        "tags": [
          "Catálogos"
        ],
        "summary": "Consultar un catálogo con sus productos",
        "operationId": "getCatalog",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/CatalogDetail"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "tags": [
          "Catálogos"
        ],
        "summary": "Editar un catálogo",
        "operationId": "updateCatalog",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CatalogInput"
              },
              "example": {
                "is_published": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Catalog"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      },
      "delete": {
        "tags": [
          "Catálogos"
        ],
        "summary": "Borrar un catálogo",
        "operationId": "deleteCatalog",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Deleted"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/catalogs/{id}/stats": {
      "get": {
        "tags": [
          "Catálogos"
        ],
        "summary": "Visitas y pedidos por WhatsApp",
        "operationId": "getCatalogStats",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "days",
            "in": "query",
            "description": "Días hacia atrás. Se recorta al historial de tu plan.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 30
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/CatalogStats"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/catalogs/{id}/products": {
      "post": {
        "tags": [
          "Catálogos"
        ],
        "summary": "Agregar un producto",
        "operationId": "createProduct",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProductInput"
              },
              "example": {
                "name": "Capuchino",
                "category": "Bebidas",
                "price": 8500
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Creado",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Product"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    },
    "/catalogs/{id}/products/{productId}": {
      "patch": {
        "tags": [
          "Catálogos"
        ],
        "summary": "Editar un producto (precio, foto, pausa)",
        "operationId": "updateProduct",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "productId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProductInput"
              },
              "example": {
                "price": 9000
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Product"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      },
      "delete": {
        "tags": [
          "Catálogos"
        ],
        "summary": "Borrar un producto",
        "operationId": "deleteProduct",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "productId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Deleted"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/customers": {
      "get": {
        "tags": [
          "Clientes"
        ],
        "summary": "Listar tus clientes",
        "operationId": "listCustomers",
        "description": "Las personas de tus tarjetas de lealtad, formularios de BioLink e importados, unidas por WhatsApp o correo. Lo más reciente primero.",
        "parameters": [
          {
            "name": "segment",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "new",
                "returning",
                "lapsed"
              ]
            },
            "description": "new: llegaron en los últimos 30 días · returning: 2 visitas o más · lapsed: sin actividad en 30 días."
          },
          {
            "name": "q",
            "in": "query",
            "description": "Busca en nombre, correo o WhatsApp.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Una página de resultados",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Customer"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PageMeta"
                    },
                    "links": {
                      "type": "object",
                      "properties": {
                        "next": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "prev": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      },
      "post": {
        "tags": [
          "Clientes"
        ],
        "summary": "Traer clientes de otro sistema",
        "operationId": "importCustomers",
        "description": "Hasta 500 por llamada. Se puede repetir sin duplicar: la misma fuente con el mismo correo o WhatsApp solo completa lo que faltaba.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "customers"
                ],
                "properties": {
                  "customers": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 500,
                    "items": {
                      "$ref": "#/components/schemas/CustomerInput"
                    }
                  }
                }
              },
              "example": {
                "customers": [
                  {
                    "name": "Ana Gómez",
                    "email": "ana@ejemplo.co",
                    "whatsapp": "300 123 4567",
                    "source": "Concurso de octubre",
                    "consented_at": "2026-10-04T14:03:36-05:00"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Se guardaron clientes nuevos",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/ImportResult"
                    }
                  }
                }
              }
            }
          },
          "200": {
            "description": "Ninguno era nuevo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/ImportResult"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      },
      "delete": {
        "tags": [
          "Clientes"
        ],
        "summary": "Borrar todos los datos de una persona",
        "operationId": "deleteCustomer",
        "description": "Para cuando alguien pide la supresión de sus datos (Ley 1581): borra sus tarjetas, sellos, respuestas de formularios e importados. Identifícala con key, email o whatsapp.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "key": {
                    "type": "string"
                  },
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "whatsapp": {
                    "type": "string"
                  }
                }
              },
              "example": {
                "email": "ana@ejemplo.co"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Listo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/CustomerDeleted"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Validation"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-KEY",
        "description": "Tu clave, en el panel → API Token."
      },
      "Bearer": {
        "type": "http",
        "scheme": "bearer"
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "success",
          "error"
        ],
        "properties": {
          "success": {
            "const": false
          },
          "message": {
            "type": "string"
          },
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "missing_key",
                  "invalid_key",
                  "key_in_url",
                  "plan_required",
                  "limit_reached",
                  "not_found",
                  "validation",
                  "rate_limited",
                  "forbidden",
                  "unauthorized",
                  "server_error"
                ]
              },
              "message": {
                "type": "string"
              }
            }
          },
          "errors": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        }
      },
      "PageMeta": {
        "type": "object",
        "properties": {
          "current_page": {
            "type": "integer"
          },
          "last_page": {
            "type": "integer"
          },
          "per_page": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          }
        }
      },
      "Design": {
        "type": "object",
        "description": "Las opciones del Studio. Lo que no envíes toma el diseño por defecto (o se queda igual al editar).",
        "properties": {
          "color": {
            "type": "string",
            "pattern": "^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"
          },
          "color2": {
            "type": "string",
            "pattern": "^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"
          },
          "background": {
            "type": "string",
            "pattern": "^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"
          },
          "gradient": {
            "type": "boolean"
          },
          "dots_style": {
            "type": "string",
            "enum": [
              "square",
              "dots",
              "rounded",
              "extra-rounded",
              "classy",
              "classy-rounded"
            ]
          },
          "corners_style": {
            "type": "string",
            "enum": [
              "leaf",
              "square",
              "dot",
              "extra-rounded",
              "classy",
              "classy-rounded",
              "rounded",
              "dots"
            ]
          },
          "corner_dot_style": {
            "type": "string",
            "enum": [
              "leaf",
              "square",
              "dot",
              "rounded",
              "dots",
              "classy",
              "classy-rounded",
              "extra-rounded"
            ]
          },
          "logo_url": {
            "type": "string",
            "format": "uri",
            "description": "https pública; PNG, JPG, WebP o SVG de máximo 500 KB."
          },
          "logo_size": {
            "type": "number",
            "minimum": 0.1,
            "maximum": 0.4
          },
          "logo_clear": {
            "type": "boolean",
            "description": "Quita los puntos detrás del logo."
          }
        }
      },
      "QrContent": {
        "type": "object",
        "properties": {
          "content_type": {
            "type": "string",
            "enum": [
              "url",
              "wifi",
              "vcard",
              "whatsapp",
              "email",
              "sms",
              "text",
              "crypto"
            ],
            "default": "url"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Atajo de un QR de URL: en vez de payload."
          },
          "payload": {
            "type": "object",
            "description": "url: {url} · wifi: {ssid, password, encryption} · vcard: {vcardName, vcardPhone, vcardEmail, vcardOrg} · whatsapp y sms: {smsPhone, smsMessage} · email: {emailTo, emailSubject} · text: {text} · crypto: {cryptoCoin, cryptoAddress}"
          },
          "design": {
            "$ref": "#/components/schemas/Design"
          }
        }
      },
      "QrCreate": {
        "allOf": [
          {
            "$ref": "#/components/schemas/QrContent"
          },
          {
            "type": "object",
            "required": [
              "title"
            ],
            "properties": {
              "title": {
                "type": "string",
                "maxLength": 255
              },
              "type": {
                "type": "string",
                "enum": [
                  "static",
                  "dynamic"
                ],
                "default": "static",
                "description": "dynamic solo para URL."
              }
            }
          }
        ]
      },
      "QrRender": {
        "allOf": [
          {
            "$ref": "#/components/schemas/QrContent"
          },
          {
            "type": "object",
            "properties": {
              "format": {
                "type": "string",
                "enum": [
                  "png",
                  "svg"
                ],
                "default": "png"
              },
              "size": {
                "type": "integer",
                "minimum": 128,
                "maximum": 4096,
                "default": 1024
              }
            }
          }
        ]
      },
      "QrUpdate": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "is_active": {
            "type": "boolean"
          },
          "tags": {
            "type": "array",
            "maxItems": 20,
            "items": {
              "type": "string",
              "maxLength": 60
            }
          },
          "design": {
            "$ref": "#/components/schemas/Design"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Solo QR dinámicos: nuevo destino."
          },
          "payload": {
            "type": "object",
            "description": "Solo QR estáticos: nuevo contenido, del mismo tipo."
          }
        }
      },
      "Qr": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "title": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "static",
              "dynamic"
            ]
          },
          "content_type": {
            "type": "string"
          },
          "content": {
            "type": "string",
            "description": "Lo que lleva el QR."
          },
          "short_code": {
            "type": [
              "string",
              "null"
            ]
          },
          "short_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "redirect_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "is_active": {
            "type": "boolean"
          },
          "tags": {
            "type": "array",
            "maxItems": 20,
            "items": {
              "type": "string",
              "maxLength": 60
            }
          },
          "scans_count": {
            "type": "integer"
          },
          "images": {
            "type": "object",
            "properties": {
              "svg": {
                "type": "string"
              },
              "png": {
                "type": "string"
              }
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "LegacyQr": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "title": {
            "type": "string"
          },
          "short_code": {
            "type": "string"
          },
          "short_url": {
            "type": "string"
          },
          "redirect_url": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Link": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "type": {
            "type": "string",
            "enum": [
              "url",
              "whatsapp"
            ]
          },
          "title": {
            "type": "string"
          },
          "alias": {
            "type": "string"
          },
          "short_url": {
            "type": "string"
          },
          "destination_url": {
            "type": "string"
          },
          "whatsapp": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "phone": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            }
          },
          "is_active": {
            "type": "boolean"
          },
          "tags": {
            "type": "array",
            "maxItems": 20,
            "items": {
              "type": "string",
              "maxLength": 60
            }
          },
          "clicks_count": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "LinkCreate": {
        "type": "object",
        "required": [
          "destination_url"
        ],
        "properties": {
          "destination_url": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "string"
          },
          "alias": {
            "type": "string",
            "pattern": "^[a-zA-Z0-9_.-]+$",
            "maxLength": 60,
            "description": "Opcional; si no, se genera."
          },
          "tags": {
            "type": "array",
            "maxItems": 20,
            "items": {
              "type": "string",
              "maxLength": 60
            }
          }
        }
      },
      "WhatsappCreate": {
        "type": "object",
        "required": [
          "phone"
        ],
        "properties": {
          "phone": {
            "type": "string",
            "example": "+57 300 123 4567",
            "description": "Con indicativo del país."
          },
          "message": {
            "type": "string",
            "maxLength": 2000
          },
          "title": {
            "type": "string"
          },
          "alias": {
            "type": "string",
            "pattern": "^[a-zA-Z0-9_.-]+$",
            "maxLength": 60
          },
          "tags": {
            "type": "array",
            "maxItems": 20,
            "items": {
              "type": "string",
              "maxLength": 60
            }
          }
        }
      },
      "LinkUpdate": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "is_active": {
            "type": "boolean"
          },
          "tags": {
            "type": "array",
            "maxItems": 20,
            "items": {
              "type": "string",
              "maxLength": 60
            }
          },
          "destination_url": {
            "type": "string",
            "format": "uri",
            "description": "Solo enlaces cortos."
          },
          "phone": {
            "type": "string",
            "description": "Solo links de WhatsApp."
          },
          "message": {
            "type": [
              "string",
              "null"
            ],
            "description": "Solo links de WhatsApp."
          }
        }
      },
      "BioLink": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "title": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "is_published": {
            "type": "boolean"
          },
          "views_count": {
            "type": "integer"
          },
          "blocks_count": {
            "type": "integer"
          },
          "leads_count": {
            "type": "integer"
          },
          "tags": {
            "type": "array",
            "maxItems": 20,
            "items": {
              "type": "string",
              "maxLength": 60
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "BioLinkDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/BioLink"
          },
          {
            "type": "object",
            "properties": {
              "blocks": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "integer"
                    },
                    "type": {
                      "type": "string"
                    },
                    "label": {
                      "type": "string"
                    },
                    "subtitle": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "url": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Solo si el bloque lleva a una página pública."
                    },
                    "is_active": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          }
        ]
      },
      "Lead": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "form": {
            "type": [
              "string",
              "null"
            ],
            "description": "Nombre del formulario."
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "phone": {
            "type": [
              "string",
              "null"
            ]
          },
          "email": {
            "type": [
              "string",
              "null"
            ]
          },
          "answers": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Campos a medida: clave → respuesta."
          },
          "consented_at": {
            "type": "string",
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "QrStats": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "days": {
            "type": "integer"
          },
          "from": {
            "type": "string",
            "format": "date"
          },
          "to": {
            "type": "string",
            "format": "date"
          },
          "unique_visitors": {
            "type": "integer"
          },
          "timeline": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "scans": {
                  "type": "integer"
                }
              }
            }
          },
          "breakdowns": {
            "type": "object",
            "description": "Por dimensión (device_type, browser y, con analítica avanzada, platform, country, referer).",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "object",
                "properties": {
                  "label": {
                    "type": "string"
                  },
                  "total": {
                    "type": "integer"
                  }
                }
              }
            }
          },
          "total_scans": {
            "type": "integer"
          }
        }
      },
      "LinkStats": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "days": {
            "type": "integer"
          },
          "from": {
            "type": "string",
            "format": "date"
          },
          "to": {
            "type": "string",
            "format": "date"
          },
          "unique_visitors": {
            "type": "integer"
          },
          "timeline": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "clicks": {
                  "type": "integer"
                }
              }
            }
          },
          "breakdowns": {
            "type": "object",
            "description": "Por dimensión (device_type, browser y, con analítica avanzada, platform, country, referer).",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "object",
                "properties": {
                  "label": {
                    "type": "string"
                  },
                  "total": {
                    "type": "integer"
                  }
                }
              }
            }
          },
          "total_clicks": {
            "type": "integer"
          }
        }
      },
      "BioLinkStats": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "days": {
            "type": "integer"
          },
          "from": {
            "type": "string",
            "format": "date"
          },
          "to": {
            "type": "string",
            "format": "date"
          },
          "unique_visitors": {
            "type": "integer"
          },
          "timeline": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "events": {
                  "type": "integer"
                }
              }
            }
          },
          "breakdowns": {
            "type": "object",
            "description": "Por dimensión (device_type, browser y, con analítica avanzada, platform, country, referer).",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "object",
                "properties": {
                  "label": {
                    "type": "string"
                  },
                  "total": {
                    "type": "integer"
                  }
                }
              }
            }
          },
          "views": {
            "type": "integer"
          },
          "clicks": {
            "type": "integer"
          },
          "click_through_rate": {
            "type": [
              "number",
              "null"
            ]
          }
        }
      },
      "Deleted": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "deleted": {
            "const": true
          }
        }
      },
      "Customer": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "description": "Identificador de la persona en tu cuenta (sirve para borrarla)."
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "email": {
            "type": [
              "string",
              "null"
            ]
          },
          "whatsapp": {
            "type": [
              "string",
              "null"
            ]
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "enum": [
                    "card",
                    "lead",
                    "contact"
                  ],
                  "description": "card = tarjeta de lealtad, lead = formulario de BioLink, contact = traído por API."
                },
                "label": {
                  "type": "string"
                }
              }
            }
          },
          "visits": {
            "type": "integer",
            "description": "Sellos recibidos en sus tarjetas."
          },
          "redeemed": {
            "type": "integer",
            "description": "Premios entregados."
          },
          "first_seen": {
            "type": "string",
            "format": "date-time"
          },
          "last_seen": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CustomerInput": {
        "type": "object",
        "required": [
          "consented_at"
        ],
        "description": "Correo o WhatsApp, al menos uno.",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 120
          },
          "email": {
            "type": "string",
            "format": "email",
            "maxLength": 190
          },
          "whatsapp": {
            "type": "string",
            "maxLength": 25,
            "description": "Con o sin +57; solo cuentan los dígitos."
          },
          "source": {
            "type": "string",
            "maxLength": 120,
            "default": "API",
            "description": "De dónde viene: se ve en Clientes. La misma fuente con el mismo correo o WhatsApp no se repite."
          },
          "consented_at": {
            "type": "string",
            "format": "date-time",
            "description": "Cuándo autorizó el tratamiento de sus datos (Ley 1581). Sin esto no se guarda."
          }
        }
      },
      "ImportResult": {
        "type": "object",
        "properties": {
          "created": {
            "type": "integer"
          },
          "updated": {
            "type": "integer",
            "description": "Ya estaban y se completó un dato que faltaba."
          },
          "unchanged": {
            "type": "integer"
          }
        }
      },
      "LoyaltyProgram": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string",
            "description": "Nombre del negocio en la tarjeta."
          },
          "reward": {
            "type": "string"
          },
          "stamps_required": {
            "type": "integer"
          },
          "logo_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "theme_accent": {
            "type": [
              "string",
              "null"
            ]
          },
          "link_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "is_published": {
            "type": "boolean",
            "description": "Inscripción abierta."
          },
          "cards_count": {
            "type": "integer"
          },
          "locations": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "latitude": {
                  "type": "number"
                },
                "longitude": {
                  "type": "number"
                },
                "label": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              }
            }
          },
          "signup_url": {
            "type": "string",
            "description": "Página de inscripción: ponla en un QR."
          },
          "caja_url": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "LoyaltyProgramInput": {
        "type": "object",
        "required": [
          "slug",
          "title",
          "reward",
          "stamps_required"
        ],
        "description": "Al editar, solo envía lo que cambia.",
        "properties": {
          "slug": {
            "type": "string",
            "pattern": "^[a-zA-Z0-9_.-]+$",
            "maxLength": 60
          },
          "title": {
            "type": "string",
            "maxLength": 80
          },
          "reward": {
            "type": "string",
            "maxLength": 120
          },
          "stamps_required": {
            "type": "integer",
            "minimum": 2,
            "maximum": 30
          },
          "logo_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "https o /storage/..."
          },
          "theme_accent": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^#[0-9a-fA-F]{6}$"
          },
          "link_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "https://"
          },
          "is_published": {
            "type": "boolean"
          },
          "locations": {
            "type": "array",
            "maxItems": 10,
            "items": {
              "type": "object",
              "required": [
                "latitude",
                "longitude"
              ],
              "properties": {
                "latitude": {
                  "type": "number"
                },
                "longitude": {
                  "type": "number"
                },
                "label": {
                  "type": "string",
                  "maxLength": 60
                }
              }
            }
          }
        }
      },
      "LoyaltyCard": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Va en el QR del cliente; úsalo para sellar."
          },
          "short_code": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "whatsapp": {
            "type": "string"
          },
          "stamps": {
            "type": "integer"
          },
          "stamps_required": {
            "type": "integer"
          },
          "rewards_available": {
            "type": "integer"
          },
          "rewards_redeemed": {
            "type": "integer"
          },
          "in_google_wallet": {
            "type": "boolean"
          },
          "url": {
            "type": "string"
          },
          "last_stamp_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "consented_at": {
            "type": "string",
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CardAction": {
        "type": "object",
        "properties": {
          "result": {
            "type": "string",
            "enum": [
              "stamped",
              "reward",
              "redeemed"
            ],
            "description": "reward: con este sello completó la tarjeta y ganó un premio."
          },
          "card": {
            "$ref": "#/components/schemas/LoyaltyCard"
          }
        }
      },
      "Coupon": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "code": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "details": {
            "type": [
              "string",
              "null"
            ]
          },
          "expires_on": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "Vence al final de ese día, hora de Colombia."
          },
          "max_claims": {
            "type": [
              "integer",
              "null"
            ]
          },
          "claims_count": {
            "type": "integer"
          },
          "redemptions_count": {
            "type": "integer"
          },
          "is_active": {
            "type": "boolean"
          },
          "expired": {
            "type": "boolean"
          },
          "url": {
            "type": "string",
            "description": "Página para reclamarlo: compártela o ponla en un QR."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CouponInput": {
        "type": "object",
        "required": [
          "title"
        ],
        "description": "Al editar, solo envía lo que cambia.",
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 60
          },
          "details": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 300
          },
          "expires_on": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "max_claims": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 1
          },
          "is_active": {
            "type": "boolean"
          }
        }
      },
      "CouponClaim": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Va en el QR del cupón del cliente."
          },
          "coupon_id": {
            "type": "integer"
          },
          "card_code": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "redeemed",
              "expired"
            ]
          },
          "url": {
            "type": "string",
            "description": "El cupón del cliente: mándaselo por WhatsApp o correo."
          },
          "redeemed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Catalog": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "slug": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "tienda",
              "menu"
            ]
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "whatsapp": {
            "type": "string",
            "description": "Solo dígitos, con indicativo: ahí llegan los pedidos."
          },
          "logo_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "theme_accent": {
            "type": [
              "string",
              "null"
            ]
          },
          "is_published": {
            "type": "boolean"
          },
          "views_count": {
            "type": "integer"
          },
          "orders_count": {
            "type": "integer"
          },
          "products_count": {
            "type": "integer"
          },
          "url": {
            "type": "string"
          },
          "tags": {
            "type": "array",
            "maxItems": 20,
            "items": {
              "type": "string",
              "maxLength": 60
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CatalogDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Catalog"
          },
          {
            "type": "object",
            "properties": {
              "products": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Product"
                }
              }
            }
          }
        ]
      },
      "CatalogInput": {
        "type": "object",
        "required": [
          "slug",
          "kind",
          "title",
          "whatsapp"
        ],
        "description": "Al editar, solo envía lo que cambia.",
        "properties": {
          "slug": {
            "type": "string",
            "pattern": "^[a-zA-Z0-9_.-]+$",
            "maxLength": 60
          },
          "kind": {
            "type": "string",
            "enum": [
              "tienda",
              "menu"
            ]
          },
          "title": {
            "type": "string",
            "maxLength": 120
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 500
          },
          "whatsapp": {
            "type": "string",
            "description": "Con indicativo del país, por ejemplo 57 300 123 4567."
          },
          "logo_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "theme_accent": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^#[0-9a-fA-F]{6}$"
          },
          "is_published": {
            "type": "boolean"
          }
        }
      },
      "Product": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "category": {
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "price": {
            "type": [
              "number",
              "null"
            ],
            "description": "Sin precio se muestra \"Consultar\"."
          },
          "image_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "is_active": {
            "type": "boolean"
          },
          "sort_order": {
            "type": "integer"
          }
        }
      },
      "ProductInput": {
        "type": "object",
        "required": [
          "name"
        ],
        "description": "Al editar, solo envía lo que cambia.",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 120
          },
          "category": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 60
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 500
          },
          "price": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0
          },
          "image_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "https o /storage/..."
          },
          "is_active": {
            "type": "boolean"
          }
        }
      },
      "GiftCard": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Va en su QR."
          },
          "short_code": {
            "type": "string"
          },
          "amount": {
            "type": "integer",
            "description": "Valor inicial en pesos."
          },
          "balance": {
            "type": "integer",
            "description": "Saldo en pesos."
          },
          "currency": {
            "const": "COP"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "spent",
              "expired",
              "void"
            ]
          },
          "recipient_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "message": {
            "type": [
              "string",
              "null"
            ]
          },
          "expires_on": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "url": {
            "type": "string",
            "description": "La tarjeta de quien la recibe: mándale este enlace."
          },
          "in_google_wallet": {
            "type": "boolean"
          },
          "issued_by": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "movements": {
            "type": "array",
            "description": "Solo al consultar una.",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "enum": [
                    "issue",
                    "charge",
                    "void"
                  ]
                },
                "amount": {
                  "type": "integer"
                },
                "balance_after": {
                  "type": "integer"
                },
                "staff": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "note": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "created_at": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            }
          }
        }
      },
      "GiftCardInput": {
        "type": "object",
        "required": [
          "amount"
        ],
        "properties": {
          "amount": {
            "type": "integer",
            "minimum": 1000,
            "maximum": 50000000,
            "description": "En pesos. Cóbralo antes por tu cuenta: Qubo no cobra."
          },
          "recipient_name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 120
          },
          "message": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200
          },
          "expires_on": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "Sin fecha, vence un año después de emitida."
          }
        }
      },
      "EventTier": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "price": {
            "type": [
              "integer",
              "null"
            ],
            "description": "En pesos, solo para mostrar."
          },
          "capacity": {
            "type": [
              "integer",
              "null"
            ]
          },
          "tickets_count": {
            "type": "integer"
          },
          "left": {
            "type": [
              "integer",
              "null"
            ]
          }
        }
      },
      "Event": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "code": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "venue": {
            "type": [
              "string",
              "null"
            ]
          },
          "image_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "starts_at": {
            "type": "string",
            "format": "date-time",
            "description": "Con la hora de Colombia (-05:00)."
          },
          "ends_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "mode": {
            "type": "string",
            "enum": [
              "signup",
              "counter"
            ],
            "description": "signup: gratis con inscripción · counter: se venden en el mostrador."
          },
          "capacity": {
            "type": [
              "integer",
              "null"
            ]
          },
          "tickets_count": {
            "type": "integer"
          },
          "left": {
            "type": [
              "integer",
              "null"
            ]
          },
          "is_published": {
            "type": "boolean"
          },
          "is_over": {
            "type": "boolean"
          },
          "url": {
            "type": "string",
            "description": "Página del evento: compártela o ponla en un QR."
          },
          "tiers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EventTier"
            }
          }
        }
      },
      "EventInput": {
        "type": "object",
        "required": [
          "title",
          "starts_at",
          "mode"
        ],
        "description": "Al editar, solo envía lo que cambia.",
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 120
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 1000
          },
          "venue": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 160
          },
          "image_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "https o /storage/..."
          },
          "starts_at": {
            "type": "string",
            "description": "Hora de Colombia, por ejemplo 2026-11-20T19:30"
          },
          "ends_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "mode": {
            "type": "string",
            "enum": [
              "signup",
              "counter"
            ]
          },
          "capacity": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 1
          },
          "is_published": {
            "type": "boolean"
          },
          "tiers": {
            "type": "array",
            "maxItems": 10,
            "description": "Sin tiers queda una localidad General. Al editar reemplaza la lista; con id edita una existente (las que tienen entradas no se borran).",
            "items": {
              "type": "object",
              "required": [
                "name"
              ],
              "properties": {
                "id": {
                  "type": "integer"
                },
                "name": {
                  "type": "string",
                  "maxLength": 60
                },
                "price": {
                  "type": [
                    "integer",
                    "null"
                  ]
                },
                "capacity": {
                  "type": [
                    "integer",
                    "null"
                  ]
                }
              }
            }
          }
        }
      },
      "Ticket": {
        "type": "object",
        "properties": {
          "event_id": {
            "type": "integer"
          },
          "code": {
            "type": "string",
            "description": "Va en el QR de la entrada."
          },
          "short": {
            "type": "string"
          },
          "order_code": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "tier": {
            "type": "string"
          },
          "holder_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "valid",
              "checked_in",
              "void",
              "past"
            ]
          },
          "checked_in_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "checked_in_by": {
            "type": [
              "string",
              "null"
            ]
          },
          "in_google": {
            "type": "boolean"
          },
          "card_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "Tarjeta de quien se inscribió."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "LoyaltyStats": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "days": {
            "type": "integer"
          },
          "from": {
            "type": "string",
            "format": "date"
          },
          "to": {
            "type": "string",
            "format": "date"
          },
          "unique_visitors": {
            "type": "integer"
          },
          "timeline": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "events": {
                  "type": "integer"
                }
              }
            }
          },
          "breakdowns": {
            "type": "object",
            "description": "Por dimensión (device_type, browser y, con analítica avanzada, platform, country, referer).",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "object",
                "properties": {
                  "label": {
                    "type": "string"
                  },
                  "total": {
                    "type": "integer"
                  }
                }
              }
            }
          },
          "cards": {
            "type": "integer"
          },
          "saved_in_google_wallet": {
            "type": "integer"
          },
          "stamps": {
            "type": "integer"
          },
          "rewards_redeemed": {
            "type": "integer"
          }
        }
      },
      "CatalogStats": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "days": {
            "type": "integer"
          },
          "from": {
            "type": "string",
            "format": "date"
          },
          "to": {
            "type": "string",
            "format": "date"
          },
          "unique_visitors": {
            "type": "integer"
          },
          "timeline": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "events": {
                  "type": "integer"
                }
              }
            }
          },
          "breakdowns": {
            "type": "object",
            "description": "Por dimensión (device_type, browser y, con analítica avanzada, platform, country, referer).",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "object",
                "properties": {
                  "label": {
                    "type": "string"
                  },
                  "total": {
                    "type": "integer"
                  }
                }
              }
            }
          },
          "views": {
            "type": "integer"
          },
          "orders": {
            "type": "integer",
            "description": "Pedidos enviados por WhatsApp."
          },
          "orders_total": {
            "type": "number"
          }
        }
      },
      "CustomerDeleted": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string"
          },
          "deleted": {
            "const": true
          }
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Falta la clave, no es válida o llegó en la URL (missing_key, invalid_key, key_in_url).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Forbidden": {
        "description": "El plan no incluye la API o se acabó el cupo (plan_required, limit_reached).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "No existe en tu cuenta (not_found).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Validation": {
        "description": "Datos inválidos (validation); errors dice cuáles.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Demasiadas solicitudes por minuto (rate_limited).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        },
        "headers": {
          "Retry-After": {
            "schema": {
              "type": "integer"
            }
          }
        }
      }
    }
  }
}
