# Listings

Source: https://ceyo.ai/docs/signal/listings

### Listings

Read a location's configured listing identity, observed profile, scheduled scan records, and listing findings.

> **Authentication**
>
> Send a platform API key in the `Authorization` header as `Bearer ceyo_platform_...`, or in `X-Api-Key`. The key requires `listings:read` and access to the requested project and location. Project and location path identifiers accept Ceyo UUIDs or partner external IDs.

### Get listing profile

`GET /projects/{project_id}/locations/{location_id}/listings/profile`

Returns the listing identity, newest retained profile, and latest scan summary for a location.

#### Path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |
| `location_id` | location UUID \| location external ID | Required | Location identifier belonging to the project. |

#### Response envelope

`listing`:**ConfiguredListing | null**`profile`:**ListingProfile | null**`latest_scan`:**ScanSummary | null**

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `listing` | ConfiguredListing \| null |  | Configured listing identity, or null when listings are disabled or the location has no configured place. |
| `profile` | ListingProfile \| null |  | Profile from the newest succeeded scan with available profile data, or null when unavailable. |
| `latest_scan` | ScanSummary \| null |  | Newest listing scan summary, or null before any scan. |

#### ConfiguredListing

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `name` | string |  | Configured listing or location name. |
| `address` | string \| null |  | Configured location address. |
| `google_maps_url` | string \| null |  | Public Google Maps URL for the configured place. |

#### ListingProfile

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `place_id` | string |  | Place identifier represented by this profile. |
| `name` | string \| null |  | Public business name. |
| `formatted_address` | string \| null |  | Publicly formatted business address. |
| `website_url` | string \| null |  | Public website linked from the listing. |
| `national_phone_number` | string \| null |  | Phone number formatted for the listing country. |
| `international_phone_number` | string \| null |  | Phone number in international format. |
| `google_maps_url` | string \| null |  | Public Google Maps URL. |
| `business_status` | string \| null |  | Current public operating status. |
| `primary_type` | string \| null |  | Machine-readable primary business type. |
| `primary_type_display_name` | string \| null |  | Display name for the primary business type. |
| `types` | string\[\] |  | Normalized business type keys associated with the place. |
| `rating` | number \| null |  | Public average review rating. |
| `review_count` | integer \| null |  | Number of public ratings represented by the average. |
| `regular_opening_hours` | OpeningHours \| null |  | Normalized weekly opening schedule and special-day notices. |
| `editorial_summary` | string \| null |  | Public editorial description of the business. |
| `reviews` | Review\[\] |  | Up to the 50 most recent public reviews available with the profile. |
| `attributes` | ListingAttributes |  | Normalized service, accessibility, parking, payment, dining, and amenity attributes. |

#### OpeningHours

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `open_now` | boolean \| null |  | Whether the business is open at the profile observation time. |
| `periods` | OpeningPeriod\[\] |  | Weekly periods containing open and, when applicable, close day and time values. |
| `weekday_descriptions` | string\[\] |  | Human-readable hours for each represented weekday. |
| `special_days` | SpecialDay\[\] |  | Special-day entries with an ISO date and an exceptional\_hours flag. |

#### OpeningPeriod

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `open` | OpeningPoint |  | Opening point with day, hour, minute, and optional date. |
| `close` | OpeningPoint \| null |  | Closing point when the period has a defined close time. |

#### OpeningPoint

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `day` | integer |  | Day of week from 0 (Sunday) through 6 (Saturday). |
| `hour` | integer |  | Hour from 0 through 23. |
| `minute` | integer |  | Minute from 0 through 59. |
| `date` | date |  | Calendar date when the point represents a dated schedule. Omitted otherwise. |

#### SpecialDay

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `date` | ISO date |  | Calendar date in YYYY-MM-DD format. |
| `exceptional_hours` | boolean |  | Whether the date uses hours that differ from the regular schedule. |

