Aller au contenu principal

Rechercher des transactions immobilières (DVF)

L'API Infoparcelle donne accès à l'historique complet des Demandes de Valeurs Foncières (DVF), la base de données officielle des transactions immobilières en France. Ce guide vous explique comment rechercher et analyser les ventes immobilières.

Vue d'ensemble

L'endpoint /api/v1/dvfs permet de rechercher des transactions immobilières par différents critères : localisation, type de bien, prix, surfaces, dates de vente, etc.

Fonctionnalités principales

  • ✅ Accès aux ventes depuis 2014
  • ✅ Filtrage par type de bien (maisons, appartements, terrains, etc.)
  • ✅ Filtrage par prix et surfaces
  • ✅ Filtrage par dates de transaction
  • ✅ Données géographiques (coordonnées GPS, codes postaux, communes)
  • ✅ Format JSON ou GeoJSON
  • ✅ Pagination par curseur

Données DVF disponibles

Les DVF (Demandes de Valeurs Foncières) contiennent les informations suivantes :

  • 📅 Date de mutation : Date de la transaction
  • 💰 Valeur foncière : Prix de vente
  • 🏠 Type de bien : Maison, appartement, terrain, etc.
  • 📏 Surfaces : Terrain, habitable, bâtie
  • 🗺️ Localisation : Coordonnées GPS, commune, parcelles cadastrales
  • 📊 Compteurs : Nombre de lots, locaux, parcelles

Recherche basique

Par code postal

curl -X GET \
"https://app.infoparcelle.fr/api/v1/dvfs?code_postal=75008&limite=10&champs=id_mutation,date_mutation,nature_mutation,bati_type,surface_batie,valeur_fonciere,municipalite" \
-H "Authorization: Bearer VOTRE_CLE_API"

Par commune

# Transactions à Lyon (code INSEE 69123)
curl "https://app.infoparcelle.fr/api/v1/dvfs?code_municipalite=69123&limite=20" \
-H "Authorization: Bearer VOTRE_CLE_API"

Filtrer par type de bien

Maisons

# Ventes de maisons à Bordeaux
curl "https://app.infoparcelle.fr/api/v1/dvfs?code_postal=33000&code_type_bien=111&limite=20" \
-H "Authorization: Bearer VOTRE_CLE_API"

Codes des maisons :

  • 110 - MAISON - INDETERMINEE
  • 111 - UNE MAISON
  • 112 - DES MAISONS

Appartements

# Ventes d'appartements à Nice
curl "https://app.infoparcelle.fr/api/v1/dvfs?code_postal=06000&code_type_bien=121&limite=30" \
-H "Authorization: Bearer VOTRE_CLE_API"

Codes des appartements :

  • 120 - APPARTEMENT INDETERMINE
  • 121 - UN APPARTEMENT
  • 122 - DEUX APPARTEMENTS

Terrains

# Ventes de terrains à bâtir (TAB) à Toulouse
curl "https://app.infoparcelle.fr/api/v1/dvfs?code_municipalite=31555&code_type_bien=21&limite=20" \
-H "Authorization: Bearer VOTRE_CLE_API"

Codes des terrains :

  • 20 - TERRAIN NON BATIS INDETERMINE
  • 21 - TERRAIN DE TYPE TAB (Terrain à bâtir)
  • 221 - TERRAIN D'AGREMENT
  • 232 - TERRAIN FORESTIER
  • 2311 - TERRAIN VITICOLE
  • 2313 - TERRAIN DE TYPE TERRE ET PRE

Locaux d'activité

# Ventes de locaux d'activité à Paris
curl "https://app.infoparcelle.fr/api/v1/dvfs?code_municipalite=75056&code_type_bien=14&limite=15" \
-H "Authorization: Bearer VOTRE_CLE_API"

Filtrer par prix

Fourchette de prix

# Appartements vendus entre 200k et 400k€ à Lyon
curl "https://app.infoparcelle.fr/api/v1/dvfs?code_municipalite=69123&code_type_bien=121&valeur_fonciere_min=200000&valeur_fonciere_max=400000&limite=30" \
-H "Authorization: Bearer VOTRE_CLE_API"

Prix au m² estimé

# Calculer le prix au m² moyen
def calculer_prix_m2(transactions):
prix_m2_list = []

for t in transactions:
if t['surface_batie'] and t['surface_batie'] > 0:
prix_m2 = t['valeur_fonciere'] / t['surface_batie']
prix_m2_list.append(prix_m2)

if prix_m2_list:
return sum(prix_m2_list) / len(prix_m2_list)
return 0

# Utilisation
response = requests.get(
'https://app.infoparcelle.fr/api/v1/dvfs',
params={
'code_postal': '75008',
'code_type_bien': '121',
'limite': 50
},
headers={'Authorization': f'Bearer {api_key}'}
)

