Reviews

GET /reviews

List the organization's reviews, newest first by default. Includes unpublished reviews waiting on moderation. Supports search, filtering and cursor pagination.

Requires the reviews:read permission.

Query Parameters

limitnumber

The number of records to return.

cursorstring

A pagination cursor. Fetch the next page by passing the nextCursor value from the previous response.

sortrating | -rating | createdAt | -createdAt | moderatedAt | -moderatedAt

The sort order. Prefix a field with - to sort descending. Defaults to -createdAt.

searchstring

A free-text search term, matched case-insensitively against the record's most identifying fields. Combined with filter using AND.

filterstring

A JSON-encoded filter document, for example {"createdAt":{"$gte":"2025-01-01T00:00:00Z"}}. Filterable fields: id, rating, published, flagged, moderatedAt, surveyId, ipAddress, browserFingerprint, metadata, createdAt, product.id, product.slug, product.title, product.metadata, product.createdAt, customer.id, customer.email, customer.firstName, customer.lastName, customer.metadata, customer.emailOptOut, customer.emailOptOutSource, customer.createdAt. See Filtering for the syntax.

includestring

A comma-separated list of extra fields to compute and return. Each one costs an additional query, so ask only for what you need. Available: importJob, customer, product, response, files, answers, collisions.

Request
curl \
  "https://api.cascade.dev/reviews" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY"
Response
{
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "siteId": "550e8400-e29b-41d4-a716-446655440000",
      "productId": "550e8400-e29b-41d4-a716-446655440000",
      "productVariantId": "550e8400-e29b-41d4-a716-446655440000",
      "customerId": "550e8400-e29b-41d4-a716-446655440000",
      "surveyId": "550e8400-e29b-41d4-a716-446655440000",
      "title": "string",
      "body": "string",
      "originalTitle": "string",
      "originalBody": "string",
      "redactedAt": "2025-01-15T09:30:00Z",
      "rating": 0,
      "published": true,
      "verifiedBuyer": true,
      "flagged": true,
      "flags": ["..."],
      "moderatedAt": "2025-01-15T09:30:00Z",
      "ipAddress": "string",
      "browserFingerprint": "string",
      "ipCountry": "string",
      "userAgent": "string",
      "submitSeconds": 0,
      "metadata": "...",
      "createdAt": "2025-01-15T09:30:00Z",
      "updatedAt": "2025-01-15T09:30:00Z",
      "importJob": {
        "id": "...",
        "type": "...",
        "action": "...",
        "row": "...",
        "createdAt": "..."
      },
      "customer": {
        "id": "...",
        "email": "...",
        "phone": "...",
        "firstName": "...",
        "lastName": "...",
        "country": "...",
        "birthday": "...",
        "metadata": "...",
        "notes": "...",
        "emailOptOut": "...",
        "emailOptOutAt": "...",
        "emailOptOutSource": "...",
        "createdAt": "...",
        "updatedAt": "..."
      },
      "product": {
        "id": "...",
        "slug": "...",
        "title": "...",
        "description": "...",
        "imageUrl": "...",
        "url": "...",
        "metadata": "...",
        "notes": "...",
        "createdAt": "...",
        "updatedAt": "..."
      },
      "response": {
        "id": "...",
        "reviewId": "...",
        "body": "...",
        "responderName": "...",
        "published": "...",
        "metadata": "...",
        "createdAt": "...",
        "updatedAt": "..."
      },
      "files": ["..."],
      "answers": ["..."],
      "collisions": {
        "browserFingerprint": "...",
        "ipAddress": "..."
      }
    }
  ],
  "nextCursor": "string"
}

PATCH /reviews/bulk-update

Publish or reject every review matching a filter, in one request. Sending no filter moderates every review in the organization. Each review is stamped as moderated either way, and every product involved has its review stats recalculated once.

Requires the reviews:write permission.

Costs 5 rate limit tokens instead of the usual one. See Rate limits.

Query Parameters

filterstring

A JSON-encoded filter document selecting the reviews to moderate. Omit it and every review in the organization is moderated. See Filtering for the syntax.

searchstring

