Find and fix listing errors

Filter a location's listings to the rows that need attention, read the publisher's reason, apply the matching fix, re-poll safely, and sweep the whole account.

Most listings sync without help. The ones that do not tell you why in displayStatus and syncIssue, and nearly every cause maps to one of five fixes. This guide walks from the raw listing rows to a per-account report of what is blocked and what to do about it.

1. Pull the listings and keep the problem rows

Fetch the premium listings and drop everything healthy. A row needs attention when actionRequired is true, or when syncStatus is FAILED, CANNOT_SUBMIT, or REQUIRING_ACTION. IN_PROGRESS and PENDING_APPROVAL are not errors; they are the publisher's queue.

Problem rows
curl -s https://listingsapi.com/api/v4/locations/TG9jYXRpb246MTgwMDI4OQ==/listings/premium \-H "Authorization: API $LISTINGSAPI_KEY" \| jq '[.data.listingsForLocation[]       | select(.actionRequired                or (.syncStatus | IN("FAILED", "CANNOT_SUBMIT", "REQUIRING_ACTION")))]'
JSON
{  "data": {    "listingsForLocation": [      {        "site": { "name": "Google Maps", "url": "maps.google.com" },        "syncStatus": "REQUIRING_ACTION",        "displayStatus": "Connect your account to sync the listing",        "actionRequired": true,        "syncIssue": null      },      {        "site": { "name": "Local Mint", "url": "localmint.com" },        "syncStatus": "FAILED",        "displayStatus": "Partner experiencing issues; awaiting response",        "actionRequired": false,        "syncIssue": "Publisher requires website URL"      }    ]  }}

2. Read the reason

Two fields explain a problem row. displayStatus is the platform's summary of where the row is. syncIssue is the publisher's own reason, when the publisher gave one. Read both: in the sample above, Local Mint's displayStatus says the partner is having issues, but syncIssue gives the real cause, a missing website.

FieldExampleUse it for
displayStatusConnect your account to sync the listingThe line you show a person.
syncIssuePublisher requires website URLPicking the fix. null when the publisher gave no reason.
actionRequiredtrueSorting: true means nothing moves until you act.

The location itself also carries a createErrors array on every read from List all locations. It holds validation problems found when the record was created and is a second place to look when a row fails with no syncIssue.

3. Map the cause to the fix

The same handful of causes account for almost every blocked row.

CauseHow it shows upFix
Account not connectedGoogle Maps, Facebook, Apple at REQUIRING_ACTION with Connect your account to sync the listing.Connect Google and import locations or Connect Facebook Pages. Apple follows the Google connection.
Missing websiteFAILED with syncIssue: Publisher requires website URL.Set bizUrl on the location. See Update a location.
Country not supported by the publisherCANNOT_SUBMIT, no syncIssue.Compare the location's countryIso with that site's supportedCountries from List plan sites. Nothing to fix; the publisher will not take it.
Hidden address not supportedCANNOT_SUBMIT or FAILED on a service-area business with hideAddress: true.Check the site's hideAddressSupportedCountries. Either show the address or accept that this publisher is skipped.
Description or category rejectedFAILED with a syncIssue naming the field.Update the description or subCategoryId on the location, then re-poll.

To check the country and hidden-address rules, pull the plan sites once and cache them; the list is unpaginated and rarely changes.

Plan sites
curl -s https://listingsapi.com/api/v4/plan-sites \-H "Authorization: API $LISTINGSAPI_KEY" \| jq '.data.planSites[] | select(.name == "Yelp")      | {name, supportedCountries, hideAddressSupportedCountries}'
JSON
{  "name": "Yelp",  "supportedCountries": ["US", "CA", "GB", "DE", "FR"],  "hideAddressSupportedCountries": ["US", "CA", "AU", "GB"]}

If the location's countryIso is not in supportedCountries, that publisher's row will never leave CANNOT_SUBMIT. Exclude it from your coverage figure rather than chasing it.

4. Re-poll after the fix

A location update triggers a fresh submission to the affected publishers. The row moves from FAILED or REQUIRING_ACTION back to IN_PROGRESS, then to SYNCED when the publisher accepts it. Publishers take minutes to weeks, so poll on a schedule measured in hours, not seconds.

Every poll counts against the rate limit. On a 429, read Retry-After and wait that many seconds; the SDKs raise RateLimitError with the same value.

Re-poll
# -D - prints response headers so you can see Retry-After on a 429curl -s -D - https://listingsapi.com/api/v4/locations/TG9jYXRpb246MTgwMDI4OQ==/listings/premium \-H "Authorization: API $LISTINGSAPI_KEY" \| grep -i -E "^HTTP|^Retry-After"

lastUpdate moving forward is the sign the publisher has looked at the new submission, even before syncStatus changes. If you have webhooks, the listing.submission event replaces this loop.

5. Run an account-wide sweep

To find every blocked row across the account, page through GET /locations (a cursor connection: first, after, edges[].node) and call the premium endpoint once per location. Collect the problem rows into one report keyed by location. The Python SDK follows cursors with auto_paging_iter(); the Node SDK does it with fetchAll: true. The samples reuse the backoff helper from step 4.

Account sweep
# One page of locations, then one listings call per location.# Repeat with &after=<pageInfo.endCursor> while hasNextPage is true.curl -s "https://listingsapi.com/api/v4/locations?first=50" \-H "Authorization: API $LISTINGSAPI_KEY" \| jq -r '.data.allLocations.edges[].node.id' \| while read -r id; do    curl -s "https://listingsapi.com/api/v4/locations/$id/listings/premium" \      -H "Authorization: API $LISTINGSAPI_KEY" \      | jq --arg id "$id" '[.data.listingsForLocation[]           | select(.syncStatus != "SYNCED" and .syncStatus != "COMPLETED")           | {location: $id, site: .site.name, status: .syncStatus, issue: .syncIssue}]'    sleep 6   # stay under 10 requests a minute on Launch  done

The report groups rows that are still in flight with rows that are truly blocked. Split it by the table in step 3 before handing it to anyone: IN_PROGRESS and PENDING_APPROVAL need patience, REQUIRING_ACTION needs a connection, and FAILED needs a field on the location.

Next steps