Reviews API

Customers who bought a product can rate it from 1 to 5 stars, with an optional title and text. The storefront shows each product’s average and its reviews, newest first, marked as verified purchases. These endpoints let you read reviews and moderate them.

Related resources:

  • Products for each product’s review_count and rating_average
  • Sites for turning reviews on or off per storefront
  • Customers for banning and shadowbanning authors

Endpoints

There is no endpoint to create, edit, or delete a review. Only the customer writes, edits, or deletes their own review, from the storefront.

Who May Review

A customer can review a product when all of these hold:

  • They are logged in to a storefront account, which requires a verified email.
  • The store hasn’t banned them.
  • They bought the product in a paid order: one whose status is paid or fulfilled. A pending order was never paid and doesn’t count.

A refund or a return doesn’t change that. Refunds don’t change an order’s status, so a customer who returned a product can still review it, and refunding them doesn’t hide a review they already wrote. Customers who returned something often write the most useful reviews, and hiding them would suppress the unfavorable ones.

Each customer can review a product once. The review records the variant they bought, which the storefront shows beside it.

Visibility

Every review has a status:

Status Shown on the storefront Counts toward the rating
published To everyone Yes
hidden Not on the product page; its author sees it in their account, marked as hidden with your reason No
shadowbanned Only to its author, who sees it as usual No
banned To no one; its author can’t log in No

A hidden review is hidden whatever its author’s standing. Otherwise the status follows the author: shadowbanned or banned when you shadowbanned or banned them, and published when you lift it.

A product’s review_count and rating_average count only published reviews, and update as soon as a review is posted, edited, deleted, hidden, or shown again, and as soon as you ban, shadowban, or lift either for its author.

Takedowns

Easel hosts what your shoppers publish too, so under the EU Digital Services Act its staff may take a review down that’s illegal or against Easel’s terms (see Moderation). Taking it down sets taken_down_at and hides the review, keeping your reason if you’d already hidden it, or giving it other. Until Easel restores it, Show Review returns 409 Conflict with TAKEN_DOWN. Once restored, taken_down_at goes back to null and the review stays hidden until you show it.

The statement of reasons was emailed to the store’s owners, and the dashboard keeps it under Settings › Activity › Easel decisions. The activity log’s taken_down event, on the store with part review, names the category in reason.

No Deletion

Stores can’t delete reviews, from the API or the dashboard. To take one down, hide it and pick a reason. Hiding keeps the review, its reason, and when it happened, so unfavorable reviews are never removed without a record, as consumer protection rules such as the FTC’s 16 CFR Part 465 and the EU Omnibus Directive expect. You can show a hidden review again at any time.

Reviews are removed only when their author deletes one, or when you delete the customer to erase their personal data, which deletes their reviews too.

Turning Reviews Off

Reviews are on by default. Set a site’s reviews_enabled to false with Update Site to turn them off for that storefront: it then shows no reviews, ratings, or review structured data, and takes no new ones. Its reviews are kept, still listed here, and can still be moderated; turning reviews back on shows them again.


List Reviews

List the store’s reviews, newest first.

Endpoint: GET /api/v1/reviews/

Scope Required: reviews:read

Query Parameters

Parameter Type Description
product string Only reviews of this product public ID
customer string Only reviews by this customer public ID
status string Only reviews with this status: published, hidden, shadowbanned, or banned
after string Cursor for pagination. Review public ID of the last item on the previous page
before string Cursor for pagination. Review public ID of the first item on the current page, for paging back to newer reviews
limit integer Number of reviews to return (default 10, max 100)

Pagination follows the same cursor rules as the product list: pass the id of the last review as after to get the next page, or of the first as before to page back, while has_more is true.

Request

curl -X GET "https://studio.easel.engineering/api/v1/reviews/?product=pro_d0b6fmv28q6vn14peun0&limit=20" \
  -H "Authorization: Bearer your_api_key_here"

Response

Status: 200 OK

