{
  "openapi": "3.1.0",
  "info": {
    "title": "API de solicitud de presupuesto · Green Globe",
    "version": "1.0.0",
    "summary": "Permite a asistentes y agentes de IA pedir presupuesto de consultoría ambiental en nombre de una persona.",
    "description": "Green Globe Sostenibilidad y Proyectos Ambientales es una consultora ambiental española (Málaga, Madrid y Sevilla) que trabaja en toda España.\n\nFlujo: (1) el agente envía la solicitud en JSON; (2) la persona recibe un correo de Green Globe y pulsa «Confirmar solicitud» (válido 48 horas); (3) solo entonces la solicitud llega al equipo, que responde en menos de 24 horas laborables.\n\nLímites: 3 solicitudes por hora y dirección IP, 2 al día por correo, una pendiente de confirmación por correo y 100 al día en total. No hay captcha: la confirmación por correo sustituye a la verificación.\n\nNo se admiten campos fuera del esquema. Los precios no se facilitan por esta vía: cada presupuesto se prepara a medida.\n\nGuía para agentes: https://www.greenglobe.es/contacto/agentes/ · Resumen del sitio: https://www.greenglobe.es/llms.txt",
    "contact": {
      "name": "Green Globe",
      "url": "https://www.greenglobe.es/contacto/",
      "email": "consultas@greenglobe.es"
    },
    "termsOfService": "https://www.greenglobe.es/servicios/politica-de-privacidad/"
  },
  "servers": [
    {
      "url": "https://www.greenglobe.es"
    }
  ],
  "paths": {
    "/api/solicitud": {
      "post": {
        "operationId": "solicitarPresupuesto",
        "summary": "Enviar una solicitud de presupuesto en nombre de una persona",
        "description": "Crea una solicitud pendiente y envía a la persona un correo de confirmación. Indíquele que debe pulsar «Confirmar solicitud» en ese correo (revise también la carpeta de spam).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Solicitud"
              },
              "example": {
                "nombre": "Ana Pérez",
                "empresa": "Industrias Ejemplo S.L.",
                "email": "ana.perez@ejemplo.com",
                "telefono": "+34 600 000 000",
                "servicio": "huella-de-carbono",
                "provincia": "Málaga",
                "mensaje": "Planta de envasado con 80 empleados. Necesitamos calcular la huella de carbono de 2025 (alcances 1 y 2) e inscribirla en el registro del MITECO antes de junio.",
                "privacidad": true,
                "agente": "ChatGPT"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Solicitud registrada; pendiente de que la persona la confirme por correo.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PendienteConfirmacion"
                }
              }
            }
          },
          "400": {
            "description": "Cuerpo no válido o campo incorrecto (code = invalid_json | invalid_field; field indica el campo).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Origen de navegador no permitido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Ya hay una solicitud pendiente de confirmación para ese correo (pending_confirmation_exists).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Cuerpo mayor de 8 KB.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "Content-Type distinto de application/json.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Límite superado (rate_limited). Respete la cabecera Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos hasta poder reintentar."
              }
            }
          },
          "502": {
            "description": "No se pudo enviar el correo de confirmación (email_failed). Reintente más tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Servicio desactivado o no disponible (unavailable). Escriba a consultas@greenglobe.es.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/solicitud/confirmar": {
      "post": {
        "operationId": "confirmarSolicitud",
        "summary": "Uso interno de la página de confirmación",
        "description": "Lo llama la página /solicitud/confirmar/ cuando la persona pulsa el botón del correo. Los agentes no deben llamarlo: el identificador y la firma solo viajan en el correo de la persona.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "sig": {
                    "type": "string"
                  }
                },
                "required": [
                  "id",
                  "sig"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Solicitud confirmada y entregada.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "const": "confirmed"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Enlace no válido (invalid_link).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "410": {
            "description": "Enlace ya usado o caducado (expired_or_used).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "Entrega fallida; la solicitud se conserva para reintentar (delivery_failed).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Servicio no disponible.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Solicitud": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "nombre",
          "email",
          "servicio",
          "mensaje",
          "privacidad"
        ],
        "properties": {
          "nombre": {
            "type": "string",
            "minLength": 2,
            "maxLength": 120,
            "description": "Persona de contacto."
          },
          "empresa": {
            "type": "string",
            "maxLength": 120,
            "description": "Empresa, administración pública u organización. Opcional."
          },
          "email": {
            "type": "string",
            "format": "email",
            "maxLength": 254,
            "description": "Correo de la persona. Recibirá el enlace de confirmación. No se admiten correos temporales ni dominios sin servidor de correo."
          },
          "telefono": {
            "type": "string",
            "maxLength": 30,
            "pattern": "^\\+?[0-9 ().-]{6,30}$",
            "description": "Opcional."
          },
          "servicio": {
            "type": "string",
            "enum": [
              "consultoria-ambiental",
              "evaluacion-de-impacto-ambiental",
              "evaluacion-ambiental-estrategica",
              "autorizacion-ambiental-integrada",
              "autorizacion-ambiental-unificada",
              "calificacion-ambiental",
              "informe-preliminar-de-suelos",
              "evaluacion-de-impacto-en-salud",
              "responsabilidad-medioambiental",
              "declaracion-anual-de-residuos",
              "due-diligence-ambiental",
              "huella-de-carbono",
              "la-ley-8-2018-y-la-huella-de-carbono-de-productos-o-servicios-prestados-a-la-junta-de-andalucia",
              "huella-hidrica",
              "analisis-ciclo-de-vida-acv",
              "informes-y-estrategias-esg",
              "cuadros-mando-ambientales-esg",
              "ods-objetivos-de-desarrollo-sostenible-para-las-empresas",
              "plan-movilidad-sostenible-empresas",
              "paces-plan-accion-por-el-clima-y-energia-sostenible",
              "plan-municipal-cambio-climatico",
              "plan-municipal-economia-circular",
              "economia-baja-carbono",
              "planes-de-movilidad-urbana-sostenible-pmus",
              "desarrollo-urbano-sostenible-integrado-dusi",
              "caminos-escolares",
              "plan-local-emergencias-incendios-forestales-pleif",
              "plan-de-autoproteccion-de-incendios-forestales",
              "plataformas-gestion-indicadores-municipales",
              "contaminacion-luminica",
              "mapas-luminicos",
              "certificacion-cielo-nocturno",
              "monitorizacion-cielo-nocturno",
              "inventariado-y-caracterizacion-de-instalaciones-de-alumbrado",
              "inventariado-y-caracterizacion-de-luminarias",
              "asesoramiento-independiente-para-el-cambio-de-alumbrado-publico",
              "proyectos-instalaciones-alumbrado-publico",
              "night-eye",
              "consultoria-del-agua",
              "concesiones-agua",
              "comunicacion-de-aprovechamiento-de-agua",
              "cambio-de-inscripcion-concesion-agua",
              "comunidad-de-usuarios-de-aguas-publicas",
              "concesion-de-extraccion-de-aridos",
              "deslinde-en-cauces",
              "idi-ambiental",
              "gestion-explotacion-datos-ambientales",
              "sistemas-informacion-geografica",
              "bases-datos-ambientales",
              "educacion-ambiental",
              "formacion-profesional",
              "comunicacion-divulgacion-ambiental",
              "otro"
            ],
            "description": "Identificador del servicio. Use «otro» si ninguno encaja. Etiquetas: consultoria-ambiental = Consultoría ambiental (general); evaluacion-de-impacto-ambiental = Evaluación de impacto ambiental; evaluacion-ambiental-estrategica = Evaluación ambiental estratégica; autorizacion-ambiental-integrada = Autorización ambiental integrada (AAI); autorizacion-ambiental-unificada = Autorización ambiental unificada (AAU / AAUS); calificacion-ambiental = Licencia ambiental y declaración responsable (antes calificación ambiental); informe-preliminar-de-suelos = Informe preliminar de situación del suelo; evaluacion-de-impacto-en-salud = Evaluación de impacto en salud; responsabilidad-medioambiental = Responsabilidad medioambiental (Ley 26/2007); declaracion-anual-de-residuos = Declaración anual de residuos; due-diligence-ambiental = Due diligence ambiental; huella-de-carbono = Huella de carbono; la-ley-8-2018-y-la-huella-de-carbono-de-productos-o-servicios-prestados-a-la-junta-de-andalucia = Huella de carbono para contratos con la Junta de Andalucía (Ley 8/2018); huella-hidrica = Huella hídrica; analisis-ciclo-de-vida-acv = Análisis de ciclo de vida (ACV); informes-y-estrategias-esg = Informes y estrategias ESG; cuadros-mando-ambientales-esg = Cuadros de mando ambientales e indicadores ESG; ods-objetivos-de-desarrollo-sostenible-para-las-empresas = ODS para empresas; plan-movilidad-sostenible-empresas = Plan de movilidad sostenible al trabajo (PMST); paces-plan-accion-por-el-clima-y-energia-sostenible = PACES (Plan de Acción para el Clima y la Energía Sostenible); plan-municipal-cambio-climatico = Plan municipal de cambio climático; plan-municipal-economia-circular = Plan municipal de economía circular; economia-baja-carbono = Economía baja en carbono para entidades locales; planes-de-movilidad-urbana-sostenible-pmus = Plan de movilidad urbana sostenible (PMUS); desarrollo-urbano-sostenible-integrado-dusi = Estrategias DUSI y fondos europeos; caminos-escolares = Caminos escolares; plan-local-emergencias-incendios-forestales-pleif = Plan local de emergencias por incendios forestales (PLEIF); plan-de-autoproteccion-de-incendios-forestales = Plan de autoprotección de incendios forestales (PAIF); plataformas-gestion-indicadores-municipales = Plataformas de indicadores municipales; contaminacion-luminica = Contaminación lumínica; mapas-luminicos = Mapas lumínicos y auditoría de alumbrado; certificacion-cielo-nocturno = Certificación de la calidad del cielo nocturno; monitorizacion-cielo-nocturno = Monitorización de la calidad del cielo nocturno; inventariado-y-caracterizacion-de-instalaciones-de-alumbrado = Inventariado de instalaciones de alumbrado; inventariado-y-caracterizacion-de-luminarias = Inventariado de luminarias; asesoramiento-independiente-para-el-cambio-de-alumbrado-publico = Asesoramiento para el cambio de alumbrado público; proyectos-instalaciones-alumbrado-publico = Proyectos de alumbrado público; night-eye = Night Eye (fotómetro de cielo nocturno); consultoria-del-agua = Consultoría del agua; concesiones-agua = Concesiones de aguas; comunicacion-de-aprovechamiento-de-agua = Comunicación de aprovechamiento de agua; cambio-de-inscripcion-concesion-agua = Cambio de inscripción de concesión de aguas; comunidad-de-usuarios-de-aguas-publicas = Comunidad de usuarios de aguas públicas; concesion-de-extraccion-de-aridos = Concesión de extracción de áridos; deslinde-en-cauces = Deslinde en cauces públicos; idi-ambiental = I+D+i y tecnologías ambientales; gestion-explotacion-datos-ambientales = Gestión y explotación de datos ambientales; sistemas-informacion-geografica = Sistemas de información geográfica (SIG); bases-datos-ambientales = Bases de datos ambientales; educacion-ambiental = Educación ambiental; formacion-profesional = Formación profesional ambiental; comunicacion-divulgacion-ambiental = Comunicación y divulgación ambiental; otro = Otro servicio"
          },
          "provincia": {
            "type": "string",
            "enum": [
              "Álava",
              "Albacete",
              "Alicante",
              "Almería",
              "Asturias",
              "Ávila",
              "Badajoz",
              "Baleares",
              "Barcelona",
              "Burgos",
              "Cáceres",
              "Cádiz",
              "Cantabria",
              "Castellón",
              "Ciudad Real",
              "Córdoba",
              "Cuenca",
              "Girona",
              "Granada",
              "Guadalajara",
              "Gipuzkoa",
              "Huelva",
              "Huesca",
              "Jaén",
              "A Coruña",
              "La Rioja",
              "Las Palmas",
              "León",
              "Lleida",
              "Lugo",
              "Madrid",
              "Málaga",
              "Murcia",
              "Navarra",
              "Ourense",
              "Palencia",
              "Pontevedra",
              "Salamanca",
              "Santa Cruz de Tenerife",
              "Segovia",
              "Sevilla",
              "Soria",
              "Tarragona",
              "Teruel",
              "Toledo",
              "Valencia",
              "Valladolid",
              "Bizkaia",
              "Zamora",
              "Zaragoza",
              "Ceuta",
              "Melilla",
              "Fuera de España"
            ],
            "description": "Provincia donde está la actividad o el proyecto. Opcional. Se admiten alias habituales (Vizcaya, La Coruña, Gerona…)."
          },
          "mensaje": {
            "type": "string",
            "minLength": 20,
            "maxLength": 3000,
            "description": "Qué necesita la persona: tipo de actividad o proyecto, situación (nueva instalación, ampliación, requerimiento de la administración…), plazo y cualquier dato útil. Texto plano."
          },
          "privacidad": {
            "type": "boolean",
            "const": true,
            "description": "Debe ser true: la persona ha leído y acepta la política de privacidad (https://www.greenglobe.es/servicios/politica-de-privacidad/)."
          },
          "agente": {
            "type": "string",
            "maxLength": 120,
            "description": "Nombre del asistente o agente que envía la solicitud (p. ej. «ChatGPT», «Claude», «Perplexity»). Opcional pero recomendado."
          }
        }
      },
      "PendienteConfirmacion": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "const": "pending_confirmation"
          },
          "message": {
            "type": "string"
          },
          "expires_in_hours": {
            "type": "integer",
            "const": 48
          },
          "next_step": {
            "type": "string"
          },
          "docs": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "const": "error"
          },
          "code": {
            "type": "string",
            "description": "Código legible por máquina."
          },
          "message": {
            "type": "string",
            "description": "Explicación en castellano, pensada para mostrarla a la persona o corregir la petición."
          },
          "field": {
            "type": "string",
            "description": "Campo afectado cuando code = invalid_field."
          },
          "retry_after_seconds": {
            "type": "integer"
          },
          "docs": {
            "type": "string",
            "format": "uri"
          }
        },
        "required": [
          "status",
          "code",
          "message"
        ]
      }
    }
  }
}