A free-text search term, matched case-insensitively against the record's most identifying fields. Combined with filter using AND.

Body Parameters

publishedbooleanrequired

Whether the selected reviews are visible on the storefront. This is the moderation switch: true publishes them, false takes them down.

Request
curl \
  -X PATCH \
  "https://api.cascade.dev/reviews/bulk-update" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "published": true
}'
Response
{
  "count": 0
}

POST /reviews/import

Bring reviews in from another platform in bulk, matching the customer by email and the product by slug. A customer Cascade has never seen is created from the email. Rows whose other references don't resolve are skipped and returned in skipped rather than failing the whole batch, so a catalog that didn't migrate cleanly still gets everything it can; set strict to fail on the first such row instead. Imported reviews count as already moderated and go live unless published says otherwise. To import a CSV instead, upload it and queue an import job with POST /import-jobs.

Requires the reviews:write permission.

Costs 10 rate limit tokens instead of the usual one. See Rate limits.

Body Parameters

dataobject[]required

The reviews to create or update.

strictboolean

When true, a row that references something missing fails the whole import with an error. Off by default: rows whose references don't resolve are skipped and reported in skipped.

Request
curl \
  -X POST \
  "https://api.cascade.dev/reviews/import" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "data": [
    {
      "externalId": "string",
      "site": "string",
      "customer": "[email protected]",
      "product": "string",
      "productExternalId": "string",
      "productUrl": "string",
      "productVariant": "string",
      "title": "string",
      "body": "string",
      "rating": 0,
      "published": true,
      "verifiedBuyer": true,
      "createdAt": "2025-01-15T09:30:00Z",
      "imageUrls": [
        "..."
      ],
      "response": "string",
      "responderName": "string",
      "responseCreatedAt": "2025-01-15T09:30:00Z",
      "answers": [
        "..."
      ],
      "metadata": "..."
    }
  ],
  "strict": true
}'
Response
{
  "imported": [
    {
      "index": 0,
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "imageUrls": ["..."]
    }
  ],
  "skipped": [
    {
      "index": 0,
      "message": "string"
    }
  ]
}

GET /reviews/{id}

Get a single review by ID.

Requires the reviews:read permission.

Path Parameters

idstring (uuid)required

The ID of the review.

Query Parameters

includestring

A comma-separated list of extra fields to compute and return. Each one costs an additional query, so ask only for what you need. Available: importJob, customer, product, response, files, answers, collisions.

Request
curl \
  "https://api.cascade.dev/reviews/550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY"
Response
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "siteId": "550e8400-e29b-41d4-a716-446655440000",
  "productId": "550e8400-e29b-41d4-a716-446655440000",
  "productVariantId": "550e8400-e29b-41d4-a716-446655440000",
  "customerId": "550e8400-e29b-41d4-a716-446655440000",
  "surveyId": "550e8400-e29b-41d4-a716-446655440000",
  "title": "string",
  "body": "string",
  "originalTitle": "string",
  "originalBody": "string",
  "redactedAt": "2025-01-15T09:30:00Z",
  "rating": 0,
  "published": true,
  "verifiedBuyer": true,
  "flagged": true,
  "flags": [
    {
      "code": "string",
      "detail": "string",
      "score": 0
    }
  ],
  "moderatedAt": "2025-01-15T09:30:00Z",
  "ipAddress": "string",
  "browserFingerprint": "string",
  "ipCountry": "string",
  "userAgent": "string",
  "submitSeconds": 0,
  "metadata": "...",
  "createdAt": "2025-01-15T09:30:00Z",
  "updatedAt": "2025-01-15T09:30:00Z",
  "importJob": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "type": "customers",
    "action": "created",
    "row": 0,
    "createdAt": "2025-01-15T09:30:00Z"
  },
  "customer": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "[email protected]",
    "phone": "string",
    "firstName": "string",
    "lastName": "string",
    "country": "string",
    "birthday": "string",
    "metadata": "...",
    "notes": "string",
    "emailOptOut": true,
    "emailOptOutAt": "2025-01-15T09:30:00Z",
    "emailOptOutSource": "customer",
    "createdAt": "2025-01-15T09:30:00Z",
    "updatedAt": "2025-01-15T09:30:00Z"
  },
  "product": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "slug": "string",
    "title": "string",
    "description": "string",
    "imageUrl": "string",
    "url": "string",
    "metadata": "...",
    "notes": "string",
    "createdAt": "2025-01-15T09:30:00Z",
    "updatedAt": "2025-01-15T09:30:00Z"
  },
  "response": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "reviewId": "550e8400-e29b-41d4-a716-446655440000",
    "body": "string",
    "responderName": "string",
    "published": true,
    "metadata": "...",
    "createdAt": "2025-01-15T09:30:00Z",
    "updatedAt": "2025-01-15T09:30:00Z"
  },
  "files": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "fileName": "string",
      "contentType": "string",
      "sizeBytes": 0,
      "url": "string"
    }
  ],
  "answers": [
    {
      "questionId": "550e8400-e29b-41d4-a716-446655440000",
      "label": "string",
      "type": "scale",
      "step": 0,
      "steps": 0,
      "lowLabel": "string",
      "highLabel": "string",
      "middleLabel": "string",
      "optionLabels": ["..."]
    }
  ],
  "collisions": {
    "browserFingerprint": 0,
    "ipAddress": 0
  }
}