#### Review

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `rating` | number \| null |  | Review rating. |
| `text` | string \| null |  | Public review text. |
| `publish_time` | datetime \| null |  | Review publication time. |
| `relative_publish_time` | string \| null |  | Human-readable relative publication time. |
| `google_maps_url` | string \| null |  | Public Google Maps URL for the review. |
| `author` | ReviewAuthor \| null |  | Public reviewer attribution when available. |

#### ReviewAuthor

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `display_name` | string \| null |  | Public display name of the reviewer. |
| `uri` | string \| null |  | Public reviewer profile URL. |
| `photo_uri` | string \| null |  | Public reviewer profile image URL. |

#### ListingAttributes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `accessibility_options` | BooleanAttributeMap |  | Normalized boolean accessibility options keyed by snake\_case attribute names. |
| `payment_options` | BooleanAttributeMap |  | Normalized boolean payment options keyed by snake\_case attribute names. |
| `parking_options` | BooleanAttributeMap |  | Normalized boolean parking options keyed by snake\_case attribute names. |
| `delivery` | boolean \| null |  | Whether delivery is offered. |
| `dine_in` | boolean \| null |  | Whether dine-in service is offered. |
| `takeout` | boolean \| null |  | Whether takeout is offered. |
| `reservable` | boolean \| null |  | Whether reservations are accepted. |
| `serves_breakfast` | boolean \| null |  | Whether breakfast is served. |
| `serves_lunch` | boolean \| null |  | Whether lunch is served. |
| `serves_dinner` | boolean \| null |  | Whether dinner is served. |
| `serves_beer` | boolean \| null |  | Whether beer is served. |
| `serves_wine` | boolean \| null |  | Whether wine is served. |
| `serves_vegetarian_food` | boolean \| null |  | Whether vegetarian food is served. |

#### BooleanAttributeMap

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `{attribute_name}` | boolean |  | Boolean value keyed by a snake\_case accessibility, payment, or parking attribute name. |

#### ScanSummary

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `id` | uuid |  | Listing scan identifier. |
| `status` | pending \| running \| succeeded \| failed \| skipped |  | Current or terminal scan status. |
| `score` | integer \| null |  | Listing quality score from 0 to 100 when available. |
| `grade` | strong \| good \| needs\_attention \| weak \| null |  | Quality grade derived from the score. |
| `error_message` | string \| null |  | Customer-safe explanation when the scan failed. |
| `completed_at` | datetime \| null |  | Time scan processing reached a terminal status. |
| `created_at` | datetime |  | Time the scan was created. |

> **Provider field availability**
>
> Profile, review, author, and attribute objects are sparse. Provider fields are omitted when unavailable; fields explicitly documented as nullable may be returned as `null`.

> **Profile availability**
>
> `profile` is selected from the newest succeeded scan with a non-empty retained profile. It is `null` when no such profile is available. Detailed profile data is retained for 29 days; historical scan scores and checks remain available through the scan endpoints.

> **Disabled or unconfigured listings**
>
> This endpoint returns `200` when no listing data is available. In that case, `listing`, `profile`, and `latest_scan` are null.

#### Request and response

```curl
curl --request GET \
  --url 'https://api.signal.ceyo.ai/v1/projects/{project_id}/locations/{location_id}/listings/profile' \
  --header 'Authorization: Bearer ceyo_platform_...'
```

