listings scanで事業者の掲載情報を監査

任意の事業者が地図、検索エンジン、ディレクトリ、AIアシスタントでどのように表示されるかを確認し、ディレクトリごとに名前、住所、電話番号の正確性を確認して、Webhookまたはポーリングで結果を取得します。

listings scan は、1つの事業者がlistingsAPIのディレクトリネットワーク全体でどのように掲載されているかを確認し、各ディレクトリで掲載情報が見つかったかどうかと、名称、住所、電話番号が指定した情報と一致するかどうかを示します。事業者がアカウント内の拠点として登録されている必要はありません。このガイドでは、スキャンを作成し、完了を待って結果を確認します。

次の用途に使用できます。

  • 導入前の見込み顧客の掲載状況を調査し、掲載情報の不足や誤りを最初の打ち合わせの議題にします。
  • 顧客の掲載情報を修正する前後で、掲載状況とNAP(名称、住所、電話番号)の一貫性を確認します。
  • 事業者をアカウントに追加せずに、AIエージェントが「この事業者はどのように掲載されていますか」という質問に回答できるようにします。

1. スキャンを作成する

POST /listings/scansは、事業者の情報を単一のinputオブジェクトとして受け取り、QUEUEDの状態のスキャンを即座に返します。ディレクトリの確認はバックグラウンドで実行されます。

フィールド必須補足
nameはい最大150文字です。
streetはい最大200文字です。
cityはい最大100文字です。
stateIsoはい(GBを除く)州または省のコードです。最大50文字です。
postalCodeはい(NGとAEを除く)最大20文字です。
countryIsoはいISO 3166-1の2文字コードです(例:US)。
phoneはい6〜15桁です。国内形式はcountryIsoに基づいて解釈され、先頭に+を付けた形式も使用できます。
Create a scan
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"}}JSON

レスポンスでは、phoneが国際形式に正規化されたスキャンが返されます。ディレクトリの確認が行われるまでresultsは空なので、idを保存しておいてください。

JSON
{  "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": []    }  }}

レスポンスにはquotaオブジェクトも含まれます。詳細は料金、制限、エラーで説明します。

先に進む前に、次の2点を確認してください。

  • reused。 過去7日間にスキャンした事業者を指定すると、listingsAPIは新しいスキャンを開始せずに、既存のスキャンをreused: trueと現在の状態(通常はCOMPLETED)とともに返します。利用可能回数は消費されず、そのスキャンについて新たなWebhookも送信されません。
  • errors。 リクエストが拒否された場合も、HTTP 200が返されます。拒否の詳細はdata.createListingScan.errorsに含まれ、scanはnullになります。電話番号が短すぎる場合は、次のようになります。
JSON
{  "data": {    "createListingScan": {      "reused": false,      "scan": null,      "errors": [        {          "code": "SY83003",          "message": "SY83003: Invalid value for phone",          "contextInfo": [            {              "key": "field",              "value": "phone"            }          ]        }      ]    }  }}

contextInfoは、検証に失敗したフィールドの名前を示します。返される可能性があるその他のコードは、エラー一覧に記載されています。

2. 結果を待つ

スキャンの状態は、QUEUEDからIN_PROGRESSへ、その後COMPLETEDまたはFAILEDへと変わります。ほとんどのスキャンは1〜7分で完了します。約15分経過しても応答しないディレクトリがある場合、そのディレクトリの結果はUNAVAILABLEに設定され、他の結果とともにスキャンが完了します。可能であればWebhookを使用し、ポーリングは代替手段としてのみ使用してください。

スキャンが最終状態に達すると、listingsAPIはlisting_scan.completedまたはlisting_scan.failedのイベントを1件、Webhook URLに送信します。そのdata.scanは、結果を含めてGETが返すオブジェクトと同じなので、後から取得する必要はありません。

JSON
{  "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": [ "..." ]    }  }}

ここではペイロードを省略して示しています。完全な例はイベントリファレンスにあります。イベントは他のすべてのイベントと同様に署名され、制限時間5秒で1回だけ配信が試行されるため、他の処理を行う前に署名を検証し、生のボディを保存して、受信確認を返してください。Webhookでイベントに対応するの受信処理には、これらの処理がすでに実装されています。必要な変更は、eventの分岐を1つ追加することだけです。

One more branch in your receiver
# 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}, 200

イベントは、Webhookが有効で、URLが検証済みのアカウントにのみ送信されます。アカウントがこの条件を満たさない場合やイベントが届かない場合は、スキャンをポーリングしてください。どちらの場合も、スキャンは90日間保持されます。署名の詳細は署名と検証を参照してください。

