Skip to content
Webhooks

Events

How to register an endpoint, verify deliveries, and read each event.

There are 39 events across 6 categories. Each delivery's JSON body is the event's model, with no shared envelope.

Configure the endpoint

Register an endpoint with POST /v1/webhooks/endpoints. On creation, a webhook.endpoint.test event is sent to the URL, and the endpoint is saved only if it returns 2xx.

RequirementValue
URLHTTPS, public, up to 2048 characters. It can't resolve to a private or local network.
UniquenessOne URL per store (and per seller, when the token belongs to a seller)
Successful responseAny 2xx
Timeout15 seconds

Delivery headers

HeaderContent
X-Ecomiq-EventEvent type, such as catalog.product.created
X-Ecomiq-DeliveryDelivery UUID
X-Ecomiq-TimestampAttempt time in Unix seconds
X-Ecomiq-Signaturesha256=<hmac>, when the endpoint has a secret

Verify the signature

With a secret configured, each delivery carries the HMAC-SHA256 of the raw body as lowercase hex. Compute it over the body exactly as received, before parsing JSON, and discard the event if it doesn't match.

import { createHmac, timingSafeEqual } from "node:crypto"

export function isValidSignature(rawBody: string, header: string, secret: string) {
  const expected = createHmac("sha256", secret).update(rawBody).digest("hex")
  const received = header.replace(/^sha256=/, "")

  const a = Buffer.from(expected, "hex")
  const b = Buffer.from(received, "hex")

  return a.length === b.length && timingSafeEqual(a, b)
}

Additional authentication

With auth, each delivery includes credentials in Authorization. With headers, you add fixed headers.

auth.typeauth.config
basicUsername and Password
bearerToken
oAuth2Public HTTPS TokenUrl, ClientId, and ClientSecret; optional Scope and TokenProperty (defaults to access_token)

Delivery and retries

Return 2xx within 15 seconds and process afterwards. Any other status or a timeout is retried with the same X-Ecomiq-Delivery, so an event can arrive more than once: process it idempotently.

Each successful response resets the failure counter. After 10 consecutive failures the endpoint is paused; fix the receiver and call POST /v1/webhooks/endpoints/{id}/enable.

To resend a failed delivery, call POST /v1/webhooks/deliveries/{id}/retry. The resend keeps the body and carries a new X-Ecomiq-Delivery.

Available events

Catalog

EventModel
catalog.product.createdProductChangedWebhookModel
catalog.product.updatedProductChangedWebhookModel
catalog.product.deletedProductDeletedWebhookModel
catalog.product.status_changedProductStatusChangedWebhookModel
catalog.stock.changedStockChangedWebhookModel
catalog.inventory.batch_processedInventoryBatchProcessedWebhookModel
catalog.price.changedPriceChangedWebhookModel
catalog.brand.createdBrandWebhookModel
catalog.brand.updatedBrandWebhookModel
catalog.brand.deletedBrandDeletedWebhookModel
catalog.category.createdCategoryWebhookModel
catalog.category.updatedCategoryWebhookModel
catalog.category.deletedCategoryDeletedWebhookModel
catalog.collection.createdCollectionWebhookModel
catalog.collection.updatedCollectionWebhookModel
catalog.collection.deletedCollectionDeletedWebhookModel

Channels

EventModel
channel.listing.publishedListingPublishedWebhookModel
channel.listing.price_changedListingPriceChangedWebhookModel
channel.createdChannelCreatedWebhookModel
channel.sales.enabledChannelStateWebhookModel
channel.deletedChannelDeletedWebhookModel

Operations

EventModel
operation.finishedOperationWebhookModel

Customers

EventModel
customer.createdCustomerWebhookModel

Carts

EventModel
cart.createdCartCreatedWebhookModel
cart.updatedCartUpdatedWebhookModel
cart.completedCartCompletedWebhookModel
cart.item_addedCartItemWebhookModel
cart.item_removedCartItemWebhookModel

