Aller au contenu

API publique

L’API REST de Digital Gap Finder donne accès, par programme, à la recherche d’entreprises, au détail de leur score de maturité numérique, aux listes de prospection et aux compteurs du compte. Elle est incluse au plan Agency.

Le contrat, c’est le segment /v1 du chemin — pas le numéro de version 1.0.0 du document. Une rupture de compatibilité donnerait un /api/v2 ; ce numéro-là, lui, suit la documentation.

Le document OpenAPI 3.1 complet est servi, sans clé, sur /api/v1/openapi : une spécification qu’il faut une clé pour lire est une spécification qu’on ne lit pas avant d’acheter.

1. Obtenir une clé

Les clés s’émettent depuis l’onglet API & webhooks des réglages du compte. Une clé commence par dgf_live_sk_ et ne s’affiche qu’une seule fois, à sa création : elle n’est pas stockée en clair, donc personne — pas même le support — ne peut vous la redonner. Une clé perdue se révoque et se remplace.

L’accès API est relu à chaque requête sur le plan courant du compte, pas seulement à l’émission de la clé. Un compte qui quitte le plan Agency reçoit 403 forbidden dès la requête suivante, sans que la clé soit pour autant révoquée.

2. Authentification

Authorization: Bearer dgf_live_sk_xxxxxxxxxxxxxxxxxxxxxxxx

C’est le seul moyen accepté : ni ?api_key=, ni X-API-Key. Une clé passée en paramètre d’URL finirait dans les journaux d’accès, dans l’historique du navigateur et dans l’en-tête Referer envoyé aux sites tiers. Et deux façons de s’authentifier, ce sont deux chemins à tenir cohérents et deux endroits où oublier une vérification.

3. Les huit endpoints

Toutes les réponses portent l’enveloppe du §4.4.2 : { success, data } en cas de succès, { success, error } en cas d’échec, plus meta sur les collections. La forme exacte de « data » n’est pas publiée : aucun schéma ne la décrit dans le produit, et la recopier ici la ferait mentir à la première évolution. Les exemples ci-dessous sont générés depuis les schémas : les champs de data y apparaissent donc vides.

Mêmes filtres que l’écran de recherche, combinés en ET logique. Un appel débite UN crédit de recherche, quel que soit le nombre de résultats.

ParamètreTypeDescription
qstringRecherche plein texte sur la dénomination.
nafstringCodes NAF, séparés par des virgules. Fusionnés sans doublon avec ceux du secteur.
sectorsante | restauration | btp | commerce | services-pro | education | transport | industrie | agriculture | culture-sport | services-entreprisesSecteur d’activité : il se développe en ses codes NAF.
regionstringCode de région INSEE.
departementstringCode de département.
postalstringCode postal : cinq chiffres exactement.
effectifMICRO | TPE | PME | ETITranche d’effectif.
score_minintegerScore de maturité numérique minimum. Un score BAS désigne un prospect chaud, pas un mauvais résultat.
score_maxintegerScore de maturité numérique maximum.
sortpertinence | score | created | effectifOrdre de tri des résultats.
pageintegerPage demandée, à partir de 1.
per_pageintegerRésultats par page. BORNÉ à 100, jamais refusé : en demander 5 000 rend 100 résultats, pas une erreur.
curl -X GET "https://digital-gap-finder.fr/api/v1/search" \
  -H "Authorization: Bearer dgf_live_sk_xxxxxxxxxxxxxxxxxxxxxxxx"

Réponse 200, générée depuis le schéma :

{
  "success": true,
  "data": [],
  "meta": {
    "page": 1,
    "per_page": 25,
    "total": 0
  }
}

GET /api/v1/leads/{siren}

Identité SIRENE et scoring de l’entreprise désignée par son SIREN.

  • siren — SIREN à neuf chiffres.
curl -X GET "https://digital-gap-finder.fr/api/v1/leads/000000000" \
  -H "Authorization: Bearer dgf_live_sk_xxxxxxxxxxxxxxxxxxxxxxxx"

Réponse 200, générée depuis le schéma :

{
  "success": true,
  "data": {}
}

