# Get product review summary

> Returns the rating breakdown, answer summaries, and media previews for a product.

Breadcrumb: API › Get product review summary
Docs index: https://docs.cevoid.com/developers/llms.txt

`GET https://api.cevoid.com/v2/product-reviews/summaries/{product_id}`

Returns the rating breakdown, answer summaries, and media previews for a product.

## Authorizations

Bearer token in the Authorization header: `Authorization: Bearer <key>` (API key).

## Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `product_id` | `string` | Yes | Opaque Cevoid identifier. Length: `1 to 200`. Example: `rev_abc123`. |

## Query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `market` | `string` | No | Presentation market. Defaults to the workspace default; does not filter collection origin. Length: `1 to 200`. Example: `mar_abc123`. |
| `include` | `string` | No | Comma-separated includes: questions, localization. Localization returns originals for included question definitions only; request both to receive them. Maximum length: `100`. Example: `questions,localization`. |

## Response

### 200: Successful response

`application/json`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `data` | `object` | Yes |  |
| `data.product_id` | `string` | No | Opaque Cevoid identifier. Length: `1 to 200`. Example: `prd_abc123`. |
| `data.rating_count` | `integer` | Yes | Number of published, visible ratings, including reviews without text. Independent of review-list filters and presentation market. Range: `0 <= x`. Example: `2`. |
| `data.text_review_count` | `integer` | Yes | Public reviews with a non-blank title or body. Range: `0 <= x`. Example: `2`. |
| `data.average_rating` | `number \| null` | Yes | Arithmetic mean of all public ratings; null when empty. Example: `4.5`. |
| `data.rating_distribution` | `object` | Yes |  |
| `data.rating_distribution.1` | `number` | Yes | Example: `0`. |
| `data.rating_distribution.2` | `number` | Yes | Example: `0`. |
| `data.rating_distribution.3` | `number` | Yes | Example: `0`. |
| `data.rating_distribution.4` | `number` | Yes | Example: `1`. |
| `data.rating_distribution.5` | `number` | Yes | Example: `1`. |
| `data.verified_purchase_count` | `integer` | Yes | Public reviews with a verified purchase. Range: `0 <= x`. Example: `1`. |
| `data.reviews_with_media_count` | `integer` | Yes | Public reviews with at least one displayable image or video. Range: `0 <= x`. Example: `1`. |
| `data.media_count` | `integer` | Yes | Displayable images and videos across all public reviews, not only the preview. Range: `0 <= x`. Example: `1`. |
| `data.languages` | `object[]` | Yes |  |
| `data.languages[].language` | `string` | Yes | Example: `en`. |
| `data.languages[].rating_count` | `number` | Yes | Example: `2`. |
| `data.question_summaries` | `object[]` | Yes | At most 20 attribute questions, ordered by response count and stable question identity. Profile properties are excluded. Maximum items: `20`. |
| `data.question_summaries[].question_id` | `string` | Yes | Opaque Cevoid identifier. Length: `1 to 200`. Example: `rvq_abc123`. |
| `data.question_summaries[].answer_count` | `integer` | Yes | Public responses counted for this question. Summaries require at least two responses. Range: `0 <= x`. Example: `2`. |
| `data.question_summaries[].average` | `number` | No | Example: `4.5`. |
| `data.question_summaries[].distribution` | `object[]` | No |  |
| `data.question_summaries[].distribution[].value` | `string \| number` | Yes | Example: `blue`. |
| `data.question_summaries[].distribution[].count` | `integer` | Yes | Range: `0 <= x`. Example: `1`. |
| `data.question_summaries[].yes_count` | `integer` | No | Range: `0 <= x`. Example: `2`. |
| `data.question_summaries[].no_count` | `integer` | No | Range: `0 <= x`. Example: `0`. |
| `data.media_preview` | `object[]` | Yes | Maximum items: `4`. |
| `data.media_preview[].review_id` | `string` | Yes | Opaque Cevoid identifier. Length: `1 to 200`. Example: `rev_abc123`. |
| `data.media_preview[].media` | `object` | Yes |  |
| `data.media_preview[].media.type` | `enum<string>` | Yes | Whether the item is an image or a video. Allowed values: `IMAGE`, `VIDEO`. Example: `IMAGE`. |
| `data.media_preview[].media.url` | `string` | Yes | Delivery URL for the full asset. Example: `https://example.com/reviews/123`. |
| `data.media_preview[].media.thumbnail_url` | `string` | Yes | Delivery URL for the thumbnail. Example: `https://example.com/reviews/123`. |
| `data.media_preview[].media.aspect_ratio` | `number` | Yes | Width divided by height. Example: `1.5`. |
| `data.media_preview[].media.aspect_ratio_type` | `enum<string>` | Yes | Coarse orientation bucket. Allowed values: `LANDSCAPE`, `PORTRAIT`, `SQUARE`. Example: `LANDSCAPE`. |
| `data.media_preview[].media.video_length` | `number` | No | Video duration in seconds. Example: `12`. |
| `data.media_preview[].media.id` | `string` | Yes | Stable opaque asset identity shared by detail and preview. Example: `rmed_abc123`. |
| `data.media_preview[].media.alt` | `string` | No | Available image alternative text, localized with source fallback. Example: `Blue shirt worn outdoors`. |
| `data.media_preview[].media.thumbnail_alt` | `string` | No | Available video poster alternative text. Example: `Blue shirt video preview`. |
| `data.media_preview[].media.video_description` | `string` | No | Available description of video imagery. Example: `A shopper shows the fit of a blue shirt.`. |
| `data.media_preview[].media.video_captions` | `string` | No | Available WebVTT captions with cue timing, localized with source fallback. Example: `WEBVTT

00:00.000 --> 00:01.000
The fit is comfortable.`. |
| `data.ai_summary` | `object` | No |  |
| `data.ai_summary.text` | `string` | Yes | Example: `Shoppers praise the comfortable fit.`. |
| `data.ai_summary.language` | `string` | Yes | Example: `en`. |
| `data.ai_summary.generated_at` | `string<date-time>` | Yes | Example: `2026-09-01T10:00:00.000Z`. |
| `data.ai_summary.review_count` | `number` | Yes | Example: `2`. |
| `included` | `object` | No |  |
| `included.localization` | `object` | No |  |
| `included.localization.questions` | `object[]` | No |  |
| `included.localization.questions[].id` | `string` | Yes | Public ID matching the returned entity or nested item. Length: `1 to 200`. Example: `rev_abc123`. |
| `included.localization.questions[].has_translations` | `boolean` | Yes | True when the returned translatable content differs from its source representation. Does not mean every field was translated. Example: `true`. |
| `included.localization.questions[].original` | `object \| null` | Yes | Complete source projection of translatable fields, with the same visibility and masking rules. Null when no returned content differs. Not edit history. |
| `included.localization.questions[].original.prompt` | `string` | Yes | Example: `How does it fit?`. |
| `included.localization.questions[].original.options` | `object[]` | No | Current selection options. Labels are localized; values remain stable selection keys. |
| `included.localization.questions[].original.options[].value` | `string` | Yes | Example: `blue`. |
| `included.localization.questions[].original.options[].label` | `string` | Yes | Example: `Blue`. |
| `included.localization.questions[].original.scale` | `object` | No |  |
| `included.localization.questions[].original.scale.start_label` | `string` | Yes | Example: `Too small`. |
| `included.localization.questions[].original.scale.end_label` | `string` | Yes | Example: `Too large`. |
| `included.localization.questions[].original.scale.center_label` | `string` | No | Example: `Just right`. |
| `included.localization.questions[].original.scale.step_labels` | `string[]` | No |  |
| `included.questions` | `object[]` | No |  |
| `included.questions[].id` | `string` | Yes | Opaque Cevoid identifier. Length: `1 to 200`. Example: `rev_abc123`. |
| `included.questions[].scope` | `enum<string>` | Yes | Allowed values: `PRODUCT`, `COMPANY`. Example: `PRODUCT`. |
| `included.questions[].type` | `enum<string>` | Yes | Allowed values: `PRODUCT_ATTRIBUTE`, `COMPANY_ATTRIBUTE`, `PROFILE_PROPERTY`. Example: `PRODUCT_ATTRIBUTE`. |
| `included.questions[].prompt` | `string` | Yes | Example: `How does it fit?`. |
| `included.questions[].format` | `enum<string>` | Yes | Allowed values: `SCALE`, `CENTERED_RANGE`, `SINGLE_SELECT`, `MULTI_SELECT`, `WOULD_RECOMMEND`, `NUMERIC`. Example: `SCALE`. |
| `included.questions[].scale` | `object` | No | Current scale size and labels, localized for the selected market. Not a submission-time snapshot. |
| `included.questions[].scale.steps` | `number` | Yes | Example: `5`. |
| `included.questions[].scale.start_label` | `string` | Yes | Example: `Too small`. |
| `included.questions[].scale.end_label` | `string` | Yes | Example: `Too large`. |
| `included.questions[].scale.center_label` | `string` | No | Example: `Just right`. |
| `included.questions[].scale.step_labels` | `string[]` | No |  |
| `included.questions[].options` | `object[]` | No | Current selection options. Labels are localized; values remain stable selection keys. |
| `included.questions[].options[].value` | `string` | Yes | Example: `blue`. |
| `included.questions[].options[].label` | `string` | Yes | Example: `Blue`. |
| `included.questions[].numeric` | `object` | No |  |
| `included.questions[].numeric.unit` | `string` | No | Example: `cm`. |
| `included.questions[].is_archived` | `boolean` | Yes | Example: `false`. |