```json
{
  "listing": {
    "name": "Harbour Coffee",
    "address": "12 Market Street, Dublin 2, Ireland",
    "google_maps_url": "https://maps.google.com/?cid=123456789"
  },
  "profile": {
    "place_id": "ChIJN1t_tDeuEmsRUsoyG83frY4",
    "name": "Harbour Coffee",
    "formatted_address": "12 Market Street, Dublin 2, Ireland",
    "website_url": "https://harbourcoffee.example",
    "national_phone_number": "01 555 0142",
    "international_phone_number": "+353 1 555 0142",
    "google_maps_url": "https://maps.google.com/?cid=123456789",
    "business_status": "OPERATIONAL",
    "primary_type": "coffee_shop",
    "primary_type_display_name": "Coffee shop",
    "types": ["coffee_shop", "cafe", "food"],
    "rating": 4.6,
    "review_count": 187,
    "regular_opening_hours": {
      "open_now": true,
      "periods": [
        {
          "open": {"day": 1, "hour": 7, "minute": 30},
          "close": {"day": 1, "hour": 18, "minute": 0}
        }
      ],
      "weekday_descriptions": [
        "Monday: 7:30 AM – 6:00 PM",
        "Tuesday: 7:30 AM – 6:00 PM"
      ],
      "special_days": [
        {
          "date": "2026-08-03",
          "exceptional_hours": true
        }
      ]
    },
    "editorial_summary": "Independent coffee shop serving seasonal drinks.",
    "reviews": [
      {
        "rating": 5,
        "text": "Friendly team and excellent coffee.",
        "publish_time": "2026-07-25T11:14:00Z",
        "relative_publish_time": "a week ago",
        "google_maps_url": "https://maps.google.com/reviews/example",
        "author": {
          "display_name": "A. Customer",
          "uri": "https://maps.google.com/maps/contrib/456",
          "photo_uri": "https://lh3.googleusercontent.com/a/reviewer"
        }
      }
    ],
    "attributes": {
      "accessibility_options": {"wheelchair_accessible_entrance": true},
      "payment_options": {"accepts_credit_cards": true},
      "parking_options": {"street_parking": true},
      "delivery": false,
      "dine_in": true,
      "takeout": true,
      "reservable": false,
      "serves_breakfast": true,
      "serves_lunch": true,
      "serves_dinner": false,
      "serves_beer": false,
      "serves_wine": false,
      "serves_vegetarian_food": true
    }
  },
  "latest_scan": {
    "id": "ea0c4cdd-430e-444e-8446-cbe8d47edb56",
    "status": "succeeded",
    "score": 82,
    "grade": "good",
    "error_message": null,
    "completed_at": "2026-07-30T09:40:03Z",
    "created_at": "2026-07-30T09:39:58Z"
  }
}
```

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "not_found",
    "message": "The requested resource was not found.",
    "details": null,
    "request_id": "req_01K1JQY1RQQ7N3C5H1K6J0P8AT"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `401` | invalid\_api\_key |  | The API key is absent, invalid, expired, or revoked. |
| `403` | forbidden |  | The API key lacks listings:read or cannot access the requested location. |
| `404` | not\_found |  | The project, location, or visibility scope was not found. |
| `429` | rate\_limit\_exceeded |  | Too many requests were made. |

### List listing scans

`GET /projects/{project_id}/locations/{location_id}/listings/scans`

Returns listing scan summaries for a location, ordered newest first.

#### Path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |
| `location_id` | location UUID \| location external ID | Required | Location identifier belonging to the project. |

#### Query parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `page` | integer | Optional; Default: 1 | The 1-based page number. |
| `per_page` | integer | Optional; Default: 20 | Number of scans per page. Maximum: 50. |

#### Response envelope

`scans`:**ScanSummary\[\]**`pagination`:**Pagination**

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `scans` | ScanSummary\[\] |  | Scan summaries ordered newest first. |
| `pagination` | Pagination |  | Pagination metadata. |

#### ScanSummary

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `id` | uuid |  | Listing scan identifier. |
| `status` | pending \| running \| succeeded \| failed \| skipped |  | Current or terminal scan status. |
| `score` | integer \| null |  | Listing quality score from 0 to 100 when available. |
| `grade` | strong \| good \| needs\_attention \| weak \| null |  | Quality grade derived from the score. |
| `error_message` | string \| null |  | Customer-safe explanation when the scan failed. |
| `completed_at` | datetime \| null |  | Time scan processing reached a terminal status. |
| `created_at` | datetime |  | Time the scan was created. |

#### Pagination

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `page` | integer |  | Current 1-based page. |
| `per_page` | integer |  | Number of records requested per page. |
| `total` | integer |  | Total records matching the request. |
| `total_pages` | integer |  | Total available pages. |

