The method
A review on a shop's page is worth what a reader can check about it. Every rule below exists so that a reader, or the shop, can say who wrote the words, when, and for which order.
Who is asked
Only a buyer whose payment went through. When an order is delivered, the lab watcher or the shop's operator sends reviewbook the order's Stripe Checkout Session id. reviewbook reads that session from the shop's own Stripe account with a read key, and it goes on only when the session's payment status is paid and its metadata.source is that shop's tag. A session from a sister shop on the same account is refused, so one shop can never ask another shop's buyers.
Asked once
The first request for an order claims it in the store with a single atomic write. A second request for the same order is refused with a 409, whoever sends it and however often. If the mail fails after the claim, the request answers with the link, and the operator pastes it to the buyer by hand; the order is not asked twice.
The link
The link in the email is /r/ followed by a token: the shop's tag and the session id, joined and signed with HMAC-SHA256 under a key only reviewbook holds. Change one character and the form refuses to open. No login, no account and no cookie: the link is the permission, and it opens one form for one order.
What is kept
Six fields: the shop's tag, a SHA-256 hash of the session id, the stars, the words, the name as the buyer gave it, and the time. The session id itself is never stored, and the buyer's email address is read from Stripe to send the request and kept nowhere. Markup is stripped and control characters removed; nothing else in the words is touched. A review runs to 1,200 characters at most, and a longer one is sent back with the words intact so the buyer can shorten it.
Hide, never edit
The shop's desk can hide a review and show it again. There is no edit call in the code, and the desk's one write changes only whether a review is shown. A shop that hides every bad review will have a page a reader learns to discount, which is the shop's choice to make in public.
The snippet
The snippet is a 2 KB script. It reads the shop's feed at /api/reviews/<shop-tag>.json without credentials, builds each entry with textContent, and writes nothing when the shop has no reviews, so an empty book never prints a prompt. Each entry shows its stars, the words, the name if one was given, the date, and the first eight characters of the order's hash, which lets the shop match a review to an order and lets nobody else find the order.
Why there is no average
An average of four reviews moves a full star when the fifth arrives. Printed as a badge, that number tells a reader more about chance than about the shop, and a number with fewer than ten reviews behind it misleads. The snippet prints each review's own stars and never sums them. When a shop has hundreds, the reader can still count.
What reviewbook does not do
It does not reply to reviews, offer anything in exchange for one, or import reviews from another site. Each of those turns a buyer's words into something the shop arranged.
Sending a request by hand
curl -X POST https://reviews.painted.app/api/request \
-H "Authorization: Bearer $REVIEWBOOK_OPS_SECRET" \
-H "content-type: application/json" \
-d '{"shop":"paintedcourse_shop","session_id":"cs_live_..."}'
The answer is {"sent": true}, or {"sent": false, "link": "...", "why": "..."} when mail is not connected for that shop, or a 409 with the reason when the session is unpaid, belongs to another shop, or was already asked.
The seed run
On 13 October 2026 the build ran three requests and three submissions through the same code with Stripe and mail replaced by stand-ins, and printed the feed through the snippet. No buyer was written to. The entries on the home page are that run, and they say so.