API Docs

Event catalog

Every webhook event the integration emits, what it means, and the shape of data.object. The envelope wrapping each payload is documented on the Webhooks page.

Subscribing to events

Subscriptions are managed from Custom Integration → Settings → Event subscriptions. The default is the wildcard *: your endpoint receives every event.

  • Tick individual events to allowlist them.
  • Wildcard a namespace with e.g. listing.* (subscribe to all listing events).
  • integration.test_event ignores subscriptions; it's always delivered when fired manually.

Echo-suppression

Don't expect to receive your own writes back

When your integration POSTs an order via /v1/orders, the corresponding order.received webhook is not delivered to your URL. Same for customer.matched: the integration that did the upsert doesn't hear about its own match. This is what stops trivial event-loops between your custom site and WatchTraderHub.

Events triggered elsewhere (other integrations like Shopify or eBay, actions taken in the dashboard) still fire to your URL as normal.

Events

Listing events

listing.published

Fires when the dealer toggles an inventory item ON for the custom channel.

data.object

{
  "id": "24f0ebb1-73d7-4e99-9901-821078594271",
  "object": "listing"
}

listing.updated

Fires when a published listing's data changes (price, photos, watch attributes, ...).

data.object

{
  "id": "24f0ebb1-73d7-4e99-9901-821078594271",
  "object": "listing"
}

data.previous_attributes: Map of changed fields with their previous values, e.g. `{"price": {"amount": 1199000}}`.

listing.unpublished

Fires when the dealer toggles a listing OFF for the custom channel.

data.object

{
  "id": "24f0ebb1-73d7-4e99-9901-821078594271",
  "object": "listing"
}

listing.sold

Fires when a listing transitions to sold (either manually or via order matching).

data.object

{
  "id": "24f0ebb1-73d7-4e99-9901-821078594271",
  "object": "listing"
}

listing.in_stock

Fires when a previously-sold listing returns to active stock (e.g. sale voided).

data.object

{
  "id": "24f0ebb1-73d7-4e99-9901-821078594271",
  "object": "listing"
}

Order events

order.received

Fires when an order is reported through the integration but not yet matched to a listing.

data.object

{
  "id": "d7df4fbe-2c0c-4328-a3b0-a32c68cabd43",
  "object": "order",
  "external_id": "shop-12345",
  "status": "pending",
  "total_amount": 1500000,
  "currency": "USD",
  "buyer": { "name": "Alice", "email": "alice@example.com", "country": "US" },
  "line_items": [{ "sku": "116610LN", "quantity": 1, "unit_amount": 1500000 }],
  "ordered_at": "2026-05-08T08:41:16.345+00:00",
  "created_at": "2026-05-08T08:41:16.770507+00:00"
}

order.fulfilled

Fires when an order is matched to a listing and the dealer marks it fulfilled.

data.object

{
  "id": "d7df4fbe-2c0c-4328-a3b0-a32c68cabd43",
  "object": "order",
  "status": "fulfilled"
}

data.previous_attributes: Always `{ "status": "pending" }`.

order.cancelled

Fires when an order is cancelled via `POST /v1/orders/{id}/cancel`.

data.object

{
  "id": "d7df4fbe-2c0c-4328-a3b0-a32c68cabd43",
  "object": "order",
  "status": "cancelled"
}

data.previous_attributes: Always `{ "status": "<previous>" }`.

Customer events

customer.matched

Fires when a customer upsert matches an existing client row instead of creating one.

data.object

{
  "id": "36f5655d-4c3a-4d58-b8e2-a68edfcda239",
  "object": "customer",
  "external_id": "ext-A1",
  "email": "a1@example.com",
  "name": "Customer A1",
  "phone": "+15551111",
  "matched_existing": true,
  "accepts_marketing": false,
  "created_at": "2026-05-08T08:40:50.417797+00:00"
}

Integration events

integration.test_event

Fires from `POST /v1/test/webhook_ping`. Always delivered regardless of `subscribed_events` filtering.

data.object

{
  "message": "Test event from /v1/test/webhook_ping."
}