Response headers:

| Header | Type | Description |
| --- | --- | --- |
| `Cevoid-Processing-Ms` | `string` | End-to-end request processing time in milliseconds |
| `Cevoid-Request-Id` | `string` | Request identifier for support and tracing |
| `RateLimit-Limit` | `string` | Current rate limit bucket size |
| `RateLimit-Remaining` | `string` | Remaining requests in the current rate limit window |
| `RateLimit-Reset` | `integer` | Seconds until the next request token is available |

```json
{
  "data": {
    "rating_count": 2,
    "text_review_count": 2,
    "average_rating": 4.5,
    "rating_distribution": {
      "1": 0,
      "2": 0,
      "3": 0,
      "4": 1,
      "5": 1
    },
    "verified_purchase_count": 0,
    "reviews_with_media_count": 0,
    "media_count": 0,
    "languages": [
      {
        "language": "en",
        "rating_count": 2
      }
    ],
    "question_summaries": [],
    "media_preview": [],
    "ai_summary": {
      "text": "Reviewers describe a positive overall experience, with ratings of four and five stars.",
      "language": "en",
      "generated_at": "2026-09-01T10:00:00.000Z",
      "review_count": 2
    }
  }
}
```

### 400: Bad request

`application/json`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `additional_data` | `object` | No | Optional machine-readable error details. |
| `additional_data.{key}` | `any` | No |  |
| `status` | `number` | Yes | HTTP status code for the error response. Example: `404`. |
| `code` | `string` | Yes | Stable machine-readable error code. Example: `not_found`. |
| `message` | `string` | Yes | Human-readable description of the error. Example: `Route not found`. |
| `request_id` | `string` | No | Request identifier for support and tracing. Example: `req_abc123`. |

