Due diligence immobilière
Vérifiez l'historique complet d'un bien avant acquisition.
Avant d'acquérir un bien, il est essentiel de vérifier son historique de transactions : fréquence des reventes, variations de prix, ventes en lot. Ces données, disponibles dans DVF depuis 2014, permettent de détecter des signaux d'alerte avant de s'engager.
Revente rapide
Un bien revendu en moins de 6 mois peut indiquer un problème caché (vices, litige de copropriété).
Hausse de prix anormale
+30% en moins de 2 ans sans rénovation connue mérite investigation.
Vente en lot
is_bulk_sale=true : le prix affiché est le total du lot, pas la valeur individuelle.
Baisse de prix
Une baisse significative peut signaler des travaux importants ou un marché en difficulté.
Récupérer l'historique
L'outil MCP get_property_history (20 crédits) retourne toutes les transactions DVF pour une adresse et un code postal. Données disponibles depuis 2014.
import requests
from datetime import datetime
API_KEY = "normi_votre_token"
BASE_URL = "https://mcp.normi.fr/v1"
# Rechercher l'historique d'un bien par adresse
def get_property_history(address: str, code_postal: str):
# Utiliser l'API MCP via tool call, ou search_properties avec adresse exacte
r = requests.get(
f"{BASE_URL}/transactions",
params={
"commune": address.split(",")[-1].strip().upper() if "," in address else None,
"code_postal": code_postal,
"limit": 50,
},
headers={"X-API-Key": API_KEY},
)
r.raise_for_status()
return r.json()
# Pour un historique précis par adresse, utiliser le MCP via Claude
# ou l'outil get_property_history directementget_property_history via Claude — l'outil normalise automatiquement l'adresse et retourne uniquement les transactions pertinentes.Analyser les signaux d'alerte
Détectez automatiquement les reventes rapides, hausses anormales et baisses de prix.
def analyze_history(transactions: list) -> dict:
"""Analyse l'historique pour détecter des signaux d'alerte."""
if len(transactions) < 2:
return {"status": "ok", "transactions": len(transactions), "alerts": []}
alerts = []
transactions_sorted = sorted(transactions, key=lambda t: t["date_mutation"])
for i in range(1, len(transactions_sorted)):
prev = transactions_sorted[i - 1]
curr = transactions_sorted[i]
# Calculer la durée entre deux ventes
d1 = datetime.fromisoformat(prev["date_mutation"])
d2 = datetime.fromisoformat(curr["date_mutation"])
months_between = (d2 - d1).days / 30.44
# Calculer la variation de prix
if prev["valeur_fonciere"] > 0:
price_change_pct = (
(curr["valeur_fonciere"] - prev["valeur_fonciere"])
/ prev["valeur_fonciere"]
* 100
)
else:
price_change_pct = 0
# Signaux d'alerte
if months_between < 6:
alerts.append({
"type": "revente_rapide",
"severity": "high",
"message": f"Revendu en {months_between:.1f} mois",
"from": prev["valeur_fonciere"],
"to": curr["valeur_fonciere"],
"change_pct": price_change_pct,
})
elif price_change_pct > 30 and months_between < 24:
alerts.append({
"type": "hausse_rapide",
"severity": "medium",
"message": f"+{price_change_pct:.1f}% en {months_between:.1f} mois",
"from": prev["valeur_fonciere"],
"to": curr["valeur_fonciere"],
"change_pct": price_change_pct,
})
elif price_change_pct < -20:
alerts.append({
"type": "baisse_prix",
"severity": "low",
"message": f"{price_change_pct:.1f}% de baisse",
"from": prev["valeur_fonciere"],
"to": curr["valeur_fonciere"],
"change_pct": price_change_pct,
})
return {
"status": "alerts" if alerts else "ok",
"transactions": len(transactions),
"alerts": alerts,
}
# Exemple d'utilisation
result = analyze_history(transactions)
print(f"Statut : {result['status']}")
for alert in result["alerts"]:
print(f" [{alert['severity'].upper()}] {alert['type']}: {alert['message']}")
print(f" {alert['from']:,} € → {alert['to']:,} €")Ventes en lot
Les ventes en lot concernent plusieurs biens dans une seule transaction (successions, opérations immobilières groupées). Le champ is_bulk_sale permet de les identifier.
# Détecter si un bien fait partie d'une vente en lot
def check_bulk_sale(transaction: dict) -> bool:
"""
is_bulk_sale=True indique que la transaction incluait plusieurs biens.
Dans ce cas, valeur_fonciere est le prix TOTAL du lot, pas du bien seul.
"""
return transaction.get("is_bulk_sale", False)
# Pour les ventes en lot, le prix est à diviser par le nombre de lots
# (non disponible directement — utiliser avec précaution)
if check_bulk_sale(transaction):
print("⚠ Vente en lot — le prix affiché est le total du lot")
print(" La valeur individuelle du bien peut différer significativement")valeur_fonciere représente le prix total de l'ensemble du lot, pas du bien individuel. Ces transactions sont exclues par défaut (exclude_bulk_sales=true) des stats et comparables pour éviter les distorsions.Limites des données DVF
Transactions depuis 2014 uniquement↓
Délai de publication semi-annuel↓
Pas de motif de vente↓
Adresses parfois imprécises↓
Avec Claude (MCP)
Claude peut effectuer toute la due diligence en une instruction :