Orders

EventModel
order.createdOrderWebhookModel
order.confirmedOrderWebhookModel
order.invoicedOrderWebhookModel
order.in_progressOrderWebhookModel
order.ready_to_pick_upOrderWebhookModel
order.in_transitOrderWebhookModel
order.deliveredOrderWebhookModel
order.cancelledOrderWebhookModel
order.returnedOrderWebhookModel
order.closedOrderWebhookModel
order.invalidatedOrderWebhookModel

Payload fields

Fields use camelCase. IDs are strings: store them as they are, without converting them to numbers.

ProductChangedWebhookModel

Events: catalog.product.created · catalog.product.updated

FieldJSON typeNullableDescription
tenantIdstringNoTenant identifier
storeIdstringNoStore identifier
sellerIdstringYesIdentifier of the seller that owns the product
productIdstringNoProduct identifier
productobjectNoProduct payload
occurredOnstring (date-time)NoEvent occurrence date
targetChannelIdsstring[]NoChannels targeted by the product event
changeTypestringNoWhether the change was created or updated

ProductDeletedWebhookModel

Events: catalog.product.deleted

FieldJSON typeNullableDescription
productIdstringNoProduct identifier
tenantIdstringNoTenant identifier
storeIdstringNoStore identifier
sellerIdstringNoSeller identifier
occurredOnstring (date-time)NoEvent occurrence date

ProductStatusChangedWebhookModel

Events: catalog.product.status_changed

FieldJSON typeNullableDescription
tenantIdstringNoTenant identifier
storeIdstringNoStore identifier
productIdstringNoProduct identifier
sellerIdstringNoSeller identifier
isActivebooleanNoWhether the product is active
occurredOnstring (date-time)NoEvent occurrence date

StockChangedWebhookModel

Events: catalog.stock.changed

FieldJSON typeNullableDescription
tenantIdstringNoTenant identifier
storeIdstringNoStore identifier
productIdstringNoProduct identifier
variantIdstringNoVariant identifier
locationIdstringNoLocation identifier
availableQuantityintegerNoAvailable stock quantity
occurredOnstring (date-time)NoEvent occurrence date

InventoryBatchProcessedWebhookModel

Events: catalog.inventory.batch_processed

FieldJSON typeNullableDescription
tenantIdstringNoTenant identifier
storeIdstringNoStore identifier
modestringNoBatch adjustment mode
adjustmentsCountintegerNoNumber of adjusted inventory lines
productsCountintegerNoNumber of affected products
variantsCountintegerNoNumber of affected variants
locationsCountintegerNoNumber of affected locations
linesarrayNoAdjusted inventory lines
occurredOnstring (date-time)NoEvent occurrence date

PriceChangedWebhookModel

Events: catalog.price.changed

FieldJSON typeNullableDescription
tenantIdstringNoTenant identifier
storeIdstringNoStore identifier
productIdstringNoProduct identifier
sellerIdstringNoSeller identifier
pricenumber (decimal)NoCurrent product price
compareAtPricenumber (decimal)YesOriginal comparison price
currencystringNoCurrency code
occurredOnstring (date-time)NoEvent occurrence date

BrandWebhookModel

Events: catalog.brand.created · catalog.brand.updated

FieldJSON typeNullableDescription
brandIdstringNoBrand identifier
tenantIdstringNoTenant identifier
storeIdstringNoStore identifier
namestringNoBrand name
slugstringNoBrand slug
isActivebooleanYesWhether the brand is active
occurredOnstring (date-time)NoEvent occurrence date

BrandDeletedWebhookModel

Events: catalog.brand.deleted

FieldJSON typeNullableDescription
brandIdstringNoBrand identifier
tenantIdstringNoTenant identifier
storeIdstringNoStore identifier
occurredOnstring (date-time)NoEvent occurrence date

CategoryWebhookModel

Events: catalog.category.created · catalog.category.updated

