fulkruma.stock.adjusted.v1

Fires every time a stock level changes — every POST /api/v1/stock/adjust, whatever its reason (a refund restock or an import included: they go through the same call). This is the highest-volume event Fulkruma emits; back-pressure your handler accordingly.

The payload carries the signed delta, the reason code, and the post-mutation quantityAfter so consumers can sync state without a separate read.

When it fires

Inside the same Prisma transaction as the underlying StockMovement insert. Exactly one emission per movement ID; retries reuse the same evt_….

Reasons that fire this event:

  • manual_adjust — merchant-initiated correction.
  • initial_stock — onboarding seed.
  • transfer_in / transfer_out — inter-warehouse movement.
  • damaged / returned_to_supplier — write-offs.
  • refund_restock — refund through Plugipay restored quantity.
  • import — bulk import.

Payload

{
  "id": "evt_01HXAB7K3M9N2P5QRS8TVWXY3Z",
  "type": "fulkruma.stock.adjusted.v1",
  "occurredAt": "2026-05-12T10:42:00.123Z",
  "accountId": "acc_01HX...",
  "data": {
    "variantId": "var_01HX...",
    "warehouseId": "wh_01HX...",
    "delta": -3,
    "reason": "damaged",
    "quantityAfter": 39,
    "movementId": "mv_01HX..."
  }
}

delta is signed: negative for decrement, positive for increment. quantityAfter is the post-mutation on-hand level; treat it as authoritative.

Handler examples

// Node
if (event.type === 'fulkruma.stock.adjusted.v1') {
  const { variantId, warehouseId, delta, reason, quantityAfter } = event.data;
  await inventory.upsertLevel(variantId, warehouseId, quantityAfter);
  if (reason === 'damaged' || reason === 'returned_to_supplier') {
    await analytics.track('stock_loss', { variantId, delta });
  }
}
# Python
if event["type"] == "fulkruma.stock.adjusted.v1":
    d = event["data"]
    inventory.upsert_level(d["variantId"], d["warehouseId"], d["quantityAfter"])
    if d["reason"] in ("damaged", "returned_to_supplier"):
        analytics.track("stock_loss", variant=d["variantId"], delta=d["delta"])
// Go
if event.Type == "fulkruma.stock.adjusted.v1" {
    var d struct {
        VariantID, WarehouseID, Reason, MovementID string
        Delta, QuantityAfter                       int
    }
    _ = json.Unmarshal(event.Data, &d)
    inventory.Upsert(ctx, d.VariantID, d.WarehouseID, d.QuantityAfter)
}

What to do

  • Mirror the level into your own inventory store, keyed by (variantId, warehouseId).
  • For low-stock alerts, subscribe to fulkruma.stock.low.v1 instead of comparing quantityAfter yourself.
  • Reconcile against Fulkruma's movements log at end-of-day — the movementId in the payload joins straight to that table.

Common pitfalls

  • Recomputing the level from delta. Use quantityAfter directly. Out-of-order delivery can make a delta-based replay drift.
  • Volume. A merchant fulfilling 1000 orders a day can fire 2-3000 stock events. Queue your handler; don't process synchronously.
  • Treating damaged as fraud-positive. It's just write-offs — routine inventory hygiene. Cross-reference with audit-log to see who triggered it.
  • Missing the movement ID. movementId is the join key to the immutable movements audit table — capture it.

fulkruma.stock.low.v1 fires right after this event when the adjustment takes the level below the variant's lowStockThreshold.

Next