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 emit inventory.low_stock — you'd compute it yourself from /v1/inventory/stock polls; 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 costCents is set. Most merchants don't set cost prices initially. Don't divide by it.
  • Treating priceCents: 0 as "free". Math.max(0, productPrice + priceDelta) is what produces this number — a negative priceDelta greater 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

Next