FieldJSON typeNullableDescription
categoryIdstringNoCategory identifier
tenantIdstringNoTenant identifier
storeIdstringNoStore identifier
namestringNoCategory name
slugstringNoCategory slug
parentIdstringYesParent category identifier
isActivebooleanYesWhether the category is active
occurredOnstring (date-time)NoEvent occurrence date

CategoryDeletedWebhookModel

Events: catalog.category.deleted

FieldJSON typeNullableDescription
categoryIdstringNoCategory identifier
tenantIdstringNoTenant identifier
storeIdstringNoStore identifier
occurredOnstring (date-time)NoEvent occurrence date

CollectionWebhookModel

Events: catalog.collection.created · catalog.collection.updated

FieldJSON typeNullableDescription
collectionIdstringNoCollection identifier
tenantIdstringNoTenant identifier
storeIdstringNoStore identifier
namestringNoCollection name
slugstringNoCollection slug
descriptionstringYesCollection description
statusstringNoCollection status
typestringNoCollection type
dynamicOperatorstringNoDynamic rule operator
validFromstring (date-time)YesCollection start date
validTostring (date-time)YesCollection end date
imageUrlstringYesCollection image URL
occurredOnstring (date-time)NoEvent occurrence date

CollectionDeletedWebhookModel

Events: catalog.collection.deleted

FieldJSON typeNullableDescription
collectionIdstringNoCollection identifier
tenantIdstringNoTenant identifier
storeIdstringNoStore identifier
occurredOnstring (date-time)NoEvent occurrence date

ListingPublishedWebhookModel

Events: channel.listing.published

FieldJSON typeNullableDescription
listingIdstringNoListing identifier
channelIdstringNoChannel identifier
productIdstringNoProduct identifier
externalIdstringNoExternal listing identifier
tenantIdstringNoTenant identifier
storeIdstringNoStore identifier
sellerIdstringNoSeller identifier
occurredOnstring (date-time)NoEvent occurrence date

ListingPriceChangedWebhookModel

Events: channel.listing.price_changed

FieldJSON typeNullableDescription
listingIdstringNoListing identifier
tenantIdstringNoTenant identifier
storeIdstringNoStore identifier
sellerIdstringNoSeller identifier
channelIdstringNoChannel identifier
productIdstringNoProduct identifier
externalIdstringYesExternal listing identifier
oldPricenumber (decimal)NoPrevious listing price
newPricenumber (decimal)NoNew listing price
occurredOnstring (date-time)NoEvent occurrence date

ChannelCreatedWebhookModel

Events: channel.created

FieldJSON typeNullableDescription
channelIdstringNoChannel identifier
tenantIdstringNoTenant identifier
storeIdstringNoStore identifier
sellerIdstringYesSeller identifier
namestringNoChannel name
integrationIdstringNoProvider identifier
channelTypestringNoChannel type
isPrincipalbooleanNoWhether the channel is the principal channel
occurredOnstring (date-time)NoEvent occurrence date

ChannelStateWebhookModel

Events: channel.sales.enabled

FieldJSON typeNullableDescription
channelIdstringNoChannel identifier
tenantIdstringNoTenant identifier
storeIdstringNoStore identifier
sellerIdstringYesSeller identifier
occurredOnstring (date-time)NoEvent occurrence date

ChannelDeletedWebhookModel

Events: channel.deleted

FieldJSON typeNullableDescription
channelIdstringNoChannel identifier
tenantIdstringNoTenant identifier
storeIdstringNoStore identifier
sellerIdstringYesSeller identifier
connectionIdstringNoConnection identifier
providerIdstringNoProvider identifier
occurredOnstring (date-time)NoEvent occurrence date

OperationWebhookModel

Events: operation.finished

FieldJSON typeNullableDescription
idstringNoOperation identifier
typestringNoOperation type
resourcestringNoResource
statusstringNoTerminal status
totalRowsintegerNoTotal rows
succeededRowsintegerNoSuccessful rows
failedRowsintegerNoFailed rows
completedOnstring (date-time)NoCompletion date

