Applies to the catalog search index (store_product).
What’s new
Sale prices now expire automatically. When you set a sale on a SKU, you give it a deactivation date; on that date the platform removes the sale from the storefront search results on its own, you no longer need to delete the sale price manually to make a storefront revert to its regular price. A background job (the “sweeper”) runs on a fixed schedule, finds every sale whose deactivation date has arrived, removes it from pricing, and refreshes the affected products in search so shoppers see the correct price.
How to schedule a sale
Set sale prices through the pricing API exactly as before. Each sale price carries two dates:
Field
Meaning
activationDate
The day the sale is intended to begin.
deactivationDate
The day the sale ends. On this date the sweeper removes it.
You do not need to take any action to end a sale. Set the deactivationDate when you create or update the sale, and the platform handles the rest.
Key rule: dates are evaluated in your configured timezone
Expiry is keyed to the calendar date in the timezone from your tenant timezone configuration (configurations/timezone), not UTC. A sale with deactivationDate = today is removed during today’s sweeps in that local calendar; a sale dated for tomorrow stays live until after your local day rolls over. The same tenant timezone drives the storefront read path and search indexing, so search, storefront, and cart evaluate product date windows against the same day boundary.
The timezone must be configured tenant-wide and enabled. Expiry reads a single tenant-level timezone record — one that applies to the whole tenant, not a per-site override. If your tenant has any of the following, the platform falls back to the service default zone (UTC) and sales will expire at UTC midnight instead of your local midnight:
no timezone configured, or
a timezone set only per-site (a record scoped to specific site IDs rather than tenant-wide), or
a tenant-wide record that is disabled.
To get local-timezone expiry, ensure a tenant-wide, enabled timezone configuration is set to your intended zone (e.g. America/Denver). The configuration is:
Field
Required value
timezone
your IANA zone id, e.g. America/Denver
enabled
true
scope
tenant-wide (no site IDs)
One timezone per tenant. Expiry applies a single tenant-level timezone to all of the tenant’s sales. A tenant operating across multiple timezones cannot currently have per-site expiry boundaries.
When changes take effect
There are two independent mechanisms, and it’s important to understand which one applies:
1. Direct pricing changes take effect immediately. Any create, update, or delete you make through the pricing API is reflected in search right away — you do not wait for the scheduled sweep. This includes:
Creating a new sale price (with any future deactivation date).
Changing a sale price value (dates unchanged).
Extending or shortening a deactivation date.
Clearing sale prices (setting salePrices to an empty array) — the sale drops from search immediately.
Deleting a SKU’s pricing entirely.
2. Scheduled expiry is handled by the sweeper. The sweeper’s only job is to remove sales whose deactivation date has arrived without you having to touch them. It runs every 30 minutes. In the worst case a sale ends up to ~30 minutes after the local date boundary; if you need a precise cutover, note that the effective moment is “the first sweep on or after local midnight in your tenant’s configured timezone” (or UTC midnight if no tenant-wide, enabled timezone is set — see the Key rule above).
What a shopper sees when a sale ends
When a sale is removed, the effective price falls back automatically:
If the SKU has a list price, the shopper sees the list price and onSale becomes false.
If the SKU has no list price but has an MSRP, the shopper sees the MSRP.
List price takes precedence over MSRP when both exist.
A sale is only shown as “on sale” when the sale price is actually lower than the list price. If a sale price is mistakenly set equal to or higher than the list price, the item is not flagged as on sale.
First run after this release (one-time backfill)
The first time the sweeper runs after this feature is deployed, it looks back over a 90-day window and cleans up any sales that already expired within that window but were never removed. This is a one-time catch-up so the index starts in a consistent state.
What you need to do: Nothing. But be aware that shortly after go-live, any sales that expired in the last ~90 days but were still lingering on the storefront will drop off as part of this catch-up. If you have sales that expired long ago (more than 90 days) and are still showing, let us know — those fall outside the automatic backfill window and may need a manual cleanup.
The look-back window is configurable per environment if a longer catch-up is needed for the initial run.
Known limitations - please read
These are current, intentional constraints of this release. Plan your merchandising around them.
Product SKUs only. Automatic sale expiry applies to product SKUs. Sales on service, warranty, and protection-plan SKUs are not currently swept by the scheduler. If you use timed sales on those SKU types, you must end them manually via the pricing API. (Confirm intended scope with the catalog team before relying on this behavior.)
Sale-only SKUs don’t appear in product search. A SKU that has a sale price but no list price and no MSRP does not appear in the store_product index at all — before, during, or after the sale. This is by design; a product needs a regular price to be listed.
SKUs with no pricing are skipped. A product with no pricing set is safely ignored by the sweeper (no errors, no index changes).
Renamed or deleted SKUs. If a SKU is renamed or removed, any leftover sale rows tied to its old identifier are still swept on their scheduled deactivation date. Sales dated far in the future will correctly remain until that date arrives.
Quick reference
You want to…
Do this
Start a sale
Set a sale price with the desired activationDate / deactivationDate.
End a sale on a specific day
Set deactivationDate to that day (evaluated in your tenant timezone). No follow-up action needed.
End a sale right now
Update salePrices to an empty array, or delete the sale price.
Extend a sale
Update deactivationDate to a later date.
Change the sale amount
Update the sale price value; effective immediately.
Questions
For scheduling questions, timezone/cutover planning, or to request a longer initial catch-up window, please contact support@upstartcommerce.com.
Applies to the catalog search index (
store_product).What’s new
Sale prices now expire automatically. When you set a sale on a SKU, you give it a deactivation date; on that date the platform removes the sale from the storefront search results on its own, you no longer need to delete the sale price manually to make a storefront revert to its regular price. A background job (the “sweeper”) runs on a fixed schedule, finds every sale whose deactivation date has arrived, removes it from pricing, and refreshes the affected products in search so shoppers see the correct price.
How to schedule a sale
Set sale prices through the pricing API exactly as before. Each sale price carries two dates:
activationDatedeactivationDateYou do not need to take any action to end a sale. Set the
deactivationDatewhen you create or update the sale, and the platform handles the rest.Key rule: dates are evaluated in your configured timezone
Expiry is keyed to the calendar date in the timezone from your tenant timezone configuration (
configurations/timezone), not UTC. A sale withdeactivationDate = todayis removed during today’s sweeps in that local calendar; a sale dated for tomorrow stays live until after your local day rolls over. The same tenant timezone drives the storefront read path and search indexing, so search, storefront, and cart evaluate product date windows against the same day boundary.The timezone must be configured tenant-wide and enabled. Expiry reads a single tenant-level timezone record — one that applies to the whole tenant, not a per-site override. If your tenant has any of the following, the platform falls back to the service default zone (UTC) and sales will expire at UTC midnight instead of your local midnight:
To get local-timezone expiry, ensure a tenant-wide, enabled timezone configuration is set to your intended zone (e.g.
America/Denver). The configuration is:America/DenvertrueWhen changes take effect
There are two independent mechanisms, and it’s important to understand which one applies:
1. Direct pricing changes take effect immediately. Any create, update, or delete you make through the pricing API is reflected in search right away — you do not wait for the scheduled sweep. This includes:
salePricesto an empty array) — the sale drops from search immediately.2. Scheduled expiry is handled by the sweeper. The sweeper’s only job is to remove sales whose deactivation date has arrived without you having to touch them. It runs every 30 minutes. In the worst case a sale ends up to ~30 minutes after the local date boundary; if you need a precise cutover, note that the effective moment is “the first sweep on or after local midnight in your tenant’s configured timezone” (or UTC midnight if no tenant-wide, enabled timezone is set — see the Key rule above).
What a shopper sees when a sale ends
When a sale is removed, the effective price falls back automatically:
onSalebecomesfalse.A sale is only shown as “on sale” when the sale price is actually lower than the list price. If a sale price is mistakenly set equal to or higher than the list price, the item is not flagged as on sale.
First run after this release (one-time backfill)
The first time the sweeper runs after this feature is deployed, it looks back over a 90-day window and cleans up any sales that already expired within that window but were never removed. This is a one-time catch-up so the index starts in a consistent state.
What you need to do: Nothing. But be aware that shortly after go-live, any sales that expired in the last ~90 days but were still lingering on the storefront will drop off as part of this catch-up. If you have sales that expired long ago (more than 90 days) and are still showing, let us know — those fall outside the automatic backfill window and may need a manual cleanup.
The look-back window is configurable per environment if a longer catch-up is needed for the initial run.
Known limitations - please read
These are current, intentional constraints of this release. Plan your merchandising around them.
Product SKUs only. Automatic sale expiry applies to product SKUs. Sales on service, warranty, and protection-plan SKUs are not currently swept by the scheduler. If you use timed sales on those SKU types, you must end them manually via the pricing API. (Confirm intended scope with the catalog team before relying on this behavior.)
Sale-only SKUs don’t appear in product search. A SKU that has a sale price but no list price and no MSRP does not appear in the
store_productindex at all — before, during, or after the sale. This is by design; a product needs a regular price to be listed.SKUs with no pricing are skipped. A product with no pricing set is safely ignored by the sweeper (no errors, no index changes).
Renamed or deleted SKUs. If a SKU is renamed or removed, any leftover sale rows tied to its old identifier are still swept on their scheduled deactivation date. Sales dated far in the future will correctly remain until that date arrives.
Quick reference
activationDate/deactivationDate.deactivationDateto that day (evaluated in your tenant timezone). No follow-up action needed.salePricesto an empty array, or delete the sale price.deactivationDateto a later date.Questions
For scheduling questions, timezone/cutover planning, or to request a longer initial catch-up window, please contact support@upstartcommerce.com.
0 Votes
0 Comments
Login or Sign up to post a comment