transactions = response.json()
prix_m2_moyen = calculer_prix_m2(transactions)
print(f"Prix au m² moyen : {prix_m2_moyen:.2f} €")

Filtrer par surface

Surface habitable

# Appartements de 60 à 100 m² vendus à Marseille
curl "https://app.infoparcelle.fr/api/v1/dvfs?code_municipalite=13055&bati_type=7&surface_habitable_min=60&surface_habitable_max=100&limite=20" \
-H "Authorization: Bearer VOTRE_CLE_API"

Surface de terrain

# Maisons avec terrain de 500 à 1500 m² à Nantes
curl "https://app.infoparcelle.fr/api/v1/dvfs?code_postal=44000&bati_type=1&surface_terrain_min=500&surface_terrain_max=1500&limite=20" \
-H "Authorization: Bearer VOTRE_CLE_API"

Filtrer par date

Transactions récentes

# Ventes depuis janvier 2024 à Strasbourg
curl "https://app.infoparcelle.fr/api/v1/dvfs?code_postal=67000&date_mutation_min=2024-01-01&limite=30" \
-H "Authorization: Bearer VOTRE_CLE_API"

Période spécifique

# Ventes entre 2022 et 2023 à Lille
curl "https://app.infoparcelle.fr/api/v1/dvfs?code_municipalite=59350&date_mutation_min=2022-01-01&date_mutation_max=2023-12-31&limite=50" \
-H "Authorization: Bearer VOTRE_CLE_API"

Filtrer par nature de mutation

Ventes classiques

# Ventes uniquement (pas d'échanges, expropriations, etc.)
curl "https://app.infoparcelle.fr/api/v1/dvfs?code_postal=13001&nature_mutation=3&limite=20" \
-H "Authorization: Bearer VOTRE_CLE_API"

Natures de mutation :

  • 0 - Adjudication : Vente aux enchères publiques
  • 1 - Echange : Échange de biens immobiliers
  • 2 - Expropriation : Acquisition forcée pour cause d'utilité publique
  • 3 - Vente : Vente classique
  • 4 - Vente en l'état futur d'achèvement (VEFA)
  • 5 - Vente terrain à bâtir

VEFA uniquement

# Ventes VEFA à Montpellier
curl "https://app.infoparcelle.fr/api/v1/dvfs?code_municipalite=34172&vefa=true&limite=20" \
-H "Authorization: Bearer VOTRE_CLE_API"

Tri et pagination

Trier les résultats

# Trier par prix décroissant
curl "https://app.infoparcelle.fr/api/v1/dvfs?code_postal=75008&champ_tri=valeur_fonciere&ordre_tri=desc&limite=20" \
-H "Authorization: Bearer VOTRE_CLE_API"

Champs de tri disponibles :

  • id_mutation - Identifiant unique
  • date_mutation - Date de vente (défaut)
  • nature_mutation - Nature de la transaction
  • bati_type - Type de bâti
  • code_type_bien - Code du type de bien
  • valeur_fonciere - Prix de vente
  • surface_batie - Surface bâtie

Pagination avec curseur

# Page 1
curl -i "https://app.infoparcelle.fr/api/v1/dvfs?code_postal=75001&limite=20" \
-H "Authorization: Bearer VOTRE_CLE_API"

# Récupérer le curseur depuis le header X-Pagination-Next-Cursor

# Page 2 (remplacer CURSEUR par la valeur obtenue)
curl "https://app.infoparcelle.fr/api/v1/dvfs?code_postal=75001&limite=20&curseur=CURSEUR" \
-H "Authorization: Bearer VOTRE_CLE_API"

Format GeoJSON

Pour afficher les transactions sur une carte :

curl "https://app.infoparcelle.fr/api/v1/dvfs?code_postal=75008&format=geojson&limite=20" \
-H "Authorization: Bearer VOTRE_CLE_API"
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [2.3522, 48.8566]
},
"properties": {
"id_mutation": "2023-12345",
"date_mutation": "2023-06-15",
"nature_mutation": "Vente",
"valeur_fonciere": 350000,
"code_type_bien": 121,
"libelle_type": "UN APPARTEMENT",
"bati_type": 7,
"surface_batie": 75.5,
"municipalite": {
"code": "75056",
"nom": "Paris"
}
}
}
]
}

Personnaliser les champs retournés

# Demander uniquement certains champs
curl "https://app.infoparcelle.fr/api/v1/dvfs?code_postal=75008&champs=id_mutation,date_mutation,valeur_fonciere,surface_batie,municipalite&limite=20" \
-H "Authorization: Bearer VOTRE_CLE_API"