{
  "data": [
    {
      "id": "rev_d0b6fmv28q6vn14peur0",
      "product_id": "pro_d0b6fmv28q6vn14peun0",
      "variant_name": "Green / Small",
      "customer_id": "cus_d0b6fmv28q6vn14peung",
      "author_name": "Bob S.",
      "rating": 5,
      "title": "So warm",
      "body": "The softest blanket I own.",
      "verified_purchase": true,
      "status": "published",
      "hidden_at": null,
      "hidden_reason": null,
      "hidden_note": null,
      "taken_down_at": null,
      "created_at": "2026-10-18T12:00:00Z",
      "updated_at": "2026-10-18T12:00:00Z"
    }
  ],
  "has_more": false
}

Error Responses

Invalid query parameter

Status: 400 Bad Request

A malformed after or before, both at once, an unknown status, or a limit over 100 is rejected:

{
  "error": "status must be published, hidden, shadowbanned, or banned",
  "code": "INVALID_FIELD"
}

Product or customer not found

Status: 404 Not Found

{
  "error": "Resource not found",
  "code": "NOT_FOUND"
}

Get Review

Endpoint: GET /api/v1/reviews/{review_id}/

Scope Required: reviews:read

Request

curl -X GET "https://studio.easel.engineering/api/v1/reviews/rev_d0b6fmv28q6vn14peur0/" \
  -H "Authorization: Bearer your_api_key_here"

Response

Status: 200 OK

Returns the Review object.

Error Responses

Review not found

Status: 404 Not Found

{
  "error": "Resource not found",
  "code": "NOT_FOUND"
}

Hide Review

Hide a review from the storefront and take it out of its product’s rating. A reason is required. The optional note is for your team; the author sees only the reason.

Endpoint: POST /api/v1/reviews/{review_id}/hide/

Scope Required: reviews:write

Request Body

Field Type Required Description
reason string Yes spam, offensive, off_topic, personal_info, or other
note string No Up to 1,000 characters

Request

curl -X POST "https://studio.easel.engineering/api/v1/reviews/rev_d0b6fmv28q6vn14peur0/hide/" \
  -H "Authorization: Bearer your_api_key_here" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: unique-request-id-24680" \
  -d '{"reason": "personal_info", "note": "Posted a phone number"}'

Response

Status: 200 OK

Returns the Review object with status hidden. Hiding a review that is already hidden replaces its reason and note.

Error Responses

Missing or unknown reason

Status: 400 Bad Request

{
  "error": "reason is required: spam, offensive, off_topic, personal_info, or other",
  "code": "INVALID_FIELD"
}

Review not found

Status: 404 Not Found


Show Review

Show a hidden review again. It counts toward its product’s rating once more, unless its author is banned or shadowbanned.

Endpoint: POST /api/v1/reviews/{review_id}/unhide/

Scope Required: reviews:write

Request

curl -X POST "https://studio.easel.engineering/api/v1/reviews/rev_d0b6fmv28q6vn14peur0/unhide/" \
  -H "Authorization: Bearer your_api_key_here" \
  -H "Idempotency-Key: unique-request-id-13579"

Response

Status: 200 OK

Returns the Review object.

Error Responses

Easel took the review down

Easel’s staff took the review down as illegal or against Easel’s terms, and its taken_down_at is set (see Takedowns). It stays hidden until Easel restores it.

Status: 409 Conflict

{
  "error": "Easel took this down, so it can't be published or shown until Easel restores it",
  "code": "TAKEN_DOWN"
}

Review Object

Field Type Description
id string Review public ID
product_id string Public ID of the product reviewed
variant_name string Name of the variant the customer bought, or empty when it no longer exists
customer_id string Public ID of the customer who wrote it
author_name string How the storefront credits the author: first name and last initial
rating integer Stars, from 1 to 5
title string Optional title, up to 120 characters
body string Optional text, up to 5,000 characters
verified_purchase boolean Whether the review is backed by a paid order. Always true for reviews posted on the storefront
status string published, hidden, shadowbanned, or banned (see Visibility)
hidden_at string|null When the store hid it
hidden_reason string|null Why: spam, offensive, off_topic, personal_info, or other
hidden_note string|null The store’s note, if any
taken_down_at string|null ISO 8601 timestamp of when Easel took the review down, or null while it hasn’t. Read-only. See Takedowns
created_at string ISO 8601 timestamp
updated_at string ISO 8601 timestamp of the author’s last edit