PATCH /reviews/{id}

Moderate or redact a review. Set published to put it live on the storefront or take it down. Edits to title and body are limited to redaction: send the current text with the spans to hide replaced by [redacted], and anything else is rejected. The first redaction stores the customer's original text on the review, visible only through this API. The rating is the customer's and cannot be changed. Triggers the review.updated webhook.

Requires the reviews:write permission.

Path Parameters

idstring (uuid)required

The ID of the review to update.

Body Parameters

titlestring | null

The review's headline. Edits are limited to redaction: the new text must be the current text with one or more spans replaced by [redacted].

bodystring | null

The review's body text. Edits are limited to redaction: the new text must be the current text with one or more spans replaced by [redacted].

publishedboolean

Whether the review is visible on the storefront. This is the moderation switch.

metadataobject

Replaces the review's metadata wholesale. Omit to leave it alone.

Request
curl \
  -X PATCH \
  "https://api.cascade.dev/reviews/550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "string",
  "body": "string",
  "published": true,
  "metadata": "..."
}'
Response
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "siteId": "550e8400-e29b-41d4-a716-446655440000",
  "productId": "550e8400-e29b-41d4-a716-446655440000",
  "productVariantId": "550e8400-e29b-41d4-a716-446655440000",
  "customerId": "550e8400-e29b-41d4-a716-446655440000",
  "surveyId": "550e8400-e29b-41d4-a716-446655440000",
  "title": "string",
  "body": "string",
  "originalTitle": "string",
  "originalBody": "string",
  "redactedAt": "2025-01-15T09:30:00Z",
  "rating": 0,
  "published": true,
  "verifiedBuyer": true,
  "flagged": true,
  "flags": [
    {
      "code": "string",
      "detail": "string",
      "score": 0
    }
  ],
  "moderatedAt": "2025-01-15T09:30:00Z",
  "ipAddress": "string",
  "browserFingerprint": "string",
  "ipCountry": "string",
  "userAgent": "string",
  "submitSeconds": 0,
  "metadata": "...",
  "createdAt": "2025-01-15T09:30:00Z",
  "updatedAt": "2025-01-15T09:30:00Z"
}

DELETE /reviews/{id}

Permanently delete a review. This is for spam, abusive content, mistakes and customer data requests: to take a review off the storefront, unpublish it instead. The reason is required and is kept in a deletion record along with who deleted it. Removes the review's attached photos and videos, recalculates the product's review stats, and triggers the review.deleted webhook.

Requires the reviews:write permission.

Path Parameters

idstring (uuid)required

The ID of the review to delete.

Body Parameters

reasoncustomer_request | spam | abusive_content | not_about_product | duplicate | test_data | otherrequired

Why the review is being deleted. Recorded permanently. To hide a review from your widgets, unpublish it instead of deleting it.

notestring

More detail on the deletion, recorded with the reason. Required for "other".

