使用 listings scan 审核企业商家信息

检查任意企业在地图、搜索引擎、目录和 AI 助手中的展示情况,查看各目录中名称、地址和电话号码的准确性,并通过 webhook 或轮询获取结果。

listings scan 会检查一个商家在 listingsAPI 目录网络中的商家信息,并逐个目录告知您是否找到了该商家,以及其名称、地址和电话是否与您提供的信息一致。该商家不必是您账户中的地点。本指南将创建一次扫描,等待扫描完成,然后读取结果。

您可以用它来:

  • 在为潜在客户办理入驻前进行审核,以便在首次沟通时讨论缺失或错误的商家信息;
  • 在修复客户的商家信息前后,检查其商家信息的覆盖情况以及 NAP(名称、地址、电话)的一致性;
  • 让 AI 智能体能够回答“这个商家的商家信息发布情况如何?”,而无需将该商家添加到账户中。

1. 创建扫描

POST /listings/scans 通过单个 input 对象接收商家信息,并立即返回处于 QUEUED 状态的扫描。目录检查在后台进行。

字段是否必填说明
name是最多 150 个字符。
street是最多 200 个字符。
city是最多 100 个字符。
stateIso是,GB 除外州或省代码,最多 50 个字符。
postalCode是,NG 和 AE 除外最多 20 个字符。
countryIso是由 2 个字母组成的 ISO 3166-1 代码,例如 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 会向您的 webhook URL 发送一个 listing_scan.completed 或 listing_scan.failed 事件。事件中的 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": [ "..." ]    }  }}

此处的负载已精简;完整示例见事件参考。与其他事件一样,这些事件会经过签名并投递,仅尝试 1 次,时限为 5 秒,因此请先验证签名、存储原始请求体并确认接收,再执行其他操作。使用 webhook 响应事件中的接收端已实现这些操作;唯一需要的更改是在 event 上增加一个分支。

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。

3. 读取结果

已完成的扫描包含一个 summary,并在 results 中为每个已检查的目录提供一个条目,具体数量取决于国家或地区,最多约 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 仅在扫描运行期间可能为非零值。

每个结果都有一个表示该目录状态的 status:

结果 status含义
FOUND该目录已收录此商家。listing 包含该目录显示的信息。
NOT_FOUND已检查该目录,其中未收录此商家。
UNAVAILABLE本次无法检查该目录。这不等同于未收录,因此请勿将其报告为缺失项。请稍后重新检查该目录。
PENDING尚未检查。仅在扫描运行期间出现。

对于 FOUND 结果,accurate 表示商家信息是否与您的输入匹配:

  • true 表示名称、地址和电话号码均匹配。
  • false 表示至少有一项不匹配。商家信息中缺失的字段也视为不匹配,因此没有电话号码的商家信息为 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 显示的电话号码则与输入不同。

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 为 SYNC_STATUS 而非 DIRECTORY_MATCH,且每条结果都包含对应商家信息的 syncStatus。

费用、限制和错误

只有全新的 DIRECTORY_SEARCH 扫描才会消耗您的月度配额,该配额取决于您的套餐,并随计费周期重置。以下扫描不消耗配额:

  • 在 7 天内重复扫描同一家商家。系统会返回您自己之前的扫描,并附带 reused: true;
  • 任何账户最近对同一家商家的扫描结果可用于本次扫描。此时返回的是 RECENT_SCAN 副本;
  • 与您自己的某个地点匹配的扫描(LOCATION_LISTINGS);
  • 以 FAILED 状态结束的扫描,其消耗的配额会退还。

扫描会保留 90 天。此后,GET 会返回 404,并附带 SY83005。

创建和列出操作的响应都包含一个 quota 对象,方便您在开始批量扫描前查看配额使用情况。列出操作按从新到旧的顺序返回您的扫描,每页包含 1 至 50 条,包含 perPage,不包含 results。

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 服务器通过 3 个工具提供此功能:listings_scans_create、listings_scans_get 和 listings_scans_list。助手可以为用户指定的商家启动扫描,使用 listings_scans_get 轮询扫描,并汇总需要关注的目录。与 REST 一样,创建扫描需要 Write 密钥。设置方法请参阅将 AI 智能体连接到 listingsAPI MCP。

后续步骤