2b. 代替手段としてポーリングする

GET /listings/scans/{scanId}は、その時点で得られている結果を含むスキャンを返します。スキャンの実行中は、ディレクトリから応答があるたびにresultsが埋まり、summary.pendingは応答待ちのディレクトリ数を示します。ポーリングは15秒間隔で行い、それより短い間隔では行わないでください。各リクエストはレート制限の対象になります。

Poll until the scan finishes
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 15done
status意味
QUEUED受け付け済みで、開始を待っています。
IN_PROGRESSディレクトリを確認中です。resultsには一部の結果のみが含まれます。
COMPLETEDすべてのディレクトリの結果が得られています。resultsとsummaryは確定しています。
FAILEDサービスが一時的に利用できなかった場合(SY83010)など、スキャンを開始できませんでした。failureにはcodeとmessageが含まれ、resultsは空です。失敗したスキャンは利用枠を消費しないため、再度作成できます。

最近のスキャンまたは自身の拠点のいずれかのデータを使用して結果を返すスキャンは、作成時点でCOMPLETEDになるため、GETを1回実行するだけで十分です。

3. 結果を読む

完了したスキャンにはsummaryがあり、resultsには確認したディレクトリごとに1件のエントリが含まれます。エントリ数は国によって異なり、最大で約60件です。businessは、送信した入力を、phoneを国際形式に正規化して返します。

JSON
{  "total": 62,  "found": 21,  "accurate": 18,  "inaccurate": 2,  "notFound": 41,  "pending": 0,  "unavailable": 0}

totalはディレクトリの総数です。foundはビジネスを掲載しているディレクトリ数で、その内訳はaccurate、inaccurate、および後述する掲載の有無のみを確認できる掲載情報です。notFoundはビジネスを掲載していないディレクトリ数です。unavailableは今回確認できなかったディレクトリ数を示し、pendingが0以外になるのはスキャンの実行中のみです。

各結果には、そのディレクトリのstatusが含まれます。

結果のstatus意味
FOUNDディレクトリにビジネスが掲載されています。listingには掲載されている内容が含まれます。
NOT_FOUNDディレクトリを確認しましたが、ビジネスは掲載されていません。
UNAVAILABLE今回はディレクトリを確認できませんでした。これは未掲載と同じではないため、掲載漏れとして報告しないでください。後でそのディレクトリを再確認してください。
PENDINGまだ確認していません。スキャンの実行中にのみ表示されます。

FOUNDの結果では、accurateが掲載情報と入力の一致 여부を示します。

  • trueは、名前、住所、電話番号がすべて一致していることを意味します。
  • falseは、少なくとも1つが一致していないことを意味します。掲載情報にないフィールドも不一致として扱うため、電話番号のない掲載情報はfalseになります。
  • nullは、ビジネスは見つかったものの、フィールドごとの確認は行われていないことを意味します。

accuracyは、name、address、phoneのそれぞれについてstatusとmessageで判定内容を説明します。statusはACCURATE、INACCURATE、MISSINGのいずれかで、フィールドが正確な場合、messageはnullです。以下は、名前と住所は一致していますが、電話番号がないFacebookページの例です。