> **Scheduled scans**
>
> This endpoint reports scan records. Scans are created by scheduled listing analysis and cannot be started from the Listings API.

#### Request and response

```curl
curl --request GET \
  --url 'https://api.signal.ceyo.ai/v1/projects/{project_id}/locations/{location_id}/listings/scans?page=1&per_page=20' \
  --header 'Authorization: Bearer ceyo_platform_...'
```

```json
{
  "scans": [
    {
      "id": "ea0c4cdd-430e-444e-8446-cbe8d47edb56",
      "status": "succeeded",
      "score": 82,
      "grade": "good",
      "error_message": null,
      "completed_at": "2026-07-30T09:40:03Z",
      "created_at": "2026-07-30T09:39:58Z"
    },
    {
      "id": "04af8634-f960-47cb-9522-98714f87ff36",
      "status": "failed",
      "score": null,
      "grade": null,
      "error_message": "Listing scan did not complete.",
      "completed_at": "2026-07-23T09:40:08Z",
      "created_at": "2026-07-23T09:39:58Z"
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 20,
    "total": 9,
    "total_pages": 1
  }
}
```

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "validation_failed",
    "message": "page must be positive and per_page must be between 1 and 50.",
    "details": null,
    "request_id": "req_01K1JQY1RQQ7N3C5H1K6J0P8AT"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `401` | invalid\_api\_key |  | The API key is absent, invalid, expired, or revoked. |
| `403` | forbidden |  | The API key lacks listings:read or cannot access the requested location. |
| `404` | not\_found |  | The project, location, or visibility scope was not found. |
| `422` | validation\_failed |  | page or per\_page is outside the supported range. |
| `429` | rate\_limit\_exceeded |  | Too many requests were made. |

### Get listing scan

`GET /projects/{project_id}/locations/{location_id}/listings/scans/{scan_id}`

Returns one listing scan with its complete scored result and checks.

#### Path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |
| `location_id` | location UUID \| location external ID | Required | Location identifier belonging to the project. |
| `scan_id` | uuid | Required | Listing scan identifier. |

#### Response envelope

`scan`:**ListingScan**

Requested listing scan and its complete result.

#### ListingScan

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `id` | uuid |  | Listing scan identifier. |
| `status` | pending \| running \| succeeded \| failed \| skipped |  | Current or terminal scan status. |
| `score` | integer \| null |  | Listing quality score from 0 to 100 when available. |
| `grade` | strong \| good \| needs\_attention \| weak \| null |  | Quality grade derived from the score. |
| `error_message` | string \| null |  | Customer-safe explanation when the scan failed. |
| `completed_at` | datetime \| null |  | Time scan processing reached a terminal status. |
| `created_at` | datetime |  | Time the scan was created. |
| `result` | ScanResult \| null |  | Complete scored result on the single-scan endpoint. Null for unscored, failed, or skipped scans. |

#### ScanResult

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `score` | integer |  | Overall listing quality score from 0 to 100. |
| `grade` | strong \| good \| needs\_attention \| weak |  | Overall grade derived from the score. |
| `summary` | string |  | Short interpretation of the listing assessment. |
| `profile` | ListingProfile \| null |  | Profile observed for this scan, or null when detailed profile data is no longer retained. |
| `checks` | ListingCheck\[\] |  | Scored checks that contributed to the result. |

#### ListingCheck

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `label` | string |  | Human-readable check label. |
| `status` | passed \| warning \| failed |  | Check outcome. |
| `score` | integer |  | Points awarded by this check. |
| `severity` | low \| medium \| high |  | Importance of the observed condition. |
| `category` | string |  | Category used to group related checks. |
| `message` | string |  | Explanation of the observed condition. |
| `recommendation` | string |  | Recommended response to the check outcome. |

