PermisAPI
marchands de biens, agents immobiliers, proptech, banques, investisseurs.
temps 6 min de lecture.budget 199 EUR/mois (plan Pro), endpoint réservé aux comptes Pro et plus.

DVF cross-ref : associer chaque permis à sa valeur foncière en 5 ms

Persona : marchands de biens, agents immobiliers, proptech, banques, investisseurs. Temps : 6 min de lecture. Budget : 199 EUR/mois (plan Pro), endpoint réservé aux comptes Pro et plus.

TL;DR : on a croisé les 311 000 permis Sitadel avec les 20 millions de transactions DVF Etalab pour répondre à une question simple : combien vaut le terrain visé par ce permis. Un appel, top 5 transactions voisines, prix au m², score de pertinence. Voici comment on l'a fait, ce qu'on a découvert dans les chiffres, et comment l'utiliser dans votre workflow.

Le problème métier

Un marchand de biens reçoit une opportunité : un permis de construire vient d'être déposé sur une parcelle à Bordeaux. Il a 48 heures pour décider s'il fait une offre.

La question principale n'est pas "quel est le permis ?" - les données Sitadel le disent déjà. La question vraie c'est : combien vaut cet emplacement ?

Le réflexe historique : ouvrir DVF.app dans le navigateur, naviguer la carte, cliquer 5 transactions voisines, noter le prix au m², calculer une médiane mentale. 8 à 12 minutes par permis. Quand vous en analysez 30 par jour, ça fait 4 heures de copier-coller.

Le réflexe API : un seul appel, 5 ms.

curl -H "X-API-Key: pk_..." \
  https://api.permisapi.fr/v1/permits/PC07404021K1/dvf

Réponse : les 5 transactions DVF les plus pertinentes dans un rayon adaptatif autour du permis, avec prix de vente, surface bâtie, type de bien, distance au permis, et un score combiné.

Les sources et le pipeline

Trois jeux de données, tous publics, tous gratuits, tous officiels.

Sitadel (SDES, ministère de la Transition écologique) : 311 203 permis de construire France depuis 2022, géocodés via la Base Adresse Nationale.

Geo-DVF (Etalab) : 19,9 millions de transactions immobilières sur 5 ans glissants (2021-2025), géocodées au niveau parcelle cadastrale en WGS-84. Mises à jour semestrielles, en avril et octobre.

Grille INSEE de densité communale 2025 : pour chaque commune, un degré 1/2/3 (Dense / Intermédiaire / Rural). 34 875 communes classifiées.

Le pipeline tourne en backend une fois par mois :

  1. Téléchargement des 5 archives full.csv.gz Geo-DVF (annuelles, ~88 MB chacune).
  2. Concat en un DataFrame en mémoire (~2,5 GB après dtypes optimisés).
  3. Indexation par code commune INSEE.
  4. Pour chaque permis géocodé, calcul vectorisé numpy haversine vers tous les DVF de sa commune.
  5. Filtrage par rayon adaptatif (50m si Dense, 150m si Intermédiaire, 400m si Rural).
  6. Score combiné distance + proximité temporelle + match type local.
  7. Top 5 stocké en base, avec une PK composite (permit_id, rank).

Résultat : 1 201 222 liens permit→transaction précalculés. À la requête API, c'est juste un B-tree lookup, soit 5 ms.

Le scoring expliqué

Chaque transaction DVF candidate reçoit un score entre 0 et 1 :

score = 0.5 × score_distance
      + 0.3 × score_temporel
      + 0.2 × bonus_type
  • score_distance : 1 si la transaction est à 0m du permis, 0 si elle est à la limite du rayon.
  • score_temporel : 1 si la transaction est de la même année que le permis, 0 si plus de 5 ans d'écart (avant ou après, indifférent).
  • bonus_type : 1 si le type de bien DVF correspond à la nature du permis (PC_LOGEMENT × Maison/Appartement = match), 0,5 sinon.

