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_xxxxxxxxxxxxxxxxxxxxxxxxC’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.
GET /api/v1/search
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ètre | Type | Description |
|---|---|---|
| q | string | Recherche plein texte sur la dénomination. |
| naf | string | Codes NAF, séparés par des virgules. Fusionnés sans doublon avec ceux du secteur. |
| sector | sante | restauration | btp | commerce | services-pro | education | transport | industrie | agriculture | culture-sport | services-entreprises | Secteur d’activité : il se développe en ses codes NAF. |
| region | string | Code de région INSEE. |
| departement | string | Code de département. |
| postal | string | Code postal : cinq chiffres exactement. |
| effectif | MICRO | TPE | PME | ETI | Tranche d’effectif. |
| score_min | integer | Score de maturité numérique minimum. Un score BAS désigne un prospect chaud, pas un mauvais résultat. |
| score_max | integer | Score de maturité numérique maximum. |
| sort | pertinence | score | created | effectif | Ordre de tri des résultats. |
| page | integer | Page demandée, à partir de 1. |
| per_page | integer | Ré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-LimitetX-RateLimit-Remainingsont 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-Aftern’apparaît que sur les 429, et donne le nombre de secondes à attendre.
6. Les erreurs
| Statut | Code | Quand |
|---|---|---|
| 400 | bad_request | Paramètre ou corps de requête invalide. Le message nomme le champ fautif. |
| 401 | unauthorized | En-tête Authorization: Bearer absent, mal formé, inconnu ou révoqué. Les quatre cas rendent le MÊME message, délibérément. |
| 403 | forbidden | Le plan COURANT du compte ne porte pas l’accès API. La clé reste valide ; c’est l’abonnement qui ne l’est plus. |
| 403 | quota_exceeded | Le plafond mensuel du compte est atteint : recherches, leads révélés, exports ou enrichissements, selon l’appel. |
| 404 | not_found | La ressource demandée n’existe pas, ou n’appartient pas au propriétaire de la clé. |
| 429 | rate_limited | Débit dépassé pour CETTE clé. La réponse porte Retry-After. |
| 500 | server_error | Panne 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>.tgzLa 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.