JSON
{  "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}

一部のディレクトリでは、ビジネスの存在のみを確認でき、比較に必要な詳細情報は表示されません。これらはFOUNDとして返され、accurate: nullが設定されます。また、foundにのみ計上され、accurateやinaccurateには計上されません。検証済みではなく、掲載ありとして扱ってください。

JSON
{  "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}

NOT_FOUNDの結果には、listingもaccuracyもありません。

JSON
{  "directory": {    "id": 352,    "name": "YellowPages",    "url": "www.yellowpages.com"  },  "status": "NOT_FOUND",  "accurate": null,  "accuracySource": "DIRECTORY_MATCH",  "accuracy": null,  "listing": null,  "syncStatus": null}

独自のデータを保持していないディレクトリもあります。Uber、Waze、LyftはGoogle Mapsのデータを表示し、CopilotはBingのデータを表示します。これらの結果は参照元のディレクトリを反映するため、通常はGoogle MapsやBingが返したものと同じ内容になり、掲載情報のurlはありません。summaryでは個別のエントリとして数えますが、独立した確認結果とは解釈しないでください。

JSON
{  "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}

ChatGPTやGeminiなどのAIアシスタントも含まれます。これらの場合、listingにはアシスタントが把握しているビジネスの情報が表示されますが、多くの場合は名前、完全な住所、電話番号のみで、フィールドごとのaccuracyはありません。

完了したスキャンから修正リストを作成するには、誤っているフィールドや欠けているフィールドがあるディレクトリをすべて出力します。

Directories that need attention
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)'

Joe's Pizzaのスキャンでは、Facebookに電話番号がないことと、Judys Bookに異なる電話番号が表示されていることを示す2行が出力されます。

Text
Facebook phone: No phone number on the listingJudys Book phone: Phone number does not match

結果の取得元

sourceはスキャン結果の取得方法を示し、resultsAsOfはデータが収集された日時を示します。

source意味
DIRECTORY_SEARCHディレクトリを新たに検索します。resultsAsOfは、このスキャンが完了した日時です。
RECENT_SCAN過去7日以内に、実行者を問わず同一のビジネスに対して実行されたスキャンのコピーです。即座に完了し、resultsAsOfは元のデータが収集された日時を示すため、createdAtより古い場合があります。
LOCATION_LISTINGS電話番号、郵便番号、国が自分の拠点のいずれかと一致したため、結果はその拠点の実際の掲載情報から取得されます。locationIdが設定され、accuracySourceはDIRECTORY_MATCHではなくSYNC_STATUSになり、各結果にはその掲載情報のsyncStatusが含まれます。

料金、制限、エラー

月間利用枠を消費するのは、新たに実行するDIRECTORY_SEARCHスキャンのみです。この利用枠はプランによって異なり、請求期間ごとにリセットされます。以下は無料です。

  • 7日以内に同じビジネスを再度スキャンする場合。自分が以前に実行したスキャンがreused: trueとともに返されます。
  • いずれかのアカウントが同じビジネスに対して最近実行したスキャンの結果を利用できる場合。これはRECENT_SCANのコピーです。
  • 自分の拠点のいずれかと一致するスキャン(LOCATION_LISTINGS)。
  • FAILEDで終了するスキャン。この場合、消費した利用枠は返還されます。

スキャンは90日間保存されます。その後、GETはSY83005とともに404を返します。

作成と一覧取得のレスポンスにはquotaオブジェクトが含まれるため、バッチ処理を開始する前に利用状況を確認できます。一覧取得では、perPageを使用し、resultsを使用せずに、1ページあたり1〜50件のスキャンを新しい順に返します。

Check your allowance
curl -s "https://listingsapi.com/api/v4/listings/scans?page=1&perPage=20" \-H "Authorization: API $LISTINGSAPI_KEY" \| jq '.data.listingScans.quota'
quotaフィールド意味
limit現在の期間にプランで許可されている新規スキャン数です。
usedこれまでに使用した新規スキャン数です。
remaininglimitからusedを引いた値で、0を下回ることはありません。
resetsAt利用枠がリセットされる日時です。

以下は、よく発生するエラーです。作成ではHTTP 200とともにレスポンスボディにエラーが返され、取得と一覧取得では通常のHTTPステータスが返されます。

コード発生箇所意味と対処方法
SY83002作成月間利用枠を使い切っています。メッセージには上限とリセット日時が含まれ、quotaが返されます。resetsAtまで待つか、過去7日以内のスキャンを無料で再利用してください。
SY83003作成、またはスキャンのfailure値が指定されていないか、無効です。contextInfoは該当するフィールド名を示します。入力を修正して再送信してください。
SY83004作成そのcountryIsoではListings scansを利用できません。
SY83001作成ご利用のプランにはlistings scansが含まれていません。
SY83005取得そのidのスキャンが存在しないか、スキャンが別のアカウントに属しているか、90日を超えています。HTTP 404が返されます。
SY83010作成、またはスキャンのfailureスキャンは一時的に利用できません。しばらくしてから再試行してください。
SY90016作成このキーは読み取り専用です。Writeキーを使用してください。

存在しないidに対するGETは、次の結果を返します。

JSON
{  "data": {    "listingScan": null  },  "errors": [    {      "message": "SY83005: Listing scan not found"    }  ]}

FAILEDで終了したスキャンでは、理由がfailureに格納され、resultsは空のままです。

JSON
{  "status": "FAILED",  "failure": {    "code": "SY83010",    "message": "SY83010: Listing scans are temporarily unavailable, try again later",    "field": null  }}

一般的なエラー形式はエラーコードに記載されています。

AIエージェント向け

ホスト型MCPサーバーは、この機能をlistings_scans_create、listings_scans_get、listings_scans_listの3つのツールとして提供します。アシスタントは、ユーザーが指定したビジネスのスキャンを開始し、listings_scans_getでポーリングして、対応が必要なディレクトリをまとめることができます。RESTと同様に、スキャンの作成にはWriteキーが必要です。設定方法はAIエージェントをlistingsAPI MCPに接続するに記載されています。

次の手順