Reviews

These endpoints are called from a shopper's browser, so they take your publishable key rather than a secret one. Anything specific to one customer also takes a signed email and timestamp: see Identifying the customer for how to produce the signature.

GET /widgets/reviews/media

Get paginated photos and videos from published reviews, either for one product or, with no product slug, from across the whole store

Query Parameters

apiPublishableKeystringrequired

Your organization's publishable key, from Settings, API keys.

productSlugstring

Slug of the product whose photos and videos to show. Leave it out for a wall of media from across the whole store.

limitnumber

How many media items to return. A review's own photos and videos are never split across pages, so a page can come back a little over this.

cursorstring

The nextCursor from the previous page.

minRatinginteger

Show only media from reviews rated this many stars or higher.

Request
curl \
  "https://api.cascade.dev/widgets/reviews/media?apiPublishableKey=pk_YOUR_PUBLISHABLE_KEY"
Response
{
  "media": [
    {
      "url": "string",
      "contentType": "string",
      "review": {
        "id": "...",
        "rating": "...",
        "title": "...",
        "excerpt": "...",
        "reviewerName": "...",
        "verifiedBuyer": "...",
        "createdAt": "..."
      },
      "product": {
        "slug": "...",
        "title": "...",
        "url": "..."
      }
    }
  ],
  "nextCursor": "string"
}

POST /widgets/reviews/{id}/vote

Vote on whether a review was helpful

Path Parameters

idstring (uuid)required

The ID of the review being voted on.

Query Parameters

apiPublishableKeystringrequired

Your organization's publishable key, from Settings, API keys.

Body Parameters

helpfulbooleanrequired

True marks the review helpful, false marks it not helpful.

voterTokenstringrequired

Random id identifying the visitor's browser. Voting again with the same token replaces the earlier vote.

Request
curl \
  -X POST \
  "https://api.cascade.dev/widgets/reviews/550e8400-e29b-41d4-a716-446655440000/vote?apiPublishableKey=pk_YOUR_PUBLISHABLE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "helpful": true,
  "voterToken": "string"
}'
Response
{
  "reviewId": "550e8400-e29b-41d4-a716-446655440000",
  "helpful": true,
  "helpfulCount": 0,
  "notHelpfulCount": 0
}

GET /widgets/reviews

Get paginated published reviews, either for one product or, with no product slug, from across the whole store

Query Parameters

apiPublishableKeystringrequired

Your organization's publishable key, from Settings, API keys.

productSlugstring

Slug of the product whose reviews to list. Leave it out to list published reviews from across the whole store, which is what a store-wide carousel shows.

limitnumber

How many reviews to return.

cursorstring

The nextCursor from the previous page.

sortnewest | highest | lowest | helpful

Order of the review list: newest first, highest or lowest rating first, or most helpful votes first. Defaults to newest for one product, and to highest across the whole store.

ratinginteger

Show only reviews with this star rating. The rating breakdown still covers them all.

minRatinginteger

Show only reviews rated this many stars or higher. The rating breakdown covers them all.

voterTokenstring

The visitor's vote token, used to mark the reviews they have already voted on.

Request
curl \
  "https://api.cascade.dev/widgets/reviews?apiPublishableKey=pk_YOUR_PUBLISHABLE_KEY"
Response
{
  "product": {
    "title": "string",
    "imageUrl": "string",
    "averageRating": 0,
    "totalReviews": 0,
    "ratingBreakdown": "..."
  },
  "summary": {
    "text": "string",
    "themes": [
      {
        "label": "...",
        "sentiment": "...",
        "reviewCount": "..."
      }
    ],
    "language": "string",
    "reviewCount": 0,
    "generatedAt": "string"
  },
  "reviewAnswers": {
    "enabled": true,
    "suggestedQuestions": ["string"]
  },
  "questions": [
    {
      "id": "string",
      "label": "string",
      "type": "scale",
      "required": true,
      "steps": 0,
      "lowLabel": "string",
      "highLabel": "string",
      "middleLabel": "string",
      "multiple": true,
      "options": ["..."]
    }
  ],
  "questionSummary": [
    {
      "id": "string",
      "label": "string",
      "type": "scale",
      "answered": 0,
      "averageStep": 0,
      "steps": 0,
      "lowLabel": "string",
      "highLabel": "string",
      "middleLabel": "string",
      "options": ["..."]
    }
  ],
  "reviews": [
    {
      "id": "string",
      "rating": 0,
      "title": "string",
      "body": "string",
      "createdAt": "string",
      "verifiedBuyer": true,
      "files": ["..."],
      "helpfulCount": 0,
      "notHelpfulCount": 0,
      "viewerVote": true,
      "response": {
        "body": "...",
        "responderName": "...",
        "createdAt": "..."
      },
      "answers": ["..."],
      "customer": {
        "firstName": "...",
        "lastInitial": "...",
        "country": "..."
      },
      "product": {
        "slug": "...",
        "title": "...",
        "url": "..."
      }
    }
  ],
  "nextCursor": "string"
}