#### ListingProfile

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `place_id` | string |  | Place identifier represented by this profile. |
| `name` | string \| null |  | Public business name. |
| `formatted_address` | string \| null |  | Publicly formatted business address. |
| `website_url` | string \| null |  | Public website linked from the listing. |
| `national_phone_number` | string \| null |  | Phone number formatted for the listing country. |
| `international_phone_number` | string \| null |  | Phone number in international format. |
| `google_maps_url` | string \| null |  | Public Google Maps URL. |
| `business_status` | string \| null |  | Current public operating status. |
| `primary_type` | string \| null |  | Machine-readable primary business type. |
| `primary_type_display_name` | string \| null |  | Display name for the primary business type. |
| `types` | string\[\] |  | Normalized business type keys associated with the place. |
| `rating` | number \| null |  | Public average review rating. |
| `review_count` | integer \| null |  | Number of public ratings represented by the average. |
| `regular_opening_hours` | OpeningHours \| null |  | Normalized weekly opening schedule and special-day notices. |
| `editorial_summary` | string \| null |  | Public editorial description of the business. |
| `reviews` | Review\[\] |  | Up to the 50 most recent public reviews available with the profile. |
| `attributes` | ListingAttributes |  | Normalized service, accessibility, parking, payment, dining, and amenity attributes. |

#### OpeningHours

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `open_now` | boolean \| null |  | Whether the business is open at the profile observation time. |
| `periods` | OpeningPeriod\[\] |  | Weekly periods containing open and, when applicable, close day and time values. |
| `weekday_descriptions` | string\[\] |  | Human-readable hours for each represented weekday. |
| `special_days` | SpecialDay\[\] |  | Special-day entries with an ISO date and an exceptional\_hours flag. |

#### OpeningPeriod

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `open` | OpeningPoint |  | Opening point with day, hour, minute, and optional date. |
| `close` | OpeningPoint \| null |  | Closing point when the period has a defined close time. |

#### OpeningPoint

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `day` | integer |  | Day of week from 0 (Sunday) through 6 (Saturday). |
| `hour` | integer |  | Hour from 0 through 23. |
| `minute` | integer |  | Minute from 0 through 59. |
| `date` | date |  | Calendar date when the point represents a dated schedule. Omitted otherwise. |

#### SpecialDay

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `date` | ISO date |  | Calendar date in YYYY-MM-DD format. |
| `exceptional_hours` | boolean |  | Whether the date uses hours that differ from the regular schedule. |

#### Review

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `rating` | number \| null |  | Review rating. |
| `text` | string \| null |  | Public review text. |
| `publish_time` | datetime \| null |  | Review publication time. |
| `relative_publish_time` | string \| null |  | Human-readable relative publication time. |
| `google_maps_url` | string \| null |  | Public Google Maps URL for the review. |
| `author` | ReviewAuthor \| null |  | Public reviewer attribution when available. |

#### ReviewAuthor

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `display_name` | string \| null |  | Public display name of the reviewer. |
| `uri` | string \| null |  | Public reviewer profile URL. |
| `photo_uri` | string \| null |  | Public reviewer profile image URL. |

#### ListingAttributes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `accessibility_options` | BooleanAttributeMap |  | Normalized boolean accessibility options keyed by snake\_case attribute names. |
| `payment_options` | BooleanAttributeMap |  | Normalized boolean payment options keyed by snake\_case attribute names. |
| `parking_options` | BooleanAttributeMap |  | Normalized boolean parking options keyed by snake\_case attribute names. |
| `delivery` | boolean \| null |  | Whether delivery is offered. |
| `dine_in` | boolean \| null |  | Whether dine-in service is offered. |
| `takeout` | boolean \| null |  | Whether takeout is offered. |
| `reservable` | boolean \| null |  | Whether reservations are accepted. |
| `serves_breakfast` | boolean \| null |  | Whether breakfast is served. |
| `serves_lunch` | boolean \| null |  | Whether lunch is served. |
| `serves_dinner` | boolean \| null |  | Whether dinner is served. |
| `serves_beer` | boolean \| null |  | Whether beer is served. |
| `serves_wine` | boolean \| null |  | Whether wine is served. |
| `serves_vegetarian_food` | boolean \| null |  | Whether vegetarian food is served. |

