<!-- Reviews API: List and Get Reviews in One JSON Shape · Prisma · https://prismareviews.com/docs/api-reference/reviews -->
> GET /v1/reviews and GET /v1/reviews/{id}: filters, cursor pagination and the normalized review object for Google, App Store, Google Play, Trustpilot and more.

# Reviews

A review is one customer review on one of your connected locations, normalized to the same JSON shape on every platform. Prisma imports reviews when a location is connected and then checks for new and edited ones on a schedule set by the platform and your plan (see [Platforms](/docs/api-reference/platforms)). You read them with two endpoints, and you get a [webhook](/docs/api-reference/webhooks) when one is created or updated.

## The review object

```json
{
  "id": "rev_01KJ8Q2M4T7HX3VB9CWD6NRZ5E",
  "platform": "google",
  "location_id": "loc_01KJ8P9W2C4D6F8G0H2J4K6M8N",
  "rating": 4,
  "title": null,
  "text": "Great flat white, a bit slow at lunchtime.",
  "author": "Marta G.",
  "language": "en",
  "url": null,
  "created_at": "2026-10-19T12:41:07.000Z",
  "updated_at": "2026-10-19T12:41:07.000Z",
  "reply": {
    "text": "Thanks Marta! We have added a second barista at lunch.",
    "created_at": "2026-10-21T09:02:11.000Z",
    "status": "published",
    "error": null
  }
}
```

| Field | Type | Description |
| --- | --- | --- |
| `id` | string | Prisma review ID (`rev_…`). Stable while the location stays connected. |
| `platform` | enum | `google`, `app_store`, `google_play`, `judge_me`, `trustpilot`, `yelp`, `tripadvisor`, `booking`, `yotpo`, `reviews_io`, `g2` |
| `location_id` | string | The [location](/docs/api-reference/locations) the review belongs to. |
| `rating` | integer \| null | 1 to 5 stars. `null` if the platform gave no rating. |
| `title` | string \| null | Review title, on platforms that have one (App Store, Trustpilot, Judge.me…). |
| `text` | string \| null | Review body. `null` for rating-only reviews. |
| `author` | string \| null | Display name as shown by the platform. |
| `language` | string \| null | Language code when the platform provides one. |
| `url` | string \| null | Public link to the review when the platform provides one. On read-only platforms (Yelp, Tripadvisor, Booking.com, Yotpo, REVIEWS.io, G2) it is always set: the link to answer the review on the platform, which for some platforms is the listing or product page. |
| `created_at` | timestamp | When the review was written on the platform. |
| `updated_at` | timestamp | When it was last edited on the platform. |
| `reply` | object \| null | The business reply, or `null` if there is none. |

**The `reply` object**

| Field | Type | Description |
| --- | --- | --- |
| `text` | string | Reply text. |
| `status` | enum | `published` (live on the platform), `queued` (sent through Prisma, waiting to be published), `failed` (the platform refused it; see `error`). |
| `created_at` | timestamp \| null | When the reply was published. `null` while it is queued. |
| `error` | string \| null | Why publishing failed, when `status` is `failed`. |

A reply that appears on the platform, whoever wrote it, comes back as `published`. How to create, replace and delete replies is on [Replies](/docs/api-reference/replies).

## List reviews

`GET /v1/reviews`

Returns the reviews of your workspace (in the mode of your key), newest first.

| Query param | Type | Description |
| --- | --- | --- |
| `location_id` | string | Only reviews of this location. Omit to list across all locations. |
| `platform` | enum | Only reviews from this platform (one of the values above). |
| `since` | ISO 8601 | Only reviews written at or after this time, by `created_at`. Either a date (`2026-10-01`, meaning midnight UTC) or a full timestamp with time zone offset (`2026-10-01T00:00:00Z`, `2026-10-01T02:00:00+02:00`). |
| `has_reply` | `true` \| `false` | `true`: reviews with a reply in any status. `false`: reviews without one. |
| `limit` | integer | Page size, 1 to 100. Default 50. |
| `cursor` | string | The `next_cursor` of the previous page. |

