{
  "openapi": "3.0.3",
  "info": {
    "title": "API ouverte Estimatiz",
    "version": "1.0.0",
    "description": "Recherche d’adresse et estimation immobilière avec rapport partageable. Sans clé et sans quota applicatif ; capacité et disponibilité du serveur restent finies. Estimatiz est indépendant et non affilié à une administration. MCP est optionnel pour les assistants compatibles. Cette documentation ne garantit aucune découverte automatique par les IA."
  },
  "servers": [
    {
      "url": "https://www.estimatiz.fr",
      "description": "API publique Estimatiz en HTTPS."
    }
  ],
  "security": [],
  "paths": {
    "/api/public/v1/addresses.php": {
      "get": {
        "operationId": "searchAddresses",
        "summary": "Rechercher une adresse",
        "description": "Faire confirmer le résultat par l’utilisateur avant estimation. Une liste vide ne prouve pas l’absence du bien.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 3,
              "maxLength": 200
            },
            "description": "Adresse recherchée, avec commune ou code postal.",
            "example": "146 boulevard Voltaire 75011 Paris"
          }
        ],
        "responses": {
          "200": {
            "description": "Résultats de recherche, éventuellement vides.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressResponse"
                },
                "examples": {
                  "noResults": {
                    "summary": "Exemple sans résultat ; ne prouve pas l’absence d’un bien.",
                    "value": {
                      "ok": true,
                      "addresses": []
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "INVALID_JSON : JSON invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED : méthode HTTP non acceptée.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "INVALID_PARAMETERS, ADDRESS_NOT_FOUND ou NO_COMPARABLES : paramètres invalides, adresse non confirmée ou données insuffisantes.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "invalidParameters": {
                    "summary": "Exemple de structure ; le message dépend du champ invalide.",
                    "value": {
                      "ok": false,
                      "error": {
                        "code": "INVALID_PARAMETERS",
                        "message": "Paramètres invalides."
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "SERVER_ERROR : échec interne.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "DEPENDENCY_UNAVAILABLE ou REPORT_CREATION_FAILED : dépendance indisponible ou échec de création du rapport. Ne pas annoncer un succès complet ni inventer une URL.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "PAYLOAD_TOO_LARGE : requête trop volumineuse.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/public/v1/estimate.php": {
      "post": {
        "operationId": "estimateProperty",
        "summary": "Calculer une estimation et enregistrer son rapport",
        "description": "Effet d’écriture : crée ou réutilise un rapport partageable non indexable. Aucun nom, e-mail ou téléphone requis. Restituer median, la fourchette low/high et report.url. Mentionner uniquement les avertissements effectivement présents dans warnings. Les dates des comparables sont des données brutes et ne demandent pas de commentaire final. Le rapport contient les informations complémentaires. En cas d’échec d’enregistrement, ne pas annoncer un succès complet.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EstimateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Estimation calculée et rapport disponible.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EstimateResponse"
                }
              }
            }
          },
          "400": {
            "description": "INVALID_JSON : JSON invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED : méthode HTTP non acceptée.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "INVALID_PARAMETERS, ADDRESS_NOT_FOUND ou NO_COMPARABLES : paramètres invalides, adresse non confirmée ou données insuffisantes.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "invalidParameters": {
                    "summary": "Exemple de structure ; le message dépend du champ invalide.",
                    "value": {
                      "ok": false,
                      "error": {
                        "code": "INVALID_PARAMETERS",
                        "message": "Paramètres invalides."
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "SERVER_ERROR : échec interne.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "DEPENDENCY_UNAVAILABLE ou REPORT_CREATION_FAILED : dépendance indisponible ou échec de création du rapport. Ne pas annoncer un succès complet ni inventer une URL.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "reportFailure": {
                    "summary": "Exemple de structure, sans URL inventée.",
                    "value": {
                      "ok": false,
                      "error": {
                        "code": "REPORT_CREATION_FAILED",
                        "message": "Le rapport n’a pas pu être enregistré."
                      }
                    }
                  }
                }
              }
            }
          },
          "413": {
            "description": "PAYLOAD_TOO_LARGE : requête trop volumineuse.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Address": {
        "type": "object",
        "required": [
          "label",
          "code_voie",
          "voie",
          "commune",
          "cp",
          "no_voie",
          "btq"
        ],
        "properties": {
          "label": {
            "type": "string"
          },
          "code_voie": {
            "type": "string"
          },
          "voie": {
            "type": "string"
          },
          "commune": {
            "type": "string"
          },
          "cp": {
            "type": "string"
          },
          "no_voie": {
            "type": "string",
            "description": "Numéro sous forme de chaîne ; peut être vide à la recherche, obligatoire pour estimer."
          },
          "btq": {
            "type": "string",
            "description": "Suffixe éventuel : vide, A, B, C, D, E, T, Q, bis, ter ou quater."
          }
        },
        "description": "Adresse retournée par la recherche et confirmée par l’utilisateur. Ne pas inventer les identifiants ni choisir arbitrairement un résultat."
      },
      "EstimateRequest": {
        "type": "object",
        "required": [
          "address",
          "property_type",
          "surface"
        ],
        "properties": {
          "address": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Address"
              },
              {
                "type": "object",
                "properties": {
                  "no_voie": {
                    "type": "string",
                    "pattern": "^[1-9][0-9]{0,4}$"
                  }
                }
              }
            ],
            "description": "Adresse numérotée obligatoire ; demander le numéro si absent de la recherche."
          },
          "property_type": {
            "type": "string",
            "enum": [
              "Appartement",
              "Maison",
              "Local",
              "Autres biens"
            ]
          },
          "surface": {
            "type": "number",
            "minimum": 5,
            "maximum": 500,
            "description": "Surface du bien en m²."
          },
          "rooms": {
            "type": "integer",
            "minimum": 1,
            "maximum": 30
          },
          "rooms_mode": {
            "type": "string",
            "enum": [
              "exact",
              "minimum"
            ],
            "default": "exact",
            "description": "minimum exige un nombre de pièces rooms."
          },
          "location_fallback": {
            "type": "string",
            "enum": [
              "none",
              "nearby_number"
            ],
            "default": "nearby_number",
            "description": "none désactive le recours au numéro voisin ; des ventes exactes peuvent encore permettre une estimation sans géolocalisation confirmée."
          }
        },
        "additionalProperties": false,
        "anyOf": [
          {
            "not": {
              "required": [
                "rooms_mode"
              ],
              "properties": {
                "rooms_mode": {
                  "enum": [
                    "minimum"
                  ]
                }
              }
            }
          },
          {
            "required": [
              "rooms"
            ]
          }
        ]
      },
      "Error": {
        "type": "object",
        "required": [
          "ok",
          "error"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "description": "Code stable exploitable par le client."
              },
              "message": {
                "type": "string",
                "description": "Explication en français, sans détails internes."
              }
            }
          }
        }
      },
      "AddressResponse": {
        "type": "object",
        "required": [
          "ok",
          "addresses"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "addresses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Address"
            }
          }
        }
      },
      "EstimateResponse": {
        "type": "object",
        "required": [
          "ok",
          "estimation",
          "report",
          "address",
          "comparables",
          "location",
          "warnings",
          "sources",
          "methodology_url",
          "generated_at"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "estimation": {
            "type": "object",
            "required": [
              "low",
              "median",
              "high",
              "price_m2",
              "currency",
              "surface"
            ],
            "properties": {
              "low": {
                "type": "number",
                "minimum": 0
              },
              "median": {
                "type": "number",
                "minimum": 0
              },
              "high": {
                "type": "number",
                "minimum": 0
              },
              "price_m2": {
                "type": "number",
                "minimum": 0
              },
              "currency": {
                "type": "string",
                "enum": [
                  "EUR"
                ]
              },
              "surface": {
                "type": "number",
                "minimum": 5,
                "maximum": 500
              }
            },
            "description": "Montants totaux en euros : low, median, high. price_m2 est le prix au m² médian. Même sélection et même calcul que le rapport."
          },
          "report": {
            "type": "object",
            "required": [
              "url"
            ],
            "properties": {
              "url": {
                "type": "string",
                "format": "uri",
                "description": "Rapport enregistré, non indexable et accessible à toute personne possédant le lien. Présenter ce lien avec les montants."
              }
            }
          },
          "address": {
            "$ref": "#/components/schemas/Address"
          },
          "comparables": {
            "type": "object",
            "required": [
              "count",
              "date_min",
              "date_max"
            ],
            "properties": {
              "count": {
                "type": "integer",
                "minimum": 1
              },
              "date_min": {
                "type": "string",
                "format": "date"
              },
              "date_max": {
                "type": "string",
                "format": "date"
              }
            }
          },
          "location": {
            "type": "object",
            "required": [
              "status",
              "note"
            ],
            "properties": {
              "status": {
                "type": "string",
                "description": "État de localisation renvoyé par Estimatiz.",
                "enum": [
                  "confirmed",
                  "approximate",
                  "unavailable",
                  "candidate_limit"
                ]
              },
              "note": {
                "type": "string",
                "nullable": true
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "name",
                "url"
              ],
              "properties": {
                "name": {
                  "type": "string"
                },
                "url": {
                  "type": "string",
                  "format": "uri"
                }
              }
            }
          },
          "methodology_url": {
            "type": "string",
            "format": "uri"
          },
          "generated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      }
    }
  }
}
