Product Life Cycle

Product Life Cycle

PromoStandards defines only two product states: sellable and closeout. This is insufficient for real-world product management — there’s no way to represent products that are incomplete (missing images or pricing) or permanently discontinued.

PSRESTful extends this with a full 4-status life cycle: draft, active, closeout, and discontinued.


Status Definitions

StatusDescriptionPromoStandards Equivalent
draftProduct is incomplete — missing images (primary_image_url is empty) or has no pricing (list_price is 0 or null). Not ready to sell.(none)
activeProduct is complete and available for sale.Sellable
closeoutProduct is being phased out, often at discounted prices.Closeout
discontinuedProduct is permanently removed from the catalog. No longer available for sale.(none)

Why We Added draft

When products are first ingested from suppliers, they may be incomplete. A product is automatically classified as draft when:

  • list_price is 0 or null
  • It has no primary image (primary_image_url is empty)

Draft products are not ready for customer-facing catalogs. This prevents showing products with $0 prices or missing images to end customers.


Why We Added discontinued

closeout in PromoStandards implies temporary clearance — products being sold off at discounted prices. But there’s no way to mark a product as permanently gone.

When a supplier stops making a product, distributors need to know so they can:

  • Remove it from their storefronts
  • Stop syncing inventory and pricing for it
  • Avoid showing stale products to customers

discontinued fills this gap — it’s a terminal state meaning “this product will not come back.”


How Status is Computed

Product status is determined by the following logic:

  1. If is_closeout is truecloseout
  2. If missing primary_image_url or list_price is null/0draft
  3. Otherwise → active

discontinued is typically set explicitly via admin action. However, it is also auto-computed in trivial cases: when a product’s status is closeout and inventory is 0 across every part, the product is automatically marked as discontinued.


Life Cycle Diagram

┌───────┐       ┌────────┐       ┌───────────┐       ┌──────────────┐
│ draft │──────▶│ active │──────▶│ closeout  │──────▶│ discontinued │
└───────┘       └────────┘       └───────────┘       └──────────────┘
                    │                                        ▲
                    │                                        │
                    └────────────────────────────────────────┘
  • draft → active: Product becomes complete (has pricing and images)
  • active → closeout: Product is being phased out at discounted prices
  • active → discontinued: Product is permanently removed from the catalog
  • closeout → discontinued: Auto-computed when inventory reaches 0 across all parts

Where Status Appears

Extra APIs (v1 & v2)

The status field is included in all product responses from both /extra/v1/products and /extra/v2/products.

You can filter products by status using the query parameter:

GET /extra/v2/products?status=active
  • v1 uses snake_case field names
  • v2 uses camelCase field names

Product Search in PromoSync

The search form includes a “By Status” dropdown filter (replacing the old “Is Closeout” boolean filter).

Filter options: Any, Active, Draft, Closeout, Discontinued

The default filter is Active.

Filter Products modal with "By Status" dropdown

Search results display color-coded status badges:

StatusBadge Color
ActiveGreen
DraftGrey
CloseoutYellow
DiscontinuedRed

Product search results showing status badges per product row

Product Detail in PromoSync

The product detail page displays the status badge next to the Product ID.

Product detail page showing "Active" badge next to Product ID

Inventory & Pricing Sync in PromoSync

Products with status == discontinued (stored as the psrestful.status Shopify metafield) are automatically skipped during inventory and pricing sync updates.

This prevents wasting API calls and avoids updating data for products that will never be sold again.


Backward Compatibility

The legacy is_closeout boolean field is maintained via dual-write sync:

Status set tois_closeout value
draftfalse
activefalse
closeouttrue
discontinuedtrue

Existing integrations using is_closeout continue to work without modification.