Case study · Collectivités territoriales

Automatiser la prospection de la Redevance Spéciale avec Power Query

Comment interroger les API publiques françaises depuis Excel pour constituer automatiquement la liste des entreprises assujetties à la redevance spéciale sur un territoire intercommunal.

CC Normandie Cabourg Pays d'Auge Power Query · Langage M API data.gouv.fr Avril 2026
38
communes couvertes par l'EPCI
2
API publiques interrogées
0 €
coût des données, sans clé API

Une tâche manuelle, répétée chaque année

La Redevance Spéciale (RS) est due par les professionnels qui produisent plus de 900 litres d'ordures ménagères par semaine sur au moins 4 semaines consécutives dans l'année. Pour un EPCI de 38 communes, identifier ces assujettis implique traditionnellement de croiser des fichiers Excel, des extractions SIRENE et des visites terrain - un processus long, source d'erreurs et difficile à maintenir à jour.

À cela s'ajoute une contrainte réglementaire : les professionnels assujettis à la RS sont exonérés de la TEOM. Un listing incomplet ou obsolète se traduit donc directement par des pertes de recettes ou des doubles facturations.

L'objectif : obtenir en un clic une liste à jour de tous les établissements actifs sur le territoire, prête à être enrichie pour le calcul et le suivi de la redevance.

Deux API publiques complémentaires

L'État met à disposition deux API gratuites, sans authentification, qui couvrent exactement le besoin :

geo.api.gouv.fr
Liste des communes d'un EPCI
Retourne les codes INSEE de toutes les communes membres à partir du code EPCI. Réponse JSON instantanée, aucune clé requise.
recherche-entreprises.api.gouv.fr
Établissements actifs par commune
Filtre par code INSEE et état actif (etat=A). Retourne SIRET, raison sociale, code NAF, adresse complète et coordonnées GPS de l'établissement local - pas du siège.

Un point important sur la localisation : l'API distingue l'objet siege (siège social, potentiellement à Paris pour une grande chaîne) de l'objet matching_etablissements (établissements réellement situés dans la commune requêtée). La requête utilise ce dernier pour garantir des coordonnées GPS locales et pertinentes.


Un enchaînement en trois requêtes Power Query

La solution s'organise autour de trois requêtes M imbriquées. La première est une fonction utilitaire réutilisable ; les deux suivantes font le travail de collecte et d'assemblage.

FnAppelAPI
Communes_EPCI
Entreprises_EPCI

Chaque requête appelle la précédente. FnAppelAPI centralise la gestion des codes d'erreur HTTP ; Communes_EPCI récupère les 38 codes INSEE en un seul appel ; Entreprises_EPCI itère sur chaque commune avec pagination automatique et agrège tous les résultats.

Requête 1 - Fonction d'appel API

Centralise les headers HTTP et la gestion silencieuse des erreurs. Retourne null en cas d'échec plutôt que de faire planter toute la requête.

FnAppelAPI Power Query M
// Fonction réutilisable - gère les erreurs HTTP silencieusement
(url as text) as any =>
let
    Source = try Json.Document(
        Web.Contents(url, [
            Headers = [
                Accept = "application/json",
                #"User-Agent" = "PowerQuery/1.0"
            ],
            ManualStatusHandling = {400, 404, 429, 500, 503}
        ])
    ) otherwise null
in
    Source

Requête 2 - Communes de l'EPCI

Un seul appel API suffit pour récupérer les 38 codes INSEE. La requête transforme la liste JSON en table Power Query exploitable.

Communes_EPCI Power Query M
let
    UrlCommunes = "https://geo.api.gouv.fr/epcis/200065563/communes"
                & "?fields=code,nom&format=json",

    Reponse = FnAppelAPI(UrlCommunes),

    ListeCommunes = if Reponse = null then {} else Reponse,

    TableCommunes = Table.FromList(
        ListeCommunes,
        Splitter.SplitByNothing(),
        null, null,
        ExtraValues.Error
    ),

    Expansion = Table.ExpandRecordColumn(
        TableCommunes, "Column1",
        {"code", "nom"},
        {"CodeCommune", "NomCommune"}
    )
in
    Expansion

Requête 3 - Entreprises avec pagination automatique

Le cœur du dispositif. Pour chaque commune, une fonction interne calcule le nombre total de pages à récupérer et les agrège. L'objet matching_etablissements garantit des coordonnées locales plutôt que celles du siège.

