Webhooks
Configuración, entrega y campos de los eventos de webhook.
Puedes suscribirte a 37 eventos en 5 categorías. El cuerpo JSON corresponde al modelo indicado para cada evento; no existe un sobre común.
Configurar el endpoint
Registra un endpoint para la tienda con POST /v1/webhooks/endpoints. La URL debe usar HTTPS, ser pública y no resolver a una red privada o local.
Al crearlo, Ecomiq envía webhook.endpoint.test. El endpoint se guarda solo si esa prueba responde con 2xx antes del límite de 15 segundos.
| Requisito | Valor |
|---|---|
| Esquema | https |
| Longitud máxima | 2048 caracteres |
| Unicidad | La misma URL no puede repetirse en el contexto actual de tienda y vendedor |
| Respuesta correcta | Cualquier 2xx |
| Tiempo límite | 15 segundos |
Cabeceras de entrega
| Cabecera | Contenido |
|---|---|
X-Ecomiq-Event | Tipo de evento, por ejemplo catalog.product.created |
X-Ecomiq-Delivery | Identificador UUID de la entrega |
X-Ecomiq-Timestamp | Momento del intento, en segundos Unix |
X-Ecomiq-Signature | sha256=<hmac>, solo cuando configuras un secreto |
Verificar la firma
Si configuras un secret, Ecomiq firma el cuerpo crudo con HMAC-SHA256 y codifica el resultado en hexadecimal minúscula. Verifica la firma antes de leer el JSON.
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)
}Autenticación adicional
Puedes configurar credenciales para que Ecomiq las incluya en cada envío. También puedes agregar cabeceras fijas con headers.
| Tipo | Configuración requerida |
|---|---|
Basic | Username y Password |
Bearer | Token |
OAuth2 | TokenUrl HTTPS pública, ClientId y ClientSecret |
Entrega y reintentos
La entrega es al menos una vez. Un fallo puede repetir el mismo evento con el mismo X-Ecomiq-Delivery; procesa el evento de forma idempotente y guarda ese identificador después de completar el trabajo.
Una respuesta correcta reinicia el contador de fallos. Tras 10 intentos fallidos consecutivos, Ecomiq pausa el endpoint. Corrige el receptor y llama a POST /v1/webhooks/endpoints/{id}/enable.
Puedes reenviar una entrega fallida con POST /v1/webhooks/deliveries/{id}/retry. El reintento manual conserva el cuerpo y crea un nuevo X-Ecomiq-Delivery.
Eventos disponibles
Catálogo
| Evento | Modelo |
|---|---|
catalog.product.created | ProductChangedWebhookModel |
catalog.product.updated | ProductChangedWebhookModel |
catalog.product.deleted | ProductDeletedWebhookModel |
catalog.product.status_changed | ProductStatusChangedWebhookModel |
catalog.stock.changed | StockChangedWebhookModel |
catalog.inventory.batch_processed | InventoryBatchProcessedWebhookModel |
catalog.price.changed | PriceChangedWebhookModel |
catalog.brand.created | BrandWebhookModel |
catalog.brand.updated | BrandWebhookModel |
catalog.brand.deleted | BrandDeletedWebhookModel |
catalog.category.created | CategoryWebhookModel |
catalog.category.updated | CategoryWebhookModel |
catalog.category.deleted | CategoryDeletedWebhookModel |
catalog.collection.created | CollectionWebhookModel |
catalog.collection.updated | CollectionWebhookModel |
catalog.collection.deleted | CollectionDeletedWebhookModel |
Canales
| Evento | Modelo |
|---|---|
channel.listing.published | ListingPublishedWebhookModel |
channel.listing.price_changed | ListingPriceChangedWebhookModel |
channel.created | ChannelCreatedWebhookModel |
channel.sales.enabled | ChannelStateWebhookModel |
channel.deleted | ChannelDeletedWebhookModel |
Clientes
| Evento | Modelo |
|---|---|
customer.created | CustomerWebhookModel |
Carritos
| Evento | Modelo |
|---|---|
cart.created | CartCreatedWebhookModel |
cart.updated | CartUpdatedWebhookModel |
cart.completed | CartCompletedWebhookModel |
cart.item_added | CartItemWebhookModel |
cart.item_removed | CartItemWebhookModel |
Pedidos
| Evento | Modelo |
|---|---|
order.confirmed | OrderWebhookModel |
order.invoiced | OrderWebhookModel |
order.in_progress | OrderWebhookModel |
order.ready_to_pick_up | OrderWebhookModel |
order.in_transit | OrderWebhookModel |
order.delivered | OrderWebhookModel |
order.cancelled | OrderWebhookModel |
order.returned | OrderWebhookModel |
order.closed | OrderWebhookModel |
order.invalidated | OrderWebhookModel |
Campos del cuerpo
El runtime actual usa nombres PascalCase y serializa los IDs snowflake como números JSON int64. En JavaScript, usa un parser que conserve enteros de 64 bits: Number puede perder precisión.
ProductChangedWebhookModel
Eventos: catalog.product.created · catalog.product.updated
| Campo | Tipo JSON | Puede ser null | Descripción |
|---|---|---|---|
TenantId | integer (int64) | No | Identificador de la organización. |
StoreId | integer (int64) | No | Identificador de la tienda. |
SellerId | integer (int64) | Sí | Identificador del vendedor propietario del producto. |
ProductId | integer (int64) | No | Identificador del producto. |
Product | object | No | Datos del producto. |
OccurredOn | string (date-time) | No | Fecha y hora en que ocurrió el evento. |
TargetChannelIds | integer[] (int64) | No | Identificadores de los canales a los que se dirige el evento. |
ChangeType | string | No | Indica si el producto se creó o actualizó. |
ProductDeletedWebhookModel
Eventos: catalog.product.deleted
| Campo | Tipo JSON | Puede ser null | Descripción |
|---|---|---|---|
ProductId | integer (int64) | No | Identificador del producto. |
TenantId | integer (int64) | No | Identificador de la organización. |
StoreId | integer (int64) | No | Identificador de la tienda. |
SellerId | integer (int64) | No | Identificador del vendedor. |
OccurredOn | string (date-time) | No | Fecha y hora en que ocurrió el evento. |
ProductStatusChangedWebhookModel
Eventos: catalog.product.status_changed
| Campo | Tipo JSON | Puede ser null | Descripción |
|---|---|---|---|
TenantId | integer (int64) | No | Identificador de la organización. |
StoreId | integer (int64) | No | Identificador de la tienda. |
ProductId | integer (int64) | No | Identificador del producto. |
SellerId | integer (int64) | No | Identificador del vendedor. |
IsActive | boolean | No | Indica si el producto está activo. |
OccurredOn | string (date-time) | No | Fecha y hora en que ocurrió el evento. |
StockChangedWebhookModel
Eventos: catalog.stock.changed
| Campo | Tipo JSON | Puede ser null | Descripción |
|---|---|---|---|
TenantId | integer (int64) | No | Identificador de la organización. |
StoreId | integer (int64) | No | Identificador de la tienda. |
ProductId | integer (int64) | No | Identificador del producto. |
VariantId | integer (int64) | No | Identificador de la variante. |
LocationId | integer (int64) | No | Identificador de la ubicación. |
AvailableQuantity | integer | No | Cantidad de stock disponible. |
OccurredOn | string (date-time) | No | Fecha y hora en que ocurrió el evento. |
InventoryBatchProcessedWebhookModel
Eventos: catalog.inventory.batch_processed
| Campo | Tipo JSON | Puede ser null | Descripción |
|---|---|---|---|
TenantId | integer (int64) | No | Identificador de la organización. |
StoreId | integer (int64) | No | Identificador de la tienda. |
Mode | string | No | Modo aplicado al lote de ajustes. |
AdjustmentsCount | integer | No | Cantidad de líneas de inventario ajustadas. |
ProductsCount | integer | No | Cantidad de productos afectados. |
VariantsCount | integer | No | Cantidad de variantes afectadas. |
LocationsCount | integer | No | Cantidad de ubicaciones afectadas. |
Lines | array | No | Líneas de inventario ajustadas. |
OccurredOn | string (date-time) | No | Fecha y hora en que ocurrió el evento. |
PriceChangedWebhookModel
Eventos: catalog.price.changed
| Campo | Tipo JSON | Puede ser null | Descripción |
|---|---|---|---|
TenantId | integer (int64) | No | Identificador de la organización. |
StoreId | integer (int64) | No | Identificador de la tienda. |
ProductId | integer (int64) | No | Identificador del producto. |
SellerId | integer (int64) | No | Identificador del vendedor. |
Price | number (decimal) | No | Precio actual del producto. |
CompareAtPrice | number (decimal) | Sí | Precio de comparación original. |
Currency | string | No | Código de moneda. |
OccurredOn | string (date-time) | No | Fecha y hora en que ocurrió el evento. |
BrandWebhookModel
Eventos: catalog.brand.created · catalog.brand.updated
| Campo | Tipo JSON | Puede ser null | Descripción |
|---|---|---|---|
BrandId | integer (int64) | No | Identificador de la marca. |
TenantId | integer (int64) | No | Identificador de la organización. |
StoreId | integer (int64) | No | Identificador de la tienda. |
Name | string | No | Nombre de la marca. |
Slug | string | No | Slug de la marca. |
IsActive | boolean | Sí | Indica si la marca está activa. |
OccurredOn | string (date-time) | No | Fecha y hora en que ocurrió el evento. |
BrandDeletedWebhookModel
Eventos: catalog.brand.deleted
| Campo | Tipo JSON | Puede ser null | Descripción |
|---|---|---|---|
BrandId | integer (int64) | No | Identificador de la marca. |
TenantId | integer (int64) | No | Identificador de la organización. |
StoreId | integer (int64) | No | Identificador de la tienda. |
OccurredOn | string (date-time) | No | Fecha y hora en que ocurrió el evento. |
CategoryWebhookModel
Eventos: catalog.category.created · catalog.category.updated
| Campo | Tipo JSON | Puede ser null | Descripción |
|---|---|---|---|
CategoryId | integer (int64) | No | Identificador de la categoría. |
TenantId | integer (int64) | No | Identificador de la organización. |
StoreId | integer (int64) | No | Identificador de la tienda. |
Name | string | No | Nombre de la categoría. |
Slug | string | No | Slug de la categoría. |
ParentId | integer (int64) | Sí | Identificador de la categoría superior. |
IsActive | boolean | Sí | Indica si la categoría está activa. |
OccurredOn | string (date-time) | No | Fecha y hora en que ocurrió el evento. |
CategoryDeletedWebhookModel
Eventos: catalog.category.deleted
| Campo | Tipo JSON | Puede ser null | Descripción |
|---|---|---|---|
CategoryId | integer (int64) | No | Identificador de la categoría. |
TenantId | integer (int64) | No | Identificador de la organización. |
StoreId | integer (int64) | No | Identificador de la tienda. |
OccurredOn | string (date-time) | No | Fecha y hora en que ocurrió el evento. |
CollectionWebhookModel
Eventos: catalog.collection.created · catalog.collection.updated
| Campo | Tipo JSON | Puede ser null | Descripción |
|---|---|---|---|
CollectionId | integer (int64) | No | Identificador de la colección. |
TenantId | integer (int64) | No | Identificador de la organización. |
StoreId | integer (int64) | No | Identificador de la tienda. |
Name | string | No | Nombre de la colección. |
Slug | string | No | Slug de la colección. |
Description | string | Sí | Descripción de la colección. |
Status | string | No | Estado de la colección. |
Type | string | No | Tipo de colección. |
DynamicOperator | string | No | Operador de las reglas dinámicas. |
ValidFrom | string (date-time) | Sí | Fecha de inicio de la colección. |
ValidTo | string (date-time) | Sí | Fecha de finalización de la colección. |
ImageUrl | string | Sí | URL de la imagen de la colección. |
OccurredOn | string (date-time) | No | Fecha y hora en que ocurrió el evento. |
CollectionDeletedWebhookModel
Eventos: catalog.collection.deleted
| Campo | Tipo JSON | Puede ser null | Descripción |
|---|---|---|---|
CollectionId | integer (int64) | No | Identificador de la colección. |
TenantId | integer (int64) | No | Identificador de la organización. |
StoreId | integer (int64) | No | Identificador de la tienda. |
OccurredOn | string (date-time) | No | Fecha y hora en que ocurrió el evento. |
ListingPublishedWebhookModel
Eventos: channel.listing.published
| Campo | Tipo JSON | Puede ser null | Descripción |
|---|---|---|---|
ListingId | integer (int64) | No | Identificador de la publicación. |
ChannelId | integer (int64) | No | Identificador del canal. |
ProductId | integer (int64) | No | Identificador del producto. |
ExternalId | string | No | Identificador externo de la publicación. |
TenantId | integer (int64) | No | Identificador de la organización. |
StoreId | integer (int64) | No | Identificador de la tienda. |
SellerId | integer (int64) | No | Identificador del vendedor. |
OccurredOn | string (date-time) | No | Fecha y hora en que ocurrió el evento. |
ListingPriceChangedWebhookModel
Eventos: channel.listing.price_changed
| Campo | Tipo JSON | Puede ser null | Descripción |
|---|---|---|---|
ListingId | integer (int64) | No | Identificador de la publicación. |
TenantId | integer (int64) | No | Identificador de la organización. |
StoreId | integer (int64) | No | Identificador de la tienda. |
SellerId | integer (int64) | No | Identificador del vendedor. |
ChannelId | integer (int64) | No | Identificador del canal. |
ProductId | integer (int64) | No | Identificador del producto. |
ExternalId | string | Sí | Identificador externo de la publicación. |
OldPrice | number (decimal) | No | Precio anterior de la publicación. |
NewPrice | number (decimal) | No | Nuevo precio de la publicación. |
OccurredOn | string (date-time) | No | Fecha y hora en que ocurrió el evento. |
ChannelCreatedWebhookModel
Eventos: channel.created
| Campo | Tipo JSON | Puede ser null | Descripción |
|---|---|---|---|
ChannelId | integer (int64) | No | Identificador del canal. |
TenantId | integer (int64) | No | Identificador de la organización. |
StoreId | integer (int64) | No | Identificador de la tienda. |
SellerId | integer (int64) | Sí | Identificador del vendedor. |
Name | string | No | Nombre del canal. |
IntegrationId | string | No | Identificador del proveedor. |
ChannelType | string | No | Tipo de canal. |
IsPrincipal | boolean | No | Indica si es el canal principal. |
OccurredOn | string (date-time) | No | Fecha y hora en que ocurrió el evento. |
ChannelStateWebhookModel
Eventos: channel.sales.enabled
| Campo | Tipo JSON | Puede ser null | Descripción |
|---|---|---|---|
ChannelId | integer (int64) | No | Identificador del canal. |
TenantId | integer (int64) | No | Identificador de la organización. |
StoreId | integer (int64) | No | Identificador de la tienda. |
SellerId | integer (int64) | Sí | Identificador del vendedor. |
OccurredOn | string (date-time) | No | Fecha y hora en que ocurrió el evento. |
ChannelDeletedWebhookModel
Eventos: channel.deleted
| Campo | Tipo JSON | Puede ser null | Descripción |
|---|---|---|---|
ChannelId | integer (int64) | No | Identificador del canal. |
TenantId | integer (int64) | No | Identificador de la organización. |
StoreId | integer (int64) | No | Identificador de la tienda. |
SellerId | integer (int64) | Sí | Identificador del vendedor. |
ConnectionId | integer (int64) | No | Identificador de la conexión. |
ProviderId | string | No | Identificador del proveedor. |
OccurredOn | string (date-time) | No | Fecha y hora en que ocurrió el evento. |
CustomerWebhookModel
Eventos: customer.created
| Campo | Tipo JSON | Puede ser null | Descripción |
|---|---|---|---|
TenantId | integer (int64) | No | Identificador de la organización. |
StoreId | integer (int64) | No | Identificador de la tienda. |
CustomerId | integer (int64) | No | Identificador del cliente. |
Email | string | Sí | Correo electrónico del cliente. |
FirstName | string | Sí | Nombre del cliente. |
LastName | string | Sí | Apellido del cliente. |
CustomerType | string | No | Tipo de cliente. |
CustomerStatus | string | No | Estado del cliente. |
OccurredOn | string (date-time) | No | Fecha y hora en que ocurrió el evento. |
CartCreatedWebhookModel
Eventos: cart.created
| Campo | Tipo JSON | Puede ser null | Descripción |
|---|---|---|---|
CartId | integer (int64) | No | Identificador del carrito. |
TenantId | integer (int64) | No | Identificador de la organización. |
StoreId | integer (int64) | No | Identificador de la tienda. |
CurrencyCode | string | No | Código de moneda. |
CreatedBy | string (uuid) | No | Identificador UUID del actor que creó el carrito. |
OccurredOn | string (date-time) | No | Fecha y hora en que ocurrió el evento. |
CartUpdatedWebhookModel
Eventos: cart.updated
| Campo | Tipo JSON | Puede ser null | Descripción |
|---|---|---|---|
CartId | integer (int64) | No | Identificador del carrito. |
TenantId | integer (int64) | No | Identificador de la organización. |
StoreId | integer (int64) | No | Identificador de la tienda. |
UpdatedBy | string (uuid) | No | Identificador UUID del actor que actualizó el carrito. |
OccurredOn | string (date-time) | No | Fecha y hora en que ocurrió el evento. |
CartCompletedWebhookModel
Eventos: cart.completed
| Campo | Tipo JSON | Puede ser null | Descripción |
|---|---|---|---|
CartId | integer (int64) | No | Identificador del carrito. |
TenantId | integer (int64) | No | Identificador de la organización. |
StoreId | integer (int64) | No | Identificador de la tienda. |
TotalAmount | number (decimal) | No | Importe total del carrito. |
CurrencyCode | string | No | Código de moneda. |
CompletedBy | string (uuid) | No | Identificador UUID del actor que completó el carrito. |
OccurredOn | string (date-time) | No | Fecha y hora en que ocurrió el evento. |
CartItemWebhookModel — cart.item_added
Eventos: cart.item_added
| Campo | Tipo JSON | Puede ser null | Descripción |
|---|---|---|---|
CartId | integer (int64) | No | Identificador del carrito. |
TenantId | integer (int64) | No | Identificador de la organización. |
StoreId | integer (int64) | No | Identificador de la tienda. |
CartItemId | integer (int64) | No | Identificador del artículo del carrito. |
ProductId | integer (int64) | No | Identificador del producto. |
VariantId | integer (int64) | No | Identificador de la variante. |
Quantity | integer | No | Cantidad agregada. |
UnitPrice | number (decimal) | No | Precio unitario. |
ActorId | string (uuid) | Sí | Identificador UUID del actor que ejecutó la operación. |
OccurredOn | string (date-time) | No | Fecha y hora en que ocurrió el evento. |
CartItemWebhookModel — cart.item_removed
Eventos: cart.item_removed
| Campo | Tipo JSON | Puede ser null | Descripción |
|---|---|---|---|
CartId | integer (int64) | No | Identificador del carrito. |
TenantId | integer (int64) | No | Identificador de la organización. |
StoreId | integer (int64) | No | Identificador de la tienda. |
CartItemId | integer (int64) | No | Identificador del artículo del carrito. |
ProductId | integer (int64) | No | Identificador del producto. |
VariantId | integer (int64) | No | Identificador de la variante. |
Quantity | integer | Sí | Siempre es null cuando se retira un artículo. |
UnitPrice | number (decimal) | Sí | Siempre es null cuando se retira un artículo. |
ActorId | string (uuid) | Sí | Identificador UUID del actor que ejecutó la operación. |
OccurredOn | string (date-time) | No | Fecha y hora en que ocurrió el evento. |
OrderWebhookModel
Eventos: 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
| Campo | Tipo JSON | Puede ser null | Descripción |
|---|---|---|---|
OrderId | integer (int64) | No | Identificador del pedido. |
TenantId | integer (int64) | No | Identificador de la organización. |
StoreId | integer (int64) | No | Identificador de la tienda. |
SellerId | integer (int64) | Sí | Identificador del vendedor al que pertenece el pedido. |
CustomerId | integer (int64) | Sí | Identificador del cliente. |
OrderNumber | string | No | Número del pedido. |
OrderGroup | string | Sí | Identificador del grupo de pedidos. |
Status | string | No | Estado anterior conservado por compatibilidad. |
State | string | No | Estado actual del ciclo de vida del pedido. |
FulfillmentStatus | string | No | Estado actual de preparación y entrega. |
ReturnStatus | string | No | Estado actual de la devolución. |
CurrencyCode | string | No | Código de moneda. |
SubTotal | number (decimal) | No | Subtotal del pedido. |
Shipping | number (decimal) | No | Importe del envío. |
Tax | number (decimal) | No | Importe de impuestos. |
Total | number (decimal) | No | Total del pedido. |
Email | string | Sí | Correo electrónico del cliente. |
FirstName | string | Sí | Nombre del cliente. |
LastName | string | Sí | Apellido del cliente. |
CancelReason | string | Sí | Motivo de la cancelación. |
TrackingCode | string | Sí | Número de seguimiento. |
TrackingUrl | string | Sí | URL de seguimiento. |
CarrierName | string | Sí | Nombre del transportista. |
OrderDate | string (date-time) | No | Fecha del pedido. |
OccurredOn | string (date-time) | No | Fecha y hora en que ocurrió el evento. |