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_countand
rating_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
statusispaidor
fulfilled. 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.
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.
A server run with EASEL_REVIEWS=false has no reviews at all. Every
endpoint on this page then returns 404 Not Found.
List Reviews
List the store's reviews, newest first.
Endpoint: GET /api/v1/reviews/
Permission Required: 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 |
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, 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,
"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, 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}/
Permission Required: 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/
Permission Required: 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/
Permission Required: 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.
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 |
created_at |
string | ISO 8601 timestamp |
updated_at |
string | ISO 8601 timestamp of the author's last edit |