List review queue
The store’s moderation queue: reviews held undecided, reviews already rejected, and the flags saying why each was held. This is the ONLY place on this API where a review that is not publicly visible appears. The two read_reviews lists serve approved rows only, in the SQL itself, so a held review is absent from them rather than merely unsorted, and no query parameter there could ever reach one. THESE ARE WORDS THE MERCHANT HAS NOT PUBLISHED, attached to a shopper’s chosen display name, alongside a machine’s judgement about them the shopper has never seen. Treat the body of a held review as unpublished content: do not syndicate it, do not show it to other customers, and do not assume rejecting it was a mistake. THERE IS NO DEFAULT FILTER. Omitting ?status= returns every status, which is what makes this usable for mirroring moderation state; pass ?status=pending for the queue proper. Only pending, approved and rejected are accepted, and anything else is a 400 rather than an empty page, so you cannot mistake a typo for an empty queue. IT BUYS DISCLOSURE, NOT AUTHORITY. Approving and rejecting is write_reviews, a different grant that this one does not imply and that does not imply this one; a tool that both shows the queue and clears it asks for both. Nothing here deletes a review, because that delete has no restore in any code path. NO MEDIA AND NO PRODUCT TITLE. The only media reader this platform has filters on approved reviews, so a held review’s attachments are unreachable rather than empty, and product_id is flat because filling a nested reference would mean a join that silently drops a held review whose product was deleted, leaving it queued forever and invisible. Resolve the product through the products family. updated_at MEANS “LAST CHANGED”, not “last moderated”: a shopper editing their own review stamps it too.
Authorizations
A secret API key. Publishable keys cannot reach this API. A key may carry an expiry, and an expired key is refused exactly like an unknown one, with a 401 that names no reason; check the key's expires_at in the dashboard rather than inferring it from a response. When a merchant rolls a key's secret they choose a grace window of up to 3 days, and for its duration BOTH the new secret and the one it replaced authenticate, so an integration moves over on its own deploy schedule instead of at the instant the button is pressed. Move before the window closes: after it, the old secret is refused. Nothing else about this contract moves with a roll. The key keeps its id and its scopes, so the only thing an integration updates is the credential itself.
Query Parameters
Rows per page. Out of range is a 400 rather than a silent clamp, so a client asking for more than 100 learns it did not get it.
1 <= x <= 100The next_cursor from the previous page. Opaque: decode nothing from it and construct nothing by hand, since its encoding is not part of this contract. Omit it to read the first page.