Champs disponibles :

  • id_mutation - Identifiant unique
  • date_mutation - Date de signature
  • nature_mutation - Nature de la mutation
  • valeur_fonciere - Prix
  • vefa - Indicateur VEFA
  • code_type_bien - Code du type
  • libelle_type - Libellé descriptif
  • bati_type - Type calculé
  • nb_lots, nb_parcelles, nb_locaux
  • nb_maisons, nb_appartements, nb_dependances
  • surface_terrain, surface_batie
  • surface_maisons, surface_appartements
  • parcelles - Liste des parcelles (max 10)
  • municipalite - Informations commune
  • centre - Point GPS

Cas d'usage avancés

1. Analyse de marché local

async function analyserMarcheImmobilier(codePostal, annee = 2024) {
/**
* Analyse le marché immobilier pour un code postal donné
*/
const apiKey = process.env.INFOPARCELLE_API_KEY;

const response = await fetch(
'https://app.infoparcelle.fr/api/v1/dvfs?' +
new URLSearchParams({
code_postal: codePostal,
date_mutation_min: `${annee}-01-01`,
nature_mutation: '3', // Ventes uniquement
limite: '50'
}),
{
headers: { 'Authorization': `Bearer ${apiKey}` }
}
);

const transactions = await response.json();

// Calculer les statistiques
const stats = {
total_ventes: transactions.length,
prix_moyen: 0,
prix_median: 0,
prix_m2_moyen: 0,
par_type: {}
};

if (transactions.length === 0) {
return stats;
}

// Prix moyen
stats.prix_moyen = transactions.reduce((sum, t) => sum + t.valeur_fonciere, 0) / transactions.length;

// Prix médian
const prixTries = transactions.map(t => t.valeur_fonciere).sort((a, b) => a - b);
stats.prix_median = prixTries[Math.floor(prixTries.length / 2)];

// Prix au m² moyen
const prixM2List = transactions
.filter(t => t.surface_batie && t.surface_batie > 0)
.map(t => t.valeur_fonciere / t.surface_batie);

if (prixM2List.length > 0) {
stats.prix_m2_moyen = prixM2List.reduce((sum, p) => sum + p, 0) / prixM2List.length;
}

// Répartition par type
transactions.forEach(t => {
const typeBien = t.libelle_type || 'Inconnu';
stats.par_type[typeBien] = (stats.par_type[typeBien] || 0) + 1;
});

return stats;
}

// Utilisation
const stats = await analyserMarcheImmobilier('75008', 2024);
console.log('Analyse du marché immobilier 75008:');
console.log(` Total ventes: ${stats.total_ventes}`);
console.log(` Prix moyen: ${stats.prix_moyen.toLocaleString('fr-FR', {maximumFractionDigits: 0})}`);
console.log(` Prix médian: ${stats.prix_median.toLocaleString('fr-FR', {maximumFractionDigits: 0})}`);
console.log(` Prix m² moyen: ${Math.round(stats.prix_m2_moyen)} €/m²`);
console.log(` Répartition:`, stats.par_type);

2. Détection d'opportunités

async function trouverOpportunites(codePostal) {
/**
* Trouver les biens vendus en dessous du prix du marché
*/
const apiKey = process.env.INFOPARCELLE_API_KEY;

// 1. Récupérer les ventes récentes
const response = await fetch(
'https://app.infoparcelle.fr/api/v1/dvfs?' +
new URLSearchParams({
code_postal: codePostal,
date_mutation_min: '2023-01-01',
code_type_bien: '121', // Appartements
limite: '50',
}),
{
headers: { 'Authorization': `Bearer ${apiKey}` }
}
);

const transactions = await response.json();

// 2. Calculer le prix au m² moyen
const prixM2List = transactions
.filter(t => t.surface_batie > 0)
.map(t => t.valeur_fonciere / t.surface_batie);

const prixM2Moyen = prixM2List.reduce((a, b) => a + b, 0) / prixM2List.length;

// 3. Trouver les ventes < 85% du prix moyen
const opportunites = transactions.filter(t => {
if (!t.surface_batie || t.surface_batie === 0) return false;
const prixM2 = t.valeur_fonciere / t.surface_batie;
return prixM2 < prixM2Moyen * 0.85;
});

return {
prixM2Moyen,
opportunites: opportunites.map(t => ({
date: t.date_mutation,
prix: t.valeur_fonciere,
surface: t.surface_batie,
prixM2: Math.round(t.valeur_fonciere / t.surface_batie),
economie: Math.round((prixM2Moyen - t.valeur_fonciere / t.surface_batie) * t.surface_batie),
})),
};
}

// Utilisation
const resultats = await trouverOpportunites('75008');
console.log(`Prix m² moyen: ${Math.round(resultats.prixM2Moyen)} €/m²`);
console.log(`Opportunités trouvées: ${resultats.opportunites.length}`);

3. Évolution des prix dans le temps