Response headers: the same as 200.

```json
{
  "additional_data": {
    "errors": [
      {
        "field": "query.market",
        "message": "Invalid input: expected string, received array"
      }
    ]
  },
  "status": 400,
  "code": "bad_request",
  "message": "Bad request",
  "request_id": "req_abc123"
}
```

### 401: Unauthorized

`application/json`

Same fields as 400.

Response headers: the same as 200.

```json
{
  "status": 401,
  "code": "unauthorized",
  "message": "Unauthorized",
  "request_id": "req_abc123"
}
```

### 403: Forbidden

`application/json`

Same fields as 400.

Response headers: the same as 200.

```json
{
  "status": 403,
  "code": "forbidden",
  "message": "Forbidden",
  "request_id": "req_abc123"
}
```

### 404: Not found

`application/json`

Same fields as 400.

Response headers: the same as 200.

```json
{
  "additional_data": {
    "errors": [
      {
        "field": "query.market",
        "message": "Invalid input: expected string, received array"
      }
    ]
  },
  "status": 404,
  "code": "not_found",
  "message": "Route not found",
  "request_id": "req_abc123"
}
```

### 409: Conflict

`application/json`

Same fields as 400.

Response headers: the same as 200.

```json
{
  "status": 409,
  "code": "conflict",
  "message": "Conflict",
  "request_id": "req_abc123"
}
```

### 422: Validation error

`application/json`

Same fields as 400.

Response headers: the same as 200.

```json
{
  "additional_data": {
    "errors": [
      {
        "field": "query.market",
        "message": "Invalid input: expected string, received array"
      }
    ]
  },
  "status": 422,
  "code": "validation_error",
  "message": "Validation error",
  "request_id": "req_abc123"
}
```

### 429: Too many requests

`application/json`

Same fields as 400.

Response headers:

| Header | Type | Description |
| --- | --- | --- |
| `Cevoid-Processing-Ms` | `string` | End-to-end request processing time in milliseconds |
| `Cevoid-Request-Id` | `string` | Request identifier for support and tracing |
| `RateLimit-Limit` | `string` | Current rate limit bucket size |
| `RateLimit-Remaining` | `string` | Remaining requests in the current rate limit window |
| `RateLimit-Reset` | `integer` | Seconds until the next request token is available |
| `Retry-After` | `integer` | Seconds to wait before retrying the request |

```json
{
  "status": 429,
  "code": "too_many_requests",
  "message": "Too many requests",
  "request_id": "req_abc123"
}
```

### 500: Internal server error

`application/json`

Same fields as 400.

Response headers: the same as 200.

```json
{
  "status": 500,
  "code": "internal_server_error",
  "message": "Internal server error",
  "request_id": "req_abc123"
}
```

## Request example

```bash
curl 'https://api.cevoid.com/v2/product-reviews/summaries/rev_abc123' \
  -H "Authorization: Bearer ${CEVOID_API_KEY}"
```

---

Canonical: https://docs.cevoid.com/developers/api/reviews/get-product-review-summary
