product.created
Fired when a new product is created in the store.
Event Structure
{
"event_type": "product.created",
"payload": { ... }
}
Payload
{
"id": "6753a1b2c3d4e5f6a7b8c9d0",
"title": "Classic Cotton T-Shirt",
"handle": "classic-cotton-t-shirt",
"description": "A comfortable 100% cotton t-shirt for everyday wear.",
"store_id": "store_abc123",
"tags": ["clothing", "t-shirt", "cotton"],
"quantity": 150,
"pricing": {
"price": 4500,
"compareAtPrice": 6000
},
"identification": {
"sku": "TSH-CLR-001",
"barcode": "1234567890123"
},
"dimensions": {
"length": 70,
"width": 50,
"height": 2
},
"weight": {
"value": 200,
"unit": "g"
},
"seo": {
"title": "Classic Cotton T-Shirt | My Store",
"description": "Shop the classic cotton t-shirt."
},
"images": [
{
"id": "img_001",
"fileName": "tshirt-front.jpg",
"fileUrl": "https://cdn.example.com/images/tshirt-front.jpg"
}
],
"collections": [
{
"id": "col_001",
"title": "Summer Collection",
"handle": "summer-collection",
"image": {
"id": "img_col_001",
"fileName": "summer.jpg",
"fileUrl": "https://cdn.example.com/images/summer.jpg"
},
"status": "active"
}
],
"options": [
{
"id": "opt_001",
"name": "Color",
"type": "color",
"values": [
{
"id": "val_001",
"label": "Black",
"type": "color",
"value": "Black",
"colorCode": "#000000",
"image": null,
"sortOrder": 0
},
{
"id": "val_002",
"label": "White",
"type": "color",
"value": "White",
"colorCode": "#FFFFFF",
"image": null,
"sortOrder": 1
}
]
},
{
"id": "opt_002",
"name": "Size",
"type": "text",
"values": [
{
"id": "val_003",
"label": "M",
"type": "text",
"value": "M",
"colorCode": null,
"image": null,
"sortOrder": 0
},
{
"id": "val_004",
"label": "L",
"type": "text",
"value": "L",
"colorCode": null,
"image": null,
"sortOrder": 1
}
]
}
],
"variants": [
{
"id": "var_001",
"options": ["val_001", "val_003"],
"images": [
{
"id": "img_002",
"fileName": "tshirt-black-m.jpg",
"fileUrl": "https://cdn.example.com/images/tshirt-black-m.jpg"
}
],
"pricing": {
"price": 4500,
"compareAtPrice": 6000
},
"quantity": 50,
"identification": {
"sku": "TSH-BLK-M",
"barcode": "1234567890124"
},
"dimensions": {
"length": 70,
"width": 50,
"height": 2
},
"weight": {
"value": 200,
"unit": "g"
},
"allowBackorder": false,
"trackQuantity": true
}
],
"createdAt": "2025-12-01T10:30:00.000Z",
"updatedAt": "2025-12-01T10:30:00.000Z"
}
Payload Fields
| Field | Type | Description |
|---|---|---|
id | string | Unique product ID |
title | string | Product title |
handle | string | URL-friendly slug |
description | string | Product description |
store_id | string | Store ID that owns this product |
tags | string[] | Array of product tags |
quantity | number | Total available quantity |
pricing | object | Product pricing info |
pricing.price | number | Price in minor units (e.g. cents) |
pricing.compareAtPrice | number | Compare-at price in minor units |
identification | object | Product identifiers |
identification.sku | string | SKU code |
identification.barcode | string | Barcode value |
dimensions | object | Product dimensions |
dimensions.length | number | Length |
dimensions.width | number | Width |
dimensions.height | number | Height |
weight | object | Product weight |
weight.value | number | Weight value |
weight.unit | string | Weight unit (e.g. g, kg) |
seo | object | SEO metadata |
seo.title | string | SEO title |
seo.description | string | SEO description |
images | array | Product images |
images[].id | string | Image ID |
images[].fileName | string | Image file name |
images[].fileUrl | string | Full image URL |
collections | array | Collections the product belongs to |
collections[].id | string | Collection ID |
collections[].title | string | Collection title |
collections[].handle | string | Collection URL slug |
collections[].image | object | null | Collection image |
collections[].status | string | Collection status |
options | array | Product options (e.g. Color, Size) |
options[].id | string | Option ID |
options[].name | string | Option name |
options[].type | string | Option type |
options[].values | array | Available values for this option |
options[].values[].id | string | Option value ID |
options[].values[].label | string | Display label |
options[].values[].type | string | Value type |
options[].values[].value | string | Raw value |
options[].values[].colorCode | string | null | Hex color code (for color type) |
options[].values[].image | string | null | Image reference (for image swatch type) |
options[].values[].sortOrder | number | Display order |
variants | array | Product variants |
variants[].id | string | Variant ID |
variants[].options | string[] | Array of selected option value IDs |
variants[].images | array | Variant-specific images |
variants[].pricing | object | Variant pricing |
variants[].quantity | number | Variant stock quantity |
variants[].identification | object | Variant SKU and barcode |
variants[].dimensions | object | Variant dimensions |
variants[].weight | object | Variant weight |
variants[].allowBackorder | boolean | Whether backorders are allowed |
variants[].trackQuantity | boolean | Whether inventory is tracked |
createdAt | string | ISO 8601 creation timestamp |
updatedAt | string | ISO 8601 last update timestamp |
Example Handler
app/routes/webhooks.products.tsx
import { authenticate } from "~/qumra.server";
export async function action({ request }: { request: Request }) {
const { payload, topic, storeId } =
await authenticate.admin(request);
if (topic === "product.created") {
console.log(`New product: ${payload.title} (${payload.id})`);
console.log(`Price: ${payload.pricing.price}`);
console.log(`Variants: ${payload.variants.length}`);
// Sync to external system, update search index, etc.
}
return Response.json({ success: true });
}