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_countandrating_average - Sites for turning reviews on or off per storefront
- Customers for banning and shadowbanning authors
Endpoints
- List Reviews -
GET /api/v1/reviews/ - Get Review -
GET /api/v1/reviews/{review_id}/ - Hide Review -
POST /api/v1/reviews/{review_id}/hide/ - Show Review -
POST /api/v1/reviews/{review_id}/unhide/
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
statusispaidorfulfilled. Apendingorder 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 |