409, a deleted message, and the two realtime connection shapes.
Every call here acts on a signed-in shopper’s own data, so it pairs an API key with the shopper’s
session token in xAuthToken. Workflow Examples has the client setup, and
Storefront Checkout covers minting that
session token. One shopper — Jane Doe, customer 9489529e-69b0-4e84-bea7-62c499085bd9 — and one
product, the Samsung Galaxy Watch 6 (0186665f-…, variant e98631a9-…), carry throughout.
Wishlist, review, and messaging writes are browser-origin storefront writes, so the publishable
client covers them; the shopper’s
xAuthToken is what proves ownership. Moderating reviews and
replying from the store side happen in the merchant admin and are not API actions.Wishlist
The shopper is not ready to buy, and saves the Watch for later. Wishlists are always customer-scoped, so every call carriescustomer_id and the matching xAuthToken.
1. Adding to the wishlist
addToWishlist saves a variant and returns the refreshed wishlist (201 Created). Its items carry
product_price, the price quoted at the time of saving — a field the cart’s items do not have.
Response
A variant can be saved once per customer. Adding the same variant again returns
409 Conflict
({ "error": { "code": "conflict", "message": "Item already exists in wishlist" } }) rather than
creating a duplicate, which makes the 409 itself a reliable “already saved” signal.2. Reading the wishlist
getWishlist lists the customer’s saved items in the same item shape as the add response.
customer_id is required, as anonymous wishlists are not supported.
Response
3. Moving a saved item to the cart (atomic)
The shopper decides to buy.moveWishlistToCart is one atomic step: it validates stock, adds the
item to the cart or merges it with an existing line, removes it from the wishlist, and returns the
refreshed cart. The response echoes removed_wishlist_item_id to identify the saved item that is
gone, and the returned cart item carries a new id, being a cart row rather than the wishlist row.
Response
4. Removing a saved item
A shopper discarding a saved item instead reachesremoveFromWishlist, which deletes it by id. The
customer_id query param is required, which is what scopes the delete to its owner.
Response
Reviews
The Watch has arrived and the shopper wants to review it. Reviews start hidden and become public only once the merchant approves them.5. Submitting a review (starts pending)
submitReview creates the review with status: "pending", and it appears in public listings only
after the merchant approves it in their admin. An order_id belonging to the shopper flags the
review verified_purchase: true.
Response
6. The duplicate review → 409 Conflict
A shopper holds only one non-rejected review per product, so a second review from Jane for the same
Watch returns 409. The resolution is editing the existing review rather than retrying the submit.
Response (409)
7. Listing approved reviews (public, with summary)
Once the merchant approves the first review,listReviews backs the product page’s review section.
On a publishable key it returns only approved reviews and always includes a summary block —
average rating plus star distribution. This is public catalog data, so no customer token is involved.
Response
8. Marking a review helpful
Upvotes let a product page surface the reviews shoppers found useful. Only approved reviews accept votes, and there is no built-in de-duplication, so per-shopper voting state belongs in your own UI.Response
A shopper can remove their own review with
storefront.reviews.deleteReview({ id, xAuthToken: session.access_token }) — it returns
{ "success": true, "message": "Review deleted" }. Deleting someone else’s review returns 403.Messaging
The shopper opens a support thread about the order, and it stays live so the store’s replies arrive without polling.9. Starting a conversation
createConversation opens a thread and posts the shopper’s first message in one call. thread_type
classifies the inquiry (general, order_inquiry, product_inquiry, support, complaint,
delivery, return, refund, technical). A customer_id comes with the matching xAuthToken.
Response
10. Sending a follow-up message
sendMessage appends to the thread just opened, with the text in message. The token must own the
thread; otherwise the call returns 403.
Response
11. Listing threads and reading the conversation
listThreads backs the shopper’s inbox, filtered by customer_id, with pinned threads first;
getThreadMessages loads one conversation’s messages, oldest-first by default.
Response
Response
12. Editing or deleting a message
A shopper can revise or retract a message they sent. Both calls require a secret key and so run server-side.editMessage rewrites the content and stamps is_edited: true plus edited_at;
deleteMessage soft-deletes — the row stays, marked is_deleted and excluded from the default
message list — and returns the deleted_at timestamp.
Response
Response
13. Marking the thread read
Opening the conversation clears the shopper’s unread state.Response
14. Streaming replies in real time
ThesubscribeToThread helper opens a WebSocket to the thread, delivering the store’s replies as
they are sent rather than on a polling interval. The same call covers a shopper who signed in through
Galactic Core and one who signed in through your own identity provider, and it pulls in no extra
packages: it uses the platform WebSocket, available in browsers, Deno, Bun, and Node 22+.
externalAuth in place of authToken; everything else is identical:
A connection managed directly, without the helper, is a WebSocket to
GET /v1/messaging/threads/{id}/subscribe carrying ?api_key= and either ?auth_token= or
?external_auth= in the URL, since browsers cannot set request headers on a WebSocket. The server
pushes one JSON frame per new message:
{ "type": "message.created", "payload": { "thread_id", "message" } }. The text frame ping keeps
an idle connection alive, and the server replies pong.Customer authentication covers bringing your
own identity provider.What’s next
- The shopper arrived from a storefront checkout, which the wishlist, reviews, and support thread sit around.
- A returning shopper can track orders and lodge a return, often
opening a
return-type thread from the same inbox. - Search & Discovery captures the
add_to_wishlistevent that put the Watch on the wishlist to begin with. - Wishlist, reviews, and messaging carry over to a multi-merchant storefront — see the Marketplace split checkout and unified shopper profile.

