storlaunch.variant.created.v1
Fires when a product variant is added via POST /v1/inventory/variants. Variants carry the SKU-level attributes (size, colour, edition) that buyers actually pick at checkout. If you mirror the catalogue, variants are the leaf node of your tree.
When it fires
Once per POST /v1/inventory/variants that returns 201. When the first variant is added to a product, you also receive a sibling storlaunch.product.updated.v1 event (the parent's hasVariants flag flipped).
Payload
The payload is the normalised variant shape with priceCents pre-resolved against the parent product (Storlaunch stores priceDelta; the event carries the absolute price so downstream consumers don't need the parent context):
{
"id": "evt_01HX...",
"type": "storlaunch.variant.created.v1",
"createdAt": "2026-05-13T11:05:00Z",
"accountId": "acc_01HX...",
"data": {
"id": "var_01HX...",
"productId": "prod_01HX...",
"storlaunchProductId": "prod_01HX...",
"sku": "FNN-MED-BLK",
"name": "Medium / Black",
"priceCents": 75000,
"costCents": 32000,
"lowStockThreshold": 10,
"isDefault": false,
"archived": false
}
}
costCents is null if the merchant hasn't set a cost price. lowStockThreshold is null if there's no alert threshold. storlaunchProductId is a duplicate of productId — it exists for Fulkruma compatibility (where the receiver wants the qualified field).
Handler examples
// Node
if (event.type === 'storlaunch.variant.created.v1') {
const v = event.data;
await mirror.variants.create({
id: v.id,
productId: v.productId,
sku: v.sku,
name: v.name,
priceCents: v.priceCents,
});
}
# Python
if event["type"] == "storlaunch.variant.created.v1":
v = event["data"]
mirror.variants.create(id=v["id"], product_id=v["productId"], sku=v.get("sku"), name=v["name"], price_cents=v["priceCents"])
// Go
if event.Type == "storlaunch.variant.created.v1" {
var v storlaunch.Variant
_ = json.Unmarshal(event.Data, &v)
mirror.CreateVariant(ctx, v)
}
What to do
- Insert the variant into your mirror keyed by
id. - If
isDefault: true, mark this as the variant your storefront should show in the default selector. - If
lowStockThreshold > 0, set up the low-stock alert handler (Storlaunch doesn't currently emitinventory.low_stock— you'd compute it yourself from/v1/inventory/stockpolls; see Inventory).
Common pitfalls
- Receiving without the parent. If you process events out-of-order, this event can arrive before you've seen the product's
created.v1. Defensive: upsert the product stub first (or fetch via API) before inserting the variant. - Assuming
costCentsis set. Most merchants don't set cost prices initially. Don't divide by it. - Treating
priceCents: 0as "free".Math.max(0, productPrice + priceDelta)is what produces this number — a negativepriceDeltagreater than the parent's price clamps to 0. Such a config is unusual but possible; either treat 0 as "free" deliberately or reject in your validation.
Related events
storlaunch.variant.updated.v1— subsequent edits.storlaunch.variant.archived.v1— soft-delete.storlaunch.product.updated.v1— emitted alongside this when it's the parent's first variant.