Entreprises_EPCI Power Query M
let
    NbParPage = 25,

    // Récupère une page de résultats pour une commune donnée
    FnUnePage = (codeCommune as text, page as number) as any =>
    let
        Url = "https://recherche-entreprises.api.gouv.fr/search?"
            & "code_commune=" & codeCommune
            & "&etat=A&per_page=" & Number.ToText(NbParPage)
            & "&page=" & Number.ToText(page),
        Reponse = FnAppelAPI(Url)
    in
        Reponse,

    // Récupère toutes les pages pour une commune (pagination auto)
    FnToutesPages = (codeCommune as text) as list =>
    let
        Page1 = FnUnePage(codeCommune, 1),
        EstValide = Page1 <> null
            and Record.HasFields(Page1, "results"),
        Resultats1 = if EstValide then Page1[results] else {},
        Total = if EstValide and Record.HasFields(Page1, "total_results")
                then Page1[total_results] else 0,
        NbPages = Number.RoundUp(Total / NbParPage),
        AutresPages = if NbPages <= 1 then {} else
            List.TransformMany(
                List.Numbers(2, NbPages - 1),
                (p) => let R = FnUnePage(codeCommune, p)
                       in if R <> null and Record.HasFields(R, "results")
                          then R[results] else {},
                (p, r) => r
            ),
        TousResultats = Resultats1 & AutresPages
    in
        TousResultats,

    // Itération sur les 38 communes de l'EPCI
    ListeCommunes = Communes_EPCI,
    AvecEntreprises = Table.AddColumn(
        ListeCommunes, "Entreprises",
        (ligne) => FnToutesPages(ligne[CodeCommune]),
        type list
    ),

    // Expansion : une ligne par entreprise
    Expansion1 = Table.ExpandListColumn(AvecEntreprises, "Entreprises"),
    SansNull = Table.SelectRows(Expansion1, each [Entreprises] <> null),

    // Extraction des champs entreprise et établissement local
    Expansion2 = Table.ExpandRecordColumn(SansNull, "Entreprises",
        {"nom_raison_sociale", "siren", "matching_etablissements"},
        {"RaisonSociale", "SIREN", "Etablissements"}
    ),

    // Expansion : une ligne par établissement local
    // (une entreprise peut avoir plusieurs établissements dans la commune)
    Expansion3 = Table.ExpandListColumn(Expansion2, "Etablissements"),
    SansNullEtab = Table.SelectRows(Expansion3, each [Etablissements] <> null),
    Expansion4 = Table.ExpandRecordColumn(SansNullEtab, "Etablissements",
        {"siret", "code_postal", "libelle_commune",
         "activite_principale", "latitude", "longitude"},
        {"SIRET", "CodePostal", "Commune",
         "CodeNAF", "Latitude", "Longitude"}
    ),

    TableFinale = Table.SelectColumns(Expansion4,
        {"RaisonSociale", "SIREN", "SIRET", "CodePostal",
         "Commune", "CodeNAF", "Latitude", "Longitude"}
    ),

    SansDoublons = Table.Distinct(TableFinale, {"SIRET"})
in
    SansDoublons

La table dans Excel

Une fois l'actualisation terminée (2 à 5 minutes pour les 38 communes), la table apparaît directement dans Excel avec toutes les colonnes prêtes à l'emploi.

Table des établissements assujettis dans Excel - colonnes RaisonSociale, SIREN, SIRET, CodePostal, Commune, CodeNAF, Latitude, Longitude

Possibilités une fois les données récupérées

La table obtenue devient le socle d'un outil de gestion complet. Plusieurs enrichissements sont envisageables sans quitter Excel :

Filtrage par code NAF
Cibler les secteurs d'activité les plus susceptibles de dépasser le seuil de 900 L/semaine : restauration, commerce alimentaire, industrie agroalimentaire…
Calcul automatique de la RS
En ajoutant le nombre de bacs et de levées, Excel calcule le montant annuel selon le barème délibéré (forfait + coût/levée OMR + tri).
Actualisation en un clic
Le fichier se met à jour automatiquement - nouveaux établissements, fermetures, changements d'activité - sans aucune ressaisie manuelle.
Cartographie des établissements
Les coordonnées GPS permettent une visualisation dans Power BI, QGIS, ou directement dans Excel via le type de données Géographie.
La même requête est réutilisable pour n'importe quel EPCI français : il suffit de remplacer le code 200065563 par celui de l'intercommunalité cible.