Reviews
Shoppers' product reviews: moderate them, reply in the shop's name, or delete them.
Reach them through admin.reviews. Reading needs the reviews:read scope, changing them reviews:write. Reviews need a plan with reviews (403 plan_required).
List reviews
admin.reviews.list(query?: ListQuery & { status?: string; rating?: number; productId?: number }): Promise<CursorPage<AdminReview>>
One page of the shop's reviews, newest first, or oldest change first with updatedSince. Read the next page with meta.nextCursor as cursor. Scope: reviews:read.
Parameters
| Parameter |
Type |
|
query |
object |
The query fields below, by name. |
Query fields
| Parameter | Type | Description |
|---|
status | any | |
rating | integer | At least 1. At most 5. |
productId | integer | |
limit | integer | At least 1. At most 100. Default 50. |
cursor | string | meta.nextCursor (or the cursor in links.next) of the previous page. At most 1000 characters. |
updatedSince | string (date-time) | Records changed at or after this time (ISO 8601, any offset or Z), oldest change first, for incremental sync. |
Returns
A CursorPage<AdminReview>:
| Field | Type | Description |
|---|
links | object | |
links.first | null | |
links.last | null | |
links.prev | string (uri) or null | |
links.next | string (uri) or null | |
meta | object | |
meta.path | string (uri) | |
meta.perPage | integer | |
meta.nextCursor | string or null | |
meta.prevCursor | string or null | |
data | array of AdminReview | |
data[].id | integer | |
data[].productId | integer or null | |
data[].customerId | integer or null | |
data[].orderId | integer or null | |
data[].rating | integer | At least 1. At most 5. |
data[].title | string or null | |
data[].body | string or null | |
data[].authorName | string or null | |
data[].verifiedBuyer | boolean | |
data[].locale | string or null | |
data[].status | string | One of pending_approval, published, rejected, flagged. |
data[].reply | object or null | |
data[].reply.body | string | |
data[].reply.updatedAt | string (date-time) or null | |
data[].publishedAt | string (date-time) or null | |
data[].createdAt | string (date-time) or null | |
data[].updatedAt | string (date-time) or null | |
Errors
| Status | When |
|---|
401 | invalid_api_key: no active Admin key in Authorization: Bearer. |
403 | admin_key_in_browser (an Origin header was sent), ip_not_allowed, plan_required(the shop's plan lacks the Integration API, or the feature the endpoint needs), orinsufficient_scope. |
422 | Validation errors ({ message, errors }), or an idempotency refusal(idempotency_key_reused, idempotency_key_invalid). |
429 | Rate limited. |
Example
const { data } = await admin.reviews.list({ rating: 1, productId: 12 });
Iterate over every review
admin.reviews.all(query?: ListQuery & { status?: string; rating?: number; productId?: number }): AsyncGenerator<AdminReview, void, undefined>
Every review matching the query, one at a time, fetching the next page as you read. It takes the same query as list, without cursor. Scope: reviews:read.
Returns
An async iterable of AdminReview, each:
| Field | Type | Description |
|---|
[].id | integer | |
[].productId | integer or null | |
[].customerId | integer or null | |
[].orderId | integer or null | |
[].rating | integer | At least 1. At most 5. |
[].title | string or null | |
[].body | string or null | |
[].authorName | string or null | |
[].verifiedBuyer | boolean | |
[].locale | string or null | |
[].status | string | One of pending_approval, published, rejected, flagged. |
[].reply | object or null | |
[].reply.body | string | |
[].reply.updatedAt | string (date-time) or null | |
[].publishedAt | string (date-time) or null | |
[].createdAt | string (date-time) or null | |
[].updatedAt | string (date-time) or null | |
Example
for await (const review of admin.reviews.all({ status: 'pending_approval' })) {
await admin.reviews.setStatus(review.id, 'published');
await admin.reviews.reply(review.id, 'Thank you for your review!');
}
Get a review
admin.reviews.get(id: number): Promise<AdminReview>
One review by its id, with the shop's reply. Scope: reviews:read.
Parameters
| Parameter |
Type |
|
id |
number |
The review's id. |
Returns
An AdminReview:
| Field | Type | Description |
|---|
id | integer | |
productId | integer or null | |
customerId | integer or null | |
orderId | integer or null | |
rating | integer | At least 1. At most 5. |
title | string or null | |
body | string or null | |
authorName | string or null | |
verifiedBuyer | boolean | |
locale | string or null | |
status | string | One of pending_approval, published, rejected, flagged. |
reply | object or null | |
reply.body | string | |
reply.updatedAt | string (date-time) or null | |
publishedAt | string (date-time) or null | |
createdAt | string (date-time) or null | |
updatedAt | string (date-time) or null | |
Errors
| Status | When |
|---|
401 | invalid_api_key: no active Admin key in Authorization: Bearer. |
403 | admin_key_in_browser (an Origin header was sent), ip_not_allowed, plan_required(the shop's plan lacks the Integration API, or the feature the endpoint needs), orinsufficient_scope. |
404 | not_found: the shop has no such record. |
429 | Rate limited. |
Moderate a review
admin.reviews.setStatus(id: number, status: AdminReview['status'], options?: RequestOptions): Promise<AdminReview>
Publishes, rejects, flags or holds a review; the product's rating follows. Scope: reviews:write.
Parameters
| Parameter |
Type |
|
id |
number |
The review's id. |
status |
string |
pending_approval, published, rejected or flagged. |
options |
RequestOptions |
idempotencyKey, signal and headers (see retries). |
Returns
The moderated AdminReview:
| Field | Type | Description |
|---|
id | integer | |
productId | integer or null | |
customerId | integer or null | |
orderId | integer or null | |
rating | integer | At least 1. At most 5. |
title | string or null | |
body | string or null | |
authorName | string or null | |
verifiedBuyer | boolean | |
locale | string or null | |
status | string | One of pending_approval, published, rejected, flagged. |
reply | object or null | |
reply.body | string | |
reply.updatedAt | string (date-time) or null | |
publishedAt | string (date-time) or null | |
createdAt | string (date-time) or null | |
updatedAt | string (date-time) or null | |
Errors
| Status | When |
|---|
401 | invalid_api_key: no active Admin key in Authorization: Bearer. |
403 | admin_key_in_browser (an Origin header was sent), ip_not_allowed, plan_required(the shop's plan lacks the Integration API, or the feature the endpoint needs), orinsufficient_scope. |
404 | not_found: the shop has no such record. |
409 | idempotency_in_progress: a request with this Idempotency-Key is still running. Retry with the same key after Retry-After seconds; the first answer is then replayed. |
422 | Validation errors ({ message, errors }), or an idempotency refusal(idempotency_key_reused, idempotency_key_invalid). |
429 | Rate limited. |
Example
await admin.reviews.setStatus(41, 'rejected');
Reply to a review
admin.reviews.reply(id: number, body: string, options?: RequestOptions): Promise<AdminReview>
Writes or rewrites the shop's public reply. It also touches the review's updatedAt. Scope: reviews:write.
Parameters
| Parameter |
Type |
|
id |
number |
The review's id. |
body |
string |
The reply, at most the platform's review body length. |
options |
RequestOptions |
idempotencyKey, signal and headers (see retries). |
Returns
The AdminReview, with its reply:
| Field | Type | Description |
|---|
id | integer | |
productId | integer or null | |
customerId | integer or null | |
orderId | integer or null | |
rating | integer | At least 1. At most 5. |
title | string or null | |
body | string or null | |
authorName | string or null | |
verifiedBuyer | boolean | |
locale | string or null | |
status | string | One of pending_approval, published, rejected, flagged. |
reply | object or null | |
reply.body | string | |
reply.updatedAt | string (date-time) or null | |
publishedAt | string (date-time) or null | |
createdAt | string (date-time) or null | |
updatedAt | string (date-time) or null | |
Errors
| Status | When |
|---|
401 | invalid_api_key: no active Admin key in Authorization: Bearer. |
403 | admin_key_in_browser (an Origin header was sent), ip_not_allowed, plan_required(the shop's plan lacks the Integration API, or the feature the endpoint needs), orinsufficient_scope. |
404 | not_found: the shop has no such record. |
409 | idempotency_in_progress: a request with this Idempotency-Key is still running. Retry with the same key after Retry-After seconds; the first answer is then replayed. |
422 | Validation errors ({ message, errors }), or an idempotency refusal(idempotency_key_reused, idempotency_key_invalid). |
429 | Rate limited. |
Example
await admin.reviews.reply(
41,
'Sorry to hear that. We have sent you a replacement.',
);
Delete the shop's reply
admin.reviews.deleteReply(id: number): Promise<AdminReview>
Removes the shop's reply and answers with the review. Scope: reviews:write.
Parameters
| Parameter |
Type |
|
id |
number |
The review's id. |
Returns
The AdminReview, without a reply:
| Field | Type | Description |
|---|
id | integer | |
productId | integer or null | |
customerId | integer or null | |
orderId | integer or null | |
rating | integer | At least 1. At most 5. |
title | string or null | |
body | string or null | |
authorName | string or null | |
verifiedBuyer | boolean | |
locale | string or null | |
status | string | One of pending_approval, published, rejected, flagged. |
reply | object or null | |
reply.body | string | |
reply.updatedAt | string (date-time) or null | |
publishedAt | string (date-time) or null | |
createdAt | string (date-time) or null | |
updatedAt | string (date-time) or null | |
Errors
| Status | When |
|---|
401 | invalid_api_key: no active Admin key in Authorization: Bearer. |
403 | admin_key_in_browser (an Origin header was sent), ip_not_allowed, plan_required(the shop's plan lacks the Integration API, or the feature the endpoint needs), orinsufficient_scope. |
404 | not_found: the shop has no such record. |
409 | idempotency_in_progress: a request with this Idempotency-Key is still running. Retry with the same key after Retry-After seconds; the first answer is then replayed. |
422 | Validation errors ({ message, errors }), or an idempotency refusal(idempotency_key_reused, idempotency_key_invalid). |
429 | Rate limited. |
Delete a review
admin.reviews.delete(id: number): Promise<void>
Deletes the review for good, with its reply. Scope: reviews:write.
Parameters
| Parameter |
Type |
|
id |
number |
The review's id. |
Returns
Nothing.
Errors
| Status | When |
|---|
401 | invalid_api_key: no active Admin key in Authorization: Bearer. |
403 | admin_key_in_browser (an Origin header was sent), ip_not_allowed, plan_required(the shop's plan lacks the Integration API, or the feature the endpoint needs), orinsufficient_scope. |
404 | not_found: the shop has no such record. |
409 | idempotency_in_progress: a request with this Idempotency-Key is still running. Retry with the same key after Retry-After seconds; the first answer is then replayed. |
422 | Validation errors ({ message, errors }), or an idempotency refusal(idempotency_key_reused, idempotency_key_invalid). |
429 | Rate limited. |