async function evolutionPrixTemporelle(codeMunicipalite, typeBien = '121') {
/**
* Analyse l'évolution des prix sur plusieurs années
*/
const apiKey = process.env.INFOPARCELLE_API_KEY;
const annees = [2020, 2021, 2022, 2023, 2024];
const evolution = {};

for (const annee of annees) {
const response = await fetch(
'https://app.infoparcelle.fr/api/v1/dvfs?' +
new URLSearchParams({
code_municipalite: codeMunicipalite,
code_type_bien: typeBien,
date_mutation_min: `${annee}-01-01`,
date_mutation_max: `${annee}-12-31`,
limite: '50'
}),
{
headers: { 'Authorization': `Bearer ${apiKey}` }
}
);

const transactions = await response.json();

if (transactions.length > 0) {
// Calculer le prix moyen au m²
const prixM2List = transactions
.filter(t => t.surface_batie && t.surface_batie > 0)
.map(t => t.valeur_fonciere / t.surface_batie);

if (prixM2List.length > 0) {
evolution[annee] = {
nb_ventes: transactions.length,
prix_m2_moyen: prixM2List.reduce((a, b) => a + b, 0) / prixM2List.length
};
}
}
}

// Calculer l'évolution en %
const anneesKeys = Object.keys(evolution).map(Number);
anneesKeys.forEach((annee, i) => {
if (i > 0) {
const anneePrecedente = anneesKeys[i - 1];
const evolutionPct = (
(evolution[annee].prix_m2_moyen - evolution[anneePrecedente].prix_m2_moyen)
/ evolution[anneePrecedente].prix_m2_moyen * 100
);
evolution[annee].evolution_pct = evolutionPct;
}
});

return evolution;
}

// Utilisation
const evolution = await evolutionPrixTemporelle('75108', '121');
for (const [annee, data] of Object.entries(evolution)) {
const evolutionTxt = data.evolution_pct !== undefined ?
` (${data.evolution_pct > 0 ? '+' : ''}${data.evolution_pct.toFixed(1)}%)` : '';
console.log(`${annee}: ${Math.round(data.prix_m2_moyen)} €/m² (${data.nb_ventes} ventes)${evolutionTxt}`);
}

4. Comparaison entre quartiers

async function comparerQuartiers(codesMunicipalite) {
/**
* Comparer les prix entre plusieurs quartiers
*/
const apiKey = process.env.INFOPARCELLE_API_KEY;
const resultats = {};

for (const code of codesMunicipalite) {
const response = await fetch(
'https://app.infoparcelle.fr/api/v1/dvfs?' +
new URLSearchParams({
code_municipalite: code,
date_mutation_min: '2024-01-01',
code_type_bien: '121',
limite: '50',
}),
{
headers: { 'Authorization': `Bearer ${apiKey}` }
}
);

const transactions = await response.json();

if (transactions.length > 0) {
const prixM2List = transactions
.filter(t => t.surface_batie > 0)
.map(t => t.valeur_fonciere / t.surface_batie);

resultats[code] = {
nom: transactions[0].municipalite.nom,
nbVentes: transactions.length,
prixM2Moyen: Math.round(prixM2List.reduce((a, b) => a + b, 0) / prixM2List.length),
};
}
}

return resultats;
}

// Utilisation : comparer Paris 1er, 8e et 16e
const comparaison = await comparerQuartiers(['75101', '75108', '75116']);
console.table(comparaison);

Bonnes pratiques

✅ À faire

  1. Filtrer par localisation (code postal ou commune)
  2. Filtrer par date pour des analyses pertinentes
  3. Utiliser la pagination par curseur pour de grands volumes
  4. Trier les résultats selon vos besoins
  5. Calculer le prix au m² pour comparer les biens
  6. Demander uniquement les champs nécessaires
  7. Gérer les valeurs nulles (certains champs peuvent être vides)
  8. Cacher les résultats pour les recherches fréquentes

❌ À éviter

  1. ❌ Ignorer les filtres de date (trop de résultats)
  2. ❌ Ne pas gérer les surfaces nulles dans les calculs
  3. ❌ Oublier la pagination (limite max : 50 résultats)
  4. ❌ Multiplier les requêtes inutiles
  5. ❌ Ne pas vérifier les en-têtes de pagination

Limites et précisions

  • Données disponibles depuis 2014 uniquement
  • France métropolitaine + DOM uniquement
  • Maximum 50 résultats par requête (utilisez la pagination)
  • Champ parcelles limité à 10 parcelles par DVF
  • Certaines transactions peuvent avoir des données incomplètes
  • VEFA : Les ventes en l'état futur d'achèvement peuvent avoir des surfaces nulles

Performances

  • Temps de réponse moyen : < 150ms
  • Cache côté serveur : 15 minutes
  • Rate limit : 1200 requêtes/minute

Voir aussi