POST /widgets/reviews

Submit a review of a product from the storefront. The review goes into moderation like any other: published in the answer says whether it is live already, which only happens when the store auto-publishes reviews at that rating. Reviews sent this way are never marked as verified buyers, because nothing proves the person bought the product. Send the customer trio for a signed-in shopper, and the reviewer's email for a guest. It is rate limited per IP address.

Query Parameters

apiPublishableKeystringrequired

Your organization's publishable key, from Settings, API keys.

customerEmailstring (email)

The signed-in shopper's address. Leave it out for a shopper who is not signed in.

timestampstring

The Unix seconds the signature was made at. Required with customerEmail.

signaturestring

The HMAC of the email and timestamp. Required with customerEmail.

Body Parameters

productSlugstringrequired

Slug of the product being reviewed.

ratingintegerrequired

The star rating, from 1 to 5.

titlestring | null

The review's headline.

bodystring | null

The review itself.

reviewerNamestring | null

The reviewer's name. Only the first name and the last initial are ever shown, the same as every other review.

emailstring (email)

The reviewer's email address. It is never shown on the storefront: it identifies the reviewer for moderation, and stops the same person reviewing one product twice. Ignored when the shopper is signed in, because the signed email is used instead.

fileKeysstring[]

Keys from POST /widgets/reviews/upload-url for the photos and videos to attach, up to five.

renderedAtnumber

Unix time in milliseconds when the form was opened, used to measure time to submit. A review that comes back instantly is flagged for a person to look at.

honeypotFilledboolean

True when the form's hidden trap field was filled in, which only a bot does.

answersobject[]

Answers to the extra questions this product's form asked, from questions on GET /widgets/reviews. Every question marked required has to be answered.

Request
curl \
  -X POST \
  "https://api.cascade.dev/widgets/reviews?apiPublishableKey=pk_YOUR_PUBLISHABLE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "productSlug": "string",
  "rating": 0,
  "title": "string",
  "body": "string",
  "reviewerName": "string",
  "email": "[email protected]",
  "fileKeys": [
    "string"
  ],
  "renderedAt": 0,
  "honeypotFilled": true,
  "answers": [
    {
      "questionId": "550e8400-e29b-41d4-a716-446655440000",
      "value": {
        "step": "..."
      }
    }
  ]
}'
Response
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "published": true
}

POST /widgets/reviews/upload-url

Get a short-lived link for uploading one photo or video to attach to a storefront review. PUT the file's bytes to uploadUrl, then send key in the review's fileKeys. It is rate limited per IP address.

Query Parameters

apiPublishableKeystringrequired

Your organization's publishable key, from Settings, API keys.

Body Parameters

fileNamestringrequired

The file's name, kept for the moderation view.

contentTypeimage/jpeg | image/png | image/gif | image/webp | video/mp4 | video/quicktime | video/webmrequired

The file's MIME type. Photos and videos only.

sizeBytesnumberrequired

The file's size in bytes.

Request
curl \
  -X POST \
  "https://api.cascade.dev/widgets/reviews/upload-url?apiPublishableKey=pk_YOUR_PUBLISHABLE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "fileName": "string",
  "contentType": "image/jpeg",
  "sizeBytes": 0
}'
Response
{
  "key": "string",
  "uploadUrl": "string",
  "expiresAt": "2025-01-15T09:30:00Z"
}