listings scan으로 업체 등록 정보 점검

어떤 업체든 지도, 검색 엔진, 디렉터리, AI 어시스턴트에 어떻게 표시되는지 확인하고, 디렉터리별 이름, 주소, 전화번호의 정확성을 확인하며, 웹훅 또는 폴링으로 결과를 받으세요.

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예US과 같은 2자리 알파벳 ISO 3166-1 코드입니다.
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입니다. 할당량은 차감되지 않으며, 해당 스캔에 대한 새 웹훅도 전송되지 않습니다.
  • 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으로 설정되고, 나머지 결과와 함께 스캔이 완료됩니다. 가능하면 웹훅을 사용하고, 대체 수단으로만 폴링을 사용하세요.

스캔이 최종 상태에 도달하면 listingsAPI은 웹훅 URL로 listing_scan.completed 또는 listing_scan.failed 이벤트를 1개 전송합니다. 이벤트의 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초이므로, 다른 처리를 시작하기 전에 서명을 검증하고 원본 본문을 저장한 다음 수신 확인 응답을 보내세요. 웹훅으로 이벤트에 대응하기의 수신 코드는 이미 이 작업을 수행하므로, 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

이벤트는 웹훅이 활성화되어 있고 검증된 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은 하나 이상이 일치하지 않는다는 의미입니다. 등록 정보에서 빠진 필드는 불일치로 처리되므로, 전화번호가 없는 등록 정보는 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}

일부 디렉터리는 업체의 존재 여부만 확인하며, 비교에 필요한 세부 정보를 충분히 표시하지 않습니다. 이러한 결과는 accurate: null이 포함된 FOUND으로 반환되며, 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~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에 연결하기에 설명되어 있습니다.

다음 단계