CustomerWebhookModel

Events: customer.created

FieldJSON typeNullableDescription
tenantIdstringNoTenant identifier
storeIdstringNoStore identifier
customerIdstringNoCustomer identifier
emailstringYesCustomer email
firstNamestringYesCustomer first name
lastNamestringYesCustomer last name
customerTypestringNoCustomer type
customerStatusstringNoCustomer status
occurredOnstring (date-time)NoEvent occurrence date

CartCreatedWebhookModel

Events: cart.created

FieldJSON typeNullableDescription
cartIdstringNoCart identifier
tenantIdstringNoTenant identifier
storeIdstringNoStore identifier
currencyCodestringNoCurrency code
createdBystring (uuid)NoActor identifier
occurredOnstring (date-time)NoEvent occurrence date

CartUpdatedWebhookModel

Events: cart.updated

FieldJSON typeNullableDescription
cartIdstringNoCart identifier
tenantIdstringNoTenant identifier
storeIdstringNoStore identifier
updatedBystring (uuid)NoActor identifier
occurredOnstring (date-time)NoEvent occurrence date

CartCompletedWebhookModel

Events: cart.completed

FieldJSON typeNullableDescription
cartIdstringNoCart identifier
tenantIdstringNoTenant identifier
storeIdstringNoStore identifier
totalAmountnumber (decimal)NoCart total amount
currencyCodestringNoCurrency code
completedBystring (uuid)NoActor identifier
occurredOnstring (date-time)NoEvent occurrence date

CartItemWebhookModel — cart.item_added

Events: cart.item_added

FieldJSON typeNullableDescription
cartIdstringNoCart identifier
tenantIdstringNoTenant identifier
storeIdstringNoStore identifier
cartItemIdstringNoCart item identifier
productIdstringNoProduct identifier
variantIdstringNoVariant identifier
quantityintegerNoQuantity added
unitPricenumber (decimal)NoUnit price
actorIdstring (uuid)YesActor identifier
occurredOnstring (date-time)NoEvent occurrence date

CartItemWebhookModel — cart.item_removed

Events: cart.item_removed

FieldJSON typeNullableDescription
cartIdstringNoCart identifier
tenantIdstringNoTenant identifier
storeIdstringNoStore identifier
cartItemIdstringNoCart item identifier
productIdstringNoProduct identifier
variantIdstringNoVariant identifier
quantityintegerYesAlways null when an item is removed
unitPricenumber (decimal)YesAlways null when an item is removed
actorIdstring (uuid)YesActor identifier
occurredOnstring (date-time)NoEvent occurrence date

OrderWebhookModel

Events: order.created · order.confirmed · order.invoiced · order.in_progress · order.ready_to_pick_up · order.in_transit · order.delivered · order.cancelled · order.returned · order.closed · order.invalidated

FieldJSON typeNullableDescription
orderIdstringNoOrder identifier
tenantIdstringNoTenant identifier
storeIdstringNoStore identifier
sellerIdstringYesIdentifier of the seller that owns the order
customerIdstringYesCustomer identifier
orderNumberstringNoOrder number
orderGroupstringYesOrder group identifier
statestringNoCurrent order lifecycle state
fulfillmentStatusstringNoCurrent fulfillment status
returnStatusstringNoCurrent return status
currencyCodestringNoCurrency code
subTotalnumber (decimal)NoOrder subtotal
shippingnumber (decimal)NoShipping amount
taxnumber (decimal)NoTax amount
totalnumber (decimal)NoOrder total
emailstringYesCustomer email
firstNamestringYesCustomer first name
lastNamestringYesCustomer last name
cancelReasonstringYesCancellation reason
trackingCodestringYesTracking number
trackingUrlstringYesTracking URL
carrierNamestringYesCarrier name
orderDatestring (date-time)NoOrder date
occurredOnstring (date-time)NoEvent occurrence date

Last updated:

On this page