#### BooleanAttributeMap

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `{attribute_name}` | boolean |  | Boolean value keyed by a snake\_case accessibility, payment, or parking attribute name. |

> **Provider field availability**
>
> Profile, review, author, and attribute objects are sparse. Provider fields are omitted when unavailable; fields explicitly documented as nullable may be returned as `null`.

> **Retained results**
>
> The score, grade, summary, and checks remain available for a completed scan. Detailed profile data is retained for 29 days, so the result's `profile` is `null` after that period while scores and checks persist.

#### Request and response

```curl
curl --request GET \
  --url 'https://api.signal.ceyo.ai/v1/projects/{project_id}/locations/{location_id}/listings/scans/{scan_id}' \
  --header 'Authorization: Bearer ceyo_platform_...'
```

```json
{
  "scan": {
    "id": "ea0c4cdd-430e-444e-8446-cbe8d47edb56",
    "status": "succeeded",
    "score": 82,
    "grade": "good",
    "result": {
      "score": 82,
      "grade": "good",
      "summary": "The profile is healthy, with a few worthwhile improvements.",
      "profile": {
        "place_id": "ChIJN1t_tDeuEmsRUsoyG83frY4",
        "name": "Harbour Coffee",
        "formatted_address": "12 Market Street, Dublin 2, Ireland",
        "website_url": "https://harbourcoffee.example",
        "national_phone_number": "01 555 0142",
        "international_phone_number": "+353 1 555 0142",
        "google_maps_url": "https://maps.google.com/?cid=123456789",
        "business_status": "OPERATIONAL",
        "primary_type": "coffee_shop",
        "primary_type_display_name": "Coffee shop",
        "types": ["coffee_shop", "cafe", "food"],
        "rating": 4.6,
        "review_count": 187,
        "regular_opening_hours": {
          "open_now": true,
          "periods": [],
          "weekday_descriptions": ["Monday: 7:30 AM – 6:00 PM"],
          "special_days": [
            {
              "date": "2026-08-03",
              "exceptional_hours": true
            }
          ]
        },
        "editorial_summary": "Independent coffee shop serving seasonal drinks.",
        "reviews": [],
        "attributes": {
          "delivery": false,
          "dine_in": true,
          "takeout": true
        }
      },
      "checks": [
        {
          "label": "Business name",
          "status": "passed",
          "score": 10,
          "severity": "medium",
          "category": "identity_consistency",
          "message": "The profile name matches the configured location.",
          "recommendation": "Keep the configured and public names aligned."
        },
        {
          "label": "Business hours",
          "status": "warning",
          "score": 8,
          "severity": "medium",
          "category": "profile_completeness",
          "message": "The profile exposes only partial business hours.",
          "recommendation": "Add complete regular and special hours."
        }
      ]
    },
    "error_message": null,
    "completed_at": "2026-07-30T09:40:03Z",
    "created_at": "2026-07-30T09:39:58Z"
  }
}
```

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "not_found",
    "message": "The requested resource was not found.",
    "details": null,
    "request_id": "req_01K1JQY1RQQ7N3C5H1K6J0P8AT"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `401` | invalid\_api\_key |  | The API key is absent, invalid, expired, or revoked. |
| `403` | forbidden |  | The API key lacks listings:read or cannot access the requested location. |
| `404` | not\_found |  | The project, location, visibility scope, or listing scan was not found. |
| `429` | rate\_limit\_exceeded |  | Too many requests were made. |

### Get listing findings

`GET /projects/{project_id}/locations/{location_id}/listings/findings`

Returns listing findings for a location with filtering and pagination.

#### Path parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `project_id` | project UUID \| project external ID | Required | Project identifier. |
| `location_id` | location UUID \| location external ID | Required | Location identifier belonging to the project. |