Pourquoi cette pondération : la distance est le critère le plus discriminant en milieu urbain dense (le bien d'à côté est presque toujours comparable), la date capture l'évolution du marché (Bordeaux a pris 30% en 5 ans), le type est un bonus qui distingue les lots vendus en série dans un même immeuble.

Une réponse concrète

Permit PC à Bordeaux, 13 rue de Vaucouleurs (33800) :

{
  "num_pa": "0330632500527",
  "matches": [
    {
      "rank": 1,
      "distance_m": 18.4,
      "date_mutation": "2023-10-27",
      "valeur_fonciere": 815671.0,
      "type_local": 1,
      "surface_reelle_bati": 149,
      "nombre_pieces": 5,
      "relevance_score": 0.576
    },
    {
      "rank": 2,
      "distance_m": 27.5,
      "date_mutation": "2023-07-12",
      "valeur_fonciere": 380000.0,
      "type_local": 1,
      "surface_reelle_bati": 83,
      "nombre_pieces": 3,
      "relevance_score": 0.467
    },
    ...
  ],
  "coverage": "5 ans glissants (2021-2025)"
}

5 maisons (type_local=1) à 18-35m du permis, vendues entre 209 k€ et 815 k€, surface entre 64 et 149 m². Médiane prix/m² : 4 900 EUR.

Pour le marchand de biens : le quartier vaut ~4 900 EUR/m² médian. Si la parcelle du permis fait 169 m² et que la maison construite fera 80 m², l'output attendu c'est 80 × 4 900 = ~390 000 EUR. À comparer au prix d'achat. Décision en 5 ms au lieu de 12 minutes.

Les 3 cas particuliers résolus

1. Paris, Lyon, Marseille. Sitadel utilise les codes commune ville-département (75056, 69123, 13055) pour tous les permis de ces 3 villes. Geo-DVF, lui, utilise les codes par arrondissement (75101-75120, 69381-69389, 13201-13216). Sans mapping, 100% des permis de ces 3 villes seraient retournés sans matches. On a donc une table de résolution code central → liste des arrondissements qui élargit l'index DVF dynamiquement. Concrètement : pour un permis du 16e arrondissement de Paris (notre exemple à 41 rue de Passy), on indexe sur les 20 arrondissements et on filtre ensuite par rayon de 50m (Paris est en classe densité 1).

2. Communes sans DVF. ~3 700 communes France n'ont enregistré aucune transaction DVF en 2024. Ce sont essentiellement des micro-communes rurales. Pour les permis dans ces communes, l'endpoint retourne matches: [] au lieu de planter. Le client peut soit accepter, soit fallback sur une stratégie ad-hoc (rayon élargi à la commune voisine, par exemple).

3. Multi-lots dans une même mutation. Une mutation DVF peut contenir plusieurs rows : un appartement vendu avec sa cave et son parking = 3 entrées avec le même id_mutation. On les conserve toutes - le client peut grouper côté API si voulu. C'est utile pour les use cases où la valeur foncière d'un appartement seul (sans dépendances) doit être isolée du prix total d'achat.

Limites connues V1

  • Couverture temporelle 5 ans glissants. Au-delà, il faudrait reconstituer les archives DVF 2014-2020 depuis des sources alternatives (Cerema DVF+, opendatarchives.fr). Backlog Phase 2 - on le fera si un client paying en demande explicite. Pour 99% des use cases marchands de biens, 5 ans est suffisant car le marché immobilier a tellement bougé que les transactions de 2014 ont peu de signal sur les prix 2026.

  • Top-5 stocké, pas top-N. La base de données stocke les 5 meilleures correspondances par permis, pas davantage. Pour un client qui voudrait toutes les transactions dans 50m sur 5 ans (cas data scientist faisant ses propres stats), on prévoit un mode full=true en V2 qui fera un spatial scan live sur Geo-DVF stocké en cold storage.

  • Rayon fixe par classe de densité. On n'utilise que la grille INSEE 2025 à 3 niveaux (50/150/400m). Une version plus fine pourrait utiliser la grille à 7 niveaux d'Eurostat, mais le gain marginal est faible et la complexité produit augmente. V1 garde les 3 niveaux.

L'utiliser dans votre stack

L'endpoint est documenté sur https://api.permisapi.fr/docs avec try-it-out. Plan Pro à 199 EUR/mois inclut DVF cross-ref + Cadastre + SIRENE + France entière + historique complet. Free tier (500 req/mois) ne donne pas accès à DVF, c'est volontaire : la valeur métier est concentrée sur les comptes payants.

Quelques exemples d'utilisation :

# Top 3 par défaut
GET /v1/permits/{num_pa}/dvf

# Top 5 max stocké
GET /v1/permits/{num_pa}/dvf?limit=5

# Filtrer par type (1=Maison, 2=Appartement, 4=Local commercial)
GET /v1/permits/{num_pa}/dvf?type_local=1,2

# Exclure les terrains nus et dépendances
GET /v1/permits/{num_pa}/dvf?include_terrains=false&include_deps=false

# Restreindre à des transactions récentes (2023+)
GET /v1/permits/{num_pa}/dvf?min_year=2023

# Cap distance personnalisé
GET /v1/permits/{num_pa}/dvf?max_distance=100

Pourquoi on l'a construit

PermisAPI est ma boîte solo. Je code et je vends seul. Quand un marchand de biens m'a écrit "votre API c'est cool mais ça me dit juste qu'il y a un permis, pas combien ça vaut", j'ai compris que le wrapper Sitadel pur n'avait pas assez de valeur. Le vrai produit c'est l'intelligence layer : le permis + son contexte foncier + son contexte SIRENE + (bientôt) son contexte cadastral.

DVF cross-ref c'est la première brique de cet intelligence layer. Le code source de l'algo de matching est lisible (200 lignes, scoring + spatial join numpy + bulk upsert idempotent). Si vous voulez répliquer ça vous-même sur vos propres données, c'est faisable. Si vous préférez payer 199 EUR/mois pour un endpoint maintenu et mis à jour automatiquement chaque mois, c'est ici : https://permisapi.fr.

Et si vous avez des suggestions d'évolution (rayons, scoring, sources additionnelles), répondez à cet article ou écrivez à evan@permisapi.fr.

Essaie l'API en 30 secondes

Pas de signup, pas de carte bleue. Entre un code postal sur la home et regarde 5 permis en temps reel.

Autres tutoriels