DVF & Location API

API duale : marché achat (DVF data.gouv) et marché location (annonces Galactus / Gédéon). Routes séparées, libellés de champs distincts.

20 186 968 transactions achat (DVF)
1 023 971 agrégats achat (DVF)
08/09/2026 11:10 agrégats achat (heure de Paris)
146 140 annonces location (gédéon)
14 247 agrégats location (gédéon)
08/09/2026 11:13 agrégats location (gédéon, heure de Paris)

Authentification

Toutes les routes /api/* sont protégées par HTTP Basic Auth (utilisateur configuré via DVF_API_USER / DVF_API_PASSWORD).

curl -u dvf:******** https://estate-stats-api.dev.studio-net.fr/api/meta

Routes achat (DVF)

Préfixe recommandé /api/sale/*. Les anciennes URLs /api/meta, /api/transactions, /api/aggregates restent disponibles.

GET/api/sale/meta

Années importées, types de locaux, date de calcul des agrégats (aggregates_calculated_at), historique d’import.

GET/api/sale/transactions

Données brutes paginées. Filtres : year, region, department, city_code (INSEE), city_name, type, room, page, per_page (max 200).

GET /api/sale/transactions?city_code=75056&type=appartement&year=2024
GET/api/sale/aggregates

Agrégats précalculés : avg_valeur_fonciere, min_valeur_fonciere, max_valeur_fonciere, avg_prix_m2, min_prix_m2, max_prix_m2, land_surface, transaction_count, calculated_at. Filtres : scope, region, department, city_code, city_name, type, room, year.

GET /api/sale/aggregates?city_name=rouen&year=2025

Routes location (Galactus)

Annonces de location (transaction=R), pas de baux conclus. L’année vient de created pour conserver l’historique. city_code n’est pas un code INSEE : {code_postal}_{slug_ville}. Filtre additionnel : postal_code.

GET/api/rent/meta

Années importées, types, date de calcul des agrégats location.

GET/api/rent/listings

Annonces paginées. Champs : rent_price, surface, land_surface, published_at, postal_code, type_source… Filtres : year, region, department, city_code, city_name, postal_code, type, room, page, per_page.

GET /api/rent/listings?department=56&type=appartement&year=2025
GET/api/rent/aggregates

Agrégats : avg_rent, min_rent, max_rent, avg_rent_m2, min_rent_m2, max_rent_m2, land_surface, listing_count. Mêmes filtres geo/type/room/year que l’achat (scope, region, …).

GET /api/rent/aggregates?department=69&type=appartement&room=2&year=2025

Filtres — types et exemples

Paramètre Type Exemples
year integer (YYYY) 2021, 2024, 2025
region INSEE region code (string, 2 chars) 11 (Île-de-France), 84 (Auvergne-Rhône-Alpes), 93 (PACA)
department department code (string, 2–3 chars) 75, 69, 2A, 971
city_code achat : code INSEE · location : {CP}_{slug} achat 75056 · location 69001_lyon
postal_code string (location only) 69001, 56170
city_name city name (string, case-insensitive) rouen, LYON, Paris
room integer (main rooms) 1, 2, 3, 4
type property type label (string, case-insensitive) Appartement, Dépendance, Local industriel, Maison — e.g. type=maison
scope enum (aggregates only) region, department, city
page / per_page integers (transactions) page=1, per_page=50 (max 200)

Les listes dynamiques (années importées, types présents en base) sont aussi disponibles via GET /api/meta.

Champs achat vs location

ConceptAchat (DVF)Location (Galactus)
Prixvaleur_fonciererent_price
Datedate_mutationpublished_at
Surfacesurfacesurface
Terrainland_surfaceland_surface
Volume agrégattransaction_countlisting_count
Moyenne agrégatavg_valeur_fonciere / avg_prix_m2avg_rent / avg_rent_m2
Min / max agrégatmin/max_valeur_fonciere · min/max_prix_m2min/max_rent · min/max_rent_m2

Mise à jour des données

# Achat (DVF)
php artisan dvf:import
php artisan dvf:import --year=2025 --force
php artisan dvf:refresh-aggregates

# Location (Galactus)
php artisan gedeon:import:location
php artisan gedeon:import:location --since-year=2021
php artisan rent:refresh-aggregates

# Contrôle (DB locale + API + Gédéon)
php artisan check:connectivity

Location : upsert par source_ad_id, année = YEAR(created). Les années N déjà en base ne sont jamais effacées.

Connectivité Gédéon

Postgres directe vers Galactus (lesiteimmov2), user RO. Même protocole en local et en k8s. Pas de tunnel SSH dans l’app : l’accès est contrôlé par UFW (ufw manager pour les nodes ; IP poste en local).

  1. Réseau — autoriser la source (node k8s ou IP locale) vers galactus:5432 via UFW.
  2. RuntimeGEDEON_DB_HOST / GEDEON_DB_PORT / GEDEON_DB_DATABASE=lesiteimmov2 / GEDEON_DB_USERNAME (RO) + mot de passe DB.
  3. Vérifierphp artisan check:connectivity (options --skip-api, --skip-gedeon).

Règles de gestion — agrégats location

Un agrégat location (région / département / commune × type × pièces × année) n’est conservé et exposé que si listing_count >= 3 (seuil configurable : GEDEON_MIN_LISTING_COUNT). En dessous, min_rent, max_rent, min_rent_m2, max_rent_m2 et les moyennes (avg_rent, avg_rent_m2) ne sont pas exploitables. Les annonces brutes restent disponibles via /api/rent/listings.