{
  "openapi": "3.1.0",
  "info": {
    "title": "FormulaMaps Balance API",
    "version": "1.0.0-beta",
    "description": "API pública (sin login) para que agentes de IA y herramientas equilibren una fórmula de heladería con el motor de FormulaMaps: devuelve POD, sólidos, materia grasa, SLNG, agua, kcal y coste, con verdicto en rango y sugerencias. El índice PAC se devuelve como beta (PAC_beta), pendiente de validación 1:1 con la app. Pastelería y panadería llegarán después.",
    "contact": { "name": "FormulaMaps", "url": "https://www.formulamaps.com" }
  },
  "servers": [{ "url": "https://www.formulamaps.com" }],
  "paths": {
    "/api/balance": {
      "get": {
        "summary": "Manifiesto del servicio y tipos disponibles",
        "responses": { "200": { "description": "Información del servicio", "content": { "application/json": {} } } }
      },
      "post": {
        "summary": "Equilibra una fórmula de heladería",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/BalanceRequest" },
              "example": {
                "craft": "helado",
                "type": "helado_leche",
                "ingredients": [
                  { "name": "Leche Entera 3,5 MG", "grams": 620 },
                  { "name": "Nata 35 MG", "grams": 110 },
                  { "name": "Sacarosa", "grams": 150 },
                  { "name": "Dextrosa", "grams": 25 },
                  { "name": "Leche Polvo 1% MG INNOVA", "grams": 55 }
                ]
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Resultado del balanceo", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BalanceResponse" } } } },
          "400": { "description": "Petición inválida" },
          "429": { "description": "Límite de peticiones superado (60/min)" }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Ingredient": {
        "type": "object",
        "properties": {
          "name": { "type": "string", "description": "Nombre del ingrediente (del catálogo de FormulaMaps) o uno propio si pasas composición." },
          "grams": { "type": "number", "description": "Cantidad. Se trabaja en proporción, no hace falta que sumen 1000." },
          "azucares": { "type": "number" }, "materiagrasa": { "type": "number" }, "esml": { "type": "number" },
          "lactosa": { "type": "number" }, "proteinas": { "type": "number" }, "otrossolidos": { "type": "number" },
          "pac": { "type": "number" }, "pod": { "type": "number" }, "kcal": { "type": "number" }, "precio": { "type": "number" }
        },
        "required": ["name", "grams"]
      },
      "BalanceRequest": {
        "type": "object",
        "properties": {
          "craft": { "type": "string", "enum": ["helado"], "default": "helado" },
          "type": { "type": "string", "enum": ["helado_leche","helado_crema","sorbete_agua","sorbete_leche","crema_untable","veteado","granizado","semifrio","sin_azucar","vegano","salado","base"] },
          "ingredients": { "type": "array", "items": { "$ref": "#/components/schemas/Ingredient" } }
        },
        "required": ["ingredients"]
      },
      "BalanceResponse": {
        "type": "object",
        "properties": {
          "status": { "type": "string" },
          "verdict": { "type": "string" },
          "params": { "type": "object" },
          "ranges": { "type": "object" },
          "inRange": { "type": "object" },
          "suggestions": { "type": "array", "items": { "type": "string" } },
          "warnings": { "type": "array", "items": { "type": "string" } }
        }
      }
    }
  }
}