GET /api/v1/leads/{siren}/score

Le détail des critères de maturité numérique, projeté par le plan du compte : un plan ne voit que les critères qu’il achète.

  • siren — SIREN à neuf chiffres.
curl -X GET "https://digital-gap-finder.fr/api/v1/leads/000000000/score" \
  -H "Authorization: Bearer dgf_live_sk_xxxxxxxxxxxxxxxxxxxxxxxx"

Réponse 200, générée depuis le schéma :

{
  "success": true,
  "data": {}
}

POST /api/v1/leads/enrich

Lot de 100 SIREN au maximum. UN crédit d’enrichissement est débité PAR SIREN traité : le lot n’est pas un forfait. Le traitement est séquentiel, parce que la cascade de fournisseurs porte un plafond de dépense.

curl -X POST "https://digital-gap-finder.fr/api/v1/leads/enrich" \
  -H "Authorization: Bearer dgf_live_sk_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"sirens":["000000000"]}'

Réponse 200, générée depuis le schéma :

{
  "success": true,
  "data": [],
  "meta": {
    "page": 1,
    "per_page": 25,
    "total": 0
  }
}

GET /api/v1/lists

Les listes du propriétaire de la clé, et d’elles seules.

curl -X GET "https://digital-gap-finder.fr/api/v1/lists" \
  -H "Authorization: Bearer dgf_live_sk_xxxxxxxxxxxxxxxxxxxxxxxx"

Réponse 200, générée depuis le schéma :

{
  "success": true,
  "data": [],
  "meta": {
    "page": 1,
    "per_page": 25,
    "total": 0
  }
}

POST /api/v1/lists/{id}/leads

Rend 201 : la requête CRÉE des leads. Le rapport distingue les ajouts des doublons ignorés.

  • id — Identifiant de la liste.
curl -X POST "https://digital-gap-finder.fr/api/v1/lists/lst_00000000/leads" \
  -H "Authorization: Bearer dgf_live_sk_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"sirens":["000000000"]}'

Réponse 201, générée depuis le schéma :

{
  "success": true,
  "data": {}
}

GET /api/v1/sequences/{id}/stats

Agrégat sur les envois de la séquence. Une séquence qui n’a rien envoyé rend des ZÉROS, pas une 404 : elle existe, elle n’a simplement pas d’historique.

  • id — Identifiant de la séquence.
curl -X GET "https://digital-gap-finder.fr/api/v1/sequences/seq_00000000/stats" \
  -H "Authorization: Bearer dgf_live_sk_xxxxxxxxxxxxxxxxxxxxxxxx"

Réponse 200, générée depuis le schéma :

{
  "success": true,
  "data": {}
}

GET /api/v1/usage

Les compteurs du compte pour la période en cours, avec la même sémantique qu’à l’écran. C’est ici qu’on lit ce qu’un 403 « quota_exceeded » a refusé.

curl -X GET "https://digital-gap-finder.fr/api/v1/usage" \
  -H "Authorization: Bearer dgf_live_sk_xxxxxxxxxxxxxxxxxxxxxxxx"

Réponse 200, générée depuis le schéma :

{
  "success": true,
  "data": {}
}

4. Pagination

Les collections se paginent par page (à partir de 1) et per_page (défaut : 25). Le bloc meta rend la page servie, sa taille et le total.

per_page est borné à 100, jamais refusé. En demander 5 000 rend 100 résultats et un meta.per_page à 100 — pas une erreur. Lisez donc la taille servie dans meta plutôt que de supposer celle que vous avez demandée.

5. Débit

100 requêtes par 60 secondes et par clé — pas par compte. Un compte qui détient trois clés ne verra donc pas une intégration en étrangler une autre ; c’est aussi pourquoi il vaut mieux une clé par intégration.

  • X-RateLimit-Limit et X-RateLimit-Remaining sont posés sur chaque réponse, y compris les 429 et les 500 : un client qui ne les recevrait que sur les succès ne pourrait pas réguler son débit au moment précis où il en a besoin.
  • Retry-After n’apparaît que sur les 429, et donne le nombre de secondes à attendre.

