Skip to main content

SKU lifecycle

Every SKU carries a LifecycleState that controls whether the SKU is operational — i.e. whether items, tags, and order lines can be created against it. The state is a string on the SKU ("Draft", "Active", "Clearance", "EOL", "Discontinued").

States and transitions

FromAllowed transitionsNotes
(create)ActiveDefault when LifecycleState is omitted. Pass "Draft" explicitly for staged setup.
DraftActive, DiscontinuedDraft SKUs can be fully configured (including prices) but are not operational.
ActiveClearance, EOL, DiscontinuedThe normal trading state.
ClearanceActive (rollback), EOL, DiscontinuedFully operational; the one state with a rollback path.
EOLDiscontinuedTerminal markdown — no rollback to Active/Clearance.
DiscontinuedDraftAdmin only, via POST api/skus/relaunch/{id}.

A same-state "transition" is an allowed no-op (the SKU's EntityVersionNo is not bumped for it).

How transitions are requested — and how rejections behave

  • Single update (updatesku): set LifecycleState on the update DTO. A disallowed transition still returns HTTP 200 — the response carries a LifecycleTransitionRejected cascading-update marker and the state is unchanged, but every other field change in the same request commits. Check the response, not just the status code (see Errors & response conventions).
  • Bulk upsert (BulkUpsert): a disallowed transition fails that row (per-row Failed status); the rest of the batch proceeds.

The operational lock

A SKU is operational when its state is not Draft and not Discontinued. Non-operational SKUs block:

OperationBehaviour when the SKU is non-operational
Create item (single)400 validation failure
Bulk item createPer-row failure
Auto-create on tag scanSilent skip — the unknown tag is simply not turned into an item
Tag generation / reservation400
New order linesOrder create → 400. Existing order lines referencing the SKU keep working.

Per-state extras:

  • Draft — price edits are allowed (stage your pricing before activation); items/tags/order lines are blocked.
  • Discontinued — price edits are blocked too (reverted with an InvalidOperation error).
  • Clearance / EOL — fully operational at the API level; the states are informational for downstream processes.
  • Deleting a SKU is not lifecycle-gated — only blocked while items still reference it.
Legacy data

A SKU whose stored state is null or unparseable (pre-lifecycle data) is treated as Draft by the transition guard but as operational by the lock — two deliberate defensive defaults so legacy SKUs keep working while their first explicit transition is validated as if from Draft.

Price changes are audited

Price updates through updatesku stamp PriceEffectiveFrom and append a SkuPriceHistory row automatically — see the price-history reference endpoints for the audit trail.

Retail vs Asset

SKU pricing (UnitCost = supplier cost, RetailPrice = RRP, SalePrice = promotional price) is the retail pricing model. Asset-management tenants track per-item cost on the item itself instead — see the Item lifecycle page.