```bash
curl "https://api.prismareviews.com/v1/reviews?location_id=loc_01KJ8P9W2C4D6F8G0H2J4K6M8N&has_reply=false&limit=20" \
  -H "Authorization: Bearer $PRISMA_API_KEY"
```
```javascript
const params = new URLSearchParams({
  location_id: "loc_01KJ8P9W2C4D6F8G0H2J4K6M8N",
  has_reply: "false",
  limit: "20",
});
const res = await fetch("https://api.prismareviews.com/v1/reviews?" + params, {
  headers: { Authorization: "Bearer " + process.env.PRISMA_API_KEY },
});
const { data, next_cursor } = await res.json();
for (const review of data) console.log(review.rating, review.author, review.text);
```
```python
import os
import requests

resp = requests.get(
    "https://api.prismareviews.com/v1/reviews",
    params={"location_id": "loc_01KJ8P9W2C4D6F8G0H2J4K6M8N", "has_reply": "false", "limit": 20},
    headers={"Authorization": f"Bearer {os.environ['PRISMA_API_KEY']}"},
    timeout=30,
)
resp.raise_for_status()
for review in resp.json()["data"]:
    print(review["rating"], review["author"], review["text"])
```

**Response `200`**

```json
{
  "data": [
    {
      "id": "rev_01KJ8Q2M4T7HX3VB9CWD6NRZ5E",
      "platform": "google",
      "location_id": "loc_01KJ8P9W2C4D6F8G0H2J4K6M8N",
      "rating": 4,
      "title": null,
      "text": "Great flat white, a bit slow at lunchtime.",
      "author": "Marta G.",
      "language": "en",
      "url": null,
      "created_at": "2026-10-19T12:41:07.000Z",
      "updated_at": "2026-10-19T12:41:07.000Z",
      "reply": null
    }
  ],
  "next_cursor": "MjAyNi0xMC0xOVQxMjo0MTowNy4wMDBafHJldl8wMUtKOFEyTTRUN0hYM1ZCOUNXRDZOUlo1RQ"
}
```

### Paging through every review

Repeat the call with `cursor` set to the last `next_cursor`, keeping the same filters, until `next_cursor` is `null`.

```javascript
let cursor = null;
do {
  const params = new URLSearchParams({ limit: "100" });
  if (cursor) params.set("cursor", cursor);
  const res = await fetch("https://api.prismareviews.com/v1/reviews?" + params, {
    headers: { Authorization: "Bearer " + process.env.PRISMA_API_KEY },
  });
  const page = await res.json();
  for (const review of page.data) console.log(review.id);
  cursor = page.next_cursor;
} while (cursor);
```
```python
import os
import requests

cursor = None
while True:
    params = {"limit": 100}
    if cursor:
        params["cursor"] = cursor
    page = requests.get(
        "https://api.prismareviews.com/v1/reviews",
        params=params,
        headers={"Authorization": f"Bearer {os.environ['PRISMA_API_KEY']}"},
        timeout=30,
    ).json()
    for review in page["data"]:
        print(review["id"])
    cursor = page["next_cursor"]
    if not cursor:
        break
```

`since` filters by when the review was written, not when it was edited. To keep a local copy in sync with edits, listen for `review.updated` webhooks and fetch the review again.

## Get a review

`GET /v1/reviews/{id}`

```bash
curl https://api.prismareviews.com/v1/reviews/rev_01KJ8Q2M4T7HX3VB9CWD6NRZ5E \
  -H "Authorization: Bearer $PRISMA_API_KEY"
```
```javascript
const res = await fetch(
  "https://api.prismareviews.com/v1/reviews/rev_01KJ8Q2M4T7HX3VB9CWD6NRZ5E",
  { headers: { Authorization: "Bearer " + process.env.PRISMA_API_KEY } }
);
console.log(await res.json());
```
```python
resp = requests.get(
    "https://api.prismareviews.com/v1/reviews/rev_01KJ8Q2M4T7HX3VB9CWD6NRZ5E",
    headers={"Authorization": f"Bearer {os.environ['PRISMA_API_KEY']}"},
    timeout=30,
)
print(resp.json())
```

Returns `200` with one review object. If no review with that ID exists in your workspace and mode, you get `404 resource_not_found`.

## Good to know

- **History.** On the first sync Prisma imports up to 90 days of history on Spark, 365 days on Beam and everything the platform returns on Spectrum and Aurora. Some platforms return less: the Google Play API only returns reviews from the last 7 days, so the history is what Prisma has stored since you connected.
- **Disconnected locations.** When you delete a connection, its reviews stay readable until they are deleted 30 days later.
- **Errors.** `422 invalid_request` for an unknown `platform`, a `since` that is neither a date nor a timestamp with offset, a `limit` out of range or a bad `cursor`. The `message` names the parameter. All codes are on [Errors](/docs/errors).