Request
curl \
  -X DELETE \
  "https://api.cascade.dev/reviews/550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "reason": "customer_request",
  "note": "string"
}'
Response
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "siteId": "550e8400-e29b-41d4-a716-446655440000",
  "productId": "550e8400-e29b-41d4-a716-446655440000",
  "productVariantId": "550e8400-e29b-41d4-a716-446655440000",
  "customerId": "550e8400-e29b-41d4-a716-446655440000",
  "surveyId": "550e8400-e29b-41d4-a716-446655440000",
  "title": "string",
  "body": "string",
  "originalTitle": "string",
  "originalBody": "string",
  "redactedAt": "2025-01-15T09:30:00Z",
  "rating": 0,
  "published": true,
  "verifiedBuyer": true,
  "flagged": true,
  "flags": [
    {
      "code": "string",
      "detail": "string",
      "score": 0
    }
  ],
  "moderatedAt": "2025-01-15T09:30:00Z",
  "ipAddress": "string",
  "browserFingerprint": "string",
  "ipCountry": "string",
  "userAgent": "string",
  "submitSeconds": 0,
  "metadata": "...",
  "createdAt": "2025-01-15T09:30:00Z",
  "updatedAt": "2025-01-15T09:30:00Z"
}

POST /reviews/{id}/response

Reply to a review as the merchant. A review takes one reply, so replying twice is a conflict: edit the existing reply instead. The reply is a draft until published is true, which is a separate decision from whether the review itself is published.

Requires the reviews:write permission.

Path Parameters

idstring (uuid)required

The ID of the review to reply to.

Body Parameters

bodystringrequired

What the merchant wants to say back to the reviewer.

publishedboolean

Whether the reply goes live right away. Leave it out to save a draft.

metadataobject

Free-form string key/value pairs for your own data.

responderNamestring

The name shown above the reply on the storefront. Defaults to the name on your account.

Request
curl \
  -X POST \
  "https://api.cascade.dev/reviews/550e8400-e29b-41d4-a716-446655440000/response" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "body": "string",
  "published": true,
  "metadata": "...",
  "responderName": "string"
}'
Response
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "reviewId": "550e8400-e29b-41d4-a716-446655440000",
  "body": "string",
  "responderName": "string",
  "published": true,
  "metadata": "...",
  "createdAt": "2025-01-15T09:30:00Z",
  "updatedAt": "2025-01-15T09:30:00Z"
}

PATCH /reviews/{id}/response

Edit a review's reply, or publish and unpublish it. Only the fields you send are changed.

Requires the reviews:write permission.

Path Parameters

idstring (uuid)required

The ID of the replied-to review.

Body Parameters

bodystring

What the merchant wants to say back to the reviewer.

responderNamestring

The name shown above the reply on the storefront. Defaults to the name on your account.

publishedboolean

Whether the reply is visible on the storefront. Omit to leave it as it is.

metadataobject

Replaces the reply's metadata wholesale. Omit to leave it alone.

Request
curl \
  -X PATCH \
  "https://api.cascade.dev/reviews/550e8400-e29b-41d4-a716-446655440000/response" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "body": "string",
  "responderName": "string",
  "published": true,
  "metadata": "..."
}'
Response
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "reviewId": "550e8400-e29b-41d4-a716-446655440000",
  "body": "string",
  "responderName": "string",
  "published": true,
  "metadata": "...",
  "createdAt": "2025-01-15T09:30:00Z",
  "updatedAt": "2025-01-15T09:30:00Z"
}

DELETE /reviews/{id}/response

Delete a review's reply, taking it off the storefront. The review itself is untouched.

Requires the reviews:write permission.

Path Parameters

idstring (uuid)required

The ID of the replied-to review.

Request
curl \
  -X DELETE \
  "https://api.cascade.dev/reviews/550e8400-e29b-41d4-a716-446655440000/response" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY"
Response
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "reviewId": "550e8400-e29b-41d4-a716-446655440000",
  "body": "string",
  "responderName": "string",
  "published": true,
  "metadata": "...",
  "createdAt": "2025-01-15T09:30:00Z",
  "updatedAt": "2025-01-15T09:30:00Z"
}