6. Les erreurs

StatutCodeQuand
400bad_requestParamètre ou corps de requête invalide. Le message nomme le champ fautif.
401unauthorizedEn-tête Authorization: Bearer absent, mal formé, inconnu ou révoqué. Les quatre cas rendent le MÊME message, délibérément.
403forbiddenLe plan COURANT du compte ne porte pas l’accès API. La clé reste valide ; c’est l’abonnement qui ne l’est plus.
403quota_exceededLe plafond mensuel du compte est atteint : recherches, leads révélés, exports ou enrichissements, selon l’appel.
404not_foundLa ressource demandée n’existe pas, ou n’appartient pas au propriétaire de la clé.
429rate_limitedDébit dépassé pour CETTE clé. La réponse porte Retry-After.
500server_errorPanne côté serveur. Aucun détail ne franchit la frontière publique.

403 « quota_exceeded » n’est pas un problème de droits

C’est le code que toute intégration finit par rencontrer, et celui qu’aucune documentation ne prend le temps d’expliquer. Le plafond mensuel du compte est atteint : recherches, leads révélés, exports ou enrichissements, selon l’appel. Votre clé est valide, votre plan porte bien l’accès API : c’est le plafond mensuel du compte qui est atteint — recherches, leads révélés, exports ou enrichissements selon l’appel.

Il ne se débloque donc pas en réessayant plus tard dans la minute, contrairement à un 429 : il se débloque au renouvellement de la période, ou en changeant de plan. C’est exactement pourquoi le code est 403 et non 429 — répondre 429 vous enverrait boucler pour rien jusqu’au 1er du mois.

L’état des compteurs se lit à tout moment par GET /api/v1/usage, qui ne débite aucun crédit.

{
  "success": false,
  "error": {
    "code": "quota_exceeded",
    "message": "…"
  }
}

401 : « clé absente » et « clé inconnue » rendent le même message

Quatre situations rendent un 401 unauthorized avec le même libellé : en-tête absent, en-tête mal formé, clé inconnue, clé révoquée. Ce n’est pas une approximation, c’est délibéré — distinguer « inconnue » de « révoquée » apprendrait à un attaquant laquelle de ses suppositions porte.

En revanche, une clé révoquée n’est jamais un 403 : « n’existe plus » et « vous n’avez pas le droit » sont deux réponses différentes, et les confondre enverrait chercher un problème d’abonnement là où il n’y en a pas.

7. SDK JavaScript

Un client TypeScript couvrant les huit endpoints est livré dans le dépôt, sous packages/sdk. Il pose l’en-tête d’authentification, remonte X-RateLimit-Remaining sur chaque résultat, rejoue une seule fois un 429 après le délai annoncé, et pagine par searchAll(). Il n’a aucune dépendance et ne met rien en cache.

Le paquet n’est pas encore publié sur npm. Aucune organisation npm n’existe à ce jour pour ce produit : afficher une commande d’installation qui rendrait une 404 serait pire que ne rien afficher. La commande qui fonctionne aujourd’hui est celle-ci, depuis une copie du dépôt :

pnpm --filter @dgf/sdk build
npm pack packages/sdk
npm install ./dgf-sdk-<version>.tgz

La procédure de publication, et le secret qui manque pour l’exécuter, sont décrits dans packages/sdk/README.md. Cette page affichera la commande d’installation le jour où elle sera vraie, et pas avant.

Ce que l’API ne lit pas

Trois filtres de la recherche existent dans le produit mais ne sont pas exposés par l’API. Ce n’est pas un oubli : les ajouter serait une modification d’API, qui mérite son propre arbitrage.

  • etatAdministratif — handlers.ts ne lit pas ce paramètre : l’API force la valeur par défaut du schéma (« A »), donc les entreprises cessées restent exclues (§3.1.3).
  • createdFrom — handlers.ts ne lit pas ce paramètre : il attend une Date, et aucune convention de sérialisation n’a été arbitrée pour l’API publique.
  • createdTo — handlers.ts ne lit pas ce paramètre, pour la même raison que createdFrom.