#### Query parameters

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `status` | open \| resolved \| ignored \| all | Optional; Default: open | Restrict findings by lifecycle status. Use all to include every status. |
| `severity` | info \| low \| medium \| high \| critical | Optional | Restrict findings to one severity. |
| `category` | string | Optional | Restrict findings to one category. |
| `q` | string | Optional | Search finding titles, descriptions, recommendations, and targets. Maximum: 200 characters. |
| `page` | integer | Optional; Default: 1 | The 1-based page number. |
| `per_page` | integer | Optional; Default: 20 | Number of findings per page. Maximum: 50. |

#### Response envelope

`findings`:**ListingFinding\[\]**`pagination`:**Pagination**

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `findings` | ListingFinding\[\] |  | Findings matching the selected filters. |
| `pagination` | Pagination |  | Pagination metadata. |

#### ListingFinding

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `category` | string |  | Category used to group related findings. |
| `severity` | info \| low \| medium \| high \| critical |  | Finding importance. |
| `status` | open \| resolved \| ignored |  | Current finding lifecycle status. |
| `target` | string \| null |  | Public target value when available. |
| `title` | string |  | Short finding title. |
| `description` | string \| null |  | Evidence-backed explanation of the finding. |
| `recommendation` | string \| null |  | Recommended response to the finding. |
| `first_seen_at` | datetime |  | Time the finding was first observed. |
| `last_seen_at` | datetime |  | Time the finding was most recently observed. |
| `resolved_at` | datetime \| null |  | Time the finding was resolved. |
| `created_at` | datetime |  | Time the finding was created. |
| `updated_at` | datetime |  | Time the finding was most recently updated. |

#### Pagination

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `page` | integer |  | Current 1-based page. |
| `per_page` | integer |  | Number of records requested per page. |
| `total` | integer |  | Total records matching the request. |
| `total_pages` | integer |  | Total available pages. |

> **Ordering**
>
> Findings are returned by most recent `last_seen_at`, with a stable identifier tie-breaker.

#### Request and response

```curl
curl --request GET \
  --url 'https://api.signal.ceyo.ai/v1/projects/{project_id}/locations/{location_id}/listings/findings?status=open&severity=medium&page=1&per_page=20' \
  --header 'Authorization: Bearer ceyo_platform_...'
```

```json
{
  "findings": [
    {
      "category": "profile_completeness",
      "severity": "medium",
      "status": "open",
      "target": "ChIJN1t_tDeuEmsRUsoyG83frY4",
      "title": "Business hours",
      "description": "The profile exposes only partial business hours.",
      "recommendation": "Add complete regular and special hours.",
      "first_seen_at": "2026-07-16T09:40:03Z",
      "last_seen_at": "2026-07-30T09:40:03Z",
      "resolved_at": null,
      "created_at": "2026-07-16T09:40:03Z",
      "updated_at": "2026-07-30T09:40:03Z"
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 20,
    "total": 1,
    "total_pages": 1
  }
}
```

#### Errors

#### Error response envelope

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `error` | Error |  | Structured error payload. |

#### Error

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `code` | string |  | Stable snake\_case code suitable for programmatic handling. |
| `message` | string |  | Human-readable explanation of the failure. |
| `details` | object \| array \| null |  | Structured validation or request context when available. |
| `request_id` | string |  | Identifier to provide when requesting support. |

```json
{
  "error": {
    "code": "invalid_filter",
    "message": "status is not a valid listing finding filter.",
    "details": {
      "status": ["is not supported"]
    },
    "request_id": "req_01K1JQY1RQQ7N3C5H1K6J0P8AT"
  }
}
```

#### Status codes

| Name | Type | Details | Description |
| --- | --- | --- | --- |
| `400` | invalid\_filter |  | A finding filter is invalid or q is longer than 200 characters. |
| `401` | invalid\_api\_key |  | The API key is absent, invalid, expired, or revoked. |
| `403` | forbidden |  | The API key lacks listings:read or cannot access the requested location. |
| `404` | not\_found |  | The project, location, or visibility scope was not found. |
| `422` | validation\_failed |  | page or per\_page is outside the supported range. |
| `429` | rate\_limit\_exceeded |  | Too many requests were made. |
