{
  "openapi": "3.1.0",
  "info": {
    "title": "Taller Venturas — API pública",
    "summary": "Envío de consultas comerciales y consulta del valor vigente de la UF.",
    "description": "Superficie pública de taller.venturas.cl. Expone únicamente dos operaciones: el envío del formulario de contacto y la lectura del indicador UF que permite convertir a pesos chilenos los precios publicados por el sitio.\n\nNo existe endpoint de contratación, pago, aprovisionamiento ni consulta de cuenta. La contratación se cierra por correo o mediante una propuesta aceptada expresamente por ambas partes.\n\nAdvertencia para agentes automáticos: la operación `submitContactEnquiry` entrega un correo a una persona real. Invóquela solamente con datos verídicos entregados por la persona usuaria y con su consentimiento explícito. No la utilice para pruebas, sondeos ni envíos repetidos.\n\nArchivo fuente: taller/static/openapi.json. Autor: @guterion.",
    "version": "1.0.0",
    "contact": {
      "name": "Taller Venturas",
      "url": "https://taller.venturas.cl/#contacto",
      "email": "taller@venturas.cl"
    },
    "license": {
      "name": "CC-BY-SA-4.0",
      "identifier": "CC-BY-SA-4.0"
    }
  },
  "externalDocs": {
    "description": "Resumen del sitio para modelos de lenguaje",
    "url": "https://taller.venturas.cl/llms.txt"
  },
  "servers": [
    {
      "url": "https://taller.venturas.cl",
      "description": "Producción"
    }
  ],
  "paths": {
    "/api/contact": {
      "post": {
        "operationId": "submitContactEnquiry",
        "summary": "Enviar una consulta comercial",
        "description": "Entrega una consulta al equipo de Taller Venturas por correo electrónico. El envío abre una conversación o cotización y no constituye contratación de ningún servicio.\n\nEl cuerpo se acepta como formulario codificado o multiparte; no se acepta JSON. La respuesta indica únicamente si la consulta fue aceptada para entrega, no si fue leída o respondida.",
        "tags": ["contacto"],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": { "$ref": "#/components/schemas/ContactEnquiry" }
            },
            "multipart/form-data": {
              "schema": { "$ref": "#/components/schemas/ContactEnquiry" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Consulta aceptada y entregada.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Success" },
                "example": { "ok": true }
              }
            }
          },
          "202": {
            "description": "Consulta aceptada pero descartada por los filtros antispam. Ocurre cuando el campo `company` llega con contenido.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Success" },
                "example": { "ok": true }
              }
            }
          },
          "400": {
            "description": "Faltan campos obligatorios (`missing_fields`) o alguno excede su largo máximo (`field_too_long`).",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Failure" },
                "example": { "ok": false, "error": "missing_fields" }
              }
            }
          },
          "405": {
            "description": "Método no permitido. Esta ruta sólo acepta POST y OPTIONS."
          },
          "500": {
            "description": "La consulta no pudo entregarse por correo (`send_failed`).",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Failure" },
                "example": { "ok": false, "error": "send_failed" }
              }
            }
          }
        }
      }
    },
    "/api/uf": {
      "get": {
        "operationId": "getUfReference",
        "summary": "Consultar el valor vigente de la UF",
        "description": "Devuelve el valor de la Unidad de Fomento en pesos chilenos observado más recientemente. Sirve para convertir a CLP los precios que el sitio publica en UF.\n\nLa conversión resultante es referencial y no contractual: la facturación se realiza según la UF vigente en la fecha de emisión de cada factura. La respuesta es cacheable durante una hora.",
        "tags": ["indicadores"],
        "responses": {
          "200": {
            "description": "Valor vigente de la UF.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/UfReference" },
                "example": {
                  "ok": true,
                  "indicator": "UF",
                  "currency": "CLP",
                  "value": 39482.15,
                  "observedAt": "2026-08-05T04:00:00.000Z",
                  "source": "mindicador.cl"
                }
              }
            }
          },
          "405": {
            "description": "Método no permitido. Esta ruta sólo acepta GET y OPTIONS."
          },
          "503": {
            "description": "El indicador no está disponible momentáneamente (`uf_unavailable`).",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Failure" },
                "example": { "ok": false, "error": "uf_unavailable" }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ContactEnquiry": {
        "type": "object",
        "required": ["name", "email", "message"],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120,
            "description": "Nombre de la persona que consulta.",
            "examples": ["Francisca Rojas"]
          },
          "email": {
            "type": "string",
            "format": "email",
            "minLength": 1,
            "maxLength": 320,
            "description": "Correo de respuesta. Se usa como Reply-To del mensaje entregado.",
            "examples": ["contacto@empresa.cl"]
          },
          "message": {
            "type": "string",
            "minLength": 1,
            "maxLength": 5000,
            "description": "Descripción del proyecto o consulta.",
            "examples": ["Necesito migrar el sitio de mi empresa y tomar un plan mensual."]
          },
          "company": {
            "type": "string",
            "maxLength": 0,
            "description": "Campo trampa contra envíos automatizados. Debe omitirse o enviarse vacío.",
            "default": ""
          }
        }
      },
      "Success": {
        "type": "object",
        "required": ["ok"],
        "properties": {
          "ok": { "type": "boolean", "const": true },
          "simulated": {
            "type": "boolean",
            "description": "Presente sólo en entornos de vista previa sin credenciales de correo."
          }
        }
      },
      "Failure": {
        "type": "object",
        "required": ["ok", "error"],
        "properties": {
          "ok": { "type": "boolean", "const": false },
          "error": {
            "type": "string",
            "enum": ["missing_fields", "field_too_long", "send_failed", "uf_unavailable"],
            "description": "Identificador estable de la condición de error."
          },
          "detail": {
            "type": "string",
            "description": "Detalle técnico expuesto únicamente en modo de depuración."
          }
        }
      },
      "UfReference": {
        "type": "object",
        "required": ["ok", "indicator", "currency", "value", "observedAt", "source"],
        "properties": {
          "ok": { "type": "boolean", "const": true },
          "indicator": { "type": "string", "const": "UF" },
          "currency": { "type": "string", "const": "CLP" },
          "value": {
            "type": "number",
            "description": "Valor de una UF expresado en pesos chilenos."
          },
          "observedAt": {
            "type": "string",
            "description": "Fecha de observación del valor, según la fuente."
          },
          "source": {
            "type": "string",
            "description": "Proveedor del indicador."
          }
        }
      }
    }
  }
}
