Auditer les fiches d’une entreprise avec un listings scan
Vérifiez toute entreprise sur cartes, moteurs, annuaires et assistants IA, ses nom/adresse/téléphone par annuaire ; résultats par webhook ou polling.
Un listings scan vérifie comment une entreprise figure dans le réseau d'annuaires listingsAPI et vous indique, annuaire par annuaire, si elle est présente et si son nom, son adresse et son numéro de téléphone correspondent aux informations que vous avez fournies. L'entreprise n'a pas besoin d'être un établissement de votre compte. Ce guide vous explique comment créer un scan, attendre qu'il se termine et consulter les résultats.
Utilisez-le pour :
- auditer un prospect avant de l'intégrer, afin de commencer le premier échange par les fiches manquantes ou incorrectes ;
- vérifier la présence d'un client et la cohérence de ses coordonnées NAP (nom, adresse, téléphone) avant et après la correction de ses fiches ;
- permettre à un agent IA de répondre à la question « Comment cette entreprise est-elle répertoriée ? » sans ajouter l'entreprise au compte.
1. Créer le scan
POST /listings/scans reçoit les informations de l'entreprise dans un seul objet input et renvoie immédiatement le scan à l'état QUEUED. Les annuaires sont vérifiés en arrière-plan.
curl -X POST https://listingsapi.com/api/v4/listings/scans \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d @- <<'JSON'{"input": { "name": "Joe's Pizza", "street": "7 Carmine Street", "city": "New York", "stateIso": "NY", "postalCode": "10014", "countryIso": "US", "phone": "2123661182"}}JSONLa réponse renvoie le scan, avec phone normalisé au format international. results reste vide tant que les annuaires n'ont pas été vérifiés ; conservez donc id.
{ "data": { "createListingScan": { "reused": false, "scan": { "id": "TGlzdGluZ1NjYW46Mzk0YTRhNWMtZjcwMy00NjZiLTg2NjAtMDU4MTlmNDhkZjMz", "status": "QUEUED", "source": "DIRECTORY_SEARCH", "locationId": null, "resultsAsOf": null, "createdAt": "2026-11-05T07:01:08Z", "startedAt": null, "completedAt": null, "business": { "name": "Joe's Pizza", "street": "7 Carmine Street", "city": "New York", "stateIso": "NY", "postalCode": "10014", "countryIso": "US", "phone": "+12123661182" }, "summary": { "total": 0, "found": 0, "accurate": 0, "inaccurate": 0, "notFound": 0, "pending": 0, "unavailable": 0 }, "failure": null, "results": [] }, "errors": [] } }}La réponse inclut également un objet quota, décrit dans Coûts, limites et erreurs.
2 points à vérifier avant de continuer :
reused. Lorsque vous demandez un scan pour une entreprise que vous avez déjà scannée au cours des 7 derniers jours, listingsAPI renvoie ce scan au lieu d'en lancer un nouveau, avecreused: trueet son état actuel, généralementCOMPLETED. Rien n'est décompté de votre quota et aucun nouveau webhook n'est envoyé pour ce scan.errors. Même lorsqu'une requête est rejetée, le statut HTTP renvoyé est200. Le rejet est indiqué dansdata.createListingScan.errors, etscanvautnull. Voici un exemple pour un numéro de téléphone trop court :
{ "data": { "createListingScan": { "reused": false, "scan": null, "errors": [ { "code": "SY83003", "message": "SY83003: Invalid value for phone", "contextInfo": [ { "key": "field", "value": "phone" } ] } ] } }}contextInfo indique le nom du champ dont la validation a échoué. Les autres codes possibles figurent dans le tableau des erreurs.
2. Attendre les résultats
Un scan passe de QUEUED à IN_PROGRESS, puis à COMPLETED ou FAILED. La plupart se terminent en 1 à 7 minutes. Si un annuaire n'a pas répondu après environ 15 minutes, son résultat est défini sur UNAVAILABLE et le scan se termine avec les autres résultats. Utilisez un webhook si possible et ne recourez aux interrogations périodiques qu'en solution de repli.
2a. Recevoir le webhook (recommandé)
Lorsque le scan atteint un état final, listingsAPI envoie un événement listing_scan.completed ou listing_scan.failed à l'URL de votre webhook. Son data.scan est le même objet que celui renvoyé par GET, résultats inclus ; vous n'avez donc rien à récupérer ensuite.
{ "event": "listing_scan.completed", "timestamp": "2026-11-05T07:01:52Z", "account_id": 12345, "data": { "scan": { "id": "TGlzdGluZ1NjYW46Mzk0YTRhNWMtZjcwMy00NjZiLTg2NjAtMDU4MTlmNDhkZjMz", "status": "COMPLETED", "summary": { "total": 62, "found": 21, "accurate": 18, "inaccurate": 2, "notFound": 41, "pending": 0, "unavailable": 0 }, "results": [ "..." ] } }}Le contenu de l'événement est abrégé ici ; l'exemple complet figure dans la référence des événements. Les événements sont signés et transmis comme tous les autres événements, avec une seule tentative et un délai maximal de 5 secondes ; vérifiez donc la signature, stockez le corps brut et accusez réception avant toute autre opération. Le récepteur présenté dans Réagir aux événements avec les webhooks effectue déjà ces opérations ; la seule modification consiste à ajouter une branche pour event.
# After the signature check and the endpoint.verification branch:if body.get("event") in ("listing_scan.completed", "listing_scan.failed"): inbox.put(raw) # commit before the 200; read data.scan from the queue return {"received": True}, 200Un événement est envoyé uniquement aux comptes dont les webhooks sont activés et dont l'URL est vérifiée. Si votre compte ne remplit pas ces conditions, ou si un événement n'arrive jamais, interrogez périodiquement le scan ; celui-ci est conservé pendant 90 jours dans tous les cas. Les détails concernant la signature figurent dans Signatures et vérification.
2b. Interroger périodiquement en solution de repli
GET /listings/scans/{scanId} renvoie l’analyse avec les résultats disponibles à ce stade. Pendant l’analyse, results se remplit à mesure que les annuaires répondent et summary.pending compte ceux dont la réponse est encore attendue. Interrogez toutes les 15 secondes, pas plus souvent ; chaque requête est prise en compte dans votre limite de débit.
SCAN_ID="TGlzdGluZ1NjYW46Mzk0YTRhNWMtZjcwMy00NjZiLTg2NjAtMDU4MTlmNDhkZjMz" while true; doscan=$(curl -s "https://listingsapi.com/api/v4/listings/scans/$SCAN_ID" \ -H "Authorization: API $LISTINGSAPI_KEY")status=$(echo "$scan" | jq -r '.data.listingScan.status')echo "status: $status"case "$status" in COMPLETED|FAILED) echo "$scan" | jq '.data.listingScan | {status, summary, failure}' break ;; null) echo "$scan" break ;;esacsleep 15doneUne analyse dont les résultats proviennent d’une analyse récente ou de l’un de vos propres établissements est COMPLETED dès sa création ; un seul appel à GET suffit donc.
3. Lire les résultats
Une analyse terminée contient un summary et une entrée dans results pour chaque annuaire vérifié, jusqu’à environ 60 selon le pays. business renvoie les données que vous avez envoyées, avec phone normalisé au format international.
{ "total": 62, "found": 21, "accurate": 18, "inaccurate": 2, "notFound": 41, "pending": 0, "unavailable": 0}total est le nombre d’annuaires. found indique combien répertorient l’entreprise et se répartit entre accurate, inaccurate et les éventuelles fiches qui confirment uniquement sa présence, décrites ci-dessous. notFound indique combien ne la répertorient pas. unavailable compte les annuaires qui n’ont pas pu être vérifiés cette fois-ci, et pending n’est différent de zéro que pendant l’analyse.
Chaque résultat comporte un status pour l’annuaire :
Pour un résultat FOUND, accurate indique si la fiche correspond aux données que vous avez fournies :
truesignifie que le nom, l’adresse et le numéro de téléphone correspondent tous.falsesignifie qu’au moins l’un d’eux ne correspond pas. Un champ absent de la fiche est considéré comme une non-correspondance ; une fiche sans numéro de téléphone est doncfalse.nullsignifie que l’entreprise a été trouvée, mais qu’aucune vérification champ par champ n’a été effectuée.
accuracy explique le résultat de la comparaison avec un status et un message pour chacun des champs name, address et phone. status vaut ACCURATE, INACCURATE ou MISSING, et message vaut null lorsque le champ est exact. Voici une page Facebook dont le nom et l’adresse correspondent, mais qui ne comporte aucun numéro de téléphone :
{ "directory": { "id": 184, "name": "Facebook", "url": "facebook.com" }, "status": "FOUND", "accurate": false, "accuracySource": "DIRECTORY_MATCH", "accuracy": { "name": { "status": "ACCURATE", "message": null }, "address": { "status": "ACCURATE", "message": null }, "phone": { "status": "MISSING", "message": "No phone number on the listing" } }, "listing": { "name": "Joe's Pizza", "street": "7 Carmine St", "city": "New York", "state": "NY", "postalCode": "10014", "country": "US", "fullAddress": "7 Carmine St, New York, NY 10014", "phones": [], "url": "https://www.facebook.com/177353602413952" }, "syncStatus": null}Certains annuaires confirment uniquement que l’entreprise existe et n’affichent pas assez de détails pour permettre une comparaison. Leurs résultats sont FOUND avec accurate: null et sont comptabilisés uniquement dans found, pas dans accurate ni dans inaccurate. Considérez ces fiches comme présentes, pas comme vérifiées :
{ "directory": { "id": 374, "name": "Map Quest", "url": "www.mapquest.com" }, "status": "FOUND", "accurate": null, "accuracySource": "DIRECTORY_MATCH", "accuracy": { "name": { "status": "ACCURATE", "message": null }, "address": { "status": "MISSING", "message": "Not shown" }, "phone": { "status": "MISSING", "message": "Not shown" } }, "listing": { "name": "Joe's Pizza", "street": "7 Carmine St", "city": "New York", "state": "NY", "postalCode": "10014", "country": null, "fullAddress": "7 Carmine St, New York, NY 10014, US", "phones": [], "url": null }, "syncStatus": null}Un résultat NOT_FOUND ne comporte ni listing ni accuracy :
{ "directory": { "id": 352, "name": "YellowPages", "url": "www.yellowpages.com" }, "status": "NOT_FOUND", "accurate": null, "accuracySource": "DIRECTORY_MATCH", "accuracy": null, "listing": null, "syncStatus": null}Plusieurs annuaires ne disposent pas de leurs propres données. Uber, Waze et Lyft affichent les données de Google Maps, et Copilot affiche celles de Bing. Leurs résultats reflètent ceux de l’annuaire source ; ils reprennent donc généralement ce que Google Maps ou Bing a renvoyé et ne comportent pas de url de fiche. Comptez-les comme des entrées distinctes dans summary, mais ne les considérez pas comme une confirmation indépendante :
{ "directory": { "id": 350, "name": "Uber", "url": "uber.com" }, "status": "FOUND", "accurate": true, "accuracySource": "DIRECTORY_MATCH", "accuracy": { "name": { "status": "ACCURATE", "message": null }, "address": { "status": "ACCURATE", "message": null }, "phone": { "status": "ACCURATE", "message": null } }, "listing": { "name": "Joe's Pizza", "street": "7 Carmine Street", "city": "New York", "state": "NY", "postalCode": "10014", "country": "US", "fullAddress": "7 Carmine St, New York, NY 10014, USA", "phones": [ "+1 212-366-1182" ], "url": null }, "syncStatus": null}Les assistants IA tels que ChatGPT et Gemini sont également inclus. Pour eux, listing affiche ce que l’assistant sait de l’entreprise, souvent uniquement un nom, une adresse complète et un numéro de téléphone, et il n’y a pas de accuracy par champ.
Pour transformer une analyse terminée en liste de corrections, affichez chaque annuaire comportant un champ incorrect ou manquant :
curl -s https://listingsapi.com/api/v4/listings/scans/TGlzdGluZ1NjYW46Mzk0YTRhNWMtZjcwMy00NjZiLTg2NjAtMDU4MTlmNDhkZjMz \-H "Authorization: API $LISTINGSAPI_KEY" \| jq -r '.data.listingScan.results[] | select(.accurate == false) | .directory.name as $directory | .accuracy | to_entries[] | select(.value.status != "ACCURATE") | $directory + " " + .key + ": " + (.value.message // .value.status)'Pour l’analyse de Joe's Pizza, cela affiche deux lignes : Facebook ne comporte aucun numéro de téléphone, et Judys Book en affiche un différent.
Facebook phone: No phone number on the listingJudys Book phone: Phone number does not matchOrigine des résultats
source indique comment les résultats de l'analyse ont été obtenus, et resultsAsOf indique quand les données ont été collectées.
Coûts, limites et erreurs
Seule une nouvelle analyse DIRECTORY_SEARCH est décomptée de votre quota mensuel, qui dépend de votre forfait et est réinitialisé à chaque période de facturation. Les opérations suivantes sont gratuites :
- relancer une analyse de la même entreprise dans un délai de 7 jours. Votre propre analyse précédente est renvoyée avec
reused: true; - une analyse dont les résultats peuvent être fournis par une analyse récente de la même entreprise, effectuée depuis n'importe quel compte. Il s'agit d'une copie
RECENT_SCAN; - les analyses qui correspondent à l'un de vos établissements (
LOCATION_LISTINGS) ; - les analyses qui se terminent avec l'état
FAILED, qui sont remboursées.
Les analyses sont conservées pendant 90 jours. Passé ce délai, GET renvoie 404 avec SY83005.
Les réponses des opérations de création et de consultation de la liste incluent un objet quota, ce qui vous permet de connaître votre consommation avant de lancer un lot. L'opération de consultation de la liste renvoie vos analyses de la plus récente à la plus ancienne, par pages de 1 à 50 résultats avec perPage, sans results.
curl -s "https://listingsapi.com/api/v4/listings/scans?page=1&perPage=20" \-H "Authorization: API $LISTINGSAPI_KEY" \| jq '.data.listingScans.quota'Voici les erreurs que vous rencontrerez le plus souvent. L'opération de création renvoie ses erreurs dans le corps de la réponse avec le statut HTTP 200 ; les opérations de récupération et de consultation de la liste renvoient le statut HTTP habituel.
Une requête GET pour un id inexistant renvoie :
{ "data": { "listingScan": null }, "errors": [ { "message": "SY83005: Listing scan not found" } ]}Lorsqu'une analyse se termine avec l'état FAILED, la raison est indiquée dans failure, et results reste vide :
{ "status": "FAILED", "failure": { "code": "SY83010", "message": "SY83010: Listing scans are temporarily unavailable, try again later", "field": null }}Le format général des erreurs est décrit dans Codes d'erreur.
Pour les agents IA
Le serveur MCP hébergé expose cette fonctionnalité au moyen de 3 outils : listings_scans_create, listings_scans_get et listings_scans_list. Un assistant peut lancer une analyse pour une entreprise désignée par l'utilisateur, en consulter régulièrement l'état avec listings_scans_get et résumer les annuaires qui nécessitent une intervention. Comme avec REST, la création d'une analyse nécessite une clé Write. La configuration est décrite dans Connecter des agents IA au serveur MCP de listingsAPI.
Étapes suivantes
- Réagir aux événements avec des webhooks : le récepteur auquel les événements d'analyse sont envoyés.
- Vérifier l'état des fiches et les liens vers les fiches en ligne et Rechercher et corriger les erreurs des fiches : une fois l'entreprise ajoutée comme établissement à votre compte, suivez et corrigez ses fiches.
- Ajouter un établissement : ajoutez l'entreprise que vous avez auditée.
- Référence : Créer un listings scan, Récupérer un listings scan, Répertorier les listings scans, Référence des événements, Codes d'erreur.