> ## Documentation Index
> Fetch the complete documentation index at: https://docs.omnicommerce.sg/llms.txt
> Use this file to discover all available pages before exploring further.

# Review webhooks

> Marketplace product review lifecycle events.

Review events are sent when OmniCommerce stores a marketplace product review,
when tracked review content changes, or when the review status changes. An
unchanged resync does not send another event. There is no `review.replied`
event: a reply, solicitation, or Seller Center handoff is `review.status.changed`.

A store's first review import is a backfill and sends no events. Later syncs
send `review.created` for reviews that are new to OmniCommerce.

Shopee and Lazada do not push reviews. OmniCommerce polls connected Shopee and
Lazada stores for new reviews once a day (09:00 Asia/Singapore), and a seller
can sync a store at any time. Events arrive when that sync stores the review.

These are OmniCommerce subscription events. They are not inbound marketplace
pushes.

<Warning>
  Review events use the original event envelope. Use `eventId` and `eventType`;
  `schemaVersion`, `subject`, and `resourceVersion` are not present. Buyer names
  and the raw marketplace payload are omitted.
</Warning>

## Events

| Event | Semantics |
| - | - |
| `review.created` | Snapshot the first time a review row is saved. `changedFields` is empty. |
| `review.updated` | Rating, comment, seller reply, product link, or other tracked content changes without a status change. |
| `review.status.changed` | Status changes. This event wins when status and content change together. |

`previousStatus` is null on creation and the stored status before the write on
later events. `changedFields` lists the tracked fields that changed.

`productId` is null when the marketplace item is not linked to a catalog
product. A later sync that stores a product link emits `review.updated`. A
read-time match that does not change the stored product id does not emit.

## Envelope

| Field | Type | Meaning |
| - | - | - |
| `eventId` | string | Stable recipient idempotency key |
| `eventType` | string | One of the review events above |
| `organizationId` | string | Tenant boundary |
| `reviewId` | string | OmniCommerce review ID |
| `productId` | string or null | Linked catalog product, when one is stored |
| `previousStatus` | string or null | Status before this write; null on creation |
| `changedFields` | string array | Tracked fields that changed; empty for creation |
| `occurredAt` | ISO timestamp | Time of this write |
| `source` | string, optional | Internal workflow provenance |
| `data.review` | object | Review snapshot without buyer name or raw data |

## Example

```json theme={null}
{
  "eventId": "evt_review_1",
  "eventType": "review.created",
  "organizationId": "org_123",
  "reviewId": "6d8c2c2e-2d4e-4c1a-9e2b-1a2b3c4d5e6f",
  "productId": "8b1e0a4c-1c2d-4e5f-a6b7-c8d9e0f1a2b3",
  "previousStatus": null,
  "changedFields": [],
  "occurredAt": "2026-09-29T04:00:00.000Z",
  "data": {
    "review": {
      "id": "6d8c2c2e-2d4e-4c1a-9e2b-1a2b3c4d5e6f",
      "organizationId": "org_123",
      "platform": "shopee",
      "accountId": "shop_1",
      "productId": "8b1e0a4c-1c2d-4e5f-a6b7-c8d9e0f1a2b3",
      "orderId": null,
      "externalItemId": "12345",
      "externalReviewId": "comment_1",
      "externalOrderId": null,
      "kind": "product_review",
      "status": "open",
      "rating": 5,
      "comment": "Great quality.",
      "sellerReply": null,
      "canReply": true,
      "reviewedAt": "2026-09-29T03:00:00.000Z"
    }
  }
}
```
